扩展to_json以获取Hash的子类

时间:2013-01-25 22:12:18

标签: ruby json

我有一个Hash的子类,它添加了一个新的字段f。我希望JSON能够序列化和反序列化f以及散列本身的内容,但是还没弄清楚如何做到这一点:

Class ExtendedHash < Hash
  attr_accessor :f
end

当然,正如所写,ExtendedHash#to_json不保留f字段:

>> c = ExtendedHash[{:a => 1, :b => 2}]
=> {:a=>1, :b=>2}
>> c.f = 123
=> 123
>> c.to_json
=> "{\"a\":1,\"b\":2}"

那么正确的定义是什么:

  def to_json(*a)
    ...
  end
  def self.load_from_json(str)
    ...
  end
end

? (我看过'How can I use Ruby's to_json in a subclass and include super's json?',但这似乎不是正确的做法。)

2 个答案:

答案 0 :(得分:1)

你可以这样做:

class ExtendedHash < Hash
  attr_accessor :f

  def to_json(*args)
    Hash[self].merge(:f => f).to_json(*args)
  end
end

答案 1 :(得分:0)

以下是正确的事情:

require 'json'

class ExtendedHash<Hash
  attr_accessor :f

  def to_json(*a)
    {
      'json_class' => self.class.name,
      'f' => f,
      'super' => super
    }.to_json(*a)
  end

  def self.json_create(s)
    self[JSON.load(s["super"])].tap {|o| o.f = s["f"]}
  end

end

它的工作原理如下:

> x = ExtendedHash["a", 1, "b", 2]
=> {"a"=>1, "b"=>2}
> x.f = 123
=> 123
> s = x.to_json
=> "{\"json_class\":\"ExtendedHash\",\"f\":123,\"super\":\"{\\\"a\\\":1,\\\"b\\\":2}\"}"
> y = JSON.load(s)
=> {"a"=>1, "b"=>2}
> y.f
=> 123

唯一令人不解的是底层哈希是“双重json”,即转换为JSON字符串,然后再次运行JSON。这会创建许多额外的转义字符,并且需要在JSON.load方法中显式调用json_create()

我可以忍受,但也许有更好的方法。