diff options
author | Nobuyoshi Nakada <[email protected]> | 2025-03-10 13:12:34 +0900 |
---|---|---|
committer | git <[email protected]> | 2025-03-10 09:55:29 +0000 |
commit | 9e265b583b5cc35b8120978c855e1a6a78abbe5b (patch) | |
tree | 5292f87b227d3c99eb3563d8a283171721104329 | |
parent | b51450f3bd77f6dc862fcb8b177922a588f0e381 (diff) |
[ruby/optparse] Add post-check of value
Fix https://github.com/ruby/optparse/pull/80
https://github.com/ruby/optparse/commit/050a87d029
-rw-r--r-- | lib/optparse.rb | 38 | ||||
-rw-r--r-- | test/optparse/test_placearg.rb | 9 |
2 files changed, 38 insertions, 9 deletions
diff --git a/lib/optparse.rb b/lib/optparse.rb index a45d99d293..731d9bdb72 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -461,6 +461,10 @@ class OptionParser candidates end + def self.completable?(key) + String.try_convert(key) or defined?(key.id2name) + end + def candidate(key, icase = false, pat = nil, &_) Completion.candidate(key, icase, pat, &method(:each)) end @@ -544,11 +548,11 @@ class OptionParser def initialize(pattern = nil, conv = nil, short = nil, long = nil, arg = nil, - desc = ([] if short or long), block = nil, &_block) + desc = ([] if short or long), block = nil, values = nil, &_block) raise if Array === pattern block ||= _block - @pattern, @conv, @short, @long, @arg, @desc, @block = - pattern, conv, short, long, arg, desc, block + @pattern, @conv, @short, @long, @arg, @desc, @block, @values = + pattern, conv, short, long, arg, desc, block, values end # @@ -581,11 +585,15 @@ class OptionParser # exception. # def conv_arg(arg, val = []) # :nodoc: + v, = *val if conv val = conv.call(*val) else val = proc {|v| v}.call(*val) end + if @values + @values.include?(val) or raise InvalidArgument, v + end return arg, block, val end private :conv_arg @@ -780,7 +788,7 @@ class OptionParser # Returns nil if argument is not present or begins with '-' and is not '-'. # def parse(arg, argv, &error) - if !(val = arg) and !(val = argv[0])&.match?(/\A(?!-.)/) + if !(val = arg) and (argv.empty? or /\A-./ =~ (val = argv[0])) return nil, block end opt = (val = parse_arg(val, &error))[1] @@ -1464,6 +1472,7 @@ XXX klass = nil q, a = nil has_arg = false + values = nil opts.each do |o| # argument class @@ -1477,7 +1486,7 @@ XXX end # directly specified pattern(any object possible to match) - if (!(String === o || Symbol === o)) and o.respond_to?(:match) + if !Completion.completable?(o) and o.respond_to?(:match) pattern = notwice(o, pattern, 'pattern') if pattern.respond_to?(:convert) conv = pattern.method(:convert).to_proc @@ -1492,6 +1501,11 @@ XXX when Proc, Method block = notwice(o, block, 'block') when Array, Hash + if Array === o + o, v = o.partition {|v| Completion.completable?(v)} + values = notwice(v, values, 'values') unless v.empty? + next if o.empty? + end case pattern when CompletingHash when nil @@ -1500,7 +1514,9 @@ XXX else raise ArgumentError, "argument pattern given twice" end - o.each {|pat, *v| pattern[pat.to_s] = v.fetch(0) {pat}} + o.each {|pat, *v| pattern[pat] = v.fetch(0) {pat}} + when Range + values = notwice(o, values, 'values') when Module raise ArgumentError, "unsupported argument type: #{o}", ParseError.filter_backtrace(caller(4)) when *ArgumentStyle.keys @@ -1568,12 +1584,18 @@ XXX end default_pattern, conv = search(:atype, default_style.pattern) unless default_pattern + if Range === values and klass + unless (!values.begin or klass === values.begin) and + (!values.end or klass === values.end) + raise ArgumentError, "range does not match class" + end + end if !(short.empty? and long.empty?) if has_arg and default_style == Switch::NoArgument default_style = Switch::RequiredArgument end s = (style || default_style).new(pattern || default_pattern, - conv, sdesc, ldesc, arg, desc, block) + conv, sdesc, ldesc, arg, desc, block, values) elsif !block if style or pattern raise ArgumentError, "no switch given", ParseError.filter_backtrace(caller) @@ -1582,7 +1604,7 @@ XXX else short << pattern s = (style || default_style).new(pattern, - conv, nil, nil, arg, desc, block) + conv, nil, nil, arg, desc, block, values) end return s, short, long, (not_style.new(not_pattern, not_conv, sdesc, ldesc, nil, desc, block) if not_style), diff --git a/test/optparse/test_placearg.rb b/test/optparse/test_placearg.rb index 511541fecd..36edf401e2 100644 --- a/test/optparse/test_placearg.rb +++ b/test/optparse/test_placearg.rb @@ -8,7 +8,8 @@ class TestOptionParserPlaceArg < TestOptionParser @opt.def_option("--option [VAL]") {|x| @flag = x} @opt.def_option("-T [level]", /^[0-4]$/, Integer) {|x| @topt = x} @opt.def_option("--enum [VAL]", [:Alpha, :Bravo, :Charlie]) {|x| @enum = x} - @opt.def_option("--integer [VAL]", [1, 2, 3]) {|x| @integer = x} + @opt.def_option("--integer [VAL]", Integer, [1, 2, 3]) {|x| @integer = x} + @opt.def_option("--range [VAL]", Integer, 1..3) {|x| @range = x} @topt = nil @opt.def_option("-n") {} @opt.def_option("--regexp [REGEXP]", Regexp) {|x| @reopt = x} @@ -105,4 +106,10 @@ class TestOptionParserPlaceArg < TestOptionParser assert_equal([], no_error {@opt.parse!(%w"--integer=1")}) assert_equal(1, @integer) end + + def test_enum_range + assert_equal([], no_error {@opt.parse!(%w"--range=1")}) + assert_equal(1, @range) + assert_raise(OptionParser::InvalidArgument) {@opt.parse!(%w"--range=4")} + end end |