16
16
# A sample array of definition hashes could look like this:
19
# { :short => 'a', :long => 'all', :argument => :forbidden },
20
# { :short => 'p', :long => 'port', :argument => :required },
19
# { :short => 'a', :long => 'all', :argument => :forbidden, :multiple => true },
20
# { :short => 'p', :long => 'port', :argument => :required, :multiple => false },
23
23
# For example, the following commandline options (which should not be
84
84
# @return [Hash] The already parsed options.
85
85
attr_reader :options
87
# The arguments that have already been parsed.
89
# If the parser was stopped before it finished, this will not contain all
90
# options and `unprocessed_arguments_and_options` will contain what is
91
# left to be processed.
93
# @return [Array] The already parsed arguments.
94
attr_reader :arguments
87
# @return [Array] The arguments that have already been parsed, including
89
attr_reader :raw_arguments
96
91
# The options and arguments that have not yet been processed. If the
97
92
# parser wasn’t stopped (using {#stop}), this list will be empty.
122
117
@unprocessed_arguments_and_options = arguments_and_options.dup
123
118
@definitions = definitions
129
124
@no_more_options = false
127
# Returns the arguments that have already been parsed.
129
# If the parser was stopped before it finished, this will not contain all
130
# options and `unprocessed_arguments_and_options` will contain what is
131
# left to be processed.
133
# @return [Array] The already parsed arguments.
135
ArgumentArray.new(@raw_arguments).freeze
132
138
# @return [Boolean] true if the parser is running, false otherwise.
161
167
e = @unprocessed_arguments_and_options.shift
164
# Handle end-of-options marker
166
@no_more_options = true
167
# Handle incomplete options
168
172
elsif e =~ /^--./ and !@no_more_options
169
# Get option key, and option value if included
170
if e =~ /^--([^=]+)=(.+)$/
174
option_key = e[2..-1]
179
definition = @definitions.find { |d| d[:long] == option_key }
180
raise IllegalOptionError.new(option_key) if definition.nil?
182
if [ :required, :optional ].include?(definition[:argument])
183
# Get option value if necessary
185
option_value = @unprocessed_arguments_and_options.shift
186
if option_value.nil? || option_value =~ /^-/
187
if definition[:argument] == :required
188
raise OptionRequiresAnArgumentError.new(option_key)
190
@unprocessed_arguments_and_options.unshift(option_value)
197
add_option(definition, option_value)
200
add_option(definition, true)
202
# Handle -xyz options
173
handle_dashdash_option(e)
203
174
elsif e =~ /^-./ and !@no_more_options
205
option_keys = e[1..-1].scan(/./)
208
option_keys.each do |option_key|
210
definition = @definitions.find { |d| d[:short] == option_key }
211
raise IllegalOptionError.new(option_key) if definition.nil?
213
if option_keys.length > 1 and definition[:argument] == :required
214
# This is a combined option and it requires an argument, so complain
215
raise OptionRequiresAnArgumentError.new(option_key)
216
elsif [ :required, :optional ].include?(definition[:argument])
218
option_value = @unprocessed_arguments_and_options.shift
219
if option_value.nil? || option_value =~ /^-/
220
if definition[:argument] == :required
221
raise OptionRequiresAnArgumentError.new(option_key)
223
@unprocessed_arguments_and_options.unshift(option_value)
229
add_option(definition, option_value)
232
add_option(definition, true)
235
# Handle normal arguments
175
handle_dash_option(e)
187
def handle_dashdash(e)
189
@no_more_options = true
192
def handle_dashdash_option(e)
193
# Get option key, and option value if included
194
if e =~ /^--([^=]+)=(.+)$/
198
option_key = e[2..-1]
203
definition = @definitions.find { |d| d[:long] == option_key }
204
raise IllegalOptionError.new(option_key) if definition.nil?
206
if [ :required, :optional ].include?(definition[:argument])
207
# Get option value if necessary
209
option_value = find_option_value(definition, option_key)
213
add_option(definition, option_value)
216
add_option(definition, true)
220
def handle_dash_option(e)
222
option_keys = e[1..-1].scan(/./)
225
option_keys.each do |option_key|
227
definition = @definitions.find { |d| d[:short] == option_key }
228
raise IllegalOptionError.new(option_key) if definition.nil?
230
if option_keys.length > 1 and definition[:argument] == :required
231
# This is a combined option and it requires an argument, so complain
232
raise OptionRequiresAnArgumentError.new(option_key)
233
elsif [ :required, :optional ].include?(definition[:argument])
235
option_value = find_option_value(definition, option_key)
238
add_option(definition, option_value)
241
add_option(definition, true)
246
def find_option_value(definition, option_key)
247
option_value = @unprocessed_arguments_and_options.shift
248
if option_value.nil? || option_value =~ /^-/
249
if definition[:argument] == :required
250
raise OptionRequiresAnArgumentError.new(option_key)
252
@unprocessed_arguments_and_options.unshift(option_value)
247
259
def add_option(definition, value)
248
260
key = (definition[:long] || definition[:short]).to_sym
261
if definition[:multiple]
263
options[key] << value
250
268
delegate.option_added(key, value, self) unless delegate.nil?
253
271
def add_argument(value)
255
delegate.argument_added(value, self) unless delegate.nil?
272
@raw_arguments << value
275
delegate.argument_added(value, self) unless delegate.nil?