clasp-ruby 0.23.0.1 → 0.23.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +63 -52
  3. data/examples/cr-example.rb +16 -16
  4. data/examples/flag_and_option_specifications.md +25 -25
  5. data/examples/flag_and_option_specifications.rb +6 -6
  6. data/examples/show_usage_and_version.md +5 -5
  7. data/examples/show_usage_and_version.rb +1 -1
  8. data/examples/simple_command_line_no_specifications.rb +1 -1
  9. data/lib/clasp/arguments.rb +538 -537
  10. data/lib/clasp/clasp.rb +7 -7
  11. data/lib/clasp/cli.rb +140 -135
  12. data/lib/clasp/doc_.rb +3 -3
  13. data/lib/clasp/old_module.rb +3 -3
  14. data/lib/clasp/specifications.rb +337 -333
  15. data/lib/clasp/util/exceptions.rb +17 -17
  16. data/lib/clasp/util/value_parser.rb +97 -97
  17. data/lib/clasp/version.rb +15 -15
  18. data/lib/clasp-ruby.rb +3 -2
  19. data/lib/clasp.rb +3 -2
  20. data/test/scratch/test_list_command_line.rb +6 -6
  21. data/test/scratch/test_specifications.rb +14 -14
  22. data/test/scratch/test_usage.rb +6 -6
  23. data/test/scratch/test_usage_from_DATA.rb +1 -1
  24. data/test/scratch/test_usage_with_duplicate_specifications.rb +6 -6
  25. data/test/unit/tc_ARGV_rewrite.rb +36 -38
  26. data/test/unit/tc_arguments_1.rb +694 -694
  27. data/test/unit/tc_arguments_2.rb +52 -53
  28. data/test/unit/tc_arguments_3.rb +77 -77
  29. data/test/unit/tc_arguments_inspect.rb +55 -56
  30. data/test/unit/tc_cli.rb +4 -4
  31. data/test/unit/tc_default_value.rb +91 -91
  32. data/test/unit/tc_defaults_1.rb +38 -38
  33. data/test/unit/tc_examples_Arguments.rb +130 -132
  34. data/test/unit/tc_extras.rb +24 -26
  35. data/test/unit/tc_option_required.rb +38 -39
  36. data/test/unit/tc_option_value_aliases.rb +44 -44
  37. data/test/unit/tc_specifications.rb +7 -8
  38. data/test/unit/tc_typed_options.rb +204 -204
  39. data/test/unit/tc_usage.rb +112 -55
  40. data/test/unit/tc_with_action.rb +23 -24
  41. data/test/unit/ts_all.rb +1 -1
  42. metadata +5 -4
@@ -6,13 +6,13 @@
6
6
  # CLASP.Ruby
7
7
  #
8
8
  # Created: 14th February 2014
9
- # Updated: 24th July 2022
9
+ # Updated: 20th January 2024
10
10
  #
11
11
  # Home: http://github.com/synesissoftware/CLASP.Ruby
12
12
  #
13
13
  # Author: Matthew Wilson
14
14
  #
15
- # Copyright (c) 2019-2022, Matthew Wilson and Synesis Information Systems
15
+ # Copyright (c) 2019-2024, Matthew Wilson and Synesis Information Systems
16
16
  # Copyright (c) 2014-2019, Matthew Wilson and Synesis Software
17
17
  # All rights reserved.
18
18
  #
@@ -63,714 +63,715 @@ module CLASP
63
63
  # The main class for processing command-line arguments
64
64
  class Arguments
65
65
 
