この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
サーモン大好き横山です。
今回はrubyのjsonモジュールの to_json
メソッドで気になる挙動があったので紹介します。
用途
そもそもこちらのメソッドは、RubyのHashやArray等のデータ型を、json形式の文字列に変換してくれるメソッドです。
コード
#!/usr/bin/env ruby
# demo.rb
require 'json'
data = {
"num" => 1,
"string" => "abc",
"array" => [1, 2, 3],
"hash" => {"key1" => "value1", "key2" => "value2"}
}
puts data.to_json
結果
$ ruby demo.rb
{"num":1,"string":"abc","array":[1,2,3],"hash":{"key1":"value1","key2":"value2"}}
jq
を使うと見やすく表示できます。
$ ruby demo.rb | jq .
{
"num": 1,
"string": "abc",
"array": [
1,
2,
3
],
"hash": {
"key1": "value1",
"key2": "value2"
}
}
to_json メソッドの気になる挙動
表題についてですが、Hash型のキーで シンボル
と 文字列
が同名のものが存在すると同一キーのハッシュとしてjsonを生成してしまいます。
これは、RFC4627 2.2 Objects
の以下の記述に反しています。
The names within an object SHOULD be unique. 1
コード
#!/usr/bin/env ruby
# demo2.rb
require 'json'
data = {
key: 1,
"key" => 2
}
puts data.to_json
実行結果
$ ruby demo2.rb
{"key":1,"key":2}
問題点
このままjqに渡すと片方のデータのみ表示してしまいます。
実行結果
$ ruby demo2.rb | jq .
{
"key": 2
}
demo2.rb
のHashの要素を入れ替えた demo3.rb
で実行するとこうなります。
コード
#!/usr/bin/env ruby
# demo3.rb
require 'json'
data = {
"key" => 2,
key: 1
}
puts data.to_json
実行結果
$ ruby demo3.rb
{"key":2,"key":1}
$ ruby demo3.rb | jq .
{
"key": 1
}
ハッシュの後ろのデータが最終的にjqで出力されます。
まとめ
以上のことから、Hash型のキーで シンボル
と 文字列
が同名のものが存在するときの to_json
の挙動は重複キーを含まれるjsonが生成されます。
jqを通した場合、ハッシュの後ろのデータが最終的にjqで出力されます。
他のサービスではどういう挙動をするのかわかりませんので、なるべくHash型をjsonに変換する時は気をつけて to_json
メソッドを呼び出すようにコードを書いたほうがいいですね。