Deserialize JSON primitives with the built-in Ruby JSON library

RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) has this to say:

2.  JSON Grammar

   A JSON text is a sequence of tokens.  The set of tokens includes six
   structural characters, strings, numbers, and three literal names.

   A JSON text is a serialized object or array.

      JSON-text = object / array

[...]

2.1.  Values

   A JSON value MUST be an object, array, number, or string, or one of
   the following three literal names:

      false null true

If you call to_json on your six sample objects, we get this:

>> objects = [ {}, [], 42, "", true, nil ]
>> objects.map { |o| puts o.to_json }
{}
[]
42
""
true
null

So the first and second are valid JSON texts whereas the last four are not valid JSON texts even though they are valid JSON values.

JSON.parse wants what it calls a JSON document:

Parse the JSON document source into a Ruby data structure and return it.

Perhaps JSON document is the library's term for what RFC 4627 calls a JSON text. If so, then raising an exception is a reasonable response to an invalid input.

If you forcibly wrap and unwrap everything:

objects.each do |o|
    json = o.to_json 
    begin
        json_text = '[' + json + ']'
        p JSON.parse(json_text)[0]
    rescue Exception => e 
        puts "Error parsing #{json.inspect}: #{e}"    
    end    
end

And as you note in your comment, using an array as the wrapper is better than an object in case the caller wants to use the :symbolize_names option. Wrapping like this means that you'll always be feeding JSON.parse a JSON text and everything should be fine.


This is quite an old question but I think it worths to have a proper answer to prevent hair loss for the ones who just encountered with the problem and still searching for a solution :)

To be able to parse "JSON primitives" with JSON gem below version 2, you can pass quirks_mode: true option like so;

JSON::VERSION # => 1.8.6

json_text = "This is a json primitive".to_json
JSON.parse(json_text, quirks_mode: true)

With the JSON gem version greater or equals to 2, the quirks_mode is not necessary anymore.

JSON::VERSION # => 2.0.0

json_text = "This is a json primitive".to_json
JSON.parse(json_text)

Before parsing the JSON, you can check the version of the JSON gem that you are using in your project with bundle show json or gem list | grep json and then use the corresponding one.

Happy JSON parsing!

Tags:

Ruby

Json