Ruby の JSON ライブラリで、ダンプ、生成、to_json、ロードと解析をいつ使用するべきですか?

概要

この質問に対する david4dev の回答では、json ライブラリを使用してオブジェクトを JSON 文字列に変換する同等の方法が 3 つあると主張しています。

JSON.dump(object)
JSON.generate(object)
object.to_json

そして、JSON 文字列をオブジェクトに変換する 2 つの同等の方法があります。

JSON.load(string)
JSON.parse(string)

しかし、ソースコードを見ると、それぞれはかなり異なっているように見え、それらの間にはいくつかの違いがあります(例:1)。

それらの違いは何ですか?いつどれを使うべきですか?

解決策

TL;DR:

一般的に:

一部の特殊な使用例では、ダンプまたはロードが必要になる場合がありますが、自分で作成したものではないデータにロードを使用するのは安全ではありません。

詳しい説明:

JSON::dump と JSON::generate

JSON::generate では、引数の署名の一部として、インデント レベルや空白の詳細などのオプションを設定できます。一方、JSON::dump は、事前に設定された特定のオプションを使用してその内部で ::generate を呼び出すため、それらを自分で設定することができなくなります。

ドキュメントによると、JSON::dump は Marshal::dump 実装スキームの一部であることを意図しています。 ::dump を自分で明示的に使用する主な理由は、::dump を使用すると IO のようなオブジェクトを 2 番目の引数として渡すことができるため、JSON データを (たとえばソケット経由で) ストリーミングしようとしていることです。 。残念ながら、生成される JSON データは、実際には生成時にストリーミングされません。これは一括して作成され、JSON が完全に作成された場合にのみ送信されます。このため、IO 引数を持つことは些細な場合にのみ役立ちます。

2 つの最後の違いは、::dump は、特定のネストの深さを超えたときに ArgumentError を発生させる制限引数を取ることもできることです。

#to_json との比較

#to_json はオプションを引数として受け入れるため、JSON::generate(foo, opts) と foo.to_json(opts) はほぼ同等です。内部実装が異なるため、驚くべき効果が生じる可能性があります (コメントを参照)。

JSON::load と JSON::parse

::dump が内部で ::generate を呼び出すのと同様に、::load は内部で ::parse を呼び出します。 ::load は、::dump と同様に IO オブジェクトを受け取ることもありますが、やはりソースは一度にすべて読み取られるため、ストリーミングは些細なケースに限定されます。ただし、::dump/::generate の二重性とは異なり、::load と ::parse は両方とも引数署名の一部としてオプションを受け入れます。

::load には proc を渡すこともでき、この proc はデータから解析されたすべての Ruby オブジェクトで呼び出されます。また、::load は信頼できるデータでのみ使用する必要があるという警告も付いています。 ::parse にはそのような制限がないため、ユーザー入力や、内容が不明なファイルやストリームなどの信頼できないデータ ソースを解析するには、JSON::parse が正しい選択です。