Skip to content

Commit

Permalink
feat(*PostProcess*): Add *GetResult* aliases
Browse files Browse the repository at this point in the history
  • Loading branch information
bartelink committed Feb 19, 2024
1 parent dc7dcd3 commit 80343d4
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 46 deletions.
4 changes: 4 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### 6.2.0
* Add `ParseResults.ProgramName` [#999](https://github.com/fsprojects/Argu/pull/999)
* Add `ParseResults.GetResult(expr, 'Field -> 'R): 'R` as alias for `PostProcessResult`, `ParseResults.GetResults(expr, 'Field -> 'R): 'R list` as alias for `PostProcessResults`, `ParseResults.TryGetResult(expr, 'Field -> 'R): 'R option` as aliases for `TryPostProcessResult` [#999](https://github.com/fsprojects/Argu/pull/999)

### 6.1.4
* Fix: remove incorrect `ReproducibleBuilds` reference [introduced in `6.1.3`](https://github.com/fsprojects/Argu/pull/174) [#202](https://github.com/fsprojects/Argu/pull/202)

Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ In this case,
* [`AltCommandLine`](reference/argu-arguattributes-altcommandlineattribute.html): specifies an alternative command line switch.
* [`EqualsAssignment`](reference/argu-arguattributes-equalsassignmentattribute.html) : enforces `--assignment=value` and `--assignment key=value` CLI syntax.
* [`EqualsAssignmentOrSpaced`](reference/argu-arguattributes-equalsassignmentorspacedattribute.html) : enforces `--assignment=value` and `--assignment value` CLI syntax.
* [`Unique`](reference/argu-arguattributes-uniqueattribute.html) : parser will fail if CLI provides this argument more than once.
Expand Down Expand Up @@ -414,7 +414,7 @@ let parsePort p =
failwith "invalid port number."
else p

let ports = results.PostProcessResults (<@ Port @>, parsePort)
let ports = results.GetResults(<@ Port @>, parsePort)

(**
Expand Down
53 changes: 43 additions & 10 deletions src/Argu/ParseResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ type ParseResults<[<EqualityConditionalOn; ComparisonConditionalOn>]'Template wh
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="parser">The post-processing parser.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
// [<System.Obsolete("Please use the revised API name instead: GetResult")>]
member r.PostProcessResult ([<ReflectedDefinition>] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R =
expr |> getResult source |> parseResult parser

Expand All @@ -179,6 +180,7 @@ type ParseResults<[<EqualityConditionalOn; ComparisonConditionalOn>]'Template wh
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="parser">The post-processing parser.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
// [<System.Obsolete("Please use the revised API name instead: GetResults")>]
member r.PostProcessResults ([<ReflectedDefinition>] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R list =
expr |> getResults source |> Seq.map (parseResult parser) |> Seq.toList

Expand All @@ -189,9 +191,40 @@ type ParseResults<[<EqualityConditionalOn; ComparisonConditionalOn>]'Template wh
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="parser">The post-processing parser.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
// [<System.Obsolete("Please use the revised API name instead: TryGetResult")>]
member r.TryPostProcessResult ([<ReflectedDefinition>] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R option =
expr |> tryGetResult source |> Option.map (parseResult parser)

/// <summary>Returns the *last* specified parameter of given type.
/// Command line parameters have precedence over AppSettings parameters.
/// Results are passed to a post-processing function that is error handled by the parser.
/// </summary>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="parser">The post-processing parser.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member r.GetResult([<ReflectedDefinition>] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R =
expr |> getResult source |> parseResult parser

/// <summary>Query parse results for given argument kind.
/// Command line parameters have precedence over AppSettings parameters.
/// Results are passed to a post-processing function that is error handled by the parser.
/// </summary>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="parser">The post-processing parser.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member r.GetResults([<ReflectedDefinition>] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R list =
expr |> getResults source |> Seq.map (parseResult parser) |> Seq.toList

/// <summary>Returns the *last* specified parameter of given type.
/// Command line parameters have precedence over AppSettings parameters.
/// Results are passed to a post-processing function that is error handled by the parser.
/// </summary>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="parser">The post-processing parser.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member r.TryGetResult([<ReflectedDefinition>] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R option =
expr |> tryGetResult source |> Option.map (parseResult parser)

/// <summary>
/// Iterates through *all* parse results for a given argument kind.
/// Command line parameters have precedence over AppSettings parameters.
Expand Down Expand Up @@ -239,30 +272,30 @@ type ParseResults<[<EqualityConditionalOn; ComparisonConditionalOn>]'Template wh

// used by StructuredFormatDisplay attribute
member private r.StructuredFormatDisplay = r.ToString()

// used by EqualityConditionalOn attribute
// used by ComparisonConditionalOn attribute
member val private CachedAllResults = lazy (getAllResults None) with get

// used by EqualityConditionalOn attribute
override r.Equals (other : obj) =
override r.Equals (other : obj) =
match other with
| :? ParseResults<'Template> as other ->
Unchecked.equals
| :? ParseResults<'Template> as other ->
Unchecked.equals
r.CachedAllResults.Value
other.CachedAllResults.Value
| _ -> false

// used by EqualityConditionalOn attribute
override r.GetHashCode () =
override r.GetHashCode () =
Unchecked.hash r.CachedAllResults.Value

// used by ComparisonConditionalOn attribute
interface System.IComparable with
interface System.IComparable with
member r.CompareTo other =
match other with
| :? ParseResults<'Template> as other ->
Unchecked.compare
r.CachedAllResults.Value
| :? ParseResults<'Template> as other ->
Unchecked.compare
r.CachedAllResults.Value
other.CachedAllResults.Value
| _ -> invalidArg "other" "cannot compare values of different types"
68 changes: 34 additions & 34 deletions tests/Argu.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ open Argu
module ``Argu Tests Main List`` =

type Exception with
member inline x.FirstLine =
member inline x.FirstLine =
x.Message.Split([|Environment.NewLine|], StringSplitOptions.RemoveEmptyEntries).[0]

[<Flags>]
Expand All @@ -31,29 +31,29 @@ module ``Argu Tests Main List`` =
| [<AltCommandLine("-f")>] Force
| [<MainCommand("COMMAND"); ExactlyOnce>] Remote of repo_name:string * branch_name:string
interface IArgParserTemplate with
member this.Usage =
member this.Usage =
match this with
| Force -> "force changes in remote repo"
| Remote _ -> "push changes to remote repository and branch"

type NewArgs =
| [<Mandatory>] Name of string
interface IArgParserTemplate with
member this.Usage =
member this.Usage =
match this with
| Name _ -> "New name"

type TagArgs =
| New of ParseResults<NewArgs>
interface IArgParserTemplate with
member this.Usage =
member this.Usage =
match this with
| New _ -> "New tag"

type CheckoutArgs =
| [<Mandatory>] Branch of string
interface IArgParserTemplate with
member this.Usage =
member this.Usage =
match this with
| Branch _ -> "push changes to remote repository and branch"

Expand Down Expand Up @@ -176,8 +176,8 @@ module ``Argu Tests Main List`` =

[<Fact>]
let ``Simple command line parsing`` () =
let args =
[| "--first-parameter" ; "bar" ; "--mandatory-arg" ; "true" ; "-D" ;
let args =
[| "--first-parameter" ; "bar" ; "--mandatory-arg" ; "true" ; "-D" ;
"--listener" ; "localhost" ; "8080" ; "--log-level" ; "2" |]

let expected_outcome = [ First_Parameter "bar" ; Mandatory_Arg true ; Detach ; Listener ("localhost", 8080) ; Log_Level 2 ]
Expand All @@ -187,7 +187,7 @@ module ``Argu Tests Main List`` =
test <@ results.Contains <@ Detach @> @>
test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @>
test <@ results.GetResults <@ Log_Level @> = [2] @>
test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @>
test <@ results.GetResult (<@ Log_Level @>, fun x -> x + 1) = 3 @>

[<Fact>]
let ``Simple AppSettings parsing`` () =
Expand All @@ -203,14 +203,14 @@ module ``Argu Tests Main List`` =
test <@ results.Contains <@ Detach @> @>
test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @>
test <@ results.GetResults <@ Log_Level @> = [2] @>
test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @>
test <@ results.GetResult (<@ Log_Level @>, fun x -> x + 1) = 3 @>

[<Fact>]
let ``Simple AppSettings contains usage comments`` () =
let args = [ Mandatory_Arg true ; Detach ; Listener ("localhost", 8080) ; Log_Level 2 ]
let xmlSource = parser.PrintAppSettingsArguments args
let usages = List.map (fun a -> (a :> IArgParserTemplate).Usage) args

test <@ xmlSource.Contains usages[0] = true @>
test <@ xmlSource.Contains usages[1] = true @>
test <@ xmlSource.Contains usages[2] = true @>
Expand Down Expand Up @@ -251,7 +251,7 @@ module ``Argu Tests Main List`` =
let ``AppSettings List param single`` () =
let results = parseFunc true (function "list" -> Some "42" | _ -> None)
test <@ results.GetResult List = [42] @>


[<Fact>]
let ``Help String`` () =
Expand Down Expand Up @@ -296,7 +296,7 @@ module ``Argu Tests Main List`` =
let ``First Parameter not placed at beginning`` () =
raisesWith<ArguParseException> <@ parser.ParseCommandLine [| "--mandatory-arg" ; "true" ; "--first-parameter" ; "foo" |] @>
(fun e -> <@ e.Message.Contains "should precede all other" @>)


[<Fact>]
let ``Rest Parameter`` () =
Expand Down Expand Up @@ -356,21 +356,21 @@ module ``Argu Tests Main List`` =
let ``Parse equals assignment 2`` () =
let result = parser.Parse([|"--dir==foo"|], ignoreMissing = true)
test <@ result.GetResult Dir = "=foo" @>

[<Fact>]
let ``Parse equals or space assignment with equals`` () =
let result = parser.Parse([|"--flex-equals-assignment=../../my-relative-path"; "--dir==foo"|], ignoreMissing = true)
test <@ result.GetResult Flex_Equals_Assignment = "../../my-relative-path" @>

[<Fact>]
let ``Parse equals or space assignment with colon fails`` () =
raises<ArguParseException> <@ parser.Parse([|"--flex-equals-assignment:../../my-relative-path"; "--dir==foo"|], ignoreMissing = true) @>

[<Fact>]
let ``Parse equals or space assignment with space`` () =
let result = parser.Parse([|"--flex-equals-assignment"; "../../my-relative-path"; "--dir==foo"|], ignoreMissing = true)
test <@ result.GetResult Flex_Equals_Assignment = "../../my-relative-path" @>

[<Fact>]
let ``Parse equals or space assignment with space and optional type`` () =
let result = parser.Parse([|"--flex-equals-assignment-with-option"; "../../my-relative-path"; "--dir==foo"|], ignoreMissing = true)
Expand All @@ -382,7 +382,7 @@ module ``Argu Tests Main List`` =
// EitherSpaceOrColonAssignmentAttribute share the same underlying implementation.
let result = parser.Parse([|"--flex-colon-assignment:../../my-relative-path"; "--dir==foo"|], ignoreMissing = true)
test <@ result.GetResult Flex_Colon_Assignment = "../../my-relative-path" @>

type DisallowedAssignmentArgs =
| [<EqualsAssignmentOrSpaced>] [<EqualsAssignment>] Flex_Equals_Assignment of string
interface IArgParserTemplate with
Expand All @@ -393,7 +393,7 @@ module ``Argu Tests Main List`` =
[<Fact>]
let ``Disallowed equals assignment combination throws`` () =
raisesWith<ArguException> <@ ArgumentParser.Create<DisallowedAssignmentArgs> (programName = "gadget") @>

type DisallowedArityWithAssignmentOrSpaced =
| [<EqualsAssignmentOrSpaced>] Flex_Equals_Assignment of string * int
interface IArgParserTemplate with
Expand All @@ -404,16 +404,16 @@ module ``Argu Tests Main List`` =
[<Fact>]
let ``EqualsAssignmentOrSpaced and arity not one combination throws`` () =
raisesWith<ArguException> <@ ArgumentParser.Create<DisallowedArityWithAssignmentOrSpaced> (programName = "gadget1") @>

[<Fact>]
let ``Should fail on incorrect assignment 1`` () =
raises<ArguParseException> <@ parser.Parse([|"--dir:foo"|], ignoreMissing = true) @>


[<Fact>]
let ``Ignore Unrecognized parameters`` () =
let args =
[| "--first-parameter" ; "bar" ; "--junk-param" ; "42" ; "--mandatory-arg" ; "true" ; "-D" ;
let args =
[| "--first-parameter" ; "bar" ; "--junk-param" ; "42" ; "--mandatory-arg" ; "true" ; "-D" ;
"--listener" ; "localhost" ; "8080" ; "--log-level" ; "2" |]

let expected_outcome = [ First_Parameter "bar" ; Mandatory_Arg true ; Detach ; Listener ("localhost", 8080) ; Log_Level 2 ]
Expand All @@ -423,7 +423,7 @@ module ``Argu Tests Main List`` =
test <@ results.Contains <@ Detach @> @>
test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @>
test <@ results.GetResults Log_Level = [2] @>
test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @>
test <@ results.GetResult(Log_Level, fun x -> x + 1) = 3 @>

[<Fact>]
let ``Fail on misplaced First parameter`` () =
Expand Down Expand Up @@ -757,7 +757,7 @@ module ``Argu Tests Main List`` =
[<Fact>]
let ``Use single dash prefix as default`` () =
let parser = ArgumentParser.Create<ArgumentSingleDash>("usage string")
let args =
let args =
[| "-argument" ; "bar" ; "-levels-deep" ; "3" |]

let expected_outcome = set [ Argument "bar" ; Levels_Deep 3 ]
Expand Down Expand Up @@ -799,7 +799,7 @@ module ``Argu Tests Main List`` =
let args = [| "--mandatory-arg" ; "true" ; "/D" |]
let results = parser.ParseCommandLine args
test <@ results.Contains <@ Detach @> @>

[<Fact>]
let ``Should fail when Usage, Mandatory and raiseOnUsage = true`` () =
raisesWith<ArguParseException> <@ parser.ParseCommandLine ([|"--help"|], raiseOnUsage = true) @>
Expand Down Expand Up @@ -905,7 +905,7 @@ module ``Argu Tests Main List`` =
module ``Argu Tests Main Primitive`` =

type Exception with
member inline x.FirstLine =
member inline x.FirstLine =
x.Message.Split([|Environment.NewLine|], StringSplitOptions.RemoveEmptyEntries).[0]

type ArgumentPrimitive =
Expand Down Expand Up @@ -955,8 +955,8 @@ module ``Argu Tests Main Primitive`` =

[<Fact>]
let ``Simple command line parsing`` () =
let args =
[| "--first-parameter" ; "bar" ; "--mandatory-arg" ; "true" ; "-D" ;
let args =
[| "--first-parameter" ; "bar" ; "--mandatory-arg" ; "true" ; "-D" ;
"--listener" ; "localhost" ; "8080" ; "--log-level" ; "2" |]

let expected_outcome = [ First_Parameter "bar" ; Mandatory_Arg true ; Detach ; Listener ("localhost", 8080) ; Log_Level 2 ]
Expand All @@ -966,22 +966,22 @@ module ``Argu Tests Main Primitive`` =
test <@ results.Contains <@ Detach @> @>
test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @>
test <@ results.GetResults <@ Log_Level @> = [2] @>
test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @>
test <@ results.GetResult(<@ Log_Level @>, fun x -> x + 1) = 3 @>

[<Fact>]
let ``Help String`` () =
raisesWith<ArguParseException> <@ parser.ParseCommandLine [| "--help" |] @>
(fun e -> <@ e.Message.Contains "USAGE:" @>)

[<Fact>]
let ``First Parameter not placed at beginning`` () =
raisesWith<ArguParseException> <@ parser.ParseCommandLine [| "--mandatory-arg" ; "true" ; "--first-parameter" ; "foo" |] @>
(fun e -> <@ e.Message.Contains "should precede all other" @>)

[<Fact>]
let ``Ignore Unrecognized parameters`` () =
let args =
[| "--first-parameter" ; "bar" ; "--junk-param" ; "42" ; "--mandatory-arg" ; "true" ; "-D" ;
let args =
[| "--first-parameter" ; "bar" ; "--junk-param" ; "42" ; "--mandatory-arg" ; "true" ; "-D" ;
"--listener" ; "localhost" ; "8080" ; "--log-level" ; "2" |]

let expected_outcome = [ First_Parameter "bar" ; Mandatory_Arg true ; Detach ; Listener ("localhost", 8080) ; Log_Level 2 ]
Expand All @@ -991,7 +991,7 @@ module ``Argu Tests Main Primitive`` =
test <@ results.Contains <@ Detach @> @>
test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @>
test <@ results.GetResults Log_Level = [2] @>
test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @>
test <@ results.GetResult(<@ Log_Level @>, fun x -> x + 1) = 3 @>

[<Fact>]
let ``Unrecognized CLI params`` () =
Expand All @@ -1007,7 +1007,7 @@ module ``Argu Tests Main Primitive`` =
test <@ results.UnrecognizedCliParams = ["foobar"] @>
test <@ results.Contains <@ Detach @> @>
test <@ results.GetResult <@ Main @> = "main" @>

[<Fact>]
let ``Trap defaulting function exceptions`` () =
let results = parser.ParseCommandLine [| "--mandatory-arg" ; "true"; "command" |]
Expand All @@ -1018,4 +1018,4 @@ module ``Argu Tests Main Primitive`` =
raisesWith<ArguParseException>
<@ results.GetResult(Working_Directory, defThunk) @>
(fun e -> <@ e.Message.StartsWith "Defaulting Failed" && e.Message.Contains "--working-directory" @>)

0 comments on commit 80343d4

Please sign in to comment.