brianmario/yajl-ruby — Issue #96: Allow encoding of already encoded JSON strings..
Author: pkieltyka
Created: 2012-02-14 21:24:26+00:00
State: open

Imagine you have a string, that already has JSON.. but you'd like to wrap that JSON object in an array with others. You may have gotten that JSON object from a cache, or maybe its a Javascript function in a string (like a Handlebars pre-compiled template). It would be nice to effectively "join" JSON objects during encoding. This is a nice optimization, and also convenient. Below is an example and idea on how to implement this.

```ruby
# One idea to implement this is....

# Get an array of json-encoded strings with ids 1, 2, 3, and 4
x = JsonCache.get([1,2,3,4]).map {|o| Yajl::JsonString.new(o) }

# x[0] = "{ id: 1, name: John}"
# x[1] = "{ id: 2, name: Peter}"
# x[2] = "{ id: 3, name: Mike}"
# x[3] = "{ id: 4, name: Allan}"

json = Yajl::Encoder.encode(x)

# json should look like:
# "[{ id: 1, name: John}, { id: 2, name: Peter}, { id: 3, name: Mike}, { id: 4, name: Allan}]"

# currently Yajl will encode each string and instead will return:
# "[\"{ id: 1, name: John}\", \"{ id: 2, name: Peter}\", \"{ id: 3, name: Mike}\", \"{ id: 4, name: Allan}\"]"
```

Of course you could just decode each object in x, put it in an array, and then re-encode. Fine. But thats unnecessary, and here's a better example that can't be achieved unless the encoder understands strings as native JSON types to just concatenate them to the result.

```ruby
# Pseudo class..
compiled_template = HandlebarsCompiler.compile("hi {{var}}")

# x
# => "function (Handlebars,depth0,helpers,partials,data) {\n helpers = helpers || Handlebars.helpers;\n var buffer = \"\", stack1, foundHelper, self=this, functionType=\"function\", helperMissing=helpers.helperMissing, undef=void 0, escapeExpression=this.escapeExpression;\n\n\n buffer += \"hi \";\n foundHelper = helpers['var'];\n stack1 = foundHelper || depth0['var'];\n if(typeof stack1 === functionType) { stack1 = stack1.call(depth0, { hash: {} }); }\n else if(stack1=== undef) { stack1 = helperMissing.call(depth0, \"var\", { hash: {} }); }\n buffer += escapeExpression(stack1);\n return buffer;}"

template = {
:name => Yajl::JsonString.new(compiled_template)
}

puts Yajl::Encoder.encode(template)

# The idea is the encoder would return: "{ name: function (Handlebars,depth0,helpers,partials,data) { ..etc. etc. } }"

Now, when parsed by the browser, it doesn't have the eval() the function.
```

I just came up with the Yajl::JsonString class, which would inherit from a String, and add a method called "is_json" set to true. This way when the encoder is traversing strings, it can test for is_json, and just concatenate instead of encode.

What do you think?