Skip to content

Commit 07e8367

Browse files
committed
Add exact: keyword argument
1 parent bbec64d commit 07e8367

File tree

2 files changed

+58
-29
lines changed

2 files changed

+58
-29
lines changed

lib/optparse.rb

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,21 +1654,21 @@ def separator(string)
16541654
#
16551655
# Returns the rest of +argv+ left unparsed.
16561656
#
1657-
def order(*argv, into: nil, &nonopt)
1657+
def order(*argv, **keywords, &nonopt)
16581658
argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1659-
order!(argv, into: into, &nonopt)
1659+
order!(argv, **keywords, &nonopt)
16601660
end
16611661

16621662
#
16631663
# Same as #order, but removes switches destructively.
16641664
# Non-option arguments remain in +argv+.
16651665
#
1666-
def order!(argv = default_argv, into: nil, &nonopt)
1666+
def order!(argv = default_argv, into: nil, **keywords, &nonopt)
16671667
setter = ->(name, val) {into[name.to_sym] = val} if into
1668-
parse_in_order(argv, setter, &nonopt)
1668+
parse_in_order(argv, setter, **keywords, &nonopt)
16691669
end
16701670

1671-
def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
1671+
def parse_in_order(argv = default_argv, setter = nil, exact: require_exact, **, &nonopt) # :nodoc:
16721672
opt, arg, val, rest = nil
16731673
nonopt ||= proc {|a| throw :terminate, a}
16741674
argv.unshift(arg) if arg = catch(:terminate) {
@@ -1679,7 +1679,7 @@ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
16791679
opt, rest = $1, $2
16801680
opt.tr!('_', '-')
16811681
begin
1682-
if require_exact
1682+
if exact
16831683
sw, = search(:long, opt)
16841684
else
16851685
sw, = complete(:long, opt, true)
@@ -1714,7 +1714,7 @@ def parse_in_order(argv = default_argv, setter = nil, &nonopt) # :nodoc:
17141714
val = arg.delete_prefix('-')
17151715
has_arg = true
17161716
rescue InvalidOption
1717-
raise if require_exact
1717+
raise if exact
17181718
# if no short options match, try completion with long
17191719
# options.
17201720
sw, = complete(:long, opt)
@@ -1779,18 +1779,18 @@ def callback!(cb, max_arity, *args) # :nodoc:
17791779
# <code>[]=</code> method (so it can be Hash, or OpenStruct, or other
17801780
# similar object).
17811781
#
1782-
def permute(*argv, into: nil)
1782+
def permute(*argv, **keywords)
17831783
argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1784-
permute!(argv, into: into)
1784+
permute!(argv, **keywords)
17851785
end
17861786

17871787
#
17881788
# Same as #permute, but removes switches destructively.
17891789
# Non-option arguments remain in +argv+.
17901790
#
1791-
def permute!(argv = default_argv, into: nil)
1791+
def permute!(argv = default_argv, **keywords)
17921792
nonopts = []
1793-
order!(argv, into: into, &nonopts.method(:<<))
1793+
order!(argv, **keywords, &nonopts.method(:<<))
17941794
argv[0, 0] = nonopts
17951795
argv
17961796
end
@@ -1802,20 +1802,20 @@ def permute!(argv = default_argv, into: nil)
18021802
# values are stored there via <code>[]=</code> method (so it can be Hash,
18031803
# or OpenStruct, or other similar object).
18041804
#
1805-
def parse(*argv, into: nil)
1805+
def parse(*argv, **keywords)
18061806
argv = argv[0].dup if argv.size == 1 and Array === argv[0]
1807-
parse!(argv, into: into)
1807+
parse!(argv, **keywords)
18081808
end
18091809

18101810
#
18111811
# Same as #parse, but removes switches destructively.
18121812
# Non-option arguments remain in +argv+.
18131813
#
1814-
def parse!(argv = default_argv, into: nil)
1814+
def parse!(argv = default_argv, **keywords)
18151815
if ENV.include?('POSIXLY_CORRECT')
1816-
order!(argv, into: into)
1816+
order!(argv, **keywords)
18171817
else
1818-
permute!(argv, into: into)
1818+
permute!(argv, **keywords)
18191819
end
18201820
end
18211821

@@ -1838,7 +1838,7 @@ def parse!(argv = default_argv, into: nil)
18381838
# # params[:bar] = "x" # --bar x
18391839
# # params[:zot] = "z" # --zot Z
18401840
#
1841-
def getopts(*args, symbolize_names: false)
1841+
def getopts(*args, symbolize_names: false, **keywords)
18421842
argv = Array === args.first ? args.shift : default_argv
18431843
single_options, *long_options = *args
18441844

@@ -1866,7 +1866,7 @@ def getopts(*args, symbolize_names: false)
18661866
end
18671867
end
18681868

1869-
parse_in_order(argv, result.method(:[]=))
1869+
parse_in_order(argv, result.method(:[]=), **keywords)
18701870
symbolize_names ? result.transform_keys(&:to_sym) : result
18711871
end
18721872

@@ -1979,10 +1979,10 @@ def candidate(word)
19791979
# The optional +into+ keyword argument works exactly like that accepted in
19801980
# method #parse.
19811981
#
1982-
def load(filename = nil, into: nil)
1982+
def load(filename = nil, **keywords)
19831983
unless filename
19841984
basename = File.basename($0, '.*')
1985-
return true if load(File.expand_path(basename, '~/.options'), into: into) rescue nil
1985+
return true if load(File.expand_path(basename, '~/.options'), **keywords) rescue nil
19861986
basename << ".options"
19871987
return [
19881988
# XDG
@@ -1994,11 +1994,11 @@ def load(filename = nil, into: nil)
19941994
'~/config/settings',
19951995
].any? {|dir|
19961996
next if !dir or dir.empty?
1997-
load(File.expand_path(basename, dir), into: into) rescue nil
1997+
load(File.expand_path(basename, dir), **keywords) rescue nil
19981998
}
19991999
end
20002000
begin
2001-
parse(*File.readlines(filename, chomp: true), into: into)
2001+
parse(*File.readlines(filename, chomp: true), **keywords)
20022002
true
20032003
rescue Errno::ENOENT, Errno::ENOTDIR
20042004
false
@@ -2011,10 +2011,10 @@ def load(filename = nil, into: nil)
20112011
#
20122012
# +env+ defaults to the basename of the program.
20132013
#
2014-
def environment(env = File.basename($0, '.*'))
2014+
def environment(env = File.basename($0, '.*'), **keywords)
20152015
env = ENV[env] || ENV[env.upcase] or return
20162016
require 'shellwords'
2017-
parse(*Shellwords.shellwords(env))
2017+
parse(*Shellwords.shellwords(env), **keywords)
20182018
end
20192019

20202020
#
@@ -2331,19 +2331,19 @@ def options
23312331
# Parses +self+ destructively in order and returns +self+ containing the
23322332
# rest arguments left unparsed.
23332333
#
2334-
def order!(&blk) options.order!(self, &blk) end
2334+
def order!(**keywords, &blk) options.order!(self, **keywords, &blk) end
23352335

23362336
#
23372337
# Parses +self+ destructively in permutation mode and returns +self+
23382338
# containing the rest arguments left unparsed.
23392339
#
2340-
def permute!() options.permute!(self) end
2340+
def permute!(**keywords) options.permute!(self, **keywords) end
23412341

23422342
#
23432343
# Parses +self+ destructively and returns +self+ containing the
23442344
# rest arguments left unparsed.
23452345
#
2346-
def parse!() options.parse!(self) end
2346+
def parse!(**keywords) options.parse!(self, **keywords) end
23472347

23482348
#
23492349
# Substitution of getopts is possible as follows. Also see
@@ -2356,8 +2356,8 @@ def parse!() options.parse!(self) end
23562356
# rescue OptionParser::ParseError
23572357
# end
23582358
#
2359-
def getopts(*args, symbolize_names: false)
2360-
options.getopts(self, *args, symbolize_names: symbolize_names)
2359+
def getopts(*args, symbolize_names: false, **keywords)
2360+
options.getopts(self, *args, symbolize_names: symbolize_names, **keywords)
23612361
end
23622362

23632363
#

test/optparse/test_optparse.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,35 @@ def test_require_exact
116116
assert_equal(false, @foo)
117117
end
118118

119+
def test_exact_option
120+
@opt.def_option('-F', '--zrs=IRS', 'zrs')
121+
%w(--zrs --zr --z -zfoo -z -F -Ffoo).each do |arg|
122+
result = {}
123+
@opt.parse([arg, 'foo'], into: result)
124+
assert_equal({zrs: 'foo'}, result)
125+
end
126+
127+
[%w(--zrs foo), %w(--zrs=foo), %w(-F foo), %w(-Ffoo)].each do |args|
128+
result = {}
129+
@opt.parse(args, into: result, exact: true)
130+
assert_equal({zrs: 'foo'}, result)
131+
end
132+
133+
assert_raise(OptionParser::InvalidOption) {@opt.parse(%w(--zr foo), exact: true)}
134+
assert_raise(OptionParser::InvalidOption) {@opt.parse(%w(--z foo), exact: true)}
135+
assert_raise(OptionParser::InvalidOption) {@opt.parse(%w(-zrs foo), exact: true)}
136+
assert_raise(OptionParser::InvalidOption) {@opt.parse(%w(-zr foo), exact: true)}
137+
assert_raise(OptionParser::InvalidOption) {@opt.parse(%w(-z foo), exact: true)}
138+
139+
@opt.def_option('-f', '--[no-]foo', 'foo') {|arg| @foo = arg}
140+
@opt.parse(%w[-f], exact: true)
141+
assert_equal(true, @foo)
142+
@opt.parse(%w[--foo], exact: true)
143+
assert_equal(true, @foo)
144+
@opt.parse(%w[--no-foo], exact: true)
145+
assert_equal(false, @foo)
146+
end
147+
119148
def test_raise_unknown
120149
@opt.def_option('--my-foo [ARG]') {|arg| @foo = arg}
121150
assert @opt.raise_unknown

0 commit comments

Comments
 (0)