clasp-ruby 0.23.0.1 → 0.23.1

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