YAML や JSON で表現されるような、スカラー値、Array、Hash で構成されたオブジェクトについて、再帰的に処理をする際、下記のようなイディオムが使える。
def foo(obj)
case obj
when Array
obj.map{|e| foo(e)} # Array の要素を再帰的に処理
when Hash
obj.inject({}) do |hash, (k, v)|
hash[k] = foo(v) # Hash の値を再帰的に処理
hash
end
else
obj
end
end
例. Hash のキーを to_s する
def stringify_keys(obj)
case obj
when Array
obj.map{|e| stringify_keys(e)}
when Hash
obj.inject({}) do |hash, (k, v)|
# ここが変わる
hash[k.to_s] = stringify_keys(v)
hash
end
else
obj
end
end
stringify_keys({a: 1, b: [{c: 3}]}) #=> {"a"=>1, "b"=>[{"c"=>3}]}
例. スカラー値を to_s する
def stringify_values(obj)
case obj
when Array
obj.map{|e| stringify_values(e)}
when Hash
obj.inject({}) do |hash, (k, v)|
hash[k] = stringify_values(v)
hash
end
else
# ここが変わる
obj.to_s
end
end
stringify_values({a: 1, b: [{c: 3}]}) #=> {:a=>"1", :b=>[{:c=>"3"}]}
例. Array を、インデックスをキーとする Hash に置き換える
def hash_arrays(obj)
case obj
when Array
# ここが変わる
Hash[
obj.each_with_index.map do |e, i|
[i, hash_arrays(e)]
end
]
when Hash
obj.inject({}) do |hash, (k, v)|
hash[k] = hash_arrays(v)
hash
end
else
obj
end
end
hash_arrays({a: 1, b: [{c: 3}]}) #=> {:a=>1, :b=>{0=>{:c=>3}}}