@@ -30,36 +30,33 @@ defmodule OptionParser do
30
30
Elixir converts switches to underscored atoms, so `--source-path` becomes
31
31
`:source_path`. This is done to better suit Elixir conventions. However, this
32
32
means that switches can't contain underscores and switches that do contain
33
- underscores are always returned in the list of invalid options .
33
+ underscores are always returned in the list of invalid switches .
34
34
35
- Without any options, this function will try to parse all switches in the `argv`.
35
+ When parsing, it is common to list switches and their expected types:
36
36
37
- iex> OptionParser.parse(["--debug"])
37
+ iex> OptionParser.parse(["--debug"], switches: [debug: :boolean] )
38
38
{[debug: true], [], []}
39
39
40
- iex> OptionParser.parse(["--source", "lib"])
40
+ iex> OptionParser.parse(["--source", "lib"], switches: [source: :string] )
41
41
{[source: "lib"], [], []}
42
42
43
- iex> OptionParser.parse(["--source-path", "lib", "test/enum_test.exs", "--verbose"])
43
+ iex> OptionParser.parse(["--source-path", "lib", "test/enum_test.exs", "--verbose"],
44
+ ...> switches: [source_path: :string, verbose: :boolean])
44
45
{[source_path: "lib", verbose: true], ["test/enum_test.exs"], []}
45
46
46
- Switches followed by a value will be assigned the value, as a string.
47
- Switches without an argument, like `--debug` in the examples above, will
48
- automatically be set to `true`.
47
+ We will explore the valid switches and operation modes of option parser below.
49
48
50
49
## Options
51
50
52
51
The following options are supported:
53
52
54
53
* `:switches` or `:strict` - see the "Switch definitions" section below
54
+ * `:allow_nonexistent_atoms` - see the "Parsing dynamic switches" section below
55
55
* `:aliases` - see the "Aliases" section below
56
- * `:allow_nonexistent_atoms` - see the "Parsing undefined switches" section below
57
56
58
57
## Switch definitions
59
58
60
- Often it is better to explicitly list the known
61
- switches and their formats. The switches can be specified via one of two
62
- options:
59
+ Switches can be specified via one of two options:
63
60
64
61
* `:switches` - defines some switches and their types. This function
65
62
still attempts to parse switches that are not in this list.
@@ -90,20 +87,20 @@ defmodule OptionParser do
90
87
* `:float` - parses the value as a float
91
88
* `:string` - parses the value as a string
92
89
93
- If a switch can't be parsed according to the given type, it is returned
94
- in the invalid options list.
90
+ If a switch can't be parsed according to the given type, it is
91
+ returned in the invalid options list.
95
92
96
93
### Modifiers
97
94
98
95
Switches can be specified with modifiers, which change how
99
96
they behave. The following modifiers are supported:
100
97
101
- * `:keep` - keeps duplicated items instead of overriding them; works with
102
- all types except `:count`. Specifying `switch_name: :keep` assumes the
103
- type of `:switch_name` will be `:string`.
98
+ * `:keep` - keeps duplicated items instead of overriding them;
99
+ works with all types except `:count`. Specifying `switch_name: :keep`
100
+ assumes the type of `:switch_name` will be `:string`.
104
101
105
- Note that if you want to use `:keep` with a type other than `:string`, use a list
106
- as the type for the switch. For example: `[foo: [:integer, :keep]]`.
102
+ To use `:keep` with a type other than `:string`, use a list as the type
103
+ for the switch. For example: `[foo: [:integer, :keep]]`.
107
104
108
105
### Negation switches
109
106
@@ -113,14 +110,45 @@ defmodule OptionParser do
113
110
iex> OptionParser.parse(["--no-op", "path/to/file"], switches: [op: :boolean])
114
111
{[op: false], ["path/to/file"], []}
115
112
116
- ### Parsing undefined switches
113
+ ### Parsing dynamic switches
114
+
115
+ `OptionParser` also includes a dynamic mode where it will attempt to parse
116
+ switches dynamically. Such can be done by not specifying the `:switches` or
117
+ `:strict` option.
118
+
119
+ iex> OptionParser.parse(["--debug"])
120
+ {[debug: true], [], []}
121
+
117
122
118
- By default, only arguments that have defined atom representation will be parsed.
119
- This happens because creating atoms at runtime is considered to be unsafe,
120
- but you can still force creation of atoms by passing `allow_nonexistent_atoms: true`
121
- to the list of function options.
123
+ Switches followed by a value will be assigned the value, as a string. Switches
124
+ without an argument, like `--debug` in the examples above, will automatically be
125
+ set to `true`.
122
126
123
- This is useful when you are building command-line applications that receive dynamically-named arguments.
127
+ Since Elixir converts switches to atoms, the dynamic mode will only parse
128
+ switches that translates to atoms used by the runtime. Therefore, the code below
129
+ likely won't parse the given option since the `:option_parser_example` atom is
130
+ never used anywhere:
131
+
132
+ OptionParser.parse(["--option-parser-example"])
133
+ # Does nothing more...
134
+
135
+ However, the code below does since the `:option_parser_example` atom is used
136
+ at some point later (or earlier) on:
137
+
138
+ {opts, _, _} = OptionParser.parse(["--option-parser-example"])
139
+ opts[:option_parser_example]
140
+
141
+ In other words, when using dynamic mode, Elixir will do the correct thing and
142
+ only parse options that are used by the runtime, ignoring all others. If you
143
+ would like to parse all switches, regardless if they exist or not, you can
144
+ force creation of atoms by passing `allow_nonexistent_atoms: true` as option.
145
+ Such option is useful when you are building command-line applications that
146
+ receive dynamically-named arguments but must be used with care on long-running
147
+ systems.
148
+
149
+ Switches followed by a value will be assigned the value, as a string.
150
+ Switches without an argument, like `--debug` in the examples above, will
151
+ automatically be set to `true`.
124
152
125
153
## Aliases
126
154
@@ -213,10 +241,12 @@ defmodule OptionParser do
213
241
214
242
## Example
215
243
216
- iex> OptionParser.parse_head(["--source", "lib", "test/enum_test.exs", "--verbose"])
244
+ iex> OptionParser.parse_head(["--source", "lib", "test/enum_test.exs", "--verbose"],
245
+ ...> switches: [source: :string, verbose: :boolean])
217
246
{[source: "lib"], ["test/enum_test.exs", "--verbose"], []}
218
247
219
- iex> OptionParser.parse_head(["--verbose", "--source", "lib", "test/enum_test.exs", "--unlock"])
248
+ iex> OptionParser.parse_head(["--verbose", "--source", "lib", "test/enum_test.exs", "--unlock"],
249
+ ...> switches: [source: :string, verbose: :boolean, unlock: :boolean])
220
250
{[verbose: true, source: "lib"], ["test/enum_test.exs", "--unlock"], []}
221
251
222
252
"""
@@ -236,10 +266,12 @@ defmodule OptionParser do
236
266
237
267
## Examples
238
268
239
- iex> OptionParser.parse_head!(["--source", "lib", "path/to/file", "--verbose"])
269
+ iex> OptionParser.parse_head!(["--source", "lib", "path/to/file", "--verbose"],
270
+ ...> switches: [source: :string, verbose: :boolean])
240
271
{[source: "lib"], ["path/to/file", "--verbose"]}
241
272
242
- iex> OptionParser.parse_head!(["--number", "lib", "test/enum_test.exs", "--verbose"], strict: [number: :integer])
273
+ iex> OptionParser.parse_head!(["--number", "lib", "test/enum_test.exs", "--verbose"],
274
+ ...> strict: [number: :integer])
243
275
** (OptionParser.ParseError) 1 error found!
244
276
--number : Expected type integer, got "lib"
245
277
@@ -309,7 +341,6 @@ defmodule OptionParser do
309
341
* `{:error, rest}` - there are no switches at the head of the given `argv`
310
342
311
343
"""
312
-
313
344
@ spec next ( argv , options ) ::
314
345
{ :ok , key :: atom , value :: term , argv } |
315
346
{ :invalid , String . t , String . t | nil , argv } |
0 commit comments