Skip to content

Commit 050a87d

Browse files
committed
Add post-check of value
Fix #80
1 parent 71e2b31 commit 050a87d

File tree

2 files changed

+38
-9
lines changed

2 files changed

+38
-9
lines changed

lib/optparse.rb

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,10 @@ def self.candidate(key, icase = false, pat = nil, &block)
461461
candidates
462462
end
463463

464+
def self.completable?(key)
465+
String.try_convert(key) or defined?(key.id2name)
466+
end
467+
464468
def candidate(key, icase = false, pat = nil, &_)
465469
Completion.candidate(key, icase, pat, &method(:each))
466470
end
@@ -544,11 +548,11 @@ def self.pattern
544548

545549
def initialize(pattern = nil, conv = nil,
546550
short = nil, long = nil, arg = nil,
547-
desc = ([] if short or long), block = nil, &_block)
551+
desc = ([] if short or long), block = nil, values = nil, &_block)
548552
raise if Array === pattern
549553
block ||= _block
550-
@pattern, @conv, @short, @long, @arg, @desc, @block =
551-
pattern, conv, short, long, arg, desc, block
554+
@pattern, @conv, @short, @long, @arg, @desc, @block, @values =
555+
pattern, conv, short, long, arg, desc, block, values
552556
end
553557

554558
#
@@ -581,11 +585,15 @@ def parse_arg(arg) # :nodoc:
581585
# exception.
582586
#
583587
def conv_arg(arg, val = []) # :nodoc:
588+
v, = *val
584589
if conv
585590
val = conv.call(*val)
586591
else
587592
val = proc {|v| v}.call(*val)
588593
end
594+
if @values
595+
@values.include?(val) or raise InvalidArgument, v
596+
end
589597
return arg, block, val
590598
end
591599
private :conv_arg
@@ -780,7 +788,7 @@ class PlacedArgument < self
780788
# Returns nil if argument is not present or begins with '-' and is not '-'.
781789
#
782790
def parse(arg, argv, &error)
783-
if !(val = arg) and !(val = argv[0])&.match?(/\A(?!-.)/)
791+
if !(val = arg) and (argv.empty? or /\A-./ =~ (val = argv[0]))
784792
return nil, block
785793
end
786794
opt = (val = parse_arg(val, &error))[1]
@@ -1464,6 +1472,7 @@ def make_switch(opts, block = nil)
14641472
klass = nil
14651473
q, a = nil
14661474
has_arg = false
1475+
values = nil
14671476

14681477
opts.each do |o|
14691478
# argument class
@@ -1477,7 +1486,7 @@ def make_switch(opts, block = nil)
14771486
end
14781487

14791488
# directly specified pattern(any object possible to match)
1480-
if (!(String === o || Symbol === o)) and o.respond_to?(:match)
1489+
if !Completion.completable?(o) and o.respond_to?(:match)
14811490
pattern = notwice(o, pattern, 'pattern')
14821491
if pattern.respond_to?(:convert)
14831492
conv = pattern.method(:convert).to_proc
@@ -1492,6 +1501,11 @@ def make_switch(opts, block = nil)
14921501
when Proc, Method
14931502
block = notwice(o, block, 'block')
14941503
when Array, Hash
1504+
if Array === o
1505+
o, v = o.partition {|v| Completion.completable?(v)}
1506+
values = notwice(v, values, 'values') unless v.empty?
1507+
next if o.empty?
1508+
end
14951509
case pattern
14961510
when CompletingHash
14971511
when nil
@@ -1500,7 +1514,9 @@ def make_switch(opts, block = nil)
15001514
else
15011515
raise ArgumentError, "argument pattern given twice"
15021516
end
1503-
o.each {|pat, *v| pattern[pat.to_s] = v.fetch(0) {pat}}
1517+
o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}}
1518+
when Range
1519+
values = notwice(o, values, 'values')
15041520
when Module
15051521
raise ArgumentError, "unsupported argument type: #{o}", ParseError.filter_backtrace(caller(4))
15061522
when *ArgumentStyle.keys
@@ -1568,12 +1584,18 @@ def make_switch(opts, block = nil)
15681584
end
15691585

15701586
default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern
1587+
if Range === values and klass
1588+
unless (!values.begin or klass === values.begin) and
1589+
(!values.end or klass === values.end)
1590+
raise ArgumentError, "range does not match class"
1591+
end
1592+
end
15711593
if !(short.empty? and long.empty?)
15721594
if has_arg and default_style == Switch::NoArgument
15731595
default_style = Switch::RequiredArgument
15741596
end
15751597
s = (style || default_style).new(pattern || default_pattern,
1576-
conv, sdesc, ldesc, arg, desc, block)
1598+
conv, sdesc, ldesc, arg, desc, block, values)
15771599
elsif !block
15781600
if style or pattern
15791601
raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller)
@@ -1582,7 +1604,7 @@ def make_switch(opts, block = nil)
15821604
else
15831605
short << pattern
15841606
s = (style || default_style).new(pattern,
1585-
conv, nil, nil, arg, desc, block)
1607+
conv, nil, nil, arg, desc, block, values)
15861608
end
15871609
return s, short, long,
15881610
(not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style),

test/optparse/test_placearg.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ def setup
88
@opt.def_option("--option [VAL]") {|x| @flag = x}
99
@opt.def_option("-T [level]", /^[0-4]$/, Integer) {|x| @topt = x}
1010
@opt.def_option("--enum [VAL]", [:Alpha, :Bravo, :Charlie]) {|x| @enum = x}
11-
@opt.def_option("--integer [VAL]", [1, 2, 3]) {|x| @integer = x}
11+
@opt.def_option("--integer [VAL]", Integer, [1, 2, 3]) {|x| @integer = x}
12+
@opt.def_option("--range [VAL]", Integer, 1..3) {|x| @range = x}
1213
@topt = nil
1314
@opt.def_option("-n") {}
1415
@opt.def_option("--regexp [REGEXP]", Regexp) {|x| @reopt = x}
@@ -105,4 +106,10 @@ def test_enum_conversion
105106
assert_equal([], no_error {@opt.parse!(%w"--integer=1")})
106107
assert_equal(1, @integer)
107108
end
109+
110+
def test_enum_range
111+
assert_equal([], no_error {@opt.parse!(%w"--range=1")})
112+
assert_equal(1, @range)
113+
assert_raise(OptionParser::InvalidArgument) {@opt.parse!(%w"--range=4")}
114+
end
108115
end

0 commit comments

Comments
 (0)