Skip to content

Commit 44ab603

Browse files
JordanMartinezsafareli
authored andcommitted
Document how to parse a comma-separated sequence of values with default (#8)
1 parent 5bbd7d2 commit 44ab603

File tree

1 file changed

+63
-1
lines changed

1 file changed

+63
-1
lines changed

README.md

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ context-sensitive bash, zsh, and fish completions.
2727
- [Arguments](#arguments)
2828
- [Commands](#commands)
2929
- [Modifiers](#modifiers)
30+
- [Common Builder Patterns](#common-builder-patterns)
31+
- [A list of values with a default](#a-list-of-values-with-a-default)
3032
- [Custom parsing and error handling](#custom-parsing-and-error-handling)
3133
- [Parser runners](#parser-runners)
3234
- [Option readers](#option-readers)
@@ -581,6 +583,66 @@ for other types of options.
581583
Many modifiers are polymorphic in this type argument, which means
582584
that they can be used with any builder.
583585

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
622+
in
623+
if Array.null strArray
624+
then Left "got empty string as input"
625+
else Right strArray
626+
627+
commaSeparatedStringList :: Parser (Array String)
628+
commaSeparatedStringList =
629+
option (multiString $ Pattern ",")
630+
( long "arg-name"
631+
<> metavar "value1,value2,...,value3"
632+
<> help "A comma-separated list of strings"
633+
<> value [ "first", "second", "third" ]
634+
<> showDefaultWith (\array -> intercalate "," array)
635+
)
636+
```
637+
Using the above, we could then pass in our arguments like this:
638+
`command --arg-name first,second,third`
639+
640+
Moreover, the help text would also display useful information here:
641+
```
642+
--arg-name value1,value2,...,value3
643+
A comma-separated list of strings. (default: first,second,third)
644+
```
645+
584646
## Custom parsing and error handling
585647

586648
### Parser runners
@@ -950,4 +1012,4 @@ simplified implementation.
9501012
[status]: http://travis-ci.org/f-o-a-m/purescript-optparse?branch=master
9511013
[status-png]: https://api.travis-ci.org/f-o-a-m/purescript-optparse.svg?branch=master
9521014
[ansi-wl-pprint]: http://hackage.haskell.org/package/ansi-wl-pprint
953-
[optparse-applicative]: https://github.com/pcapriotti/optparse-applicative
1015+
[optparse-applicative]: https://github.com/pcapriotti/optparse-applicative

0 commit comments

Comments
 (0)