Getting `TypeError: wrong argument type JSON::Pure::Generator::State (expected Data)` from json/pure when dumping a hash after loading json/ext
Given json_pure_bug.rb:
require 'json/ext'
require 'json/pure'
hash = { "a" => 7, "nested" => { "hash" => [1, 2, 3] }}
JSON.dump(hash)
When I run it:
➜ ruby --version
ruby 1.9.3p448 (2013-06-27 revision 41675) [x86_64-darwin12.4.0]
➜ ruby json_pure_bug.rb
/Users/myron/code/vcr/bundle/ruby/1.9.1/gems/json-1.8.0/lib/json/pure/generator.rb:366:in `to_json': wrong argument type JSON::Pure::Generator::State (expected Data) (TypeError)
from /Users/myron/code/vcr/bundle/ruby/1.9.1/gems/json-1.8.0/lib/json/pure/generator.rb:366:in `block in json_transform'
from /Users/myron/code/vcr/bundle/ruby/1.9.1/gems/json-1.8.0/lib/json/pure/generator.rb:359:in `each'
from /Users/myron/code/vcr/bundle/ruby/1.9.1/gems/json-1.8.0/lib/json/pure/generator.rb:359:in `json_transform'
from /Users/myron/code/vcr/bundle/ruby/1.9.1/gems/json-1.8.0/lib/json/pure/generator.rb:341:in `to_json'
from /Users/myron/code/vcr/bundle/ruby/1.9.1/gems/json-1.8.0/lib/json/pure/generator.rb:293:in `generate'
from /Users/myron/code/vcr/bundle/ruby/1.9.1/gems/json-1.8.0/lib/json/common.rb:223:in `generate'
from /Users/myron/code/vcr/bundle/ruby/1.9.1/gems/json-1.8.0/lib/json/common.rb:394:in `dump'
from json_pure_bug.rb:5:in `<main>'
Note that when I comment out the json/ext require, the problem goes away.
Obviously, it's not recommended to load both json/ext and json/pure; however, for VCR's test suite, as part of testing its multi_json integration, I iterate through a set of multi_json's adapters (including both :json_gem and :json_pure), set MultiJson.engine to it, and run a test against that adapter. As a result, json/ext and json/pure both get loaded in the same process, and this error occurs.
Unfortunately in Ruby Mixins cannot be unincluded, so I cannot avoid this error. Maybe using refinements can be used as an alternative approach. I remember trying this once, but there were still some problems I encountered.
It works if you reverse the require order, though:
require 'json/pure'
require 'json/ext'
hash = { "a" => 7, "nested" => { "hash" => [1, 2, 3] }}
JSON.dump(hash)
Also, I totally understand about this not being a use case you want to support. That's fine. But maybe your library could detect that json/ext has been loaded, and, if so, make json/pure be a no-op that prints a warning like:
WARNING: Ignoring require of `json/pure` since `json/ext` has already been successfully loaded and both cannot be active at the same time.