66
- # Class that represents a parsed flag
67
- class FlagArgument
68
-
69
- # @!visibility private
70
- #
71
- # [PRIVATE] This method is subject to changed between versions and
72
- # should not be called directly from application code
73
- def initialize(arg, given_index, given_name, resolved_name, argument_spec, given_hyphens, given_label, extras) # :nodoc:
74
-
75
- @arg = arg
76
- @given_index = given_index
77
- @given_name = given_name
78
- @argument_specification = argument_spec
79
- @given_hyphens = given_hyphens
80
- @given_label = given_label
81
- @name = resolved_name || given_name
82
- @extras = extras.nil? ? {} : extras
83
- end
84
-
85
- # (Integer) The command-line index of the argument
86
- attr_reader :given_index
87
- # (String) The given name of the argument as it appeared in the command-line
88
- attr_reader :given_name
89
- # (CLASP::FlagSpecification) The specification matching the argument, or +nil+
90
- attr_reader :argument_specification
91
- # (Integer) The number of hyphens of the argument as it appeared in the command-line
92
- attr_reader :given_hyphens
93
- # (String) The label of the argument as it appeared in the command-line
94
- attr_reader :given_label
95
- # (String) The resolved name of the argument
96
- attr_reader :name
97
- # (Object, Hash) The extras associated with the argument
98
- attr_reader :extras
99
-
100
- # [DEPRECATED] Use +argument_specification+
101
- def argument_alias; @argument_specification; end
102
-
103
- # (String) The string form of the flag, which is the same as +name+
104
- def to_s
105
-
106
- @name
107
- end
108
-
109
- # @!visibility private
110
- def eql?(rhs) # :nodoc:
111
-
112
- return false if rhs.nil?
113
-
114
- # check name and aliases
115
- return true if @name == rhs
116
- return argument_specification.aliases.include? rhs if argument_specification
117
- false
118
- end
119
-
120
- # @!visibility private
121
- def ==(rhs) # :nodoc:
122
-
123
- return false if rhs.nil?
124
- if not rhs.instance_of? String
125
-
126
- rhs = rhs.name
127
- end
128
- eql? rhs
129
- end
130
-
131
- # A hash-code for this instance
132
- def hash
133
-
134
- @arg.hash
135
- end
136
- end
137
-
138
- # Class that represents a parsed option
139
- class OptionArgument
140
-
141
- include ::CLASP::Util::ValueParser
142
-
143
- # @!visibility private
144
- #
145
- # [PRIVATE] This method is subject to changed between versions and
146
- # should not be called directly from application code
147
- def initialize(arg, given_index, given_name, resolved_name, argument_spec, given_hyphens, given_label, value, extras) # :nodoc:
148
-
149
- resolved_value = nil
150
-
151
- if argument_spec
152
-
153
- case constraint = (argument_spec.constraint || {})
66
+ # Class that represents a parsed flag
67
+ class FlagArgument
68
+
69
+ # @!visibility private
70
+ #
71
+ # [PRIVATE] This method is subject to changed between versions and
72
+ # should not be called directly from application code
73
+ def initialize(arg, given_index, given_name, resolved_name, argument_spec, given_hyphens, given_label, extras) # :nodoc:
74
+
75
+ @arg = arg
76
+ @given_index = given_index
77
+ @given_name = given_name
78
+ @argument_specification = argument_spec
79
+ @given_hyphens = given_hyphens
80
+ @given_label = given_label
81
+ @name = resolved_name || given_name
82
+ @extras = extras.nil? ? {} : extras
83
+ end
84
+
85
+ # (Integer) The command-line index of the argument
86
+ attr_reader :given_index
87
+ # (String) The given name of the argument as it appeared in the command-line
88
+ attr_reader :given_name
89
+ # (CLASP::FlagSpecification) The specification matching the argument, or +nil+
90
+ attr_reader :argument_specification
91
+ # (Integer) The number of hyphens of the argument as it appeared in the command-line
92
+ attr_reader :given_hyphens
93
+ # (String) The label of the argument as it appeared in the command-line
94
+ attr_reader :given_label
95
+ # (String) The resolved name of the argument
96
+ attr_reader :name
97
+ # (Object, Hash) The extras associated with the argument
98
+ attr_reader :extras
99
+
100
+ # [DEPRECATED] Use +argument_specification+
101
+ def argument_alias; @argument_specification; end
102
+
103
+ # (String) The string form of the flag, which is the same as +name+
104
+ def to_s
105
+
106
+ @name
107
+ end
108
+
109
+ # @!visibility private
110
+ def eql?(rhs) # :nodoc:
111
+
112
+ return false if rhs.nil?
113
+
114
+ # check name and aliases
115
+ return true if @name == rhs
116
+ return argument_specification.aliases.include? rhs if argument_specification
117
+ false
118
+ end
119
+
120
+ # @!visibility private
121
+ def ==(rhs) # :nodoc:
122
+
123
+ return false if rhs.nil?
124
+ if not rhs.instance_of? String
125
+
126
+ rhs = rhs.name
127
+ end
128
+ eql? rhs
129
+ end
130
+
131
+ # A hash-code for this instance
132
+ def hash
133
+
134
+ @arg.hash
135
+ end
136
+ end
137
+
138
+ # Class that represents a parsed option
139
+ class OptionArgument
140
+
141
+ include ::CLASP::Util::ValueParser
142
+
143
+ # @!visibility private
144
+ #
145
+ # [PRIVATE] This method is subject to changed between versions and
146
+ # should not be called directly from application code
147
+ def initialize(arg, given_index, given_name, resolved_name, argument_spec, given_hyphens, given_label, value, extras) # :nodoc:
148
+
149
+ resolved_value = nil
150
+
151
+ if argument_spec
152
+
153
+ case constraint = (argument_spec.constraint || {})
154
154
  =begin
155
- when Proc
155
+ when Proc
156
156
 
157
- resolved_value = value_from_Proc(constraint, value, arg, given_index, given_name, argument_spec, extras)
157
+ resolved_value = value_from_Proc(constraint, value, arg, given_index, given_name, argument_spec, extras)
158
158
  =end
159
- when Hash
160
-
161
- if constraint.empty?
162
-
163
- resolved_value = (value || '').empty? ? argument_spec.default_value : value
164
- else
165
-
166
- resolved_value = value_from_Hash(constraint, value, arg, given_index, given_name, argument_spec, extras)
167
- end
168
- else
169
-
170
- warn "unexpected constraint on argument specification #{argument_spec} when parsing argument '#{arg}'"
171
- end
172
- else
173
-
174
- resolved_value = value
175
- end
176
-
177
- @arg = arg
178
- @given_index = given_index
179
- @given_name = given_name
180
- @argument_specification = argument_spec
181
- @given_hyphens = given_hyphens
182
- @given_label = given_label
183
- @given_value = value
184
- @value = resolved_value
185
- @name = resolved_name || given_name
186
- @extras = extras.nil? ? {} : extras
187
- end
188
-
189
- # (Integer) The command-line index of the argument
190
- attr_reader :given_index
191
- # (String) The given name of the argument as it appeared in the command-line
192
- attr_reader :given_name
193
- # (CLASP::OptionSpecification) The specification matching the argument, or +nil+
194
- attr_reader :argument_specification
195
- # (Integer) The number of hyphens of the argument as it appeared in the command-line
196
- attr_reader :given_hyphens
197
- # (String) The label of the argument as it appeared in the command-line
198
- attr_reader :given_label
199
- # (String) The resolved name of the argument
200
- attr_reader :name
201
- # (String) The given value of the option
202
- attr_reader :given_value
203
- # (????) The value of the option, which may be of a type other than string subject to the option specification's constraint
204
- attr_reader :value
205
- # (Object, Hash) The extras associated with the argument
206
- attr_reader :extras
207
-
208
- # [DEPRECATED] Use +argument_specification+
209
- def argument_alias; @argument_specification; end
210
-
211
- # @!visibility private
212
- def eql?(rhs) # :nodoc:
213
-
214
- return false if rhs.nil?
215
-
216
- # check name and aliases
217
- return true if @name == rhs
218
- return argument_specification.aliases.include? rhs if argument_specification
219
- false
220
- end
159
+ when Hash
160
+
161
+ if constraint.empty?
162
+
163
+ resolved_value = (value || '').empty? ? argument_spec.default_value : value
164
+ else
165
+
166
+ resolved_value = value_from_Hash(constraint, value, arg, given_index, given_name, argument_spec, extras)
167
+ end
168
+ else
169
+
170
+ warn "unexpected constraint on argument specification #{argument_spec} when parsing argument '#{arg}'"
171
+ end
172
+ else
173
+
174
+ resolved_value = value
175
+ end
176
+
177
+ @arg = arg
178
+ @given_index = given_index
179
+ @given_name = given_name
180
+ @argument_specification = argument_spec
181
+ @given_hyphens = given_hyphens
182
+ @given_label = given_label
183
+ @given_value = value
184
+ @value = resolved_value
185
+ @name = resolved_name || given_name
186
+ @extras = extras.nil? ? {} : extras
187
+ end
188
+
189
+ # (Integer) The command-line index of the argument
190
+ attr_reader :given_index
191
+ # (String) The given name of the argument as it appeared in the command-line
192
+ attr_reader :given_name
193
+ # (CLASP::OptionSpecification) The specification matching the argument, or +nil+
194
+ attr_reader :argument_specification
195
+ # (Integer) The number of hyphens of the argument as it appeared in the command-line
196
+ attr_reader :given_hyphens
197
+ # (String) The label of the argument as it appeared in the command-line
198
+ attr_reader :given_label
199
+ # (String) The resolved name of the argument
200
+ attr_reader :name
201
+ # (String) The given value of the option
202
+ attr_reader :given_value
203
+ # (????) The value of the option, which may be of a type other than string subject to the option specification's constraint
204
+ attr_reader :value
205
+ # (Object, Hash) The extras associated with the argument
206
+ attr_reader :extras
207
+
208
+ # [DEPRECATED] Use +argument_specification+
209
+ def argument_alias; @argument_specification; end
210
+
211
+ # @!visibility private
212
+ def eql?(rhs) # :nodoc:
213
+
214
+ return false if rhs.nil?
215
+
216
+ # check name and aliases
217
+ return true if @name == rhs
218
+ return argument_specification.aliases.include? rhs if argument_specification
219
+ false
220
+ end
221
221
 
