Skip to content

Commit

Permalink
added support for create_id in Oj and in mimic_JSON mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Ohler committed Apr 18, 2012
1 parent 4477f09 commit c2287f1
Show file tree
Hide file tree
Showing 8 changed files with 73 additions and 12 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -24,9 +24,9 @@ A fast JSON parser and Object marshaller as a Ruby gem.

## <a name="release">Release Notes</a>

### Release 1.2.4
### Release 1.2.5

- Removed all use of math.h to get around CentOS 5.4 compile problem.
- Added support for create_id in Oj and in mimic_JSON mode

## <a name="description">Description</a>

Expand Down
4 changes: 2 additions & 2 deletions ext/oj/load.c
Expand Up @@ -475,8 +475,8 @@ read_obj(ParseInfo pi) {
rb_hash_aset(obj, key, val);
}
if ((CompatMode == mode || ObjectMode == mode) &&
0 == json_class_name &&
0 != ks && 'j' == *ks && 0 == strcmp("json_class", ks) &&
0 == json_class_name && 0 != ks &&
0 != pi->options->create_id && *pi->options->create_id == *ks && 0 == strcmp(pi->options->create_id, ks) &&
T_STRING == rb_type(val)) {
json_class_name = StringValuePtr(val);
}
Expand Down
48 changes: 47 additions & 1 deletion ext/oj/oj.c
Expand Up @@ -77,6 +77,7 @@ static VALUE ascii_only_sym;
static VALUE auto_define_sym;
static VALUE circular_sym;
static VALUE compat_sym;
static VALUE create_id_sym;
static VALUE indent_sym;
static VALUE mode_sym;
static VALUE null_sym;
Expand All @@ -101,13 +102,16 @@ Cache oj_attr_cache = 0;
rb_encoding *oj_utf8_encoding = 0;
#endif

static const char json_class[] = "json_class";

struct _Options oj_default_options = {
0, // indent
No, // circular
Yes, // auto_define
No, // sym_key
No, // ascii_only
ObjectMode, // mode
json_class, // create_id
0, // dump_opts
};

Expand All @@ -121,6 +125,7 @@ static VALUE define_mimic_json(VALUE self);
* - auto_define: [true|false|nil] automatically define classes if they do not exist
* - symbol_keys: [true|false|nil] use symbols instead of strings for hash keys
* - mode: [:object|:strict|:compat|:null] load and dump modes to use for JSON
* - create_id: [String|nil] create id for json compatible object encoding, default is 'json_create'
* @return [Hash] all current option settings.
*/
static VALUE
Expand All @@ -139,6 +144,8 @@ get_def_opts(VALUE self) {
case ObjectMode:
default: rb_hash_aset(opts, mode_sym, object_sym); break;
}
rb_hash_aset(opts, create_id_sym, (0 == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));

return opts;
}

