Skip to content

Commit 29fea8c

Browse files
committed
README
1 parent 0230eab commit 29fea8c

3 files changed

Lines changed: 68 additions & 13 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
Notable changes are recorded here.
22

3+
# WoofWare.Myriad.Plugins 10.2.1
4+
5+
The `ArgParserGenerator` now ships with (limited) discriminated-union support: you can specify mutually exclusive sets of args and the parser will select the correct set.
6+
37
# WoofWare.Myriad.Plugins 10.1.1
48

59
Fixes a number of bugs in the `ArgParserGenerator` by extracting the "untyped" logic into a standalone module.

README.md

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,24 @@ For an example of using both `JsonParse` and `JsonSerialize` together with compl
157157
Takes a record like this:
158158

159159
```fsharp
160+
type FishArgs =
161+
{
162+
[<ArgumentLongForm "number-of-fins">]
163+
Fins : int
164+
}
165+
166+
type FowlArgs =
167+
{
168+
Species : string
169+
}
170+
171+
type AnimalArgs =
172+
| Fish of FishArgs
173+
| Fowl of FowlArgs
174+
160175
type DryRunMode =
161-
| [<ArgumentFlag true> Dry
162-
| [<ArgumentFlag false> Wet
176+
| [<ArgumentFlag true>] Dry
177+
| [<ArgumentFlag false>] Wet
163178
164179
[<ArgParser>]
165180
type Foo =
@@ -173,11 +188,7 @@ type Foo =
173188
BWithEnv : Choice<int, int>
174189
[<ArgumentDefaultFunction>]
175190
DryRun : DryRunMode
176-
[<ArgumentLongForm "longer-form-replaces-c">]
177-
C : float list
178-
// optionally:
179-
[<PositionalArgs>]
180-
Rest : string list // or e.g. `int list` if you want them parsed into a type too
191+
AnimalPart : AnimalArgs
181192
}
182193
static member DefaultB () = 4
183194
static member DefaultDryRun () = DryRunMode.Wet
@@ -194,23 +205,62 @@ module Foo =
194205
let parse (args : string list) : Foo = ...
195206
```
196207

208+
The user specifies, for example:
209+
210+
```
211+
./my-app --some-flag --species pheasant
212+
```
213+
214+
or
215+
216+
```
217+
./my-app --some-flag false --number-of-fins=39 --b-with-env 8
218+
```
219+
220+
and you get back respectively these objects:
221+
222+
```fsharp
223+
{
224+
SomeFlag = true
225+
A = None
226+
B = Choice2Of2 4
227+
BWithEnv = Choice2Of2 100 // whatever the value of $MY_ENV_VAR was, or a failed parse
228+
DryRun = DryRunMode.Wet
229+
AnimalPart = AnimalArgs.Fowl { Species = "pheasant" }
230+
}
231+
232+
{
233+
SomeFlag = false
234+
A = None
235+
B = Choice2Of2 4
236+
BWithEnv = Choice1Of2 8
237+
DryRun = DryRunMode.Wet
238+
AnimalPart = AnimalArgs.Fish { Fins = 39 }
239+
}
240+
```
241+
197242
Default arguments are handled as `Choice<'a, 'a>`:
198243
you get a `Choice1Of2` if the user provided the input, or a `Choice2Of2` if the parser filled in your specified default value.
199244

200245
You can control `TimeSpan` and friends with the `[<InvariantCulture>]` and `[<ParseExact @"hh\:mm\:ss">]` attributes.
201246

202247
You can generate extension methods for the type, instead of a module with the type's name, using `[<ArgParser (* isExtensionMethod = *) true>]`.
203248

249+
You can collect leftover args as positional args, with `[<PositionalArgs>]`; this respects a trailing `--` so that you can specify positional args which look like flags.
250+
The positional args feature is currently *not* supported simultaneously with DUs, though: the generator will fail at build time.
251+
204252
If `--help` appears in a position where the parser is expecting a key (e.g. in the first position, or after a `--foo=bar`), the parser fails with help text.
205253
The parser also makes a limited effort to supply help text when encountering an invalid parse.
206254

255+
Records compose: if your record contains other records which are visible to the source generator (that is, they're in the same file as the main args type), the fields of *those* records will also be included in the command line, as if you'd specified them inline in the top-level record.
256+
257+
Discriminated unions compose with each other and with records, hopefully as you would expect: the fields specified by the record of a DU field must be mutually satisified, or the parse will fail to select that DU field.
258+
207259
### What's the point?
208260

209261
I got fed up of waiting for us to find time to rewrite the in-house one at work.
210-
That one has a bunch of nice compositional properties, which my version lacks:
211-
I can basically only deal with primitive types, and e.g. you can't stack records and discriminated unions inside each other.
212-
213-
But I *do* want an F#-native argument parser suitable for AOT-compilation.
262+
That one has slightly nicer usability properties, because it operates by reflection so it has fuller information at runtime.
263+
(But I *do* want an F#-native argument parser suitable for AOT-compilation, so perhaps the limitations of my one here are inherent.)
214264

215265
Why not [Argu](https://fsprojects.github.io/Argu/)?
216266
Answer: I got annoyed with having to construct my records by hand even after Argu returned and said the parsing was all "done".
@@ -221,9 +271,10 @@ This is very bare-bones, but do raise GitHub issues if you like (or if you find
221271

222272
* Help is signalled by throwing an exception, so you'll get an unsightly stack trace and a nonzero exit code.
223273
* Help doesn't take into account any arguments the user has entered. Ideally you'd get contextual information like an identification of which args the user has supplied at the point where the parse failed or help was requested.
224-
* I don't handle very many types, and in particular a real arg parser would handle DUs and records with nesting.
274+
* I don't handle very many types at the leaves. You may find yourself needing to write wrapper types to contain the leaf values, if you want to parse them correctly.
225275
* I don't try very hard to find a valid parse. It may well be possible to find a case where I fail to parse despite there existing a valid parse.
226276
* There's no subcommand support (you'll have to do that yourself).
277+
* Discriminated unions can't currently be specified in a type that contains positional args. This is a limitation I hope to relax soon.
227278

228279
It should work fine if you just want to compose a few primitive types, though.
229280

WoofWare.Myriad.Plugins/version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "10.1",
2+
"version": "10.2",
33
"publicReleaseRefSpec": [
44
"^refs/heads/main$"
55
],

0 commit comments

Comments
 (0)