222
- # @!visibility private
223
- def ==(rhs) # :nodoc:
222
+ # @!visibility private
223
+ def ==(rhs) # :nodoc:
224
224
 
225
- return false if rhs.nil?
226
- if not rhs.instance_of? String
225
+ return false if rhs.nil?
226
+ if not rhs.instance_of? String
227
227
 
228
- rhs = rhs.name
229
- end
230
- eql? rhs
231
- end
228
+ rhs = rhs.name
229
+ end
230
+ eql? rhs
231
+ end
232
232
 
233
- # A hash-code for this instance
234
- def hash
233
+ # A hash-code for this instance
234
+ def hash
235
235
 
236
- @arg.hash
237
- end
236
+ @arg.hash
237
+ end
238
238
 
239
- # (String) The string form of the flag, which is the same as +name+=+value+
240
- def to_s
239
+ # (String) The string form of the flag, which is the same as +name+=+value+
240
+ def to_s
241
241
 
242
- "#{name}=#{value}"
243
- end
244
- end
242
+ "#{name}=#{value}"
243
+ end
244
+ end
245
245
 
246
- # ######################
247
- # Construction
246
+ # ######################
247
+ # Construction
248
248
 
249
- # Loads an instance of the class, as specified by +source+, according to the given parameters
250
- #
251
- # See the documentation for the ::CLASP module for examples
252
- #
253
- # === Signature
254
- #
255
- # * *Parameters:*
256
- # - +argv+ (+Array+) The arguments array. May not be +nil+. Defaults to +ARGV+
257
- # - +source+ (+Hash+, +IO+) The arguments specification, either as a Hash or an instance of an IO-implementing type containing a YAML specification
258
- # - +options+ An options hash, containing any of the following options
259
- #
260
- # * *Options:*
261
- # - +mutate_argv:+ (+Boolean+) Determines if the library should mutate +argv+. Defaults to +true+. This is essential when using CLASP in conjunction with <tt>$\<</tt>
262
- #
263
- def self.load(argv, source, options = {}) # :yields: An instance of +CLASP::Arguments+
249
+ # Loads an instance of the class, as specified by +source+, according to the given parameters
250
+ #
251
+ # See the documentation for the ::CLASP module for examples
252
+ #
253
+ # === Signature
254
+ #
255
+ # * *Parameters:*
256
+ # - +argv+ (+Array+) The arguments array. May not be +nil+. Defaults to +ARGV+
257
+ # - +source+ (+Hash+, +IO+) The arguments specification, either as a Hash or an instance of an IO-implementing type containing a YAML specification
258
+ # - +options+ An options hash, containing any of the following options
259
+ #
260
+ # * *Options:*
261
+ # - +:mutate_argv+ (+Boolean+) Determines if the library should mutate +argv+. Defaults to +true+. This is essential when using CLASP in conjunction with <tt>$\<</tt>
262
+ #
263
+ def self.load(argv, source, options = {}) # :yields: An instance of +CLASP::Arguments+
264
264
 
265
- options ||= {}
265
+ options ||= {}
266
266
 
267
- specs = load_specifications(source, options)
267
+ specs = load_specifications(source, options)
268
268
 
269
- self.new argv, specs, options
270
- end
269
+ self.new argv, specs, options
270
+ end
271
271
 
272
- # Loads the specifications as specified by +source+, according to the given parameters
273
- #
274
- # === Signature
275
- #
276
- # * *Parameters:*
277
- # - +source+ (+Hash+, +IO+) The arguments specification, either as a Hash or an instance of an IO-implementing type containing a YAML specification
278
- # - +options+ An options hash, containing any of the following options
279
- def self.load_specifications(source, options = {}) # :yields: An array of specification instances
272
+ # Loads the specifications as specified by +source+, according to the given parameters
273
+ #
274
+ # === Signature
275
+ #
276
+ # * *Parameters:*
277
+ # - +source+ (+Hash+, +IO+) The arguments specification, either as a Hash or an instance of an IO-implementing type containing a YAML specification
278
+ # - +options+ An options hash, containing any of the following options
279
+ def self.load_specifications(source, options = {}) # :yields: An array of specification instances
280
280
 
281
- options ||= {}
281
+ options ||= {}
282
282
 
283
- h = nil
283
+ h = nil
284
284
 
285
- case source
286
- when ::IO
285
+ case source
286
+ when ::IO
287
287
 
