猫の魔法

主にruby系の技術メモを記載

JSON.loadはオプションが取れる

先日の記事の中でJSON.loadのgithubの実装を紹介した。

Rubyの公式ドキュメント(以下るりま)JSON.loadの説明githubのコードを眺めていてあれ?るりまの説明と実装が違う。。。と言う事に気がついた。

るりま側のloadの定義は以下の通り

load(source, proc = nil) -> object

github側のloadの定義は以下の通りで、最後にオプションを取るかどうかがるりま側の物と異なる。

def load(source, proc = nil, options = {})

実際に試してみると、procの後ろにparseで指定出来るオプションをハッシュで渡すとちゃんと動く。

hoge1.json
{"color":{"red":1,"blue":2,"green":NaN}}
hoge.rb
require 'json'

File.open("hoge1.json") do |f|
   p JSON.load(f,nil,{ :symbolize_names=>true })
end
=> {:color=>{:red=>1, :blue=>2, :green=>NaN}}

これ、今まで「loadはoptionが渡せないからfileをreadしてからparseを使おう」と考えていた人も結構いるだろうなと思う。

なお、もっというとJSON.loadはload_default_optionsというインスタンス変数をメソッド内でデフォルトオプションとして定義していて、 下記のようなオプションが事前に設定されている。

require 'json'

p JSON.load_default_options
=> {:max_nesting=>false, :allow_nan=>true, :quirks_mode=>true, :create_additions=>true}

このload_default_optionsはatter_accessorとして定義されており、 外から設定を変更する事が出来る。

要するに、loadにオプションを指定する方法は、loadの第3引数に値を与える方法と、 load_default_optionsに値をセットする方法の2通りがあるという事になる。

自分は前者は一時的に指定するオプションを、 後者はアプリケーション全体で指定するオプションを設定するようなイメージかと勝手に解釈してる。

ところでこのJSON.#load、ソース上に以下の記述がある。

  # BEWARE: This method is meant to serialise data from trusted user input,
  # like from your own database server or clients under your control, it could
  # be dangerous to allow untrusted users to pass JSON sources into it. The
  # default options for the parser can be changed via the load_default_options
  # method.

詰まる所、このメソッドは与えられるJSONが必ず信頼出来る物でなければいけないという制約があるようで、 実装上はparseの方を使う方が安全なようだ*1

上記の制約は恐らく :create_additionsがデフォルトでtrueな事が原因だと思うが、それなら今回の方式でfalseに出来そうな気もする。正直よく分からないので、知っている人いたら教えて下さい。。。

とりあえず、loadの記載については以下の記事参考にして、るりまに修正のプルリクエストを 投げてみた

http://qiita.com/tbpgr/items/2072a9a743918b8cfb34

※何か更新しない理由があって、直さなくていい物だったら恥ずかしいけど。。。これも勉強ですな。

※2017/2/11追記 mergeして頂きました。