diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | ext/ffi_yajl/ext/encoder/encoder.c | 42 | ||||
-rw-r--r-- | lib/ffi_yajl.rb | 33 | ||||
-rw-r--r-- | lib/ffi_yajl/ffi/encoder.rb | 20 |
4 files changed, 81 insertions, 18 deletions
@@ -1,6 +1,8 @@ *.gem *.rake_tasks~ *.rbc +*.so +*.bundle *.swo *.swp */tags @@ -20,10 +22,10 @@ doc doc/ erl_crash.dump lib/bundler/man +mkmf.log pkg rdoc spec/reports test/tmp test/version_tmp tmp -mkmf.log diff --git a/ext/ffi_yajl/ext/encoder/encoder.c b/ext/ffi_yajl/ext/encoder/encoder.c index 0687f51..ade2199 100644 --- a/ext/ffi_yajl/ext/encoder/encoder.c +++ b/ext/ffi_yajl/ext/encoder/encoder.c @@ -10,18 +10,33 @@ typedef struct { int processing_key; } ffi_state_t; -static VALUE mEncoder_encode(VALUE self, VALUE obj) { +static VALUE mEncoder_do_yajl_encode(VALUE self, VALUE obj, VALUE yajl_gen_opts) { ID sym_ffi_yajl = rb_intern("ffi_yajl"); + VALUE sym_yajl_gen_beautify = ID2SYM(rb_intern("yajl_gen_beautify")); + VALUE sym_yajl_gen_validate_utf8 = ID2SYM(rb_intern("yajl_gen_validate_utf8")); + VALUE sym_yajl_gen_indent_string = ID2SYM(rb_intern("yajl_gen_indent_string")); yajl_gen yajl_gen; const unsigned char *buf; size_t len; ffi_state_t state; VALUE ret; + VALUE indent_string; yajl_gen = yajl_gen_alloc(NULL); - yajl_gen_config(yajl_gen, yajl_gen_beautify, 1); - yajl_gen_config(yajl_gen, yajl_gen_validate_utf8, 1); + if ( rb_hash_aref(yajl_gen_opts, sym_yajl_gen_beautify) == Qtrue ) { + yajl_gen_config(yajl_gen, yajl_gen_beautify, 1); + } + if ( rb_hash_aref(yajl_gen_opts, sym_yajl_gen_validate_utf8) == Qtrue ) { + yajl_gen_config(yajl_gen, yajl_gen_validate_utf8, 1); + } + + indent_string = rb_hash_aref(yajl_gen_opts, sym_yajl_gen_indent_string); + if (indent_string != Qnil) { + yajl_gen_config(yajl_gen, yajl_gen_indent_string, RSTRING_PTR(indent_string)); + } else { + yajl_gen_config(yajl_gen, yajl_gen_indent_string, " "); + } state.processing_key = 0; @@ -97,10 +112,11 @@ static VALUE rb_cFalseClass_ffi_yajl(VALUE self, VALUE yajl_gen, VALUE state) { } static VALUE rb_cFixnum_ffi_yajl(VALUE self, VALUE yajl_gen, VALUE state) { + ID sym_to_s = rb_intern("to_s"); VALUE str; if ( ((ffi_state_t *)state)->processing_key ) { - str = rb_any_to_s(self); + str = rb_funcall(self, sym_to_s, 0); yajl_gen_string((struct yajl_gen_t *) yajl_gen, (unsigned char *)RSTRING_PTR(str), RSTRING_LEN(str)); } else { yajl_gen_integer((struct yajl_gen_t *) yajl_gen, NUM2INT(self)); @@ -123,8 +139,20 @@ static VALUE rb_cString_ffi_yajl(VALUE self, VALUE yajl_gen, VALUE state) { return Qnil; } +// FIXME: args is a splat/varargs, does it matter? and what about the block? +static VALUE rb_cObject_to_json(VALUE self, VALUE args) { + // FIXME: need to wrap quotes around this + VALUE str; + str = rb_any_to_s(self); + return str; +} + static VALUE rb_cObject_ffi_yajl(VALUE self, VALUE yajl_gen, VALUE state) { - rb_raise( rb_eNotImpError, "Object#ffi_yajl not implemented"); + ID sym_to_json = rb_intern("to_json"); + VALUE str; + + str = rb_funcall(self, sym_to_json, 1, ((ffi_state_t *)state)->json_opts); + yajl_gen_number((struct yajl_gen_t *) yajl_gen, (char *)RSTRING_PTR(str), RSTRING_LEN(str)); return Qnil; } @@ -132,7 +160,7 @@ void Init_encoder() { mFFI_Yajl = rb_define_module("FFI_Yajl"); mExt = rb_define_module_under(mFFI_Yajl, "Ext"); mEncoder = rb_define_module_under(mExt, "Encoder"); - rb_define_method(mEncoder, "encode", mEncoder_encode, 1); + rb_define_method(mEncoder, "do_yajl_encode", mEncoder_do_yajl_encode, 2); rb_define_method(rb_cHash, "ffi_yajl", rb_cHash_ffi_yajl, 2); rb_define_method(rb_cArray, "ffi_yajl", rb_cArray_ffi_yajl, 2); @@ -143,6 +171,8 @@ void Init_encoder() { rb_define_method(rb_cBignum, "ffi_yajl", rb_cBignum_ffi_yajl, 2); rb_define_method(rb_cFloat, "ffi_yajl", rb_cFloat_ffi_yajl, 2); rb_define_method(rb_cString, "ffi_yajl", rb_cString_ffi_yajl, 2); +// FIXME: make this conditional on ActiveSupport not being defined: + rb_define_method(rb_cObject, "to_json", rb_cObject_to_json, 1); rb_define_method(rb_cObject, "ffi_yajl", rb_cObject_ffi_yajl, 2); } diff --git a/lib/ffi_yajl.rb b/lib/ffi_yajl.rb index 1a38079..40c26e4 100644 --- a/lib/ffi_yajl.rb +++ b/lib/ffi_yajl.rb @@ -5,6 +5,23 @@ module FFI_Yajl class Encoder attr_accessor :opts + def encode(obj) + # initialization that we can do in pure ruby + yajl_gen_opts = {} + + yajl_gen_opts[:yajl_gen_validate_utf8] = true + yajl_gen_opts[:yajl_gen_beautify] = false + yajl_gen_opts[:yajl_gen_indent_string] = " " + + if opts[:pretty] + yajl_gen_opts[:yajl_gen_beautify] = true + yajl_gen_opts[:yajl_gen_indent_string] = opts[:indent] ? opts[:indent] : " " + end + + # call either the ext or ffi hook + do_yajl_encode(obj, yajl_gen_opts) + end + def self.encode(obj, *args) new(*args).encode(obj) end @@ -13,12 +30,24 @@ module FFI_Yajl @opts = opts end - begin + if ENV['FORCE_FFI_YAJL'] == "ext" require 'ffi_yajl/ext' include FFI_Yajl::Ext::Encoder - rescue LoadError + elsif ENV['FORCE_FFI_YAJL'] == "ffi" + require 'ffi_yajl/ffi' + include FFI_Yajl::FFI::Encoder + elsif defined?(Yajl) + # on Linux yajl-ruby and non-FFI ffi_yajl conflict require 'ffi_yajl/ffi' include FFI_Yajl::FFI::Encoder + else + begin + require 'ffi_yajl/ext' + include FFI_Yajl::Ext::Encoder + rescue LoadError + require 'ffi_yajl/ffi' + include FFI_Yajl::FFI::Encoder + end end end end diff --git a/lib/ffi_yajl/ffi/encoder.rb b/lib/ffi_yajl/ffi/encoder.rb index 7798f8d..42725b0 100644 --- a/lib/ffi_yajl/ffi/encoder.rb +++ b/lib/ffi_yajl/ffi/encoder.rb @@ -5,17 +5,18 @@ require 'ffi' module FFI_Yajl module FFI module Encoder - def encode(obj) + def do_yajl_encode(obj, yajl_gen_opts = {}) + yajl_gen = FFI_Yajl.yajl_gen_alloc(nil); # configure the yajl encoder - FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_beautify, :int, 1) if opts[:pretty] - FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_validate_utf8, :int, 1) - indent = if opts[:pretty] - opts[:indent] ? opts[:indent] : " " - else - " " - end + if yajl_gen_opts[:yajl_gen_beautify] + FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_beautify, :int, 1) + end + if yajl_gen_opts[:yajl_gen_validate_utf8] + FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_validate_utf8, :int, 1) + end + indent = yajl_gen_opts[:yajl_gen_indent_string] || " " FFI_Yajl.yajl_gen_config(yajl_gen, :yajl_gen_indent_string, :string, indent) # setup our own state @@ -97,7 +98,8 @@ end class Bignum def ffi_yajl(yajl_gen, state) - raise NotImpelementedError + str = self.to_s + FFI_Yajl.yajl_gen_number(yajl_gen, str, str.length) end end |