clasp-ruby 0.23.0.1 → 0.23.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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