Consider the following scenario, I have quite a few big hashes that I need to put in an array and then convert it to json:
hash1 = { ... big hash ... }
hash2 = { ... big hash ... }
hash3 = { ... big hash ... }
array = [hash1, hash2, hash3]
json = JSON.dump(array)
The problem is that generating json from those hashes takes a long time, so I would like to cache it. However, I can't cache the whole array, only separate items. Obviously putting cached json string in array gives bad results:
hash1 = {:a => 1}
hash1json = JSON.dump(hash1)
array = [hash1json]
JSON.generate(array)
==> ["{\"a\":1}"]
while I need
==> [{"a":1}]
The only way I can think of is doing something like this:
"[#{[hash1json].join(",")}]"
==> [{"a":1}]
which might be enough for this specific case, but it will be much harder if one wanted to cache some deep structure instead of simple array.
Turns out this is actually dead simple:
class CachedJson
def initialize(str)
@str = str
end
def to_json
@str
end
end
puts Yajl::Encoder.encode(:data => [{:a => 1}, '{"b":2}'])
# => {"data":[{"a":1},"{\"b\":2}"]}
puts Yajl::Encoder.encode(:data => [{:a => 1}, CachedJson.new('{"b":2}')])
# => {"data":[{"a":1},{"b":2}]}
Under the hood yajl calls to_json
on every object, and this method must return string, so it's just a matter of wrapping cached json string with CachedJson
object