diff --git a/CHANGELOG.md b/CHANGELOG.md index d084bb2..a888298 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ ### Changed * Change permit setting to work with parameters converted to an array or a hash * Change formatting of a hash value in parameter validation error message -* Change array conversion to work with non-string values +* Change array and hash conversions to work with non-string values ### Fixed * Fix argument check against permitted values to allow nil value when optional diff --git a/lib/tty/option/conversions.rb b/lib/tty/option/conversions.rb index be53eca..894c984 100644 --- a/lib/tty/option/conversions.rb +++ b/lib/tty/option/conversions.rb @@ -88,16 +88,15 @@ module Conversions convert :map, :hash do |val| next Const::Undefined if val.nil? + next val if val.is_a?(Hash) - values = val.respond_to?(:each) ? val : val.to_s.split(/[& ]/) + values = val.respond_to?(:split) ? val.split(/[& ]/) : Array(val) values.each_with_object({}) do |pair, pairs| - key, value = pair.split(/[=:]/, 2) - if (current = pairs[key.to_sym]) - pairs[key.to_sym] = Array(current) << value - else - pairs[key.to_sym] = value - end - pairs + is_string = pair.respond_to?(:split) + key, value = is_string ? pair.split(/[=:]/, 2) : pair + new_key = is_string ? key.to_sym : key + current = pairs[new_key] + pairs[new_key] = current ? Array(current) << value : value end end diff --git a/spec/unit/conversions_spec.rb b/spec/unit/conversions_spec.rb index f41186e..9d52680 100644 --- a/spec/unit/conversions_spec.rb +++ b/spec/unit/conversions_spec.rb @@ -207,6 +207,10 @@ context ":map" do { "" => {}, + "a" => {a: nil}, + :a => {a: nil}, + 1 => {1 => nil}, + true => {true => nil}, "a=1" => {a: "1"}, "a=1&b=2" => {a: "1", b: "2"}, "a=&b=2" => {a: "", b: "2"}, @@ -214,7 +218,9 @@ "a:1 b:2" => {a: "1", b: "2"}, "a:1 b:2 a:3" => {a: %w[1 3], b: "2"}, %w[a:1 b:2 c:3] => {a: "1", b: "2", c: "3"}, - %w[a=1 b=2 c=3] => {a: "1", b: "2", c: "3"} + %w[a=1 b=2 c=3] => {a: "1", b: "2", c: "3"}, + {a: :a, b: 1, c: true} => {a: :a, b: 1, c: true}, + {"a" => :a, "b" => 1, "c" => true} => {"a" => :a, "b" => 1, "c" => true} }.each do |input, obj| it "converts #{input.inspect} to #{obj.inspect}" do expect(described_class[:map].(input)).to eq(obj) @@ -227,10 +233,15 @@ { [:int_map, "a:1 b:2 c:3"] => {a: 1, b: 2, c: 3}, + [:int_map, {a: "1",b: "2",c: "3"}] => {a: 1, b: 2, c: 3}, [:float_map, "a:1 b:2 c:3"] => {a: 1.0, b: 2.0, c: 3.0}, + [:float_map, {a: "1",b: "2", c: "3"}] => {a: 1.0, b: 2.0, c: 3.0}, [:bool_map, "a:t b:f c:t"] => {a: true, b: false, c: true}, + [:bool_map, {a: "t",b: "f", c: "t"}] => {a: true, b: false, c: true}, [:symbol_map, "a:t b:f c:t"] => {a: :t, b: :f, c: :t}, - [:regexp_map, "a:t b:f c:t"] => {a: /t/, b: /f/, c: /t/} + [:symbol_map, {a: "t", b: "f", c: "t"}] => {a: :t, b: :f, c: :t}, + [:regexp_map, "a:t b:f c:t"] => {a: /t/, b: /f/, c: /t/}, + [:regexp_map, {a: "t", b: "f", c: "t"}] => {a: /t/, b: /f/, c: /t/} }.each do |(type, input), obj| it "converts #{input.inspect} to #{obj.inspect}" do expect(described_class[type].(input)).to eq(obj) diff --git a/spec/unit/parse_spec.rb b/spec/unit/parse_spec.rb index 01e5fb9..f84271c 100644 --- a/spec/unit/parse_spec.rb +++ b/spec/unit/parse_spec.rb @@ -621,6 +621,34 @@ expect(cmd.params[:foo]).to eq([1, 2, 3]) end + + it "defaults a string to a hash with integer values" do + cmd = new_command do + option :foo do + long "--foo VAL" + convert :int_map + default "a:1 b:2 c:3" + end + end + + cmd.parse([]) + + expect(cmd.params[:foo]).to eq({a: 1, b: 2, c: 3}) + end + + it "defaults to a hash with integer values" do + cmd = new_command do + option :foo do + long "--foo VAL" + convert :int_map + default({"a" => 1, "b" => 2, "c" => 3}) + end + end + + cmd.parse([]) + + expect(cmd.params[:foo]).to eq({"a" => 1, "b" => 2, "c" => 3}) + end end context "convert" do