288
- h = YAML.load(source.read)
289
- when ::Hash
288
+ h = YAML.load(source.read)
289
+ when ::Hash
290
290
 
291
- h = source
292
- else
291
+ h = source
292
+ else
293
293
 
294
- if source.respond_to?(:to_hash)
294
+ if source.respond_to?(:to_hash)
295
295
 
296
- h = source.to_hash
297
- else
296
+ h = source.to_hash
297
+ else
298
298
 
299
- raise TypeError, "#{self}.#{__method__}() 'source' argument must be a #{::Hash}, or an object implementing #{::IO}, or a type implementing to_hash'"
300
- end
301
- end
299
+ raise TypeError, "#{self}.#{__method__}() 'source' argument must be a #{::Hash}, or an object implementing #{::IO}, or a type implementing to_hash'"
300
+ end
301
+ end
302
302
 
303
- specs = []
303
+ specs = []
304
304
 
305
- _clasp = h['clasp'] or raise ArgumentError, "missing top-level 'clasp' element in load configuration"
306
- ::Hash === _clasp or raise ArgumentError, "top-level 'clasp' element must be a #{::Hash}"
305
+ _clasp = h['clasp'] or raise ArgumentError, "missing top-level 'clasp' element in load configuration"
306
+ ::Hash === _clasp or raise ArgumentError, "top-level 'clasp' element must be a #{::Hash}"
307
307
 
308
- _specs = (_clasp['arg-specs'] || _clasp['specifications'] || _clasp['aliases']) or raise ArgumentError, "missing element 'clasp/specifications'"
309
- ::Array === _specs or raise ArgumentError, "top-level 'specifications' element must be a #{::Hash}"
308
+ _specs = (_clasp['arg-specs'] || _clasp['specifications'] || _clasp['aliases']) or raise ArgumentError, "missing element 'clasp/specifications'"
309
+ ::Array === _specs or raise ArgumentError, "top-level 'specifications' element must be a #{::Hash}"
310
310
 
311
- _specs.each do |_spec|
311
+ _specs.each do |_spec|
312
312
 
313
- case _spec
314
- when ::Hash
313
+ case _spec
314
+ when ::Hash
315
315
 
316
- # TODO: make a utility function and shrink all the following
316
+ # TODO: make a utility function and shrink all the following
317
317
 
318
- _spec.each do |_arg_type, _details|
318
+ _spec.each do |_arg_type, _details|
319
319
 
320
- case _arg_type
321
- when 'flag', :flag
320
+ case _arg_type
321
+ when 'flag', :flag
322
322
 
323
- _name = _details['name']
323
+ _name = _details['name']
324
324
 
325
- unless _name
325
+ unless _name
326
326
 
327
- warn "flag specification missing required 'name' field"
328
- else
327
+ warn "flag specification missing required 'name' field"
328
+ else
329
329
 
330
- _alias = _details['alias']
331
- _aliases = _details['aliases']
332
- _help = _details['help'] || _details['description']
330
+ _alias = _details['alias']
331
+ _aliases = _details['aliases']
332
+ _help = _details['help'] || _details['description']
333
333
 
334
- specs << CLASP.Flag(_name, alias: _alias, aliases: _aliases, help: _help)
335
- end
336
- when 'option', :option
334
+ specs << CLASP.Flag(_name, alias: _alias, aliases: _aliases, help: _help)
335
+ end
336
+ when 'option', :option
337
337
 
338
- _name = _details['name']
338
+ _name = _details['name']
339
339
 
340
- unless _name
340
+ unless _name
341
341
 
342
- warn "option specification missing required 'name' field"
343
- else
342
+ warn "option specification missing required 'name' field"
343
+ else
344
344
 
345
- _alias = _details['alias']
346
- _aliases = _details['aliases']
347
- _default_value = _details['default_value'] || _details['default']
348
- _help = _details['help'] || _details['description']
349
- _required = _details['required']
350
- _required_message = _details['required_message']
351
- _values_range = _details['values_range'] || _details['values']
345
+ _alias = _details['alias']
346
+ _aliases = _details['aliases']
347
+ _default_value = _details['default_value'] || _details['default']
348
+ _help = _details['help'] || _details['description']
349
+ _required = _details['required']
350
+ _required_message = _details['required_message']
351
+ _values_range = _details['values_range'] || _details['values']
352
352
 
353
- specs << CLASP.Option(_name, alias: _alias, aliases: _aliases, default_value: _default_value, help: _help, required: _required, required_message: _required_message, values_range: _values_range)
354
- end
355
- when 'alias', :alias
353
+ specs << CLASP.Option(_name, alias: _alias, aliases: _aliases, default_value: _default_value, help: _help, required: _required, required_message: _required_message, values_range: _values_range)
354
+ end
355
+ when 'alias', :alias
356
356
 
357
- _resolved = _details['resolved']
357
+ _resolved = _details['resolved']
358
358
 
359
- unless _resolved
359
+ unless _resolved
360
360
 
361
- warn "alias specification missing required 'resolved' field"
362
- else
361
+ warn "alias specification missing required 'resolved' field"
362
+ else
363
363
 
364
- _alias = _details['alias']
365
- _aliases = _details['aliases']
364
+ _alias = _details['alias']
365
+ _aliases = _details['aliases']
366
366
 
367
- unless _alias || _aliases
367
+ unless _alias || _aliases
368
368
 
369
- warn "alias specification missing required 'alias' or 'aliases' field"
370
- else
369
+ warn "alias specification missing required 'alias' or 'aliases' field"
370
+ else
371
371
 
372
- specs << CLASP.Flag(_resolved, alias: _alias, aliases: _aliases)
373
- end
374
- end
375
- else
372
+ specs << CLASP.Flag(_resolved, alias: _alias, aliases: _aliases)
373
+ end
374
+ end
375
+ else
376
376
 
377
- warn "unknown arg-type '#{_arg_type}' specified"
378
- end
379
- end
380
- else
377
+ warn "unknown arg-type '#{_arg_type}' specified"
378
+ end
379
+ end
380
+ else
381
381
 
