Skip to content

Commit 7dff0ef

Browse files
committed
v0.15.0-beta4 - Input configuration overloads
1 parent 6880038 commit 7dff0ef

File tree

3 files changed

+90
-19
lines changed

3 files changed

+90
-19
lines changed

src/FSharp.SystemCommandLine/FSharp.SystemCommandLine.fsproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<TargetFramework>net6.0</TargetFramework>
55
<GenerateDocumentationFile>true</GenerateDocumentationFile>
6-
<Version>0.14.0-beta4</Version>
6+
<Version>0.15.0-beta4</Version>
77
<Description>F# computation expressions for working with the System.CommandLine API.</Description>
88
<Authors>Jordan Marr</Authors>
99
<PackageTags>F# fsharp System.CommandLine cli</PackageTags>

src/FSharp.SystemCommandLine/Inputs.fs

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,31 +24,61 @@ type HandlerInput(source: HandlerInputSource) =
2424

2525
type HandlerInput<'T>(inputType: HandlerInputSource) =
2626
inherit HandlerInput(inputType)
27+
/// Converts a System.CommandLine.Option<'T> for usage with the CommandBuilder.
2728
static member OfOption<'T>(o: Option<'T>) = o :> Option |> ParsedOption |> HandlerInput<'T>
29+
/// Converts a System.CommandLine.Argument<'T> for usage with the CommandBuilder.
2830
static member OfArgument<'T>(a: Argument<'T>) = a :> Argument |> ParsedArgument |> HandlerInput<'T>
2931
member this.GetValue(ctx: System.CommandLine.Invocation.InvocationContext) =
3032
match this.Source with
3133
| ParsedOption o -> o :?> Option<'T> |> ctx.ParseResult.GetValueForOption
3234
| ParsedArgument a -> a :?> Argument<'T> |> ctx.ParseResult.GetValueForArgument
3335
| Context -> ctx |> unbox<'T>
34-
36+
37+
let private applyConfiguration configure a =
38+
configure a; a
3539

3640
/// Creates CLI options and arguments to be passed as command `inputs`.
3741
type Input =
38-
42+
43+
/// Converts a System.CommandLine.Option<'T> for usage with the CommandBuilder.
44+
static member OfOption<'T>(o: Option<'T>) =
45+
HandlerInput.OfOption o
46+
47+
/// Converts a System.CommandLine.Argument<'T> for usage with the CommandBuilder.
48+
static member OfArgument<'T>(a: Argument<'T>) =
49+
HandlerInput.OfArgument a
50+
51+
/// Creates a CLI option of type 'T with the ability to manually configure the underlying properties.
52+
static member Option<'T>(name: string, configure) =
53+
Option<'T>(name)
54+
|> applyConfiguration configure
55+
|> HandlerInput.OfOption
56+
57+
/// Creates a CLI option of type 'T with the ability to manually configure the underlying properties.
58+
static member Option<'T>(aliases: string seq, configure) =
59+
Option<'T>(Seq.toArray aliases)
60+
|> applyConfiguration configure
61+
|> HandlerInput.OfOption
62+
63+
/// Creates a CLI argument of type 'T with the ability to manually configure the underlying properties.
64+
static member Argument<'T>(name: string, configure) =
65+
Argument<'T>(name)
66+
|> applyConfiguration configure
67+
|> HandlerInput.OfArgument
68+
3969
/// Creates a CLI option of type 'T.
4070
static member Option<'T>(name: string, ?description: string) =
4171
Option<'T>(
4272
name,
43-
description = (description |> Option.defaultValue null)
73+
?description = description
4474
)
4575
|> HandlerInput.OfOption
4676

4777
/// Creates a CLI option of type 'T.
4878
static member Option<'T>(aliases: string seq, ?description: string) =
4979
Option<'T>(
50-
aliases |> Seq.toArray,
51-
description = (description |> Option.defaultValue null)
80+
Seq.toArray aliases,
81+
?description = description
5282
)
5383
|> HandlerInput.OfOption
5484

@@ -57,59 +87,81 @@ type Input =
5787
Option<'T>(
5888
name,
5989
getDefaultValue = (fun () -> defaultValue),
60-
description = (description |> Option.defaultValue null)
90+
?description = description
6191
)
6292
|> HandlerInput.OfOption
6393

6494
/// Creates a CLI option of type 'T with a default value.
6595
static member Option<'T>(aliases: string seq, defaultValue: 'T, ?description: string) =
6696
Option<'T>(
67-
aliases |> Seq.toArray,
97+
Seq.toArray aliases,
6898
getDefaultValue = (fun () -> defaultValue),
69-
description = (description |> Option.defaultValue null)
99+
?description = description
70100
)
71101
|> HandlerInput.OfOption
72102

