clasp-ruby 0.20.3 → 0.21.0
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.
- checksums.yaml +7 -0
- data/lib/clasp/arguments.rb +65 -20
- data/lib/clasp/clasp.rb +9 -0
- data/lib/clasp/specifications.rb +17 -5
- data/lib/clasp/util/exceptions.rb +82 -0
- data/lib/clasp/util/value_parser.rb +222 -0
- data/lib/clasp/version.rb +1 -1
- data/test/unit/tc_typed_options.rb +310 -0
- metadata +20 -28
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5d4b4a9b8453b84575f693c6c1cf3d58c0af5999843c360295f799d60dc6b57d
|
4
|
+
data.tar.gz: 2089b0ead4ef6161d6cdda4d2129f2361567d434ea5aa3bcb257918093bdad7a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c24103543ec9d290ae1731ab49a8937e02148b48e567c199ed1c3bb7a12edda0c892b4cd36eeb0fa6a8232fd9936db2fbae254e8db1a835bdf054a3df0f82af0
|
7
|
+
data.tar.gz: c1ea7534927c52c7c138da6da8f43c2c28f13222f35ff751c5d6b4a6aa456d18b6e655de5eaec3373d21aee864913d4ae6dc70d32e7d6e0b33815dc3fe40f57e
|
data/lib/clasp/arguments.rb
CHANGED
@@ -46,7 +46,8 @@
|
|
46
46
|
|
47
47
|
|
48
48
|
|
49
|
-
require File.join(File.dirname(__FILE__), 'specifications
|
49
|
+
require File.join(File.dirname(__FILE__), 'specifications')
|
50
|
+
require File.join(File.dirname(__FILE__), 'util', 'value_parser')
|
50
51
|
|
51
52
|
require 'yaml'
|
52
53
|
|
@@ -136,17 +137,40 @@ class Arguments
|
|
136
137
|
# Class that represents a parsed option
|
137
138
|
class OptionArgument
|
138
139
|
|
140
|
+
include ::CLASP::Util::ValueParser
|
141
|
+
|
139
142
|
# @!visibility private
|
140
143
|
#
|
141
144
|
# [PRIVATE] This method is subject to changed between versions and
|
142
145
|
# should not be called directly from application code
|
143
146
|
def initialize(arg, given_index, given_name, resolved_name, argument_spec, given_hyphens, given_label, value, extras) # :nodoc:
|
144
147
|
|
145
|
-
|
148
|
+
resolved_value = nil
|
149
|
+
|
150
|
+
if argument_spec
|
151
|
+
|
152
|
+
case constraint = (argument_spec.constraint || {})
|
153
|
+
=begin
|
154
|
+
when Proc
|
155
|
+
|
156
|
+
resolved_value = value_from_Proc(constraint, value, arg, given_index, given_name, argument_spec, extras)
|
157
|
+
=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
|
146
168
|
|
147
|
-
|
169
|
+
warn "unexpected constraint on argument specification #{argument_spec} when parsing argument '#{arg}'"
|
170
|
+
end
|
171
|
+
else
|
148
172
|
|
149
|
-
|
173
|
+
resolved_value = value
|
150
174
|
end
|
151
175
|
|
152
176
|
@arg = arg
|
@@ -155,7 +179,8 @@ class Arguments
|
|
155
179
|
@argument_specification = argument_spec
|
156
180
|
@given_hyphens = given_hyphens
|
157
181
|
@given_label = given_label
|
158
|
-
@
|
182
|
+
@given_value = value
|
183
|
+
@value = resolved_value
|
159
184
|
@name = resolved_name || given_name
|
160
185
|
@extras = extras.nil? ? {} : extras
|
161
186
|
end
|
@@ -172,7 +197,9 @@ class Arguments
|
|
172
197
|
attr_reader :given_label
|
173
198
|
# (String) The resolved name of the argument
|
174
199
|
attr_reader :name
|
175
|
-
# (String) The value of the option
|
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
|
176
203
|
attr_reader :value
|
177
204
|
# (Object, Hash) The extras associated with the argument
|
178
205
|
attr_reader :extras
|
@@ -458,7 +485,7 @@ class Arguments
|
|
458
485
|
values = []
|
459
486
|
|
460
487
|
forced_value = false
|
461
|
-
|
488
|
+
pending_option = nil
|
462
489
|
|
463
490
|
argv.each_with_index do |arg, index|
|
464
491
|
|
@@ -563,15 +590,22 @@ class Arguments
|
|
563
590
|
|
564
591
|
if argument_spec and argument_spec.is_a? CLASP::OptionSpecification and not value
|
565
592
|
|
566
|
-
|
567
|
-
|
593
|
+
pending_option = {
|
594
|
+
|
595
|
+
arg: arg,
|
596
|
+
index: index,
|
597
|
+
given_name: given_name,
|
598
|
+
resolved_name: resolved_name,
|
599
|
+
argument_spec: argument_spec,
|
600
|
+
hyphens_size: hyphens.size,
|
601
|
+
given_label: given_label,
|
602
|
+
extras: argument_spec ? argument_spec.extras : nil,
|
603
|
+
}
|
568
604
|
elsif value
|
569
605
|
|
570
|
-
want_option_value = false
|
571
606
|
options << OptionArgument.new(arg, index, given_name, resolved_name, argument_spec, hyphens.size, given_label, value, argument_spec ? argument_spec.extras : nil)
|
572
607
|
else
|
573
608
|
|
574
|
-
want_option_value = false
|
575
609
|
flags << FlagArgument.new(arg, index, given_name, resolved_name, argument_spec, hyphens.size, given_label, argument_spec ? argument_spec.extras : nil)
|
576
610
|
end
|
577
611
|
|
@@ -579,20 +613,31 @@ class Arguments
|
|
579
613
|
end
|
580
614
|
end
|
581
615
|
|
582
|
-
if
|
616
|
+
if pending_option
|
583
617
|
|
584
|
-
|
585
|
-
option.instance_eval("@value='#{arg}'")
|
586
|
-
want_option_value = false
|
587
|
-
else
|
618
|
+
value = forced_value ? nil : arg
|
588
619
|
|
589
|
-
arg
|
590
|
-
arg_ix = ::Integer === index ? index : index.dup
|
620
|
+
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])
|
591
621
|
|
592
|
-
|
622
|
+
pending_option = nil
|
593
623
|
|
594
|
-
|
624
|
+
next unless forced_value
|
595
625
|
end
|
626
|
+
|
627
|
+
arg = arg.dup
|
628
|
+
arg_ix = ::Integer === index ? index : index.dup
|
629
|
+
|
630
|
+
arg.define_singleton_method(:given_index) { arg_ix }
|
631
|
+
|
632
|
+
values << arg
|
633
|
+
end
|
634
|
+
|
635
|
+
if pending_option
|
636
|
+
|
637
|
+
value = nil
|
638
|
+
|
639
|
+
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])
|
640
|
+
|
596
641
|
end
|
597
642
|
|
598
643
|
return flags, options, values
|
data/lib/clasp/clasp.rb
CHANGED
@@ -50,6 +50,15 @@ require 'clasp/specifications'
|
|
50
50
|
require 'clasp/cli'
|
51
51
|
require 'clasp/version'
|
52
52
|
|
53
|
+
module CLASP
|
54
|
+
|
55
|
+
# TBC (but is a shorthand for calling +Arguments.new()+
|
56
|
+
def self.parse(argv = ARGV, specifications = nil, options = {})
|
57
|
+
|
58
|
+
return Arguments.new(argv, specifications, options)
|
59
|
+
end
|
60
|
+
end # module CLASP
|
61
|
+
|
53
62
|
# ############################## end of file ############################# #
|
54
63
|
|
55
64
|
|
data/lib/clasp/specifications.rb
CHANGED
@@ -69,6 +69,8 @@ class FlagSpecification
|
|
69
69
|
# - +aliases+ (+Array+) 0 or more strings specifying short-form or option-value aliases
|
70
70
|
# - +help+ (+String+) The help string, which may be +nil+
|
71
71
|
# - +extras+ An application-defined additional parameter. If +nil+, it is assigned an empty +Hash+
|
72
|
+
#
|
73
|
+
# *NOTE:* Users should prefer the +CLASP::Flag()+ method
|
72
74
|
def initialize(name, aliases, help, extras = nil)
|
73
75
|
|
74
76
|
@name = name
|
@@ -169,8 +171,11 @@ class OptionSpecification
|
|
169
171
|
# - +default_value+ (+String+) The default value of the option, which will be used in the case where an option is specified without a value. May be +nil+
|
170
172
|
# - +required+ (boolean) Whether the option is required. May be +nil+
|
171
173
|
# - +required_message+ (::String) Message to be used when reporting that a required option is missing. May be +nil+ in which case a message of the form "<option-name> not specified; use --help for usage". If begins with the nul character ("\0"), then is used in the place of the <option-name> and placed into the rest of the standard form message
|
174
|
+
# - +constraint+ (Hash) Constraint to be applied to the parsed values of options matching this specification. NOTE: only integer constraints are supported in the current version
|
172
175
|
# - +extras+ An application-defined additional parameter. If +nil+, it is assigned an empty +Hash+
|
173
|
-
|
176
|
+
#
|
177
|
+
# *NOTE:* Users should prefer the +CLASP::Option()+ method
|
178
|
+
def initialize(name, aliases, help, values_range, default_value, required, required_message, constraint, extras = nil)
|
174
179
|
|
175
180
|
@name = name
|
176
181
|
@aliases = (aliases || []).select { |a| a and not a.empty? }
|
@@ -179,6 +184,7 @@ class OptionSpecification
|
|
179
184
|
@default_value = default_value
|
180
185
|
@required = required
|
181
186
|
@required_message = nil
|
187
|
+
@constraint = constraint || {}
|
182
188
|
@extras = extras || {}
|
183
189
|
|
184
190
|
rm_name = nil
|
@@ -214,16 +220,17 @@ class OptionSpecification
|
|
214
220
|
attr_reader :default_value
|
215
221
|
# Indicates whether the option is required
|
216
222
|
def required?; @required; end
|
217
|
-
# The message to be used when reporting that a required option is
|
218
|
-
# missing
|
223
|
+
# The message to be used when reporting that a required option is missing
|
219
224
|
attr_reader :required_message
|
225
|
+
# The value constraint
|
226
|
+
attr_reader :constraint
|
220
227
|
# The option's extras
|
221
228
|
attr_reader :extras
|
222
229
|
|
223
230
|
# String form of the option
|
224
231
|
def to_s
|
225
232
|
|
226
|
-
"{#{name}; aliases=#{aliases.join(', ')}; values_range=[ #{values_range.join(', ')} ]; default_value='#{default_value}'; help='#{help}'; required?=#{required?}; extras=#{extras}}"
|
233
|
+
"{#{name}; aliases=#{aliases.join(', ')}; values_range=[ #{values_range.join(', ')} ]; default_value='#{default_value}'; help='#{help}'; required?=#{required?}; required_message=#{required_message}; constraint=#{constraint}; extras=#{extras}}"
|
227
234
|
end
|
228
235
|
|
229
236
|
# @!visibility private
|
@@ -366,6 +373,7 @@ end
|
|
366
373
|
# - +required+ (boolean) Whether the option is required. May be +nil+
|
367
374
|
# - +required_message+ (::String) Message to be used when reporting that a required option is missing. May be +nil+ in which case a message of the form "<option-name> not specified; use --help for usage". If begins with the nul character ("\0"), then is used in the place of the <option-name> and placed into the rest of the standard form message
|
368
375
|
# - +extras+ An application-defined additional parameter. If +nil+, it is assigned an empty +Hash+.
|
376
|
+
# - +constraint+ (Hash) Constraint to be applied to the parsed values of options matching this specification. NOTE: only integer constraints are supported in the current version
|
369
377
|
# - +:values_range+ (::Array) An array defining the accepted values for the option
|
370
378
|
# - +:values+ [DEPRECATED] Alternative to +:values_range+
|
371
379
|
def CLASP.Option(name, options = {})
|
@@ -376,6 +384,7 @@ def CLASP.Option(name, options = {})
|
|
376
384
|
default_value = nil
|
377
385
|
required = false
|
378
386
|
require_message = nil
|
387
|
+
constraint = nil
|
379
388
|
extras = nil
|
380
389
|
|
381
390
|
options.each do |k, v|
|
@@ -407,6 +416,9 @@ def CLASP.Option(name, options = {})
|
|
407
416
|
when :extras
|
408
417
|
|
409
418
|
extras = v
|
419
|
+
when :constraint
|
420
|
+
|
421
|
+
constraint = v
|
410
422
|
else
|
411
423
|
|
412
424
|
raise ArgumentError, "invalid option for option: '#{k}' => '#{v}'"
|
@@ -417,7 +429,7 @@ def CLASP.Option(name, options = {})
|
|
417
429
|
end
|
418
430
|
end
|
419
431
|
|
420
|
-
CLASP::OptionSpecification.new(name, aliases, help, values_range, default_value, required, require_message, extras)
|
432
|
+
CLASP::OptionSpecification.new(name, aliases, help, values_range, default_value, required, require_message, constraint, extras)
|
421
433
|
end
|
422
434
|
|
423
435
|
def CLASP.Alias(name, *args)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
|
2
|
+
# ######################################################################## #
|
3
|
+
# File: clasp/util/exceptions.rb
|
4
|
+
#
|
5
|
+
# Purpose: Exception classes
|
6
|
+
#
|
7
|
+
# Created: 20th April 2019
|
8
|
+
# Updated: 28th April 2019
|
9
|
+
#
|
10
|
+
# Home: http://github.com/synesissoftware/CLASP.Ruby
|
11
|
+
#
|
12
|
+
# Author: Matthew Wilson
|
13
|
+
#
|
14
|
+
# Copyright (c) 2019, Matthew Wilson and Synesis Software
|
15
|
+
# All rights reserved.
|
16
|
+
#
|
17
|
+
# Redistribution and use in source and binary forms, with or without
|
18
|
+
# modification, are permitted provided that the following conditions are
|
19
|
+
# met:
|
20
|
+
#
|
21
|
+
# * Redistributions of source code must retain the above copyright
|
22
|
+
# notice, this list of conditions and the following disclaimer.
|
23
|
+
#
|
24
|
+
# * Redistributions in binary form must reproduce the above copyright
|
25
|
+
# notice, this list of conditions and the following disclaimer in the
|
26
|
+
# documentation and/or other materials provided with the distribution.
|
27
|
+
#
|
28
|
+
# * Neither the names of the copyright holder nor the names of its
|
29
|
+
# contributors may be used to endorse or promote products derived from
|
30
|
+
# this software without specific prior written permission.
|
31
|
+
#
|
32
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
33
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
34
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
35
|
+
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
36
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
37
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
38
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
39
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
40
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
41
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
42
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
43
|
+
#
|
44
|
+
# ######################################################################## #
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
=begin
|
49
|
+
=end
|
50
|
+
|
51
|
+
module CLASP # :nodoc:
|
52
|
+
|
53
|
+
# Exceptions
|
54
|
+
module Exceptions
|
55
|
+
|
56
|
+
# Root exception for CLASP
|
57
|
+
class CLASPException < RuntimeError; end
|
58
|
+
|
59
|
+
# Root exception for value parsing
|
60
|
+
class ValueParserException < CLASPException; end
|
61
|
+
|
62
|
+
# No value specified (and no default value) for an option
|
63
|
+
class MissingValueException < ValueParserException; end
|
64
|
+
|
65
|
+
# Exception class indicating invalid values (as opposed to types)
|
66
|
+
class InvalidValueException < ValueParserException; end
|
67
|
+
|
68
|
+
# The given value could not be recognised as a (properly-formatted) number
|
69
|
+
class InvalidNumberException < InvalidValueException; end
|
70
|
+
|
71
|
+
# The given value could not be recognised as a (properly-formatted) integer
|
72
|
+
class InvalidIntegerException < InvalidNumberException; end
|
73
|
+
|
74
|
+
# The value was a valid integer but is out of range
|
75
|
+
class IntegerOutOfRangeException < InvalidValueException; end
|
76
|
+
|
77
|
+
end # module Exceptions
|
78
|
+
end # module CLASP
|
79
|
+
|
80
|
+
# ############################## end of file ############################# #
|
81
|
+
|
82
|
+
|
@@ -0,0 +1,222 @@
|
|
1
|
+
|
2
|
+
# ######################################################################## #
|
3
|
+
# File: clasp/util/value_parser.rb
|
4
|
+
#
|
5
|
+
# Purpose: Utility component for typed values
|
6
|
+
#
|
7
|
+
# Created: 20th April 2019
|
8
|
+
# Updated: 28th April 2019
|
9
|
+
#
|
10
|
+
# Home: http://github.com/synesissoftware/CLASP.Ruby
|
11
|
+
#
|
12
|
+
# Author: Matthew Wilson
|
13
|
+
#
|
14
|
+
# Copyright (c) 2019, Matthew Wilson and Synesis Software
|
15
|
+
# All rights reserved.
|
16
|
+
#
|
17
|
+
# Redistribution and use in source and binary forms, with or without
|
18
|
+
# modification, are permitted provided that the following conditions are
|
19
|
+
# met:
|
20
|
+
#
|
21
|
+
# * Redistributions of source code must retain the above copyright
|
22
|
+
# notice, this list of conditions and the following disclaimer.
|
23
|
+
#
|
24
|
+
# * Redistributions in binary form must reproduce the above copyright
|
25
|
+
# notice, this list of conditions and the following disclaimer in the
|
26
|
+
# documentation and/or other materials provided with the distribution.
|
27
|
+
#
|
28
|
+
# * Neither the names of the copyright holder nor the names of its
|
29
|
+
# contributors may be used to endorse or promote products derived from
|
30
|
+
# this software without specific prior written permission.
|
31
|
+
#
|
32
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
33
|
+
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
34
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
35
|
+
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
36
|
+
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
37
|
+
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
38
|
+
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
39
|
+
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
40
|
+
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
41
|
+
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
42
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
43
|
+
#
|
44
|
+
# ######################################################################## #
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
require File.join(File.dirname(__FILE__), 'exceptions')
|
49
|
+
|
50
|
+
=begin
|
51
|
+
=end
|
52
|
+
|
53
|
+
module CLASP # :nodoc:
|
54
|
+
module Util # :nodoc:
|
55
|
+
|
56
|
+
# @!visibility private
|
57
|
+
module ValueParser # :nodoc: all
|
58
|
+
|
59
|
+
module Internal_ # :nodoc: all
|
60
|
+
|
61
|
+
include Exceptions
|
62
|
+
|
63
|
+
def self.is_integer? type
|
64
|
+
|
65
|
+
h = {}
|
66
|
+
|
67
|
+
return true if Integer == type
|
68
|
+
return true if :integer == type
|
69
|
+
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.obtain_integer value, constraint, argument_spec
|
74
|
+
|
75
|
+
# If no value is given, then use the default (and don't do any
|
76
|
+
# range testing)
|
77
|
+
|
78
|
+
if (value || '').empty?
|
79
|
+
|
80
|
+
def_value = argument_spec.default_value
|
81
|
+
|
82
|
+
if (def_value || '').to_s.empty?
|
83
|
+
|
84
|
+
msg = "no value specified for the option '#{argument_spec.name}', which has no default value either"
|
85
|
+
|
86
|
+
warn msg if $DEBUG
|
87
|
+
|
88
|
+
raise MissingValueException, msg
|
89
|
+
end
|
90
|
+
|
91
|
+
begin
|
92
|
+
|
93
|
+
return Integer(def_value)
|
94
|
+
rescue ArgumentError => x
|
95
|
+
|
96
|
+
msg = "default value '#{def_value}' specified for option '#{argument_spec.name}' that requires the value to be an integer"
|
97
|
+
|
98
|
+
warn msg if $DEBUG
|
99
|
+
|
100
|
+
raise InvalidIntegerException, msg
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# obtain the integer from the value
|
105
|
+
|
106
|
+
v = nil
|
107
|
+
|
108
|
+
begin
|
109
|
+
|
110
|
+
v = Integer(value)
|
111
|
+
rescue ArgumentError => x
|
112
|
+
|
113
|
+
msg = "value '#{value}' specified for option '#{argument_spec.name}' that requires the value to be an integer"
|
114
|
+
|
115
|
+
warn msg if $DEBUG
|
116
|
+
|
117
|
+
raise InvalidIntegerException, msg
|
118
|
+
end
|
119
|
+
|
120
|
+
# Is there a value constraint?:
|
121
|
+
#
|
122
|
+
# - values (obtained from argument_spec#values)
|
123
|
+
# - range
|
124
|
+
# - minimum & maximum
|
125
|
+
|
126
|
+
values_range = argument_spec.values_range
|
127
|
+
|
128
|
+
unless values_range.empty?
|
129
|
+
|
130
|
+
v_s = v.to_s
|
131
|
+
|
132
|
+
v_s = '+' + v_s unless '-' == v_s[0]
|
133
|
+
|
134
|
+
vr_s = values_range.map { |x| x.to_s }.map { |x| '-' == x[0] ? x : '+' + x }
|
135
|
+
|
136
|
+
unless vr_s.include? v_s
|
137
|
+
|
138
|
+
msg = "given value '#{value}' specified for option '#{argument_spec.name}' does not fall within the required range"
|
139
|
+
|
140
|
+
raise IntegerOutOfRangeException, msg
|
141
|
+
end
|
142
|
+
else
|
143
|
+
|
144
|
+
case range = constraint[:range]
|
145
|
+
when :negative
|
146
|
+
|
147
|
+
if v >= 0
|
148
|
+
|
149
|
+
msg = "given value '#{value}' specified for option '#{argument_spec.name}' must be a negative integer"
|
150
|
+
|
151
|
+
raise IntegerOutOfRangeException, msg
|
152
|
+
end
|
153
|
+
when :positive
|
154
|
+
|
155
|
+
if v < 1
|
156
|
+
|
157
|
+
msg = "given value '#{value}' specified for option '#{argument_spec.name}' must be a positive integer"
|
158
|
+
|
159
|
+
raise IntegerOutOfRangeException, msg
|
160
|
+
end
|
161
|
+
when :non_positive
|
162
|
+
|
163
|
+
if v > 0
|
164
|
+
|
165
|
+
msg = "given value '#{value}' specified for option '#{argument_spec.name}' must be a non-positive integer"
|
166
|
+
|
167
|
+
raise IntegerOutOfRangeException, msg
|
168
|
+
end
|
169
|
+
when :non_negative
|
170
|
+
|
171
|
+
if v < 0
|
172
|
+
|
173
|
+
msg = "given value '#{value}' specified for option '#{argument_spec.name}' must be a non-negative integer"
|
174
|
+
|
175
|
+
raise IntegerOutOfRangeException, msg
|
176
|
+
end
|
177
|
+
when Range
|
178
|
+
|
179
|
+
unless range.include?
|
180
|
+
|
181
|
+
msg = "given value '#{value}' specified for option '#{argument_spec.name}' does not fall within the required range"
|
182
|
+
|
183
|
+
raise IntegerOutOfRangeException, msg
|
184
|
+
end
|
185
|
+
else
|
186
|
+
|
187
|
+
;
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
v
|
192
|
+
end
|
193
|
+
end # module Internal_
|
194
|
+
|
195
|
+
def value_from_Proc(constraint, value, arg, given_index, given_name, argument_spec, extras)
|
196
|
+
|
197
|
+
value
|
198
|
+
end
|
199
|
+
|
200
|
+
def value_from_Hash(constraint, value, arg, given_index, given_name, argument_spec, extras)
|
201
|
+
|
202
|
+
# Check if type is specified; if not, String is assumed
|
203
|
+
|
204
|
+
type = constraint[:type]
|
205
|
+
|
206
|
+
|
207
|
+
if Internal_.is_integer?(type)
|
208
|
+
|
209
|
+
return Internal_.obtain_integer(value, constraint, argument_spec)
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
value
|
214
|
+
end
|
215
|
+
end # module ValueParser
|
216
|
+
|
217
|
+
end # module util
|
218
|
+
end # module CLASP
|
219
|
+
|
220
|
+
# ############################## end of file ############################# #
|
221
|
+
|
222
|
+
|
data/lib/clasp/version.rb
CHANGED
@@ -0,0 +1,310 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), '../..', 'lib')
|
4
|
+
|
5
|
+
require 'clasp'
|
6
|
+
|
7
|
+
require 'xqsr3/extensions/test/unit' if RUBY_VERSION >= '2'
|
8
|
+
|
9
|
+
require 'test/unit'
|
10
|
+
|
11
|
+
class Test_TypedOptionValues < Test::Unit::TestCase
|
12
|
+
|
13
|
+
if RUBY_VERSION < '2'
|
14
|
+
|
15
|
+
def assert_raise_with_message(type_spec, message_spec, *args, &block)
|
16
|
+
|
17
|
+
assert_raise(type_spec, *args, &block)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_Integer_no_range
|
22
|
+
|
23
|
+
specifications = [
|
24
|
+
|
25
|
+
CLASP.Option('--level', default_value: 1234, constraint: { type: Integer })
|
26
|
+
]
|
27
|
+
|
28
|
+
# with no arguments
|
29
|
+
begin
|
30
|
+
|
31
|
+
argv = []
|
32
|
+
args = CLASP.parse argv, specifications
|
33
|
+
|
34
|
+
assert_equal 0, args.flags.size
|
35
|
+
assert_equal 0, args.options.size
|
36
|
+
assert_equal 0, args.values.size
|
37
|
+
end
|
38
|
+
|
39
|
+
# with default value
|
40
|
+
begin
|
41
|
+
|
42
|
+
argv = [ '--level=' ]
|
43
|
+
|
44
|
+
args = CLASP.parse argv, specifications
|
45
|
+
|
46
|
+
assert_equal 0, args.flags.size
|
47
|
+
assert_equal 1, args.options.size
|
48
|
+
assert_equal 0, args.values.size
|
49
|
+
|
50
|
+
opt = args.options[0]
|
51
|
+
|
52
|
+
assert_equal 0, opt.given_index
|
53
|
+
assert_equal specifications[0], opt.argument_specification
|
54
|
+
assert_equal '--level', opt.name
|
55
|
+
assert_equal '', opt.given_value
|
56
|
+
assert_equal 1234, opt.value
|
57
|
+
end
|
58
|
+
|
59
|
+
# with explicit value 0
|
60
|
+
begin
|
61
|
+
|
62
|
+
argv = [ '--level=0' ]
|
63
|
+
|
64
|
+
args = CLASP.parse argv, specifications
|
65
|
+
|
66
|
+
assert_equal 0, args.flags.size
|
67
|
+
assert_equal 1, args.options.size
|
68
|
+
assert_equal 0, args.values.size
|
69
|
+
|
70
|
+
opt = args.options[0]
|
71
|
+
|
72
|
+
assert_equal 0, opt.given_index
|
73
|
+
assert_equal specifications[0], opt.argument_specification
|
74
|
+
assert_equal '--level', opt.name
|
75
|
+
assert_equal '0', opt.given_value
|
76
|
+
assert_equal 0, opt.value
|
77
|
+
end
|
78
|
+
|
79
|
+
# with explicit value -100
|
80
|
+
begin
|
81
|
+
|
82
|
+
argv = [ '--level=-100' ]
|
83
|
+
|
84
|
+
args = CLASP.parse argv, specifications
|
85
|
+
|
86
|
+
assert_equal 0, args.flags.size
|
87
|
+
assert_equal 1, args.options.size
|
88
|
+
assert_equal 0, args.values.size
|
89
|
+
|
90
|
+
opt = args.options[0]
|
91
|
+
|
92
|
+
assert_equal 0, opt.given_index
|
93
|
+
assert_equal specifications[0], opt.argument_specification
|
94
|
+
assert_equal '--level', opt.name
|
95
|
+
assert_equal '-100', opt.given_value
|
96
|
+
assert_equal -100, opt.value
|
97
|
+
end
|
98
|
+
|
99
|
+
# with explicit value 123456789
|
100
|
+
begin
|
101
|
+
|
102
|
+
argv = [ '--level=123456789' ]
|
103
|
+
|
104
|
+
args = CLASP.parse argv, specifications
|
105
|
+
|
106
|
+
assert_equal 0, args.flags.size
|
107
|
+
assert_equal 1, args.options.size
|
108
|
+
assert_equal 0, args.values.size
|
109
|
+
|
110
|
+
opt = args.options[0]
|
111
|
+
|
112
|
+
assert_equal 0, opt.given_index
|
113
|
+
assert_equal specifications[0], opt.argument_specification
|
114
|
+
assert_equal '--level', opt.name
|
115
|
+
assert_equal '123456789', opt.given_value
|
116
|
+
assert_equal 123456789, opt.value
|
117
|
+
end
|
118
|
+
|
119
|
+
# with explicit value +123456789
|
120
|
+
begin
|
121
|
+
|
122
|
+
argv = [ '--level=+123456789' ]
|
123
|
+
|
124
|
+
args = CLASP.parse argv, specifications
|
125
|
+
|
126
|
+
assert_equal 0, args.flags.size
|
127
|
+
assert_equal 1, args.options.size
|
128
|
+
assert_equal 0, args.values.size
|
129
|
+
|
130
|
+
opt = args.options[0]
|
131
|
+
|
132
|
+
assert_equal 0, opt.given_index
|
133
|
+
assert_equal specifications[0], opt.argument_specification
|
134
|
+
assert_equal '--level', opt.name
|
135
|
+
assert_equal '+123456789', opt.given_value
|
136
|
+
assert_equal 123456789, opt.value
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_Integer_positive
|
141
|
+
|
142
|
+
specifications = [
|
143
|
+
|
144
|
+
CLASP.Option('--level', default_value: 1234, constraint: { type: Integer, range: :positive })
|
145
|
+
]
|
146
|
+
|
147
|
+
# with no arguments
|
148
|
+
begin
|
149
|
+
|
150
|
+
argv = []
|
151
|
+
args = CLASP.parse argv, specifications
|
152
|
+
|
153
|
+
assert_equal 0, args.flags.size
|
154
|
+
assert_equal 0, args.options.size
|
155
|
+
assert_equal 0, args.values.size
|
156
|
+
end
|
157
|
+
|
158
|
+
# with default value
|
159
|
+
begin
|
160
|
+
|
161
|
+
argv = [ '--level=' ]
|
162
|
+
|
163
|
+
args = CLASP.parse argv, specifications
|
164
|
+
|
165
|
+
assert_equal 0, args.flags.size
|
166
|
+
assert_equal 1, args.options.size
|
167
|
+
assert_equal 0, args.values.size
|
168
|
+
|
169
|
+
opt = args.options[0]
|
170
|
+
|
171
|
+
assert_equal 0, opt.given_index
|
172
|
+
assert_equal specifications[0], opt.argument_specification
|
173
|
+
assert_equal '--level', opt.name
|
174
|
+
assert_equal '', opt.given_value
|
175
|
+
assert_equal 1234, opt.value
|
176
|
+
end
|
177
|
+
|
178
|
+
# with explicit value 0
|
179
|
+
begin
|
180
|
+
|
181
|
+
argv = [ '--level=0' ]
|
182
|
+
|
183
|
+
assert_raise_with_message(CLASP::Exceptions::IntegerOutOfRangeException, /\b0\b.*--level.*must be a positive integer/) { CLASP.parse argv, specifications }
|
184
|
+
end
|
185
|
+
|
186
|
+
# with explicit value -100
|
187
|
+
begin
|
188
|
+
|
189
|
+
argv = [ '--level=-100' ]
|
190
|
+
|
191
|
+
assert_raise_with_message(CLASP::Exceptions::IntegerOutOfRangeException, /-100\b.*--level.*must be a positive integer/) { CLASP.parse argv, specifications }
|
192
|
+
end
|
193
|
+
|
194
|
+
# with explicit value 123456789
|
195
|
+
begin
|
196
|
+
|
197
|
+
argv = [ '--level=123456789' ]
|
198
|
+
|
199
|
+
args = CLASP.parse argv, specifications
|
200
|
+
|
201
|
+
assert_equal 0, args.flags.size
|
202
|
+
assert_equal 1, args.options.size
|
203
|
+
assert_equal 0, args.values.size
|
204
|
+
|
205
|
+
opt = args.options[0]
|
206
|
+
|
207
|
+
assert_equal 0, opt.given_index
|
208
|
+
assert_equal specifications[0], opt.argument_specification
|
209
|
+
assert_equal '--level', opt.name
|
210
|
+
assert_equal '123456789', opt.given_value
|
211
|
+
assert_equal 123456789, opt.value
|
212
|
+
end
|
213
|
+
|
214
|
+
# with explicit value +123456789
|
215
|
+
begin
|
216
|
+
|
217
|
+
argv = [ '--level=+123456789' ]
|
218
|
+
|
219
|
+
args = CLASP.parse argv, specifications
|
220
|
+
|
221
|
+
assert_equal 0, args.flags.size
|
222
|
+
assert_equal 1, args.options.size
|
223
|
+
assert_equal 0, args.values.size
|
224
|
+
|
225
|
+
opt = args.options[0]
|
226
|
+
|
227
|
+
assert_equal 0, opt.given_index
|
228
|
+
assert_equal specifications[0], opt.argument_specification
|
229
|
+
assert_equal '--level', opt.name
|
230
|
+
assert_equal '+123456789', opt.given_value
|
231
|
+
assert_equal 123456789, opt.value
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_Integer_range_values_range
|
236
|
+
|
237
|
+
specifications = [
|
238
|
+
|
239
|
+
CLASP.Option('--level', default_value: 1234, values_range: [ 1234, -1234, 7, 19 ], constraint: { type: Integer })
|
240
|
+
]
|
241
|
+
|
242
|
+
# with no arguments
|
243
|
+
begin
|
244
|
+
|
245
|
+
argv = []
|
246
|
+
args = CLASP.parse argv, specifications
|
247
|
+
|
248
|
+
assert_equal 0, args.flags.size
|
249
|
+
assert_equal 0, args.options.size
|
250
|
+
assert_equal 0, args.values.size
|
251
|
+
end
|
252
|
+
|
253
|
+
# with default value
|
254
|
+
begin
|
255
|
+
|
256
|
+
argv = [ '--level=' ]
|
257
|
+
|
258
|
+
args = CLASP.parse argv, specifications
|
259
|
+
|
260
|
+
assert_equal 0, args.flags.size
|
261
|
+
assert_equal 1, args.options.size
|
262
|
+
assert_equal 0, args.values.size
|
263
|
+
|
264
|
+
opt = args.options[0]
|
265
|
+
|
266
|
+
assert_equal 0, opt.given_index
|
267
|
+
assert_equal specifications[0], opt.argument_specification
|
268
|
+
assert_equal '--level', opt.name
|
269
|
+
assert_equal '', opt.given_value
|
270
|
+
assert_equal 1234, opt.value
|
271
|
+
end
|
272
|
+
|
273
|
+
# with explicit value 0
|
274
|
+
begin
|
275
|
+
|
276
|
+
argv = [ '--level=0' ]
|
277
|
+
|
278
|
+
assert_raise_with_message(CLASP::Exceptions::IntegerOutOfRangeException, /\b0\b.*--level.*does not fall within the required range/) { CLASP.parse argv, specifications }
|
279
|
+
end
|
280
|
+
|
281
|
+
spec0 = specifications[0]
|
282
|
+
values = spec0.values_range.sort[0]..spec0.values_range.sort[-1]
|
283
|
+
|
284
|
+
values.each do |val|
|
285
|
+
|
286
|
+
argv = [ "--level=#{val}" ]
|
287
|
+
|
288
|
+
if spec0.values_range.include? val
|
289
|
+
|
290
|
+
args = CLASP.parse argv, specifications
|
291
|
+
|
292
|
+
assert_equal 0, args.flags.size
|
293
|
+
assert_equal 1, args.options.size
|
294
|
+
assert_equal 0, args.values.size
|
295
|
+
|
296
|
+
opt = args.options[0]
|
297
|
+
|
298
|
+
assert_equal 0, opt.given_index
|
299
|
+
assert_equal specifications[0], opt.argument_specification
|
300
|
+
assert_equal '--level', opt.name
|
301
|
+
assert_equal val.to_s, opt.given_value
|
302
|
+
assert_equal val, opt.value
|
303
|
+
else
|
304
|
+
|
305
|
+
assert_raise_with_message(CLASP::Exceptions::IntegerOutOfRangeException, /#{val}\b.*--level.*does not fall within the required range/) { CLASP.parse argv, specifications }
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
metadata
CHANGED
@@ -1,72 +1,66 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clasp-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.21.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Matt Wilson
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-28 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: xqsr3
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0.30'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0.30'
|
30
|
-
description:
|
31
|
-
powerful
|
32
|
-
|
33
|
-
abstraction of command-line interpretation facilities. CLASP.Ruby is a Ruby port
|
34
|
-
of the popular CLASP (C/C++) library, and provides declarative specification of
|
35
|
-
command-line flags and options, aliasing, flag combination, UNIX de-facto standard
|
36
|
-
flag processing, and a number of utility functions for expressing usage and version
|
37
|
-
information.
|
38
|
-
|
39
|
-
'
|
27
|
+
description: |
|
28
|
+
Command-Line Argument Sorting and Parsing library that provides a powerful
|
29
|
+
abstraction of command-line interpretation facilities. CLASP.Ruby is a Ruby port of the popular CLASP (C/C++) library, and provides declarative specification of command-line flags and options, aliasing, flag combination, UNIX de-facto standard flag processing, and a number of utility functions for expressing usage and version information.
|
40
30
|
email: matthew@synesis.com.au
|
41
31
|
executables: []
|
42
32
|
extensions: []
|
43
33
|
extra_rdoc_files: []
|
44
34
|
files:
|
35
|
+
- LICENSE
|
36
|
+
- README.md
|
45
37
|
- examples/cr-example.rb
|
46
38
|
- examples/flag_and_option_specifications.md
|
47
39
|
- examples/flag_and_option_specifications.rb
|
48
40
|
- examples/show_usage_and_version.md
|
49
41
|
- examples/show_usage_and_version.rb
|
50
42
|
- examples/simple_command_line_no_specifications.rb
|
43
|
+
- lib/clasp-ruby.rb
|
44
|
+
- lib/clasp.rb
|
51
45
|
- lib/clasp/arguments.rb
|
52
46
|
- lib/clasp/clasp.rb
|
53
47
|
- lib/clasp/cli.rb
|
54
48
|
- lib/clasp/doc_.rb
|
55
49
|
- lib/clasp/old_module.rb
|
56
50
|
- lib/clasp/specifications.rb
|
51
|
+
- lib/clasp/util/exceptions.rb
|
52
|
+
- lib/clasp/util/value_parser.rb
|
57
53
|
- lib/clasp/version.rb
|
58
|
-
- lib/clasp-ruby.rb
|
59
|
-
- lib/clasp.rb
|
60
54
|
- test/scratch/test_list_command_line.rb
|
61
55
|
- test/scratch/test_specifications.rb
|
62
56
|
- test/scratch/test_usage.rb
|
63
57
|
- test/scratch/test_usage_from_DATA.rb
|
64
58
|
- test/scratch/test_usage_with_duplicate_specifications.rb
|
59
|
+
- test/unit/tc_ARGV_rewrite.rb
|
65
60
|
- test/unit/tc_arguments_1.rb
|
66
61
|
- test/unit/tc_arguments_2.rb
|
67
62
|
- test/unit/tc_arguments_3.rb
|
68
63
|
- test/unit/tc_arguments_inspect.rb
|
69
|
-
- test/unit/tc_ARGV_rewrite.rb
|
70
64
|
- test/unit/tc_cli.rb
|
71
65
|
- test/unit/tc_default_value.rb
|
72
66
|
- test/unit/tc_defaults_1.rb
|
@@ -75,33 +69,31 @@ files:
|
|
75
69
|
- test/unit/tc_option_required.rb
|
76
70
|
- test/unit/tc_option_value_aliases.rb
|
77
71
|
- test/unit/tc_specifications.rb
|
72
|
+
- test/unit/tc_typed_options.rb
|
78
73
|
- test/unit/tc_usage.rb
|
79
74
|
- test/unit/ts_all.rb
|
80
|
-
- README.md
|
81
|
-
- LICENSE
|
82
75
|
homepage: http://github.com/synesissoftware/CLASP.Ruby
|
83
76
|
licenses:
|
84
77
|
- BSD-3-Clause
|
78
|
+
metadata: {}
|
85
79
|
post_install_message:
|
86
80
|
rdoc_options: []
|
87
81
|
require_paths:
|
88
82
|
- lib
|
89
83
|
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
-
none: false
|
91
84
|
requirements:
|
92
|
-
- -
|
85
|
+
- - ">="
|
93
86
|
- !ruby/object:Gem::Version
|
94
87
|
version: 1.9.3
|
95
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
-
none: false
|
97
89
|
requirements:
|
98
|
-
- -
|
90
|
+
- - ">="
|
99
91
|
- !ruby/object:Gem::Version
|
100
92
|
version: '0'
|
101
93
|
requirements: []
|
102
94
|
rubyforge_project:
|
103
|
-
rubygems_version:
|
95
|
+
rubygems_version: 2.7.6
|
104
96
|
signing_key:
|
105
|
-
specification_version:
|
97
|
+
specification_version: 4
|
106
98
|
summary: CLASP.Ruby
|
107
99
|
test_files: []
|