You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-[A list of values with a default](#a-list-of-values-with-a-default)
30
32
-[Custom parsing and error handling](#custom-parsing-and-error-handling)
31
33
-[Parser runners](#parser-runners)
32
34
-[Option readers](#option-readers)
@@ -581,6 +583,66 @@ for other types of options.
581
583
Many modifiers are polymorphic in this type argument, which means
582
584
that they can be used with any builder.
583
585
586
+
### Common Builder Patterns
587
+
588
+
#### A list of values with a default
589
+
590
+
We'll show one wrong way to do it and then show 2 ways of implementing it.
591
+
592
+
Wrong way: using `some (strOption modifiers)`/`many (strOption modifiers)`.
593
+
We could use `some (strOption (long "arg-name" <> value "default"))`, which allows you to pass in values like this:
594
+
`command --arg-name value1 --arg-name value2`
595
+
596
+
However, combining `some`/`many` with a default `value` modifier guarantees that the parser will never terminate. Rather, it'll run forever and eventually your machine will run out of stack/memory and crash. Why? Because `some`/`many` work by parsing forever until they fail and then they return all the results they found. If the `value` modifier is added, then these parsers will never fail.
597
+
598
+
Right way (but inconsistent): using `many (optionArgs) <|> pure ("default" : Nil)`
599
+
This will terminate, but it's implementation is not consistent with how we implement other options with a default value that appears in the help text.
600
+
601
+
Using a more verbose example:
602
+
```purescript
603
+
parseStringList :: Parser (List String)
604
+
parseStringList =
605
+
let
606
+
defaultValue = "default" : Nil
607
+
listStrOption =
608
+
many (strOption ( long "arg-name"
609
+
<> help ("Option explanation, \
610
+
\default: " <> show defaultValue
611
+
)
612
+
)
613
+
)
614
+
in listStrOption <|> (pure defaultValue)
615
+
```
616
+
617
+
Right way (and consistent: use `eitherReader` to define our own `ReadM` that properly handles this:
618
+
```purescript
619
+
multiString :: Pattern -> ReadM (Array String)
620
+
multiString splitPattern = eitherReader \s ->
621
+
let strArray = filter String.null $ split splitPattern s
0 commit comments