環境
* MacBook Air MC506J/A
* ruby 1.8.7 (2010-08-16 patchlevel 302) [i686-darwin10]

MacBook Air にて RubyGems を使って JSON ライブラリをインストール。


$ sudo gem install json
Successfully installed json-1.5.0

インストールされたライブラリはこれ ⇒ JSON implementation for Ruby

Ruby 1.9系には標準添付ライブラリとしてこのJSONライブラリが付いてくるらしく、日本語に訳されたドキュメントがある。
Ruby 1.9.2 リファレンスマニュアル ⇒ library json

で、どんなデータを渡せばいいのか使い方がよくわからなかったのでJSON文字列を生成するサンプル的なコードを書いてみた。


$ cat ./jsonsample.rb 
#!/usr/bin/env ruby
 
require 'rubygems'
require 'json'
 
def output(json_data)
  json_str_1 = JSON.generate(json_data)
  json_str_2 = JSON.pretty_generate(json_data)
  print json_str_1
  print "\n"
  print json_str_2
  print "\n"
end
 
data1 = {
  :a => 'xyz',
  :b => 123,
  :c => {:d => 'xxyyzz', :e => 456},
  :f => [1,2,3,5,8,13]
}
output data1
 
data2 = Hash.new
data2["A"] = 'LMN'
data2["B"] = 789
data2["C"] = {"D" => 'XXYYZZ', "E" => 987}
data2["F"] = [1,2,3,5,7,11,13]
output data2
 
data3 = {}
data3["info"] = {
  "count" => 3,
  "query" => 'hoge'
}
data3a = Array.new
data3a[0] = {
  "id" => 1,
  "name" => "Alice"
} 
data3a[1] = {
  "id" => 2,
  "name" => "Bob"
} 
data3a[2] = {
  "id" => 3,
  "name" => "Carol"
} 
data3["entry"] = data3a
output data3

JSON.generate はサイズが小さめの1行でのJSON形式の文字列に変換してくれる。
JSON.pretty_generate だと複数行に渡る読みやすいJSON形式の文字列に変換してくれる。

プログラムの実行結果がこれ。


$ ruby ./jsonsample.rb 
{"f":[1,2,3,5,8,13],"a":"xyz","b":123,"c":{"d":"xxyyzz","e":456}}
{
  "f": [
    1,
    2,
    3,
    5,
    8,
    13
  ],
  "a": "xyz",
  "b": 123,
  "c": {
    "d": "xxyyzz",
    "e": 456
  }
}
{"A":"LMN","B":789,"C":{"D":"XXYYZZ","E":987},"F":[1,2,3,5,7,11,13]}
{
  "A": "LMN",
  "B": 789,
  "C": {
    "D": "XXYYZZ",
    "E": 987
  },
  "F": [
    1,
    2,
    3,
    5,
    7,
    11,
    13
  ]
}
{"info":{"count":3,"query":"hoge"},"entry":[{"name":"Alice","id":1},{"name":"Bob","id":2},{"name":"Carol","id":3}]}
{
  "info": {
    "count": 3,
    "query": "hoge"
  },
  "entry": [
    {
      "name": "Alice",
      "id": 1
    },
    {
      "name": "Bob",
      "id": 2
    },
    {
      "name": "Carol",
      "id": 3
    }
  ]
}

HashじゃないオブジェクトをHashのように使ってみたい。

オブジェクトの Hash への暗黙の変換が必要なときに内部で呼ばれます。デフォルトでは定義されていません。

説明のためここに記載してありますが、このメソッドは実際には Object クラスには定義されていません。必要に応じてサブクラスで定義すべきものです。

このメソッドを定義する条件は、

* ハッシュが使われるすべての場面で代置可能であるような、
* ハッシュそのものとみなせるようなもの

という厳しいものになっています。

instance method Object#to_hash (Ruby 1.8.6 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Objectクラス > to_hash)

そこで以下のような ToHashImplSmpl クラスを書いてみたけど、JSONライブラリでは to_hash を見てくれないみたい。
じゃあ、ToHashImplSmpl2 って Hash を継承したクラスに to_hash を実装してみたけど、これだとサブクラスの to_hash ではなくスーパークラスの Hash のほうの to_hash を使うみたい。


$ cat ./jsonsample2.rb 
#!/usr/bin/env ruby
 
require 'rubygems'
require 'json'
 
def output(json_data)
  json_str_1 = JSON.generate(json_data)
  json_str_2 = JSON.pretty_generate(json_data)
  print json_str_1
  print "\n"
  print json_str_2
  print "\n"
end
 
class ToHashImplSmpl
  def to_hash
    { "a" => "A", "b" => 123}
  end
end
 
class ToHashImplSmpl2 < Hash
  def to_hash
    { "a" => "A", "b" => 123}
  end
end
 
data1 = {
  "c" => "xyz",
  "ToHashImplSmpl.new" => ToHashImplSmpl.new,
  "ToHashImplSmpl.new.to_hash" => ToHashImplSmpl.new.to_hash,
  "ToHashImplSmpl2.new" => ToHashImplSmpl2.new,
  "ToHashImplSmpl2.new.to_hash" => ToHashImplSmpl2.new.to_hash
}
output data1
 
# test for to_hash 
p({"test" => "ToHashImplSmpl.new"}.merge(ToHashImplSmpl.new))
p({"test" => "ToHashImplSmpl.new.to_hash"}.merge(ToHashImplSmpl.new.to_hash))
p({"test" => "ToHashImplSmpl2.new"}.merge(ToHashImplSmpl2.new))
p({"test" => "ToHashImplSmpl2.new.to_hash"}.merge(ToHashImplSmpl2.new.to_hash))

実行結果は以下。撃沈。


$ ruby ./jsonsample2.rb
{"ToHashImplSmpl2.new.to_hash":{"a":"A","b":123},"ToHashImplSmpl.new.to_hash":{"a":"A","b":123},"c":"xyz","ToHashImplSmpl.new":"#<ToHashImplSmpl:0x100631630>","ToHashImplSmpl2.new":{}}
{
  "ToHashImplSmpl2.new.to_hash": {
    "a": "A",
    "b": 123
  },
  "ToHashImplSmpl.new.to_hash": {
    "a": "A",
    "b": 123
  },
  "c": "xyz",
  "ToHashImplSmpl.new": "#<ToHashImplSmpl:0x100631630>",
  "ToHashImplSmpl2.new": {
  }
}
{"a"=>"A", "b"=>123, "test"=>"ToHashImplSmpl.new"}
{"a"=>"A", "b"=>123, "test"=>"ToHashImplSmpl.new.to_hash"}
{"test"=>"ToHashImplSmpl2.new"}
{"a"=>"A", "b"=>123, "test"=>"ToHashImplSmpl2.new.to_hash"}

tags: Ruby JSON zurazure

Posted by NI-Lab. (@nilab)