diff --git a/lib/fluent/config/types.rb b/lib/fluent/config/types.rb index b295ef5816..85499c9910 100644 --- a/lib/fluent/config/types.rb +++ b/lib/fluent/config/types.rb @@ -80,19 +80,58 @@ def self.bool_value(str) SIZE_TYPE = Proc.new { |val, opts| Config.size_value(val) } BOOL_TYPE = Proc.new { |val, opts| Config.bool_value(val) } TIME_TYPE = Proc.new { |val, opts| Config.time_value(val) } + + REFORMAT_VALUE = ->(type, value) { + if value.nil? + value + else + case type + when :string then value.to_s + when :integer then value.to_i + when :float then value.to_f + when :size then Config.size_value(value) + when :bool then Config.bool_value(value) + when :time then Config.time_value(value) + else + raise "unknown type in REFORMAT: #{type}" + end + end + } + HASH_TYPE = Proc.new { |val, opts| - param = val.is_a?(String) ? JSON.load(val) : val + param = if val.is_a?(String) + val.start_with?('{') ? JSON.load(val) : Hash[val.strip.split(/\s*,\s*/).map{|v| v.split(':', 2)}] + else + val + end if param.class != Hash raise ConfigError, "hash required but got #{val.inspect}" end - param + if opts.empty? + param + else + newparam = {} + param.each_pair do |key, value| + new_key = opts[:symbolize_keys] ? key.to_sym : key + newparam[new_key] = opts[:value_type] ? REFORMAT_VALUE.call(opts[:value_type], value) : value + end + newparam + end } ARRAY_TYPE = Proc.new { |val, opts| - param = val.is_a?(String) ? JSON.load(val) : val + param = if val.is_a?(String) + val.start_with?('[') ? JSON.load(val) : val.strip.split(/\s*,\s*/) + else + val + end if param.class != Array raise ConfigError, "array required but got #{val.inspect}" end - param + if opts[:value_type] + param.map{|v| REFORMAT_VALUE.call(opts[:value_type], v) } + else + param + end } end diff --git a/test/config/test_types.rb b/test/config/test_types.rb index 2821b115a5..ffd96b2bc2 100644 --- a/test/config/test_types.rb +++ b/test/config/test_types.rb @@ -124,10 +124,38 @@ class TestConfigTypes < ::Test::Unit::TestCase test 'hash' do assert_equal({"x"=>"v","k"=>1}, Config::HASH_TYPE.call('{"x":"v","k":1}', {})) + assert_equal({"x"=>"v","k"=>"1"}, Config::HASH_TYPE.call('x:v,k:1', {})) + assert_equal({"x"=>"v","k"=>"1"}, Config::HASH_TYPE.call('x:v, k:1', {})) + assert_equal({"x"=>"v","k"=>"1"}, Config::HASH_TYPE.call(' x:v, k:1 ', {})) + assert_equal({"x"=>"v","k"=>"1"}, Config::HASH_TYPE.call('x:v , k:1 ', {})) + + assert_equal({"x"=>"v:v","k"=>"1"}, Config::HASH_TYPE.call('x:v:v, k:1', {})) + + assert_equal({x: "v", k: 1}, Config::HASH_TYPE.call('{"x":"v","k":1}', {symbolize_keys: true})) + assert_equal({x: "v", k: "1"}, Config::HASH_TYPE.call('x:v,k:1', {symbolize_keys: true, value_type: :string})) + assert_equal({x: "v", k: "1"}, Config::HASH_TYPE.call('{"x":"v","k":1}', {symbolize_keys: true, value_type: :string})) + assert_equal({x: 0, k: 1}, Config::HASH_TYPE.call('x:0,k:1', {symbolize_keys: true, value_type: :integer})) + + assert_equal({"x"=>1,"y"=>60,"z"=>3600}, Config::HASH_TYPE.call('{"x":"1s","y":"1m","z":"1h"}', {value_type: :time})) + assert_equal({"x"=>1,"y"=>60,"z"=>3600}, Config::HASH_TYPE.call('x:1s,y:1m,z:1h', {value_type: :time})) end test 'array' do assert_equal(["1","2",1], Config::ARRAY_TYPE.call('["1","2",1]', {})) + assert_equal(["1","2","1"], Config::ARRAY_TYPE.call('1,2,1', {})) + + assert_equal(["a","b","c"], Config::ARRAY_TYPE.call('["a","b","c"]', {})) + assert_equal(["a","b","c"], Config::ARRAY_TYPE.call('a,b,c', {})) + assert_equal(["a","b","c"], Config::ARRAY_TYPE.call('a, b, c', {})) + assert_equal(["a","b","c"], Config::ARRAY_TYPE.call('a , b , c', {})) + + assert_equal(["a a","b,b"," c "], Config::ARRAY_TYPE.call('["a a","b,b"," c "]', {})) + + assert_equal(["a a","b","c"], Config::ARRAY_TYPE.call('a a,b,c', {})) + + assert_equal([1,2,1], Config::ARRAY_TYPE.call('[1,2,1]', {})) + assert_equal([1,2,1], Config::ARRAY_TYPE.call('["1","2","1"]', {value_type: :integer})) + assert_equal([1,2,1], Config::ARRAY_TYPE.call('1,2,1', {value_type: :integer})) array_options = { default: [],