Skip to content

Commit

Permalink
Merge pull request #100 from fsprojects/reflected-definition
Browse files Browse the repository at this point in the history
Use ReflectedDefinitionAttribute for quotation-based query APIs
  • Loading branch information
eiriktsarpalis authored Jan 27, 2018
2 parents 83049b5 + e70381e commit 9601575
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 40 deletions.
8 changes: 4 additions & 4 deletions docs/content/tutorial.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ it is more likely that you need to query the results for specific parameters:
*)

let detach = results.Contains <@ Detach @>
let listener = results.GetResults <@ Listener @>
let detach = results.Contains Detach
let listener = results.GetResults Listener

(** The following methods return the last observed result for given argument case *)

let dataOpt = results.TryGetResult <@ Data @>
let logLevel = results.GetResult (<@ Log_Level @>, defaultValue = 0)
let dataOpt = results.TryGetResult Data
let logLevel = results.GetResult (Log_Level, defaultValue = 0)

(**
Expand Down
2 changes: 1 addition & 1 deletion paket.dependencies
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ group Legacy
source https://www.nuget.org/api/v2
redirects: force

nuget FSharp.Core >= 3.1 lowest_matching:true
nuget FSharp.Core >= 4.0 lowest_matching:true
nuget SourceLink.Create.CommandLine copy_local: true

group Build
Expand Down
4 changes: 2 additions & 2 deletions paket.lock
Original file line number Diff line number Diff line change
Expand Up @@ -804,12 +804,12 @@ NUGET
xunit.runner.console (2.3.1)
GITHUB
remote: fsharp/FAKE
modules/Octokit/Octokit.fsx (642a01a5e17b870f816cdd7ee09115e018b786f0)
modules/Octokit/Octokit.fsx (51a7cae12acc7292db4623ae0e3cc3a2ce6ca1c9)
Octokit (>= 0.20)
GROUP Legacy
REDIRECTS: FORCE
RESTRICTION: == net40
NUGET
remote: https://www.nuget.org/api/v2
FSharp.Core (3.1.2)
FSharp.Core (4.0.0.1)
SourceLink.Create.CommandLine (2.7.3) - copy_local: true
2 changes: 1 addition & 1 deletion samples/Argu.Samples.LS/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ let main argv =
let results = parser.ParseCommandLine argv

printfn "Got parse results %A" <| results.GetAllResults()
let files = results.GetResult(<@ Files @>, defaultValue = [])
let files = results.GetResult(Files, defaultValue = [])
printfn "Listing files %A" files

0
1 change: 1 addition & 0 deletions src/Argu/Argu.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<Tailcalls>false</Tailcalls>
<OutputPath>..\..\bin\Debug\</OutputPath>
<DocumentationFile>..\..\bin\Debug\net40\Argu.XML</DocumentationFile>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>RELEASE</DefineConstants>
Expand Down
4 changes: 2 additions & 2 deletions src/Argu/ArgumentParser.fs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ and [<Sealed; NoEquality; NoComparison; AutoSerializable(false)>]
/// Gets a subparser associated with specific subcommand instance
/// </summary>
/// <param name="expr">Expression providing the subcommand union constructor.</param>
member __.GetSubCommandParser (expr : Expr<ParseResults<'SubTemplate> -> 'Template>) : ArgumentParser<'SubTemplate> =
member __.GetSubCommandParser ([<ReflectedDefinition>] expr : Expr<ParseResults<'SubTemplate> -> 'Template>) : ArgumentParser<'SubTemplate> =
let uci = expr2Uci expr
let case = argInfo.Cases.[uci.Tag]
match case.ParameterInfo with
Expand All @@ -208,7 +208,7 @@ and [<Sealed; NoEquality; NoComparison; AutoSerializable(false)>]
/// Gets argument metadata for given union case constructor
/// </summary>
/// <param name="ctorExpr">Quoted union case constructor.</param>
member __.GetArgumentCaseInfo(ctorExpr : Expr<'Fields -> 'Template>) : ArgumentCaseInfo =
member __.GetArgumentCaseInfo([<ReflectedDefinition>] ctorExpr : Expr<'Fields -> 'Template>) : ArgumentCaseInfo =
let uci = expr2Uci ctorExpr
argInfo.Cases.[uci.Tag].ToArgumentCaseInfo()

Expand Down
26 changes: 13 additions & 13 deletions src/Argu/ParseResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ type ParseResults<'Template when 'Template :> IArgParserTemplate>
/// <summary>Query parse results for parameterless argument.</summary>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member __.GetResults (expr : Expr<'Template>, ?source : ParseSource) : 'Template list =
member __.GetResults ([<ReflectedDefinition>] expr : Expr<'Template>, ?source : ParseSource) : 'Template list =
expr |> getResults source |> Seq.map (fun r -> r.Value :?> 'Template) |> Seq.toList

/// <summary>Query parse results for argument with parameters.</summary>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member __.GetResults (expr : Expr<'Fields -> 'Template>, ?source : ParseSource) : 'Fields list =
member __.GetResults ([<ReflectedDefinition>] expr : Expr<'Fields -> 'Template>, ?source : ParseSource) : 'Fields list =
expr |> getResults source |> Seq.map (fun r -> r.FieldContents :?> 'Fields) |> Seq.toList

/// <summary>Gets all parse results.</summary>
Expand All @@ -84,22 +84,22 @@ type ParseResults<'Template when 'Template :> IArgParserTemplate>
/// Command line parameters have precedence over AppSettings parameters.</summary>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member __.TryGetResult (expr : Expr<'Template>, ?source : ParseSource) : 'Template option =
member __.TryGetResult ([<ReflectedDefinition>] expr : Expr<'Template>, ?source : ParseSource) : 'Template option =
expr |> tryGetResult source |> Option.map (fun r -> r.Value :?> 'Template)

/// <summary>Returns the *last* specified parameter of given type, if it exists.
/// Command line parameters have precedence over AppSettings parameters.</summary>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member __.TryGetResult (expr : Expr<'Fields -> 'Template>, ?source : ParseSource) : 'Fields option =
member __.TryGetResult ([<ReflectedDefinition>] expr : Expr<'Fields -> 'Template>, ?source : ParseSource) : 'Fields option =
expr |> tryGetResult source |> Option.map (fun r -> r.FieldContents :?> 'Fields)

/// <summary>Returns the *last* specified parameter of given type.
/// Command line parameters have precedence over AppSettings parameters.</summary>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="defaultValue">Return this of no parameter of specific kind has been specified.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member s.GetResult (expr : Expr<'Template>, ?defaultValue : 'Template, ?source : ParseSource) : 'Template =
member s.GetResult ([<ReflectedDefinition>] expr : Expr<'Template>, ?defaultValue : 'Template, ?source : ParseSource) : 'Template =
match defaultValue with
| None -> let r = getResult source expr in r.Value :?> 'Template
| Some def -> defaultArg (s.TryGetResult(expr, ?source = source)) def
Expand All @@ -109,19 +109,19 @@ type ParseResults<'Template when 'Template :> IArgParserTemplate>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="defaultValue">Return this of no parameter of specific kind has been specified.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member s.GetResult (expr : Expr<'Fields -> 'Template>, ?defaultValue : 'Fields , ?source : ParseSource) : 'Fields =
member s.GetResult ([<ReflectedDefinition>] expr : Expr<'Fields -> 'Template>, ?defaultValue : 'Fields , ?source : ParseSource) : 'Fields =
match defaultValue with
| None -> let r = getResult source expr in r.FieldContents :?> 'Fields
| Some def -> defaultArg (s.TryGetResult expr) def

/// <summary>Checks if parameter of specific kind has been specified.</summary>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member __.Contains (expr : Expr<'Template>, ?source : ParseSource) : bool = containsResult source expr
member __.Contains ([<ReflectedDefinition>] expr : Expr<'Template>, ?source : ParseSource) : bool = containsResult source expr
/// <summary>Checks if parameter of specific kind has been specified.</summary>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="source">Optional source restriction: AppSettings or CommandLine.</param>
member __.Contains (expr : Expr<'Fields -> 'Template>, ?source : ParseSource) : bool = containsResult source expr
member __.Contains ([<ReflectedDefinition>] expr : Expr<'Fields -> 'Template>, ?source : ParseSource) : bool = containsResult source expr

/// <summary>Raise an error through the argument parser's exiter mechanism. Display usage optionally.</summary>
/// <param name="msg">The error message to be displayed.</param>
Expand Down Expand Up @@ -153,7 +153,7 @@ type ParseResults<'Template when 'Template :> IArgParserTemplate>
/// <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.PostProcessResult (expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R =
member r.PostProcessResult ([<ReflectedDefinition>] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R =
expr |> getResult source |> parseResult parser

/// <summary>Query parse results for given argument kind.
Expand All @@ -163,7 +163,7 @@ type ParseResults<'Template when 'Template :> IArgParserTemplate>
/// <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.PostProcessResults (expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R list =
member r.PostProcessResults ([<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.
Expand All @@ -173,7 +173,7 @@ type ParseResults<'Template when 'Template :> IArgParserTemplate>
/// <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.TryPostProcessResult (expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R option =
member r.TryPostProcessResult ([<ReflectedDefinition>] expr : Expr<'Field -> 'Template>, parser : 'Field -> 'R, ?source) : 'R option =
expr |> tryGetResult source |> Option.map (parseResult parser)

/// <summary>
Expand All @@ -184,7 +184,7 @@ type ParseResults<'Template when 'Template :> IArgParserTemplate>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="iterator">The iterator body.</param>
/// <param name="source">Option source restriction: AppSettings or CommandLine.</param>
member r.IterResults (expr : Expr<'Field -> 'Template>, iterator : 'Field -> unit, ?source) : unit =
member r.IterResults ([<ReflectedDefinition>] expr : Expr<'Field -> 'Template>, iterator : 'Field -> unit, ?source) : unit =
expr |> getResults source |> Seq.iter (parseResult iterator)

/// <summary>
Expand All @@ -195,7 +195,7 @@ type ParseResults<'Template when 'Template :> IArgParserTemplate>
/// <param name="expr">The name of the parameter, expressed as quotation of DU constructor.</param>
/// <param name="iterator">The iterator body.</param>
/// <param name="source">Option source restriction: AppSettings or CommandLine.</param>
member r.IterResult (expr : Expr<'Field -> 'Template>, iterator : 'Field -> unit, ?source) : unit =
member r.IterResult ([<ReflectedDefinition>] expr : Expr<'Field -> 'Template>, iterator : 'Field -> unit, ?source) : unit =
expr |> tryGetResult source |> Option.iter (parseResult iterator)

/// <summary>
Expand Down
34 changes: 17 additions & 17 deletions tests/Argu.Tests/Tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -156,39 +156,39 @@ module ``Argu Tests`` =
[<Fact>]
let ``AppSettings CSV parsing`` () =
let results = parseFunc true (function "rest arg" -> Some("1,2,3,4,5") | _ -> None)
test <@ results.GetResults <@ Rest_Arg @> = [1 .. 5] @>
test <@ results.GetResults Rest_Arg = [1 .. 5] @>

[<Fact>]
let ``AppSettings Flag parsing`` () =
let results = parseFunc true (function "a" -> Some("true") | "b" -> Some("false") | _ -> None)
test <@ results.Contains <@ A @> @>
test <@ results.Contains <@ B @> |> not @>
test <@ results.Contains <@ C @> |> not @>
test <@ results.Contains A @>
test <@ results.Contains B |> not @>
test <@ results.Contains C |> not @>

[<Fact>]
let ``AppSettings multi-parameter parsing 1`` () =
let results = parseFunc true (function "env" -> Some("key,value") | _ -> None)
test <@ results.GetResult <@ Env @> = ("key", "value") @>
test <@ results.GetResult Env = ("key", "value") @>

[<Fact>]
let ``AppSettings multi-parameter parsing 2`` () =
let results = parseFunc true (function "listener" -> Some("localhost:80") | _ -> None)
test <@ results.GetResult <@ Listener @> = ("localhost", 80) @>
test <@ results.GetResult Listener = ("localhost", 80) @>

[<Fact>]
let ``AppSettings Optional param`` () =
let results = parseFunc true (function "optional" -> Some "42" | _ -> None)
test <@ results.GetResult <@ Optional @> = (Some 42) @>
test <@ results.GetResult Optional = (Some 42) @>

[<Fact>]
let ``AppSettings List param populated`` () =
let results = parseFunc true (function "list" -> Some "1,2,3,4,5" | _ -> None)
test <@ results.GetResult <@ List @> = [1 .. 5] @>
test <@ results.GetResult List = [1 .. 5] @>

[<Fact>]
let ``AppSettings List param single`` () =
let results = parseFunc true (function "list" -> Some "42" | _ -> None)
test <@ results.GetResult <@ List @> = [42] @>
test <@ results.GetResult List = [42] @>


[<Fact>]
Expand Down Expand Up @@ -221,7 +221,7 @@ module ``Argu Tests`` =
let ``Rest Parameter`` () =
let args = [|1..100|] |> Array.map string |> Array.append [| "--mandatory-arg" ; "true" ; "--rest-arg" |]
let result = parser.ParseCommandLine args
test <@ result.GetResults <@ Rest_Arg @> = [1..100] @>
test <@ result.GetResults Rest_Arg = [1..100] @>

[<Fact>]
let ``Multiple AltCommandLine`` () =
Expand All @@ -239,7 +239,7 @@ module ``Argu Tests`` =
let bytes = [|1uy .. 255uy|]
let args = parser.PrintCommandLineArguments [ Mandatory_Arg false ; Data(42, bytes) ]
let results = parser.ParseCommandLine args
test <@ let _,bytes' = results.GetResult <@ Data @> in bytes' = bytes @>
test <@ let _,bytes' = results.GetResult Data in bytes' = bytes @>

[<Fact>]
let ``Parse colon assignment 1`` () =
Expand All @@ -259,7 +259,7 @@ module ``Argu Tests`` =
let arg = [ Env("foo", "bar") ]
let clp = parser.PrintCommandLineArguments arg
let result = parser.Parse(clp, ignoreMissing = true)
test <@ result.GetResult <@ Env @> = ("foo", "bar") @>
test <@ result.GetResult Env = ("foo", "bar") @>

[<Fact>]
let ``Parse key-value equals assignment 2`` () =
Expand All @@ -269,12 +269,12 @@ module ``Argu Tests`` =
[<Fact>]
let ``Parse equals assignment`` () =
let result = parser.Parse([|"--dir=../../my-relative-path"|], ignoreMissing = true)
test <@ result.GetResult <@ Dir @> = "../../my-relative-path" @>
test <@ result.GetResult Dir = "../../my-relative-path" @>

[<Fact>]
let ``Parse equals assignment 2`` () =
let result = parser.Parse([|"--dir==foo"|], ignoreMissing = true)
test <@ result.GetResult <@ Dir @> = "=foo" @>
test <@ result.GetResult Dir = "=foo" @>

[<Fact>]
let ``Should fail on incorrect assignment 1`` () =
Expand All @@ -293,7 +293,7 @@ module ``Argu Tests`` =

test <@ results.Contains <@ Detach @> @>
test <@ results.GetResult <@ Listener @> = ("localhost", 8080) @>
test <@ results.GetResults <@ Log_Level @> = [2] @>
test <@ results.GetResults Log_Level = [2] @>
test <@ results.PostProcessResult (<@ Log_Level @>, fun x -> x + 1) = 3 @>

[<Fact>]
Expand Down Expand Up @@ -327,7 +327,7 @@ module ``Argu Tests`` =
let ``Simple subcommand parsing 2`` () =
let args = [|"clean"; "-fdx"|]
let results = parser.ParseCommandLine(args, ignoreMissing = true)
let nested = results.GetResult <@ Clean @>
let nested = results.GetResult Clean
test <@ match results.TryGetSubCommand() with Some (Clean _) -> true | _ -> false @>
test <@ nested.GetAllResults() = [F; D; X] @>

Expand Down Expand Up @@ -361,7 +361,7 @@ module ``Argu Tests`` =
let ``Main command taking list of arguments`` () =
let args = [|"--mandatory-arg" ; "true" ; "a" ; "b" ; "c" ; "ff" ; "d" |]
let results = parser.ParseCommandLine(args, ignoreUnrecognized = true)
test <@ results.GetResult <@ Main @> = ['a' ; 'b' ; 'c'] @>
test <@ results.GetResult Main = ['a' ; 'b' ; 'c'] @>

[<Fact>]
let ``SubParsers should correctly handle inherited params`` () =
Expand Down

0 comments on commit 9601575

Please sign in to comment.