Expand All @@ -158,7 +165,9 @@ get_def_opts(VALUE self) {
* variables if neither is found. The :object mode ignores to_hash()
* and to_json() methods and encodes variables using code internal to
* the Oj gem. The :null mode ignores non-supported Objects and
* replaces them with a null. @return [nil]
* replaces them with a null.
* @param [String|nil] :create_id create id for json compatible object encoding
* @return [nil]
*/
static VALUE
set_def_opts(VALUE self, VALUE opts) {
Expand Down Expand Up @@ -194,6 +203,22 @@ set_def_opts(VALUE self, VALUE opts) {
rb_raise(rb_eArgError, ":mode must be :object, :strict, :compat, or :null.\n");
}

if (Qtrue == rb_funcall(opts, rb_intern("has_key?"), 1, create_id_sym)) {
if (0 != oj_default_options.create_id) {
if (json_class != oj_default_options.create_id) {
xfree((char*)oj_default_options.create_id);
}
oj_default_options.create_id = 0;
}
v = rb_hash_lookup(opts, create_id_sym);
if (Qnil != v) {
size_t len = RSTRING_LEN(v) + 1;

oj_default_options.create_id = ALLOC_N(char, len);
strcpy((char*)oj_default_options.create_id, StringValuePtr(v));
}
}

for (o = ynos; 0 != o->attr; o++) {
if (Qtrue != rb_funcall(opts, rb_intern("has_key?"), 1, o->sym)) {
continue;
Expand Down Expand Up @@ -659,6 +684,25 @@ no_op1(VALUE self, VALUE obj) {
return Qnil;
}

static VALUE
mimic_create_id(VALUE self, VALUE id) {
Check_Type(id, T_STRING);

if (0 != oj_default_options.create_id) {
if (json_class != oj_default_options.create_id) {
xfree((char*)oj_default_options.create_id);
}
oj_default_options.create_id = 0;
}
if (Qnil != id) {
size_t len = RSTRING_LEN(id) + 1;

oj_default_options.create_id = ALLOC_N(char, len);
strcpy((char*)oj_default_options.create_id, StringValuePtr(id));
}
return id;
}

/* call-seq: mimic_JSON() => Module
*
* Creates the JSON module with methods and classes to mimic the JSON
Expand All @@ -679,6 +723,7 @@ define_mimic_json(VALUE self) {

rb_define_module_function(mimic, "parser=", no_op1, 1);
rb_define_module_function(mimic, "generator=", no_op1, 1);
rb_define_module_function(mimic, "create_id=", mimic_create_id, 1);

rb_define_module_function(mimic, "dump", mimic_dump, -1);
rb_define_module_function(mimic, "load", mimic_load, -1);
Expand Down Expand Up @@ -745,6 +790,7 @@ void Init_oj() {
auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_ary_push(keep, auto_define_sym);
circular_sym = ID2SYM(rb_intern("circular")); rb_ary_push(keep, circular_sym);
compat_sym = ID2SYM(rb_intern("compat")); rb_ary_push(keep, compat_sym);
create_id_sym = ID2SYM(rb_intern("create_id")); rb_ary_push(keep, create_id_sym);
indent_sym = ID2SYM(rb_intern("indent")); rb_ary_push(keep, indent_sym);
mode_sym = ID2SYM(rb_intern("mode")); rb_ary_push(keep, mode_sym);
symbol_keys_sym = ID2SYM(rb_intern("symbol_keys")); rb_ary_push(keep, symbol_keys_sym);
Expand Down
1 change: 1 addition & 0 deletions ext/oj/oj.h
Expand Up @@ -95,6 +95,7 @@ typedef struct _Options {
char sym_key; // YesNo
char ascii_only; // YesNo
char mode; // Mode
const char *create_id; // 0 or string
DumpOpts dump_opts;
} *Options;

Expand Down
2 changes: 1 addition & 1 deletion lib/oj/version.rb
@@ -1,5 +1,5 @@

module Oj
# Current version of the module.
VERSION = '1.2.4'
VERSION = '1.2.5'
end
2 changes: 0 additions & 2 deletions notes
Expand Up @@ -6,8 +6,6 @@
- next

- support create_id in mimic
- allow nil as well
- add string to options

- optimize read_hex in load.c
- add options for path in fetch
Expand Down
5 changes: 5 additions & 0 deletions test/test_mimic.rb
Expand Up @@ -171,6 +171,11 @@ def test_parse_additions
assert_equal(jam, obj)
obj = JSON.parse(json, :create_additions => false)
assert_equal({'json_class' => 'Jam', 'x' => true, 'y' => 58}, obj)
json.gsub!('json_class', 'kson_class')
JSON.create_id = 'kson_class'
obj = JSON.parse(json, :create_additions => true)
JSON.create_id = 'json_class'
assert_equal(jam, obj)
end
def test_parse_bang
json = %{{"a":1,"b":[true,false]}}
Expand Down
19 changes: 15 additions & 4 deletions test/tests.rb
Expand Up @@ -106,7 +106,8 @@ def test0_get_options
:auto_define=>true,
:symbol_keys=>false,
:ascii_only=>false,
:mode=>:object}, opts)
:mode=>:object,
:create_id=>'json_class'}, opts)
end

def test0_set_options
Expand All @@ -116,18 +117,20 @@ def test0_set_options
:auto_define=>true,
:symbol_keys=>false,
:ascii_only=>false,
:mode=>:object}
:mode=>:object,
:create_id=>'json_class'}
o2 = {
:indent=>4,
:circular=>true,
:auto_define=>false,
:symbol_keys=>true,
:ascii_only=>true,
:mode=>:compat}
:mode=>:compat,
:create_id=>nil}
o3 = { :indent => 4 }
Oj.default_options = o2
opts = Oj.default_options()
assert_equal(opts, o2);
assert_equal(o2, opts);
Oj.default_options = o3 # see if it throws an exception
Oj.default_options = orig # return to original
end
Expand Down Expand Up @@ -339,6 +342,14 @@ def test_json_object_compat
%{{"json_class":"Jeez","y":58,"x":true}} == json)
dump_and_load(obj, false)
end
def test_json_object_create_id
Oj.default_options = { :mode => :compat, :create_id => 'kson_class' }
expected = Jeez.new(true, 58)
json = %{{"kson_class":"Jeez","x":true,"y":58}}
obj = Oj.load(json)
assert_equal(expected, obj)
Oj.default_options = { :create_id => 'json_class' }
end
def test_json_object_object
obj = Jeez.new(true, 58)
json = Oj.dump(obj, :mode => :object, :indent => 2)
Expand Down

0 comments on commit c2287f1

Please sign in to comment.