@@ -86,7 +86,8 @@ defmodule OptionParser do
86
86
87
87
"""
88
88
def parse ( argv , opts \\ [ ] ) when is_list ( argv ) and is_list ( opts ) do
89
- parse ( argv , opts , true )
89
+ config = compile_config ( opts , all: true )
90
+ do_parse ( argv , config , [ ] , [ ] , [ ] )
90
91
end
91
92
92
93
@ doc """
@@ -105,74 +106,117 @@ defmodule OptionParser do
105
106
106
107
"""
107
108
def parse_head ( argv , opts \\ [ ] ) when is_list ( argv ) and is_list ( opts ) do
108
- parse ( argv , opts , false )
109
+ config = compile_config ( opts , all: false )
110
+ do_parse ( argv , config , [ ] , [ ] , [ ] )
109
111
end
110
112
111
- ## Helpers
112
113
113
- defp parse ( argv , opts , bool ) do
114
- aliases = opts [ :aliases ] || [ ]
115
- switches = opts [ :switches ] || [ ]
116
- parse ( argv , aliases , switches , bool )
114
+ defp do_parse ( [ ] , _config , opts , args , invalid ) do
115
+ { Enum . reverse ( opts ) , Enum . reverse ( args ) , Enum . reverse ( invalid ) }
116
+ end
117
+
118
+ defp do_parse ( argv , { aliases , switches , all } = config , opts , args , invalid ) do
119
+ case next ( argv , aliases , switches ) do
120
+ { :ok , option , value , rest } ->
121
+ # the option exist and it was successfully parsed
122
+ kinds = List . wrap Keyword . get ( switches , option )
123
+ new_opts = do_store_option ( opts , option , value , kinds )
124
+ do_parse ( rest , config , new_opts , args , invalid )
125
+
126
+ { :error , option , value , rest } ->
127
+ # the option exist but it has wrong value
128
+ do_parse ( rest , config , opts , args , [ { option , value } | invalid ] )
129
+
130
+ { :error , option , rest } ->
131
+ # the option does not exist (for strict cases)
132
+ do_parse ( rest , config , opts , args , [ { option , nil } | invalid ] )
133
+
134
+ { :error , [ "--" | rest ] } ->
135
+ { Enum . reverse ( opts ) , Enum . reverse ( args , rest ) , Enum . reverse ( invalid ) }
136
+
137
+ { :error , [ arg | rest ] = remaining_args } ->
138
+ # there is no option
139
+ if all do
140
+ do_parse ( rest , config , opts , [ arg | args ] , invalid )
141
+ else
142
+ { Enum . reverse ( opts ) , Enum . reverse ( args , remaining_args ) , Enum . reverse ( invalid ) }
143
+ end
144
+ end
117
145
end
118
146
119
- defp parse ( argv , aliases , switches , all ) do
120
- parse ( argv , aliases , switches , [ ] , [ ] , [ ] , all )
147
+
148
+ @ doc """
149
+ Low-level function that parses one option.
150
+ """
151
+ def next ( argv , opts \\ [ ] ) when is_list ( argv ) and is_list ( opts ) do
152
+ { aliases , switches , _ } = compile_config ( opts , false )
153
+ next ( argv , aliases , switches )
121
154
end
122
155
123
- defp parse ( [ "--" | t ] , _aliases , _switches , dict , args , invalid , _all ) do
124
- { Enum . reverse ( dict ) , Enum . reverse ( args , t ) , Enum . reverse ( invalid ) }
156
+ defp next ( [ ] , _aliases , _switches ) do
157
+ { :error , [ ] }
125
158
end
126
159
127
- defp parse ( [ "-" <> option | t ] , aliases , switches , dict , args , invalid , all ) do
160
+ defp next ( [ "--" | _ ] = argv , _aliases , _switches ) do
161
+ { :error , argv }
162
+ end
163
+
164
+ defp next ( [ "-" <> option | rest ] , aliases , switches ) do
128
165
{ option , value } = split_option ( option )
129
166
{ option , kinds , value } = normalize_option ( option , value , switches , aliases )
130
- { value , kinds , t } = normalize_value ( value , kinds , t )
131
- { dict , invalid } = store_option ( dict , invalid , option , value , kinds )
132
- parse ( t , aliases , switches , dict , args , invalid , all )
133
- end
134
167
135
- defp parse ( [ h | t ] , aliases , switches , dict , args , invalid , true ) do
136
- parse ( t , aliases , switches , dict , [ h | args ] , invalid , true )
168
+ #FIXME: don't modify rest for unknown options in strict mode
169
+ { value , kinds , rest } = normalize_value ( value , kinds , rest )
170
+
171
+ case validate_option ( option , value , kinds ) do
172
+ { :ok , new_value } ->
173
+ { :ok , option , new_value , rest }
174
+
175
+ :invalid ->
176
+ { :error , option , value , rest }
177
+ end
137
178
end
138
179
139
- defp parse ( [ ] , _ , _switches , dict , args , invalid , true ) do
140
- { Enum . reverse ( dict ) , Enum . reverse ( args ) , Enum . reverse ( invalid ) }
180
+ defp next ( argv , _aliases , _switches ) do
181
+ { :error , argv }
141
182
end
142
183
143
- defp parse ( value , _ , _switches , dict , _args , invalid , false ) do
144
- { Enum . reverse ( dict ) , value , Enum . reverse ( invalid ) }
184
+ ## Helpers
185
+
186
+ defp compile_config ( opts , all: flag ) do
187
+ aliases = opts [ :aliases ] || [ ]
188
+ switches = opts [ :switches ] || [ ]
189
+ { aliases , switches , flag }
145
190
end
146
191
147
- defp store_option ( dict , invalid , option , value , kinds ) do
148
- { invalid_option , value } =
149
- cond do
150
- :invalid in kinds ->
151
- { option , value }
152
- :boolean in kinds ->
153
- case value do
154
- t when t in [ true , "true" ] -> { nil , true }
155
- f when f in [ false , "false" ] -> { nil , false }
156
- _ -> { option , value }
157
- end
158
- :integer in kinds ->
159
- case Integer . parse ( value ) do
160
- { value , "" } -> { nil , value }
161
- _ -> { option , value }
162
- end
163
- :float in kinds ->
164
- case Float . parse ( value ) do
165
- { value , "" } -> { nil , value }
166
- _ -> { option , value }
167
- end
168
- true ->
169
- { nil , value }
170
- end
171
-
172
- if invalid_option do
173
- { dict , [ { option , value } | invalid ] }
192
+ defp validate_option ( option , value , kinds ) do
193
+ { invalid_opt , value } = cond do
194
+ :invalid in kinds ->
195
+ { option , value }
196
+ :boolean in kinds ->
197
+ case value do
198
+ t when t in [ true , "true" ] -> { nil , true }
199
+ f when f in [ false , "false" ] -> { nil , false }
200
+ _ -> { option , value }
201
+ end
202
+ :integer in kinds ->
203
+ case Integer . parse ( value ) do
204
+ { value , "" } -> { nil , value }
205
+ _ -> { option , value }
206
+ end
207
+ :float in kinds ->
208
+ case Float . parse ( value ) do
209
+ { value , "" } -> { nil , value }
210
+ _ -> { option , value }
211
+ end
212
+ true ->
213
+ { nil , value }
214
+ end
215
+
216
+ if invalid_opt do
217
+ :invalid
174
218
else
175
- { do_store_option ( dict , option , value , kinds ) , invalid }
219
+ { :ok , value }
176
220
end
177
221
end
178
222
0 commit comments