382
- warn "non-#{::Hash} element in 'clasp/specifications': #{_spec} (of type #{_spec.class})"
383
- end
384
- end
382
+ warn "non-#{::Hash} element in 'clasp/specifications': #{_spec} (of type #{_spec.class})"
383
+ end
384
+ end
385
385
 
386
- specs
387
- end
386
+ specs
387
+ end
388
388
 
389
- # Constructs an instance of the class, according to the given parameters
390
- #
391
- # See the documentation for the ::CLASP module for examples
392
- #
393
- # === Signature
394
- #
395
- # * *Parameters:*
396
- # - +argv+ (+Array+) The arguments array. May not be +nil+. Defaults to +ARGV+
397
- # - +specifications+ (+Array+) The specifications array. Defaults to +nil+. If none supplied, no aliasing will be performed
398
- # - +options+ An options hash, containing any of the following options
399
- #
400
- # * *Options:*
401
- # - +mutate_argv:+ (+Boolean+) Determines if the library should mutate +argv+. Defaults to +true+. This is essential when using CLASP in conjunction with <tt>$\<</tt>
402
- #
403
- def initialize(argv = ARGV, specifications = nil, options = {})
389
+ # Constructs an instance of the class, according to the given parameters
390
+ #
391
+ # See the documentation for the ::CLASP module for examples
392
+ #
393
+ # === Signature
394
+ #
395
+ # * *Parameters:*
396
+ # - +argv+ (+Array+) The arguments array. May not be +nil+. Defaults to +ARGV+
397
+ # - +specifications+ (+Array+) The specifications array. Defaults to +nil+. If none supplied, no aliasing will be performed
398
+ # - +options+ An options hash, containing any of the following options
399
+ #
400
+ # * *Options:*
401
+ # - +:mutate_argv+ (+Boolean+) Determines if the library should mutate +argv+. Defaults to +true+. This is essential when using CLASP in conjunction with <tt>$\<</tt>
402
+ #
403
+ def initialize(argv = ARGV, specifications = nil, options = {})
404
404
 
405
- # have to do this name-swap, as 'options' has CLASP-specific
406
- # meaning
407
- init_opts, options = options.dup, nil
405
+ # have to do this name-swap, as 'options' has CLASP-specific
406
+ # meaning
407
+ init_opts, options = options.dup, nil
408
408
 
409
- init_opts[:mutate_argv] = true unless init_opts.has_key? :mutate_argv
409
+ init_opts[:mutate_argv] = true unless init_opts.has_key? :mutate_argv
410
410
 
411
- @program_name = init_opts[:program_name] || Arguments.derive_program_name_
411
+ @program_name = init_opts[:program_name] || Arguments.derive_program_name_
412
412
 
413
- @argv = argv
414
- argv = argv.dup
415
- @argv_original_copy = argv.dup.freeze
413
+ @argv = argv
414
+ argv = argv.dup
415
+ @argv_original_copy = argv.dup.freeze
416
416
 
417
- @specifications = specifications
418
- @aliases = @specifications
417
+ @specifications = specifications
418
+ @aliases = @specifications
419
419
 
420
- specifications = nil if specifications and specifications.empty?
420
+ specifications = nil if specifications and specifications.empty?
421
421
 
422
- flags, options, values, double_slash_index = Arguments.parse_(argv, specifications)
422
+ flags, options, values, double_slash_index = Arguments.parse_(argv, specifications)
423
423
 
424
- [ flags, options, values ].each do |ar|
424
+ [ flags, options, values ].each do |ar|
425
425
 
426
- class << ar
426
+ class << ar
427
427
 
428
- undef :inspect
429
- undef :to_s
428
+ undef :inspect
429
+ undef :to_s
430
430
 
431
- def to_s
431
+ def to_s
432
432
 
433
- s = ''
433
+ s = ''
434
434
 
435
- s += '['
436
- s += self.map { |v| %Q<"#{v}"> }.join(', ')
437
- s += ']'
435
+ s += '['
436
+ s += self.map { |v| %Q<"#{v}"> }.join(', ')
437
+ s += ']'
438
438
 
439
- s
440
- end
439
+ s
440
+ end
441
441
 
442
- def inspect
442
+ def inspect
443
443
 
444
- s = ''
444
+ s = ''
445
445
 
446
- s += "#<#{self.class}:0x#{(object_id << 1).to_s(16)} ["
447
- s += self.map { |v| v.inspect }.join(', ')
448
- s += "]>"
446
+ s += "#<#{self.class}:0x#{(object_id << 1).to_s(16)} ["
447
+ s += self.map { |v| v.inspect }.join(', ')
448
+ s += "]>"
449
449
 
450
- s
451
- end
452
- end
453
- end
450
+ s
451
+ end
452
+ end
453
+ end
454
454
 
455
- @flags = flags.freeze
456
- @options = options.freeze
457
- @values = values.freeze
455
+ @flags = flags.freeze
456
+ @options = options.freeze
457
+ @values = values.freeze
458
458
 
459
- @double_slash_index = double_slash_index
459
+ @double_slash_index = double_slash_index
460
460
 
461
- # do argv-mutation, if required
462
- if init_opts[:mutate_argv]
461
+ # do argv-mutation, if required
462
+ if init_opts[:mutate_argv]
463
463
 
464
- while not argv.empty?
464
+ while not argv.empty?
465
465
 
466
- argv.shift
467
- end
466
+ argv.shift
467
+ end
468
468
 
469
- @values.each do |v|
469
+ @values.each do |v|
470
470
 
471
- argv << v
472
- end
473
- end
474
- end
471
+ argv << v
472
+ end
473
+ end
474
+ end
475
475
 
476
- private
477
- # @!visibility private
478
- def self.derive_program_name_ # :nodoc:
476
+ private
477
+ # @!visibility private
478
+ def self.derive_program_name_ # :nodoc:
479
479
 
480
- $0
481
- end
480
+ $0
481
+ end
482
482
 
483
- # @!visibility private
484
- def self.parse_(argv, specifications) # :nodoc:
483
+ # @!visibility private
484
+ def self.parse_(argv, specifications) # :nodoc:
485
485
 
486
- flags = []
487
- options = []
488
- values = []
486
+ flags = []
487
+ options = []
488
+ values = []
489
489
 
