Skip to content

Commit

Permalink
Add support to option for parsing map of arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrmurach committed Mar 31, 2020
1 parent 3a009e1 commit a163c3d
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 3 deletions.
13 changes: 10 additions & 3 deletions lib/tty/option/parser/options.rb
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ def process_single_option(short, other_singles)
def consume_arguments(opt, values: [])
while (value = @argv.first) && !option?(value)
val = @argv.shift
values << val
parts = val.include?("&") ? val.split(/&/) : [val]
parts.each { |part| values << part }
end

values.size == 1 ? values.first : values
Expand Down Expand Up @@ -247,8 +248,14 @@ def record_error(type, message, opt = nil)
# @api private
def assign_option(opt, val)
if opt.multiple?
Array(ParamConversion[opt, val]).each do |v|
(@parsed[opt.name] ||= []) << v
converted = ParamConversion[opt, val]
case converted
when Hash
(@parsed[opt.name] ||= {}).merge!(converted)
else
Array(converted).each do |v|
(@parsed[opt.name] ||= []) << v
end
end
else
@parsed[opt.name] = ParamConversion[opt, val]
Expand Down
103 changes: 103 additions & 0 deletions spec/unit/parser/options_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -474,4 +474,107 @@ def parse(argv, options, **config)
expect(params[:foo]).to eq([])
end
end

context "when map argument" do
it "parses short option with a map argument" do
options = []
options << option(:foo, short: "-f map", convert: :map)
options << option(:bar, short: "-b")

params, = parse(%w[-f a:1 b:2 c:3 -b], options)

expect(params[:foo]).to eq({a:"1", b:"2", c:"3"})
expect(params[:bar]).to eq(true)
end

it "parses compacted short options with a separate map argument" do
options = []
options << option(:foo, short: "-f")
options << option(:bar, short: "-b")
options << option(:qux, short: "-q map", convert: :map)

params, = parse(%w[-fbq a:1 b:2 c:3], options)

expect(params[:foo]).to eq(true)
expect(params[:bar]).to eq(true)
expect(params[:qux]).to eq({a:"1", b:"2", c:"3"})
end

it "parses compacted short options with a map argument glued together" do
options = []
options << option(:foo, short: "-f")
options << option(:bar, short: "-b")
options << option(:qux, short: "-q map", convert: :map)

params, = parse(%w[-fbqa:1 b:2 c:3], options)

expect(params[:foo]).to eq(true)
expect(params[:bar]).to eq(true)
expect(params[:qux]).to eq({a:"1", b:"2", c:"3"})
end

it "parses long option with a map argument delimited by space" do
options = []
options << option(:foo, long: "--foo map", convert: :map)
options << option(:bar, long: "--bar")

params, rest = parse(%w[--foo a:1 b:2 c:3 --bar], options)

expect(params[:foo]).to eq({a:"1", b:"2", c:"3"})
expect(params[:bar]).to eq(true)
expect(rest).to eq([])
end

it "parses long option with a map argument delimited by ampersand" do
options = []
options << option(:foo, long: "--foo map", convert: :map)
options << option(:bar, long: "--bar")

params, rest = parse(%w[--foo a:1&b:2&c:3 --bar], options)

expect(params[:foo]).to eq({a:"1", b:"2", c:"3"})
expect(params[:bar]).to eq(true)
expect(rest).to eq([])
end

it "parses long option with a map argument and assigment symbol" do
options = []
options << option(:foo, long: "--foo=map", convert: :map)

params, = parse(%w[--foo=a:1 b:2 c:3], options)

expect(params[:foo]).to eq({a:"1", b:"2", c:"3"})
end

it "doesn't mix maps from other long options" do
options = []
options << option(:foo, long: "--foo map", convert: :int_map)
options << option(:bar, long: "--bar map", convert: :int_map)

params, rest = parse(%w[--foo a:1 b:2 c:3 --bar x:1 y:2], options)

expect(params[:foo]).to eq({a:1, b:2, c:3})
expect(params[:bar]).to eq({x:1, y:2})
expect(rest).to eq([])
end

it "combines multiple options with map arguments" do
options = []
options << option(:foo, short: "-f map", convert: :int_map, arity: :any)

params, rest = parse(%w[-f a:1 b:2 -f c:3 d:4], options)

expect(params[:foo]).to eq({a:1, b:2, c:3, d: 4})
expect(rest).to eq([])
end

it "parses option with an empty map" do
options = []
options << option(:foo, long: "--foo=map", convert: :map)

params, = parse(%w[--foo=], options)

expect(params[:foo]).to eq({})
end
end
end

0 comments on commit a163c3d

Please sign in to comment.