diff options
-rw-r--r-- | CHANGELOG.md | 3 | ||||
-rw-r--r-- | ext/ffi_yajl/ext/encoder/encoder.c | 20 | ||||
-rw-r--r-- | lib/ffi_yajl/ffi/encoder.rb | 11 | ||||
-rw-r--r-- | spec/ffi_yajl/encoder_spec.rb | 17 |
4 files changed, 42 insertions, 9 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 59eb314..651c40c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ ### Changes +* Encoding Object will no longer blindly call .to_json(). It will first check if the Object supports a .to_json() method +and if it does not it will call .to_s(). This prevents NoSuchMethod errors when not using the JSON gem. + ### Bugs fixed * Change Config to RbConfig for FFI-based dlopen for non-DL/non-Fiddle fallback. diff --git a/ext/ffi_yajl/ext/encoder/encoder.c b/ext/ffi_yajl/ext/encoder/encoder.c index 0c917cb..90b125b 100644 --- a/ext/ffi_yajl/ext/encoder/encoder.c +++ b/ext/ffi_yajl/ext/encoder/encoder.c @@ -272,14 +272,20 @@ static VALUE rb_cObject_ffi_yajl(VALUE self, VALUE rb_yajl_gen, VALUE state) { yajl_gen_status status; ID sym_to_json = rb_intern("to_json"); VALUE str; - VALUE json_opts = rb_hash_aref(state, rb_str_new2("json_opts")); - struct yajl_gen_t *yajl_gen; - Data_Get_Struct(rb_yajl_gen, struct yajl_gen_t, yajl_gen); - str = rb_funcall(self, sym_to_json, 1, json_opts); - CHECK_STATUS( - yajl_gen_number(yajl_gen, (char *)RSTRING_PTR(str), RSTRING_LEN(str)) - ); + if ( rb_respond_to(self, sym_to_json) ) { + VALUE json_opts = rb_hash_aref(state, rb_str_new2("json_opts")); + struct yajl_gen_t *yajl_gen; + Data_Get_Struct(rb_yajl_gen, struct yajl_gen_t, yajl_gen); + + str = rb_funcall(self, sym_to_json, 1, json_opts); + CHECK_STATUS( + yajl_gen_number(yajl_gen, (char *)RSTRING_PTR(str), RSTRING_LEN(str)) + ); + } else { + object_to_s_ffi_yajl(self, rb_yajl_gen, state); + } + return Qnil; } diff --git a/lib/ffi_yajl/ffi/encoder.rb b/lib/ffi_yajl/ffi/encoder.rb index 3df366c..8177f5f 100644 --- a/lib/ffi_yajl/ffi/encoder.rb +++ b/lib/ffi_yajl/ffi/encoder.rb @@ -201,8 +201,15 @@ end # I feel dirty class Object def ffi_yajl(yajl_gen, state) - json = self.to_json(state[:json_opts]) - if ( status = FFI_Yajl.yajl_gen_number(yajl_gen, json, json.bytesize) ) != 0 + if self.respond_to?(:to_json) + json = self.to_json(state[:json_opts]) + # #yajl_gen_number outputs a string without quotes around it + status = FFI_Yajl.yajl_gen_number(yajl_gen, json, json.bytesize) + else + str = self.to_s + status = FFI_Yajl.yajl_gen_string(yajl_gen, str, str.bytesize) + end + if ( status ) != 0 FFI_Yajl::Encoder.raise_error_for_status(status) end end diff --git a/spec/ffi_yajl/encoder_spec.rb b/spec/ffi_yajl/encoder_spec.rb index f658d95..02bc020 100644 --- a/spec/ffi_yajl/encoder_spec.rb +++ b/spec/ffi_yajl/encoder_spec.rb @@ -87,4 +87,21 @@ describe "FFI_Yajl::Encoder" do expect(encoder.encode(ruby)).to eq( %q{"2001-02-03T04:05:06+07:00"} ) end + describe "testing .to_json for Objects" do + class NoToJson; end + class HasToJson + def to_json(*args) + "{}" + end + end + + it "calls .to_s for objects without .to_json" do + expect(encoder.encode(NoToJson.new)).to match(/^"#<NoToJson:\w+>"$/) + end + + it "calls .to_json for objects wit .to_json" do + expect(encoder.encode(HasToJson.new)).to eq("{}") + end + end + end |