490
- double_slash_index = nil
490
+ double_slash_index = nil
491
491
 
492
- forced_value = false
493
- pending_option = nil
492
+ forced_value = false
493
+ pending_option = nil
494
494
 
495
- argv.each_with_index do |arg, index|
495
+ argv.each_with_index do |arg, index|
496
496
 
497
- if not forced_value
497
+ if not forced_value
498
498
 
499
- if '--' == arg
499
+ if '--' == arg
500
500
 
501
- # all subsequent arguments are values
502
- forced_value = true
501
+ # all subsequent arguments are values
502
+ forced_value = true
503
503
 
504
- double_slash_index = index if double_slash_index.nil?
504
+ double_slash_index = index if double_slash_index.nil?
505
505
 
506
- next
507
- end
506
+ next
507
+ end
508
508
 
509
- # do regex test to see if option/flag/value
510
- if arg =~ /^(-+)([^=]+)/
509
+ # do regex test to see if option/flag/value
510
+ if arg =~ /^(-+)([^=]+)/
511
511
 
512
- hyphens = $1
513
- given_label = $2
514
- given_name = "#$1#$2"
515
- value = ($' and not $'.empty?) ? $'[1 ... $'.size] : nil
516
- argument_spec = nil
517
- resolved_name = nil
512
+ hyphens = $1
513
+ given_label = $2
514
+ given_name = "#$1#$2"
515
+ value = ($' and not $'.empty?) ? $'[1 ... $'.size] : nil
516
+ argument_spec = nil
517
+ resolved_name = nil
518
518
 
519
- (specifications || []).each do |s|
519
+ (specifications || []).each do |s|
520
520
 
521
- if s.name == given_name or s.aliases.include? given_name
521
+ if s.name == given_name or s.aliases.include? given_name
522
522
 
523
- argument_spec = s
524
- resolved_name = s.name
523
+ argument_spec = s
524
+ resolved_name = s.name
525
525
 
526
- # need to check whether the alias is a default-option
527
- # and, if so, expand out its name and value, and replace
528
- # the name and (if none previously specified) the value
529
- if resolved_name =~ /^(-+)([^=]+)=/
526
+ # need to check whether the alias is a default-option
527
+ # and, if so, expand out its name and value, and replace
528
+ # the name and (if none previously specified) the value
529
+ if resolved_name =~ /^(-+)([^=]+)=/
530
530
 
531
- resolved_name = "#$1#$2"
532
- value ||= $'
531
+ resolved_name = "#$1#$2"
532
+ value ||= $'
533
533
 
534
- # now find the underlying (option) specification
535
- specifications.each do |t|
534
+ # now find the underlying (option) specification
535
+ specifications.each do |t|
536
536
 
537
- if t.name == resolved_name or t.aliases.include? resolved_name
537
+ if t.name == resolved_name or t.aliases.include? resolved_name
538
538
 
539
- argument_spec = t
539
+ argument_spec = t
540
540
 
541
- break
542
- end
543
- end
544
- end
541
+ break
542
+ end
543
+ end
544
+ end
545
545
 
546
- break
547
- end
548
- end
546
+ break
547
+ end
548
+ end
549
549
 
550
- # Here we intercept and (potentially) cater to grouped flags
551
- if not argument_spec and not value and specifications and 1 == hyphens.size
550
+ # Here we intercept and (potentially) cater to grouped flags
551
+ if not argument_spec and not value and specifications and 1 == hyphens.size
552
552
 
553
- # Must match all
554
- flag_aliases = []
555
- given_label[0 ... given_label.size].each_char do |c|
553
+ # Must match all
554
+ flag_aliases = []
555
+ given_label[0 ... given_label.size].each_char do |c|
556
556
 
557
- new_flag = "-#{c.chr}"
557
+ new_flag = "-#{c.chr}"
558
558
 
559
- flag_alias = nil
559
+ flag_alias = nil
560
560
 
561
- # special case where the flag's actual name is short form and found here
562
- flag_alias ||= specifications.detect { |s| s.is_a?(CLASP::FlagSpecification) && s.name == new_flag }
561
+ # special case where the flag's actual name is short form and found here
562
+ flag_alias ||= specifications.detect { |s| s.is_a?(CLASP::FlagSpecification) && s.name == new_flag }
563
563
 
564
- # if not found as a flag, look in each specifications' aliases
565
- flag_alias ||= specifications.detect { |s| s.aliases.include? new_flag }
564
+ # if not found as a flag, look in each specifications' aliases
565
+ flag_alias ||= specifications.detect { |s| s.aliases.include? new_flag }
566
566
 
567
- if not flag_alias
567
+ if not flag_alias
568
568
 
569
- flag_aliases = nil
570
- break
571
- else
569
+ flag_aliases = nil
570
+ break
571
+ else
572
572
 
573
- flag_aliases << flag_alias
574
- end
575
- end
573
+ flag_aliases << flag_alias
574
+ end
575
+ end
576
576
 
577
- if flag_aliases
577
+ if flag_aliases
578
578
 
579
- # got them all, so now have to process them all
580
- # as normal. Note: is this susceptible to
581
- # infinite recursion
579
+ # got them all, so now have to process them all
580
+ # as normal. Note: is this susceptible to
581
+ # infinite recursion
582
582
 
583
- # convert to argv and invoke
584
- flags_argv = flag_aliases.map { |s| s.name }
583
+ # convert to argv and invoke
584
+ flags_argv = flag_aliases.map { |s| s.name }
585
585
 
586
- grp_flags, grp_options, grp_value, grp_double_slash_index = Arguments.parse_(flags_argv, specifications)
586
+ grp_flags, grp_options, grp_value, grp_double_slash_index = Arguments.parse_(flags_argv, specifications)
587
587
 