73103
/// Creates a CLI option of type 'T that is required.
74104
static member OptionRequired<'T>(aliases: string seq, ?description: string) =
75105
Option<'T>(
76-
aliases |> Seq.toArray,
77-
description = (description |> Option.defaultValue null),
106+
Seq.toArray aliases,
107+
?description = description,
78108
IsRequired = true
79109
)
80110
|> HandlerInput.OfOption
81111

82112
/// Creates a CLI option of type 'T that is required.
83113
static member OptionRequired<'T>(name: string, ?description: string) =
84-
Input.OptionRequired<'T>([| name |], description |> Option.defaultValue null)
114+
Input.OptionRequired<'T>([| name |], ?description = description)
115+
116+
/// Creates a CLI option of type 'T option with the ability to manually configure the underlying properties.
117+
static member OptionMaybe<'T>(aliases: string seq, configure) =
118+
let isBool = typeof<'T> = typeof<bool>
119+
Option<'T option>(
120+
Seq.toArray aliases,
121+
parseArgument = (fun argResult ->
122+
match argResult.Tokens |> Seq.toList with
123+
| [] when isBool -> true |> unbox<'T> |> Some
124+
| [] -> None
125+
| [ token ] -> MaybeParser.parseTokenValue token.Value
126+
| _ :: _ -> failwith "F# Option can only be used with a single argument."
127+
),
128+
Arity = ArgumentArity(0, 1)
129+
)
130+
|> fun o -> o.SetDefaultValue(None); o
131+
|> applyConfiguration configure
132+
|> HandlerInput.OfOption
133+
134+
/// Creates a CLI option of type 'T option with the ability to manually configure the underlying properties.
135+
static member OptionMaybe<'T>(name: string, configure) =
136+
Input.OptionMaybe<'T>([|name|], configure = configure)
85137

86138
/// Creates a CLI option of type 'T option.
87139
static member OptionMaybe<'T>(aliases: string seq, ?description: string) =
88140
let isBool = typeof<'T> = typeof<bool>
89141
Option<'T option>(
90-
aliases |> Seq.toArray,
142+
Seq.toArray aliases,
91143
parseArgument = (fun argResult ->
92144
match argResult.Tokens |> Seq.toList with
93145
| [] when isBool -> true |> unbox<'T> |> Some
94146
| [] -> None
95147
| [ token ] -> MaybeParser.parseTokenValue token.Value
96148
| _ :: _ -> failwith "F# Option can only be used with a single argument."
97149
),
98-
description = (description |> Option.defaultValue null),
150+
?description = description,
99151
Arity = ArgumentArity(0, 1)
100152
)
101153
|> fun o -> o.SetDefaultValue(None); o
102154
|> HandlerInput.OfOption
103155

104156
/// Creates a CLI option of type 'T option.
105-
static member OptionMaybe<'T>(name: string, ?description: string) =
106-
Input.OptionMaybe<'T>([| name |], description |> Option.defaultValue null)
157+
static member OptionMaybe<'T>(name: string, ?description) =
158+
Input.OptionMaybe<'T>([| name |], ?description = description)
107159

108160
/// Creates a CLI argument of type 'T.
109161
static member Argument<'T>(name: string, ?description: string) =
110162
Argument<'T>(
111163
name,
112-
description = (description |> Option.defaultValue null)
164+
?description = description
113165
)
114166
|> HandlerInput.OfArgument
115167

@@ -118,7 +170,7 @@ type Input =
118170
Argument<'T>(
119171
name,
120172
getDefaultValue = (fun () -> defaultValue),
121-
description = (description |> Option.defaultValue null)
173+
?description = description
122174
)
123175
|> HandlerInput.OfArgument
124176

@@ -132,7 +184,7 @@ type Input =
132184
| [ token ] -> MaybeParser.parseTokenValue token.Value
133185
| _ :: _ -> failwith "F# Option can only be used with a single argument."
134186
),
135-
description = (description |> Option.defaultValue null)
187+
?description = description
136188
)
137189
|> fun o -> o.SetDefaultValue(None); o
138190
|> HandlerInput.OfArgument

src/Tests/SimpleAppTest.fs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,22 @@ let ``03 --word Hello -w World -s * return int`` () =
5959
}
6060

6161
code =! 5
62+
63+
[<Test>]
64+
let ``04 --word Hello -w World -s * return int using manual configured options`` () =
65+
let code =
66+
testRootCommand "--word Hello -w World -s *" {
67+
description "Appends words together"
68+
inputs (
69+
Input.Option(["--word"; "-w"], fun o -> o.SetDefaultValue Array.empty; o.Description <- "A list of words to be appended"),
70+
Input.OptionMaybe(["--separator"; "-s"], fun o -> o.Description <- "A character that will separate the joined words.")
71+
)
72+
setHandler (fun (words, separator) ->
73+
words =! [| "Hello"; "World" |]
74+
separator =! Some "*"
75+
handlerCalled <- true
76+
5
77+
)
78+
}
79+
80+
code =! 5

0 commit comments

Comments
 (0)