588
- grp_flags.map! { |f| FlagArgument.new(arg, index, given_name, f.name, f.argument_specification, hyphens.size, given_label, argument_spec ? argument_spec.extras : nil) }
589
- grp_options.map! { |o| OptionArgument.new(arg, index, given_name, o.name, o.argument_specification, hyphens.size, given_label, o.value, argument_spec ? argument_spec.extras : nil) }
588
+ grp_flags.map! { |f| FlagArgument.new(arg, index, given_name, f.name, f.argument_specification, hyphens.size, given_label, argument_spec ? argument_spec.extras : nil) }
589
+ grp_options.map! { |o| OptionArgument.new(arg, index, given_name, o.name, o.argument_specification, hyphens.size, given_label, o.value, argument_spec ? argument_spec.extras : nil) }
590
590
 
591
- flags.push(*grp_flags)
592
- options.push(*grp_options)
593
- values.push(*grp_value)
591
+ flags.push(*grp_flags)
592
+ options.push(*grp_options)
593
+ values.push(*grp_value)
594
594
 
595
- next
596
- end
597
- end
595
+ next
596
+ end
597
+ end
598
598
 
599
- if argument_spec and argument_spec.is_a? CLASP::OptionSpecification and not value
599
+ if argument_spec and argument_spec.is_a? CLASP::OptionSpecification and not value
600
600
 
601
- pending_option = {
601
+ pending_option = {
602
602
 
603
- arg: arg,
604
- index: index,
605
- given_name: given_name,
606
- resolved_name: resolved_name,
607
- argument_spec: argument_spec,
608
- hyphens_size: hyphens.size,
609
- given_label: given_label,
610
- extras: argument_spec ? argument_spec.extras : nil,
611
- }
612
- elsif value
603
+ arg: arg,
604
+ index: index,
605
+ given_name: given_name,
606
+ resolved_name: resolved_name,
607
+ argument_spec: argument_spec,
608
+ hyphens_size: hyphens.size,
609
+ given_label: given_label,
610
+ extras: argument_spec ? argument_spec.extras : nil,
611
+ }
612
+ elsif value
613
613
 
614
- options << OptionArgument.new(arg, index, given_name, resolved_name, argument_spec, hyphens.size, given_label, value, argument_spec ? argument_spec.extras : nil)
615
- else
614
+ options << OptionArgument.new(arg, index, given_name, resolved_name, argument_spec, hyphens.size, given_label, value, argument_spec ? argument_spec.extras : nil)
615
+ else
616
616
 
617
- flags << FlagArgument.new(arg, index, given_name, resolved_name, argument_spec, hyphens.size, given_label, argument_spec ? argument_spec.extras : nil)
618
- end
617
+ flags << FlagArgument.new(arg, index, given_name, resolved_name, argument_spec, hyphens.size, given_label, argument_spec ? argument_spec.extras : nil)
618
+ end
619
619
 
620
- next
621
- end
622
- end
620
+ next
621
+ end
622
+ end
623
623
 
624
- if pending_option
624
+ if pending_option
625
625
 
626
- value = forced_value ? nil : arg
626
+ value = forced_value ? nil : arg
627
627
 
628
- options << OptionArgument.new(pending_option[:arg], pending_option[:index], pending_option[:given_name], pending_option[:resolved_name], pending_option[:argument_spec], pending_option[:hyphens_size], pending_option[:given_label], value, pending_option[:extras])
628
+ options << OptionArgument.new(pending_option[:arg], pending_option[:index], pending_option[:given_name], pending_option[:resolved_name], pending_option[:argument_spec], pending_option[:hyphens_size], pending_option[:given_label], value, pending_option[:extras])
629
629
 
630
- pending_option = nil
630
+ pending_option = nil
631
631
 
632
- next unless forced_value
633
- end
632
+ next unless forced_value
633
+ end
634
634
 
635
- arg = arg.dup
636
- arg_ix = ::Integer === index ? index : index.dup
635
+ arg = arg.dup
636
+ arg_ix = ::Integer === index ? index : index.dup
637
637
 
638
- arg.define_singleton_method(:given_index) { arg_ix }
638
+ arg.define_singleton_method(:given_index) { arg_ix }
639
639
 
640
- values << arg
641
- end
640
+ values << arg
641
+ end
642
642
 
643
- if pending_option
643
+ if pending_option
644
644
 
645
- value = nil
645
+ value = nil
646
646
 
647
- options << OptionArgument.new(pending_option[:arg], pending_option[:index], pending_option[:given_name], pending_option[:resolved_name], pending_option[:argument_spec], pending_option[:hyphens_size], pending_option[:given_label], value, pending_option[:extras])
647
+ options << OptionArgument.new(pending_option[:arg], pending_option[:index], pending_option[:given_name], pending_option[:resolved_name], pending_option[:argument_spec], pending_option[:hyphens_size], pending_option[:given_label], value, pending_option[:extras])
648
648
 
649
- end
649
+ end
650
650
 
651
- return flags, options, values, double_slash_index
652
- end
651
+ return flags, options, values, double_slash_index
652
+ end
653
653
 
654
- # ######################
655
- # Attributes
654
+ # ######################
655
+ # Attributes
656
656
 
657
- public
658
- # (Array) a frozen array of specifications
659
- attr_reader :specifications
657
+ public
658
+ # (Array) a frozen array of specifications
659
+ attr_reader :specifications
660
660
 
661
- # [DEPRECATED] Instead refer to +specifications+
662
- attr_reader :aliases
661
+ # [DEPRECATED] Instead refer to +specifications+
662
+ attr_reader :aliases
663
663
 
664
- # (Array) a frozen array of flags
665
- attr_reader :flags
664
+ # (Array) a frozen array of flags
665
+ attr_reader :flags
666
666
 
667
- # (Array) a frozen array of options
668
- attr_reader :options
667
+ # (Array) a frozen array of options
668
+ attr_reader :options
669
669
 
670
- # (Array) a frozen array of values
671
- attr_reader :values
670
+ # (Array) a frozen array of values
671
+ attr_reader :values
672
672
 
673
- # (Integer, +nil+) index of the first '--', if present; +nil+ otherwise
674
- attr_reader :double_slash_index
673
+ # (Integer, +nil+) index of the first '--', if present; +nil+ otherwise
674
+ attr_reader :double_slash_index
675
675
 
676
- # (Array) the (possibly mutated) array of arguments instance passed to new
677
- attr_reader :argv
676
+ # (Array) the (possibly mutated) array of arguments instance passed to new
677
+ attr_reader :argv
678
678
 
679
- # (Array) unchanged copy of the original array of arguments passed to new
680
- attr_reader :argv_original_copy
679
+ # (Array) unchanged copy of the original array of arguments passed to new
680
+ attr_reader :argv_original_copy
681
681
 
682
- # (String) The program name
683
- attr_reader :program_name
682
+ # (String) The program name
683
+ attr_reader :program_name
684
684
 
685
- # Finds the first unknown flag or option; +nil+ if all used
686
- #
687
- # === Signature
688
- #
689
- # * *Parameters:*
690
- # - +options+ (Hash) options
691
- #
692
- # * *Options:*
693
- # - +:specifications+ ([CLASP::Specification]) Array of specifications. If not specified, the instance's +specifications+ attribute is used
694
- #
695
- # === Return
696
- # (CLASP::Arguments::OptionArgument) The first unknown option; +nil+ if none found
697
- def find_first_unknown options = {}
685
+ # Finds the first unknown flag or option; +nil+ if all used
686
+ #
687
+ # === Signature
688
+ #
689
+ # * *Parameters:*
690
+ # - +options+ (Hash) options
691
+ #
692
+ # * *Options:*
693
+ # - +:specifications+ ([CLASP::Specification]) Array of specifications. If not specified, the instance's +specifications+ attribute is used
694
+ #
695
+ # === Return
696
+ # (CLASP::Arguments::OptionArgument) The first unknown option; +nil+ if none found
697
+ def find_first_unknown options = {}
698
698
 
699
- option = {} if options.nil?
699
+ option = {} if options.nil?
700
700
 
701
- raise ArgumentError, "options must be nil or Hash - #{option.class} given" unless options.is_a? ::Hash
701
+ raise ArgumentError, "options must be nil or Hash - #{option.class} given" unless options.is_a? ::Hash
702
702
 
703
- specifications = options[:specifications] || options[:aliases] || @specifications
703
+ specifications = options[:specifications] || options[:aliases] || @specifications
704
704
 
705
- raise ArgumentError, "specifications may not be nil" if specifications.nil?
705
+ raise ArgumentError, "specifications may not be nil" if specifications.nil?
706
706
 
707
- flags.each do |f|
707
+ flags.each do |f|
708
708
 
709
- return f unless specifications.any? { |al| al.is_a?(::CLASP::FlagSpecification) && al.name == f.name }
710
- end
709
+ return f unless specifications.any? { |al| al.is_a?(::CLASP::FlagSpecification) && al.name == f.name }
710
+ end
711
711
 
712
- self.options.each do |o|
712
+ self.options.each do |o|
713
713
 
714
- return o unless specifications.any? { |al| al.is_a?(::CLASP::OptionSpecification) && al.name == o.name }
715
- end
714
+ return o unless specifications.any? { |al| al.is_a?(::CLASP::OptionSpecification) && al.name == o.name }
715
+ end
716
716
 
717
- nil
718
- end
717
+ nil
718
+ end
719
719
 
720
- # Searches for a flag that matches the given id, returning the flag if
721
- # found; +nil+ otherwise
722
- #
723
- # === Signature
724
- #
725
- # * *Parameters:*
726
- # - +id+ (String, CLASP::FlagArgument) The name of a flag, or the flag itself
727
- #
728
- # === Return
729
- # (CLASP::Arguments::FlagArgument) The first flag matching +id+; +nil+ if none found
730
- def find_flag(id)
720
+ # Searches for a flag that matches the given id, returning the flag if
721
+ # found; +nil+ otherwise
722
+ #
723
+ # === Signature
724
+ #
725
+ # * *Parameters:*
726
+ # - +id+ (String, CLASP::FlagArgument) The name of a flag, or the flag itself
727
+ #
728
+ # === Return
729
+ # (CLASP::Arguments::FlagArgument) The first flag matching +id+; +nil+ if none found
730
+ def find_flag(id)
731
731
 
732
- flags.each do |flag|
732
+ flags.each do |flag|
733
733
 
734
- return flag if flag == id
735
- end
734
+ return flag if flag == id
735
+ end
736
736
 
737
- nil
738
- end
737
+ nil
738
+ end
739
739
 
740
- # Searches for a option that matches the given id, returning the option
741
- # if found; +nil+ otherwise
742
- #
743
- # === Signature
744
- #
745
- # * *Parameter:*
746
- # - +id+ (String, CLASP::OptionArgument) The name of a option, or the option itself
747
- #
748
- # === Return
749
- # (CLASP::Arguments::OptionArgument) The first option matching +id+; +nil+ if none found
750
- def find_option(id)
740
+ # Searches for a option that matches the given id, returning the option
741
+ # if found; +nil+ otherwise
742
+ #
743
+ # === Signature
744
+ #
745
+ # * *Parameter:*
746
+ # - +id+ (String, CLASP::OptionArgument) The name of a option, or the option itself
747
+ #
748
+ # === Return
749
+ # (CLASP::Arguments::OptionArgument) The first option matching +id+; +nil+ if none found
750
+ def find_option(id)
751
751
 
752
- options.each do |option|
752
+ options.each do |option|
753
753
 
754
- return option if option == id
755
- end
754
+ return option if option == id
755
+ end
756
756
 
757
- nil
758
- end
757
+ nil
758
+ end
759
759
 
760
- # #################################################################### #
761
- # backwards-compatible
760
+ # #################################################################### #
761
+ # backwards-compatible
762
762
 
763
- # @!visibility private
764
- Flag = FlagArgument # :nodoc:
765
- # @!visibility private
766
- Option = OptionArgument # :nodoc:
763
+ # @!visibility private
764
+ Flag = FlagArgument # :nodoc:
765
+ # @!visibility private
766
+ Option = OptionArgument # :nodoc:
767
767
  end # class Arguments
768
768
 
769
+
769
770
  # ######################################################################## #
770
771
  # module
771
772
 
772
773
  end # module CLASP
773
774
 
774
- # ############################## end of file ############################# #
775
775
 
776
+ # ############################## end of file ############################# #
776
777