From 0cf0b824182fc643c4e295b7178b84e71fdded54 Mon Sep 17 00:00:00 2001 From: naruse Date: Wed, 28 Nov 2007 09:22:57 +0000 Subject: * ext/json, lib/json, test/json: Update to JSON 1.1.2. (RubyForge#15447) * math.c: fix typo. -- M ChangeLog M math.c M ext/json/ext/generator/generator.c M ext/json/ext/parser/parser.rl M ext/json/ext/parser/parser.c M lib/json/version.rb M lib/json/editor.rb M lib/json/common.rb M lib/json/pure/parser.rb M test/json/test_json_unicode.rb M test/json/test_json_fixtures.rb M test/json/test_json_generate.rb M test/json/test_json_addition.rb M test/json/test_json.rb M test/json/runner.rb git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@14044 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 7 ++ ext/json/ext/generator/generator.c | 23 +++-- ext/json/ext/parser/parser.c | 172 +++++++++++++++++++++---------------- ext/json/ext/parser/parser.rl | 50 ++++++++--- lib/json/common.rb | 9 ++ lib/json/editor.rb | 160 ++++++++++++++++++++++++---------- lib/json/pure/parser.rb | 10 ++- lib/json/version.rb | 2 +- math.c | 2 +- test/json/runner.rb | 2 + test/json/test_json.rb | 1 - test/json/test_json_addition.rb | 57 +++++++++++- test/json/test_json_fixtures.rb | 1 - test/json/test_json_generate.rb | 1 - test/json/test_json_unicode.rb | 1 - 15 files changed, 346 insertions(+), 152 deletions(-) diff --git a/ChangeLog b/ChangeLog index dc16d8d625..67ec30f4c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Wed Nov 28 18:08:00 2007 NARUSE, Yui + + * ext/json, lib/json, test/json: Update to JSON 1.1.2. + (RubyForge#15447) + + * math.c: fix typo. + Wed Nov 28 16:29:35 2007 Koichi Sasada * insnhelper.ci (vm_invoke_block): should splat args. diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index d030a72326..5239cc31d4 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -1,9 +1,9 @@ /* vim: set cin et sw=4 ts=4: */ -#include "ruby/ruby.h" +#include +#include "ruby.h" #include "ruby/st.h" #include "unicode.h" -#include #include #define check_max_nesting(state, depth) do { \ @@ -69,6 +69,7 @@ static int hash_to_json_state_i(VALUE key, VALUE value, VALUE Vstate) rb_str_buf_append(buf, rb_str_times(state->indent, Vdepth)); } json = rb_funcall(rb_funcall(key, i_to_s, 0), i_to_json, 2, Vstate, Vdepth); + Check_Type(json, T_STRING); rb_str_buf_append(buf, json); OBJ_INFECT(buf, json); if (RSTRING_LEN(state->space_before)) { @@ -77,6 +78,7 @@ static int hash_to_json_state_i(VALUE key, VALUE value, VALUE Vstate) rb_str_buf_cat2(buf, ":"); if (RSTRING_LEN(state->space)) rb_str_buf_append(buf, state->space); json = rb_funcall(value, i_to_json, 2, Vstate, Vdepth); + Check_Type(json, T_STRING); state->flag = 1; rb_str_buf_append(buf, json); OBJ_INFECT(buf, json); @@ -113,10 +115,12 @@ static int hash_to_json_i(VALUE key, VALUE value, VALUE buf) if (key == Qundef) return ST_CONTINUE; if (RSTRING_LEN(buf) > 1) rb_str_buf_cat2(buf, ","); tmp = rb_funcall(rb_funcall(key, i_to_s, 0), i_to_json, 0); + Check_Type(tmp, T_STRING); rb_str_buf_append(buf, tmp); OBJ_INFECT(buf, tmp); rb_str_buf_cat2(buf, ":"); tmp = rb_funcall(value, i_to_json, 0); + Check_Type(tmp, T_STRING); rb_str_buf_append(buf, tmp); OBJ_INFECT(buf, tmp); @@ -192,7 +196,9 @@ inline static VALUE mArray_json_transfrom(VALUE self, VALUE Vstate, VALUE Vdepth OBJ_INFECT(result, element); if (i > 0) rb_str_buf_append(result, delim); rb_str_buf_append(result, shift); - rb_str_buf_append(result, rb_funcall(element, i_to_json, 2, Vstate, LONG2FIX(depth + 1))); + element = rb_funcall(element, i_to_json, 2, Vstate, LONG2FIX(depth + 1)); + Check_Type(element, T_STRING); + rb_str_buf_append(result, element); } if (RSTRING_LEN(state->array_nl)) { rb_str_buf_append(result, state->array_nl); @@ -213,7 +219,9 @@ inline static VALUE mArray_json_transfrom(VALUE self, VALUE Vstate, VALUE Vdepth OBJ_INFECT(result, element); if (i > 0) rb_str_buf_append(result, delim); rb_str_buf_append(result, shift); - rb_str_buf_append(result, rb_funcall(element, i_to_json, 2, Vstate, LONG2FIX(depth + 1))); + element = rb_funcall(element, i_to_json, 2, Vstate, LONG2FIX(depth + 1)); + Check_Type(element, T_STRING); + rb_str_buf_append(result, element); } rb_str_buf_append(result, state->array_nl); if (RSTRING_LEN(state->array_nl)) { @@ -246,7 +254,9 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) { VALUE element = RARRAY_PTR(self)[i]; OBJ_INFECT(result, element); if (i > 0) rb_str_buf_cat2(result, ","); - rb_str_buf_append(result, rb_funcall(element, i_to_json, 0)); + element = rb_funcall(element, i_to_json, 0); + Check_Type(element, T_STRING); + rb_str_buf_append(result, element); } rb_str_buf_cat2(result, "]"); } else { @@ -787,6 +797,9 @@ static VALUE cState_forget(VALUE self, VALUE object) return rb_hash_delete(state->seen, rb_obj_id(object)); } +/* + * + */ void Init_generator() { mJSON = rb_define_module("JSON"); diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index a6b7021f7e..5a5d6f1dc4 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -1,7 +1,7 @@ #line 1 "parser.rl" -/* -*-c-*- vim: set cin et sw=4 ts=4: */ +/* vim: set cin et sw=4 ts=4: */ -#include "ruby/ruby.h" +#include "ruby.h" #include "ruby/re.h" #include "ruby/st.h" #include "unicode.h" @@ -11,8 +11,8 @@ static VALUE mJSON, mExt, cParser, eParserError, eNestingError; static VALUE CNaN, CInfinity, CMinusInfinity; -static ID i_json_creatable_p, i_json_create, i_create_id, i_chr, i_max_nesting, - i_allow_nan; +static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions, + i_chr, i_max_nesting, i_allow_nan; #define MinusInfinity "-Infinity" @@ -386,11 +386,13 @@ case 26: #line 114 "parser.rl" if (cs >= JSON_object_first_final) { - VALUE klassname = rb_hash_aref(*result, json->create_id); - if (!NIL_P(klassname)) { - VALUE klass = rb_path2class(StringValueCStr(klassname)); - if RTEST(rb_funcall(klass, i_json_creatable_p, 0)) { - *result = rb_funcall(klass, i_json_create, 1, *result); + if (RTEST(json->create_id)) { + VALUE klassname = rb_hash_aref(*result, json->create_id); + if (!NIL_P(klassname)) { + VALUE klass = rb_path2class(StringValueCStr(klassname)); + if RTEST(rb_funcall(klass, i_json_creatable_p, 0)) { + *result = rb_funcall(klass, i_json_create, 1, *result); + } } } return p + 1; @@ -400,14 +402,14 @@ case 26: } -#line 404 "parser.c" +#line 406 "parser.c" static const int JSON_value_start = 1; static const int JSON_value_first_final = 21; static const int JSON_value_error = 0; static const int JSON_value_en_main = 1; -#line 210 "parser.rl" +#line 212 "parser.rl" static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -415,13 +417,13 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul int cs = EVIL; -#line 419 "parser.c" +#line 421 "parser.c" { cs = JSON_value_start; } -#line 217 "parser.rl" +#line 219 "parser.rl" -#line 425 "parser.c" +#line 427 "parser.c" { if ( p == pe ) goto _out; @@ -445,14 +447,14 @@ case 1: st0: goto _out0; tr0: -#line 158 "parser.rl" +#line 160 "parser.rl" { char *np = JSON_parse_string(json, p, pe, result); if (np == NULL) goto _out21; else {p = (( np))-1;} } goto st21; tr2: -#line 163 "parser.rl" +#line 165 "parser.rl" { char *np; if(pe > p + 9 && !strncmp(MinusInfinity, p, 9)) { @@ -472,7 +474,7 @@ tr2: } goto st21; tr5: -#line 181 "parser.rl" +#line 183 "parser.rl" { char *np; json->current_nesting += 1; @@ -482,7 +484,7 @@ tr5: } goto st21; tr9: -#line 189 "parser.rl" +#line 191 "parser.rl" { char *np; json->current_nesting += 1; @@ -492,7 +494,7 @@ tr9: } goto st21; tr16: -#line 151 "parser.rl" +#line 153 "parser.rl" { if (json->allow_nan) { *result = CInfinity; @@ -502,7 +504,7 @@ tr16: } goto st21; tr18: -#line 144 "parser.rl" +#line 146 "parser.rl" { if (json->allow_nan) { *result = CNaN; @@ -512,19 +514,19 @@ tr18: } goto st21; tr22: -#line 138 "parser.rl" +#line 140 "parser.rl" { *result = Qfalse; } goto st21; tr25: -#line 135 "parser.rl" +#line 137 "parser.rl" { *result = Qnil; } goto st21; tr28: -#line 141 "parser.rl" +#line 143 "parser.rl" { *result = Qtrue; } @@ -533,9 +535,9 @@ st21: if ( ++p == pe ) goto _out21; case 21: -#line 197 "parser.rl" +#line 199 "parser.rl" { goto _out21; } -#line 539 "parser.c" +#line 541 "parser.c" goto st0; st2: if ( ++p == pe ) @@ -695,7 +697,7 @@ case 20: _out: {} } -#line 218 "parser.rl" +#line 220 "parser.rl" if (cs >= JSON_value_first_final) { return p; @@ -705,14 +707,14 @@ case 20: } -#line 709 "parser.c" +#line 711 "parser.c" static const int JSON_integer_start = 1; static const int JSON_integer_first_final = 5; static const int JSON_integer_error = 0; static const int JSON_integer_en_main = 1; -#line 234 "parser.rl" +#line 236 "parser.rl" static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -720,14 +722,14 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res int cs = EVIL; -#line 724 "parser.c" +#line 726 "parser.c" { cs = JSON_integer_start; } -#line 241 "parser.rl" +#line 243 "parser.rl" json->memo = p; -#line 731 "parser.c" +#line 733 "parser.c" { if ( p == pe ) goto _out; @@ -760,14 +762,14 @@ case 3: goto st0; goto tr4; tr4: -#line 231 "parser.rl" +#line 233 "parser.rl" { goto _out5; } goto st5; st5: if ( ++p == pe ) goto _out5; case 5: -#line 771 "parser.c" +#line 773 "parser.c" goto st0; st4: if ( ++p == pe ) @@ -785,7 +787,7 @@ case 4: _out: {} } -#line 243 "parser.rl" +#line 245 "parser.rl" if (cs >= JSON_integer_first_final) { long len = p - json->memo; @@ -797,14 +799,14 @@ case 4: } -#line 801 "parser.c" +#line 803 "parser.c" static const int JSON_float_start = 1; static const int JSON_float_first_final = 10; static const int JSON_float_error = 0; static const int JSON_float_en_main = 1; -#line 265 "parser.rl" +#line 267 "parser.rl" static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -812,14 +814,14 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul int cs = EVIL; -#line 816 "parser.c" +#line 818 "parser.c" { cs = JSON_float_start; } -#line 272 "parser.rl" +#line 274 "parser.rl" json->memo = p; -#line 823 "parser.c" +#line 825 "parser.c" { if ( p == pe ) goto _out; @@ -876,14 +878,14 @@ case 5: goto st0; goto tr7; tr7: -#line 259 "parser.rl" +#line 261 "parser.rl" { goto _out10; } goto st10; st10: if ( ++p == pe ) goto _out10; case 10: -#line 887 "parser.c" +#line 889 "parser.c" goto st0; st6: if ( ++p == pe ) @@ -943,7 +945,7 @@ case 9: _out: {} } -#line 274 "parser.rl" +#line 276 "parser.rl" if (cs >= JSON_float_first_final) { long len = p - json->memo; @@ -956,14 +958,14 @@ case 9: -#line 960 "parser.c" +#line 962 "parser.c" static const int JSON_array_start = 1; static const int JSON_array_first_final = 17; static const int JSON_array_error = 0; static const int JSON_array_en_main = 1; -#line 310 "parser.rl" +#line 312 "parser.rl" static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -976,13 +978,13 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul *result = rb_ary_new(); -#line 980 "parser.c" +#line 982 "parser.c" { cs = JSON_array_start; } -#line 322 "parser.rl" +#line 324 "parser.rl" -#line 986 "parser.c" +#line 988 "parser.c" { if ( p == pe ) goto _out; @@ -1020,7 +1022,7 @@ case 2: goto st2; goto st0; tr2: -#line 291 "parser.rl" +#line 293 "parser.rl" { VALUE v = Qnil; char *np = JSON_parse_value(json, p, pe, &v); @@ -1036,7 +1038,7 @@ st3: if ( ++p == pe ) goto _out3; case 3: -#line 1040 "parser.c" +#line 1042 "parser.c" switch( (*p) ) { case 13: goto st3; case 32: goto st3; @@ -1136,14 +1138,14 @@ case 12: goto st3; goto st12; tr4: -#line 302 "parser.rl" +#line 304 "parser.rl" { goto _out17; } goto st17; st17: if ( ++p == pe ) goto _out17; case 17: -#line 1147 "parser.c" +#line 1149 "parser.c" goto st0; st13: if ( ++p == pe ) @@ -1198,7 +1200,7 @@ case 16: _out: {} } -#line 323 "parser.rl" +#line 325 "parser.rl" if(cs >= JSON_array_first_final) { return p + 1; @@ -1264,14 +1266,14 @@ static VALUE json_string_unescape(char *p, char *pe) } -#line 1268 "parser.c" +#line 1270 "parser.c" static const int JSON_string_start = 1; static const int JSON_string_first_final = 8; static const int JSON_string_error = 0; static const int JSON_string_en_main = 1; -#line 401 "parser.rl" +#line 403 "parser.rl" static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -1280,14 +1282,14 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu *result = rb_str_new("", 0); -#line 1284 "parser.c" +#line 1286 "parser.c" { cs = JSON_string_start; } -#line 409 "parser.rl" +#line 411 "parser.rl" json->memo = p; -#line 1291 "parser.c" +#line 1293 "parser.c" { if ( p == pe ) goto _out; @@ -1311,19 +1313,19 @@ case 2: goto st0; goto st2; tr2: -#line 393 "parser.rl" +#line 395 "parser.rl" { *result = json_string_unescape(json->memo + 1, p); if (NIL_P(*result)) goto _out8; else {p = (( p + 1))-1;} } -#line 398 "parser.rl" +#line 400 "parser.rl" { goto _out8; } goto st8; st8: if ( ++p == pe ) goto _out8; case 8: -#line 1327 "parser.c" +#line 1329 "parser.c" goto st0; st3: if ( ++p == pe ) @@ -1398,7 +1400,7 @@ case 7: _out: {} } -#line 411 "parser.rl" +#line 413 "parser.rl" if (cs >= JSON_string_first_final) { return p + 1; @@ -1409,14 +1411,14 @@ case 7: -#line 1413 "parser.c" +#line 1415 "parser.c" static const int JSON_start = 1; static const int JSON_first_final = 10; static const int JSON_error = 0; static const int JSON_en_main = 1; -#line 445 "parser.rl" +#line 447 "parser.rl" /* @@ -1448,6 +1450,9 @@ static const int JSON_en_main = 1; * * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in * defiance of RFC 4627 to be parsed by the Parser. This option defaults to * false. + * * *create_additions*: If set to false, the Parser doesn't create + * additions even if a matchin class and create_id was found. This option + * defaults to true. */ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) { @@ -1462,8 +1467,6 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) if (len < 2) { rb_raise(eParserError, "A JSON text must at least contain two octets!"); } - json->max_nesting = 19; - json->allow_nan = 0; if (!NIL_P(opts)) { opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash"); if (NIL_P(opts)) { @@ -1478,13 +1481,32 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } else { json->max_nesting = 0; } + } else { + json->max_nesting = 19; } tmp = ID2SYM(i_allow_nan); if (st_lookup(RHASH_TBL(opts), tmp, 0)) { VALUE allow_nan = rb_hash_aref(opts, tmp); - if (RTEST(allow_nan)) json->allow_nan = 1; + json->allow_nan = RTEST(allow_nan) ? 1 : 0; + } else { + json->allow_nan = 0; + } + tmp = ID2SYM(i_create_additions); + if (st_lookup(RHASH_TBL(opts), tmp, 0)) { + VALUE create_additions = rb_hash_aref(opts, tmp); + if (RTEST(create_additions)) { + json->create_id = rb_funcall(mJSON, i_create_id, 0); + } else { + json->create_id = Qnil; + } + } else { + json->create_id = rb_funcall(mJSON, i_create_id, 0); } } + } else { + json->max_nesting = 19; + json->allow_nan = 0; + json->create_id = rb_funcall(mJSON, i_create_id, 0); } json->current_nesting = 0; /* @@ -1502,7 +1524,6 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) json->len = len; json->source = ptr; json->Vsource = source; - json->create_id = rb_funcall(mJSON, i_create_id, 0); return self; } @@ -1520,15 +1541,15 @@ static VALUE cParser_parse(VALUE self) GET_STRUCT; -#line 1524 "parser.c" +#line 1545 "parser.c" { cs = JSON_start; } -#line 548 "parser.rl" +#line 569 "parser.rl" p = json->source; pe = p + json->len; -#line 1532 "parser.c" +#line 1553 "parser.c" { if ( p == pe ) goto _out; @@ -1583,7 +1604,7 @@ case 5: goto st1; goto st5; tr3: -#line 434 "parser.rl" +#line 436 "parser.rl" { char *np; json->current_nesting = 1; @@ -1592,7 +1613,7 @@ tr3: } goto st10; tr4: -#line 427 "parser.rl" +#line 429 "parser.rl" { char *np; json->current_nesting = 1; @@ -1604,7 +1625,7 @@ st10: if ( ++p == pe ) goto _out10; case 10: -#line 1608 "parser.c" +#line 1629 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -1660,7 +1681,7 @@ case 9: _out: {} } -#line 551 "parser.rl" +#line 572 "parser.rl" if (cs >= JSON_first_final && p == pe) { return result; @@ -1669,7 +1690,7 @@ case 9: } } -static JSON_Parser *JSON_allocate() +inline static JSON_Parser *JSON_allocate() { JSON_Parser *json = ALLOC(JSON_Parser); MEMZERO(json, JSON_Parser, 1); @@ -1724,6 +1745,7 @@ void Init_parser() i_json_creatable_p = rb_intern("json_creatable?"); i_json_create = rb_intern("json_create"); i_create_id = rb_intern("create_id"); + i_create_additions = rb_intern("create_additions"); i_chr = rb_intern("chr"); i_max_nesting = rb_intern("max_nesting"); i_allow_nan = rb_intern("allow_nan"); diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index 9c51e90223..840b8e0f10 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -1,6 +1,6 @@ -/* -*-c-*- vim: set cin et sw=4 ts=4: */ +/* vim: set cin et sw=4 ts=4: */ -#include "ruby/ruby.h" +#include "ruby.h" #include "ruby/re.h" #include "ruby/st.h" #include "unicode.h" @@ -10,8 +10,8 @@ static VALUE mJSON, mExt, cParser, eParserError, eNestingError; static VALUE CNaN, CInfinity, CMinusInfinity; -static ID i_json_creatable_p, i_json_create, i_create_id, i_chr, i_max_nesting, - i_allow_nan; +static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions, + i_chr, i_max_nesting, i_allow_nan; #define MinusInfinity "-Infinity" @@ -113,11 +113,13 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu %% write exec; if (cs >= JSON_object_first_final) { - VALUE klassname = rb_hash_aref(*result, json->create_id); - if (!NIL_P(klassname)) { - VALUE klass = rb_path2class(StringValueCStr(klassname)); - if RTEST(rb_funcall(klass, i_json_creatable_p, 0)) { - *result = rb_funcall(klass, i_json_create, 1, *result); + if (RTEST(json->create_id)) { + VALUE klassname = rb_hash_aref(*result, json->create_id); + if (!NIL_P(klassname)) { + VALUE klass = rb_path2class(StringValueCStr(klassname)); + if RTEST(rb_funcall(klass, i_json_creatable_p, 0)) { + *result = rb_funcall(klass, i_json_create, 1, *result); + } } } return p + 1; @@ -473,6 +475,9 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu * * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in * defiance of RFC 4627 to be parsed by the Parser. This option defaults to * false. + * * *create_additions*: If set to false, the Parser doesn't create + * additions even if a matchin class and create_id was found. This option + * defaults to true. */ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) { @@ -487,8 +492,6 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) if (len < 2) { rb_raise(eParserError, "A JSON text must at least contain two octets!"); } - json->max_nesting = 19; - json->allow_nan = 0; if (!NIL_P(opts)) { opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash"); if (NIL_P(opts)) { @@ -503,13 +506,32 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } else { json->max_nesting = 0; } + } else { + json->max_nesting = 19; } tmp = ID2SYM(i_allow_nan); if (st_lookup(RHASH_TBL(opts), tmp, 0)) { VALUE allow_nan = rb_hash_aref(opts, tmp); - if (RTEST(allow_nan)) json->allow_nan = 1; + json->allow_nan = RTEST(allow_nan) ? 1 : 0; + } else { + json->allow_nan = 0; + } + tmp = ID2SYM(i_create_additions); + if (st_lookup(RHASH_TBL(opts), tmp, 0)) { + VALUE create_additions = rb_hash_aref(opts, tmp); + if (RTEST(create_additions)) { + json->create_id = rb_funcall(mJSON, i_create_id, 0); + } else { + json->create_id = Qnil; + } + } else { + json->create_id = rb_funcall(mJSON, i_create_id, 0); } } + } else { + json->max_nesting = 19; + json->allow_nan = 0; + json->create_id = rb_funcall(mJSON, i_create_id, 0); } json->current_nesting = 0; /* @@ -527,7 +549,6 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) json->len = len; json->source = ptr; json->Vsource = source; - json->create_id = rb_funcall(mJSON, i_create_id, 0); return self; } @@ -556,7 +577,7 @@ static VALUE cParser_parse(VALUE self) } } -static JSON_Parser *JSON_allocate() +inline static JSON_Parser *JSON_allocate() { JSON_Parser *json = ALLOC(JSON_Parser); MEMZERO(json, JSON_Parser, 1); @@ -611,6 +632,7 @@ void Init_parser() i_json_creatable_p = rb_intern("json_creatable?"); i_json_create = rb_intern("json_create"); i_create_id = rb_intern("create_id"); + i_create_additions = rb_intern("create_additions"); i_chr = rb_intern("chr"); i_max_nesting = rb_intern("max_nesting"); i_allow_nan = rb_intern("allow_nan"); diff --git a/lib/json/common.rb b/lib/json/common.rb index c988677a1d..7bc5ae0656 100644 --- a/lib/json/common.rb +++ b/lib/json/common.rb @@ -115,6 +115,9 @@ module JSON # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in # defiance of RFC 4627 to be parsed by the Parser. This option defaults # to false. + # * *create_additions*: If set to false, the Parser doesn't create + # additions even if a matchin class and create_id was found. This option + # defaults to true. def parse(source, opts = {}) JSON.parser.new(source, opts).parse end @@ -131,6 +134,9 @@ module JSON # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in # defiance of RFC 4627 to be parsed by the Parser. This option defaults # to true. + # * *create_additions*: If set to false, the Parser doesn't create + # additions even if a matchin class and create_id was found. This option + # defaults to true. def parse!(source, opts = {}) opts = { :max_nesting => false, @@ -161,6 +167,9 @@ module JSON # * *allow_nan*: true if NaN, Infinity, and -Infinity should be # generated, otherwise an exception is thrown, if these values are # encountered. This options defaults to false. + # * *max_nesting*: The maximum depth of nesting allowed in the data + # structures from which JSON is to be generated. Disable depth checking + # with :max_nesting => false, it defaults to 19. # # See also the fast_generate for the fastest creation method with the least # amount of sanity checks, and the pretty_generate method for some diff --git a/lib/json/editor.rb b/lib/json/editor.rb index 3dbcce5536..9a65400622 100644 --- a/lib/json/editor.rb +++ b/lib/json/editor.rb @@ -457,16 +457,16 @@ module JSON def create add_item("Change node", ?n, &method(:change_node)) add_separator - add_item("Cut node", ?x, &method(:cut_node)) - add_item("Copy node", ?c, &method(:copy_node)) - add_item("Paste node (appending)", ?v, &method(:paste_node_appending)) - add_item("Paste node (inserting before)", ?V, + add_item("Cut node", ?X, &method(:cut_node)) + add_item("Copy node", ?C, &method(:copy_node)) + add_item("Paste node (appending)", ?A, &method(:paste_node_appending)) + add_item("Paste node (inserting before)", ?I, &method(:paste_node_inserting_before)) add_separator add_item("Append new node", ?a, &method(:append_new_node)) add_item("Insert new node before", ?i, &method(:insert_new_node)) add_separator - add_item("Collapse/Expand node (recursively)", ?C, + add_item("Collapse/Expand node (recursively)", ?e, &method(:collapse_expand)) menu.show_all @@ -544,17 +544,32 @@ module JSON class EditMenu include MenuExtension + # Copy data from model into primary clipboard. + def copy(item) + data = Editor.model2data(model.iter_first) + json = JSON.pretty_generate(data, :max_nesting => false) + c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY) + c.text = json + end + + # Copy json text from primary clipboard into model. + def paste(item) + c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY) + if json = c.wait_for_text + window.ask_save if @changed + begin + window.edit json + rescue JSON::ParserError + window.clear + end + end + end + # Find a string in all nodes' contents and select the found node in the # treeview. def find(item) - search = ask_for_find_term or return - begin - @search = Regexp.new(search) - rescue => e - Editor.error_dialog(self, "Evaluation of regex /#{search}/ failed: #{e}!") - return - end - iter = model.get_iter('0') + @search = ask_for_find_term(@search) or return + iter = model.get_iter('0') or return iter.recursive_each do |i| if @iter if @iter != i @@ -630,6 +645,9 @@ module JSON def create title = MenuItem.new('Edit') title.submenu = menu + add_item('Copy', ?c, &method(:copy)) + add_item('Paste', ?v, &method(:paste)) + add_separator add_item('Find', ?f, &method(:find)) add_item('Find Again', ?g, &method(:find_again)) add_separator @@ -812,12 +830,13 @@ module JSON [ Stock::OK, Dialog::RESPONSE_ACCEPT ], [ Stock::CANCEL, Dialog::RESPONSE_REJECT ] ) + dialog.width_request = 640 hbox = HBox.new(false, 5) - hbox.pack_start(Label.new("Key:")) + hbox.pack_start(Label.new("Key:"), false) hbox.pack_start(key_input = Entry.new) key_input.text = @key || '' - dialog.vbox.add(hbox) + dialog.vbox.pack_start(hbox, false) key_input.signal_connect(:activate) do if parent.any? { |c| c.content == key_input.text } toplevel.display_status('Key already exists in Hash!') @@ -828,11 +847,11 @@ module JSON end hbox = HBox.new(false, 5) - hbox.add(Label.new("Type:")) + hbox.pack_start(Label.new("Type:"), false) hbox.pack_start(type_input = ComboBox.new(true)) ALL_TYPES.each { |t| type_input.append_text(t) } type_input.active = @type || 0 - dialog.vbox.add(hbox) + dialog.vbox.pack_start(hbox, false) type_input.signal_connect(:changed) do value_input.editable = false @@ -852,10 +871,11 @@ module JSON end hbox = HBox.new(false, 5) - hbox.add(Label.new("Value:")) + hbox.pack_start(Label.new("Value:"), false) hbox.pack_start(value_input = Entry.new) + value_input.width_chars = 60 value_input.text = @value || '' - dialog.vbox.add(hbox) + dialog.vbox.pack_start(hbox, false) dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER) dialog.show_all @@ -884,7 +904,7 @@ module JSON [ Stock::CANCEL, Dialog::RESPONSE_REJECT ] ) hbox = HBox.new(false, 5) - hbox.add(Label.new("Type:")) + hbox.pack_start(Label.new("Type:"), false) hbox.pack_start(type_input = ComboBox.new(true)) default_active = 0 types = parent ? ALL_TYPES : CONTAINER_TYPES @@ -895,18 +915,19 @@ module JSON end end type_input.active = default_active - dialog.vbox.add(hbox) + dialog.vbox.pack_start(hbox, false) type_input.signal_connect(:changed) do configure_value(value_input, types[type_input.active]) end hbox = HBox.new(false, 5) - hbox.add(Label.new("Value:")) + hbox.pack_start(Label.new("Value:"), false) hbox.pack_start(value_input = Entry.new) + value_input.width_chars = 60 value_input.text = value_text if value_text configure_value(value_input, types[type_input.active]) - dialog.vbox.add(hbox) + dialog.vbox.pack_start(hbox, false) dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER) dialog.show_all @@ -940,13 +961,14 @@ module JSON ) hbox = HBox.new(false, 5) - hbox.add(Label.new("Order:")) + hbox.pack_start(Label.new("Order:"), false) hbox.pack_start(order_input = Entry.new) order_input.text = @order || 'x' + order_input.width_chars = 60 - hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse')) + hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse'), false) - dialog.vbox.add(hbox) + dialog.vbox.pack_start(hbox, false) dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER) dialog.show_all @@ -963,7 +985,7 @@ module JSON # Ask for a find term to search for in the tree. Returns the term as a # string. - def ask_for_find_term + def ask_for_find_term(search = nil) dialog = Dialog.new( "Find a node matching regex in tree.", nil, nil, @@ -972,18 +994,28 @@ module JSON ) hbox = HBox.new(false, 5) - hbox.add(Label.new("Regex:")) + hbox.pack_start(Label.new("Regex:"), false) hbox.pack_start(regex_input = Entry.new) - regex_input.text = @regex || '' + hbox.pack_start(icase_checkbox = CheckButton.new('Icase'), false) + regex_input.width_chars = 60 + if search + regex_input.text = search.source + icase_checkbox.active = search.casefold? + end - dialog.vbox.add(hbox) + dialog.vbox.pack_start(hbox, false) dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER) dialog.show_all self.focus = dialog dialog.run do |response| if response == Dialog::RESPONSE_ACCEPT - return @regex = regex_input.text + begin + return Regexp.new(regex_input.text, icase_checkbox.active? ? Regexp::IGNORECASE : 0) + rescue => e + Editor.error_dialog(self, "Evaluation of regex /#{regex_input.text}/ failed: #{e}!") + return + end end end return @@ -1040,6 +1072,18 @@ module JSON data = read_data(@filename) view_new_model Editor.data2model(data) end + + signal_connect(:button_release_event) do |_,event| + if event.button == 2 + c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY) + if url = c.wait_for_text + location_open url + end + false + else + true + end + end end # Creates the menu bar with the pulldown menus and returns it. @@ -1132,6 +1176,7 @@ module JSON def location_open(uri = nil) uri = ask_for_location unless uri uri or return + ask_save if @changed data = load_location(uri) or return view_new_model Editor.data2model(data) end @@ -1144,6 +1189,15 @@ module JSON view_new_model Editor.data2model(data) end + # Edit the string _json_ in the editor. + def edit(json) + if json.respond_to? :read + json = json.read + end + data = parse_json json + view_new_model Editor.data2model(data) + end + # Save the current file. def file_save if @filename @@ -1164,10 +1218,11 @@ module JSON if path data = Editor.model2data(@treeview.model.iter_first) File.open(path + '.tmp', 'wb') do |output| + data or break if @options_menu.pretty_item.active? - output.puts JSON.pretty_generate(data) + output.puts JSON.pretty_generate(data, :max_nesting => false) else - output.write JSON.unparse(data) + output.write JSON.generate(data, :max_nesting => false) end end File.rename path + '.tmp', path @@ -1205,17 +1260,22 @@ module JSON data end + def parse_json(json) + check_pretty_printed(json) + if @encoding && !/^utf8$/i.match(@encoding) + iconverter = Iconv.new('utf8', @encoding) + json = iconverter.iconv(json) + end + JSON::parse(json, :max_nesting => false, :create_additions => false) + end + private :parse_json + # Read a JSON document from the file named _filename_, parse it into a # ruby data structure, and return the data. def read_data(filename) open(filename) do |f| json = f.read - check_pretty_printed(json) - if @encoding && !/^utf8$/i.match(@encoding) - iconverter = Iconv.new('utf8', @encoding) - json = iconverter.iconv(json) - end - return JSON::parse(json, :max_nesting => false) + return parse_json(json) end rescue => e Editor.error_dialog(self, "Failed to parse JSON file: #{e}!") @@ -1226,11 +1286,15 @@ module JSON # selected filename or nil, if no file was selected. def select_file(message) filename = nil - fs = FileSelection.new(message).set_modal(true). - set_filename(Dir.pwd + "/").set_transient_for(self) + fs = FileSelection.new(message) + fs.set_modal(true) + @default_dir = File.join(Dir.pwd, '') unless @default_dir + fs.set_filename(@default_dir) + fs.set_transient_for(self) fs.signal_connect(:destroy) { Gtk.main_quit } fs.ok_button.signal_connect(:clicked) do filename = fs.filename + @default_dir = File.join(File.dirname(filename), '') fs.destroy Gtk.main_quit end @@ -1253,12 +1317,12 @@ module JSON ) hbox = HBox.new(false, 5) - hbox.add(Label.new("Location:")) + hbox.pack_start(Label.new("Location:"), false) hbox.pack_start(location_input = Entry.new) location_input.width_chars = 60 location_input.text = @location || '' - dialog.vbox.add(hbox) + dialog.vbox.pack_start(hbox, false) dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER) dialog.show_all @@ -1276,8 +1340,7 @@ module JSON class << self # Starts a JSON Editor. If a block was given, it yields # to the JSON::Editor::MainWindow instance. - def start(encoding = nil) # :yield: window - encoding ||= 'utf8' + def start(encoding = 'utf8') # :yield: window Gtk.init @window = Editor::MainWindow.new(encoding) @window.icon_list = [ Editor.fetch_icon('json') ] @@ -1286,6 +1349,13 @@ module JSON Gtk.main end + # Edit the string _json_ with encoding _encoding_ in the editor. + def edit(json, encoding = 'utf8') + start(encoding) do |window| + window.edit json + end + end + attr_reader :window end end diff --git a/lib/json/pure/parser.rb b/lib/json/pure/parser.rb index 4d63464320..e886ba8d2c 100644 --- a/lib/json/pure/parser.rb +++ b/lib/json/pure/parser.rb @@ -58,6 +58,9 @@ module JSON # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in # defiance of RFC 4627 to be parsed by the Parser. This option defaults # to false. + # * *create_additions*: If set to false, the Parser doesn't create + # additions even if a matchin class and create_id was found. This option + # defaults to true. def initialize(source, opts = {}) super if !opts.key?(:max_nesting) # defaults to 19 @@ -68,7 +71,9 @@ module JSON @max_nesting = 0 end @allow_nan = !!opts[:allow_nan] - @create_id = JSON.create_id + ca = true + ca = opts[:create_additions] if opts.key?(:create_additions) + @create_id = ca ? JSON.create_id : nil end alias source string @@ -235,11 +240,10 @@ module JSON if delim raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!" end - if klassname = result[@create_id] + if @create_id and klassname = result[@create_id] klass = JSON.deep_const_get klassname break unless klass and klass.json_creatable? result = klass.json_create(result) - result end break when skip(IGNORE) diff --git a/lib/json/version.rb b/lib/json/version.rb index 2e12c8c9e0..3d674ac44f 100644 --- a/lib/json/version.rb +++ b/lib/json/version.rb @@ -1,6 +1,6 @@ module JSON # JSON version - VERSION = '1.1.1' + VERSION = '1.1.2' VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc: VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc: VERSION_MINOR = VERSION_ARRAY[1] # :nodoc: diff --git a/math.c b/math.c index e37ec75b49..85040f9c59 100644 --- a/math.c +++ b/math.c @@ -32,7 +32,7 @@ domain_check(double x, char *msg) if (isnan(x)) { #if defined(EDOM) errno = EDOM; -#elif define(ERANGE) +#elif defined(ERANGE) errno = ERANGE; #endif continue; diff --git a/test/json/runner.rb b/test/json/runner.rb index 930fed7579..91bc12a594 100755 --- a/test/json/runner.rb +++ b/test/json/runner.rb @@ -8,6 +8,7 @@ require 'test_json' require 'test_json_generate' require 'test_json_unicode' require 'test_json_addition' +require 'test_json_rails' require 'test_json_fixtures' class TS_AllTests @@ -17,6 +18,7 @@ class TS_AllTests suite << TC_JSON.suite suite << TC_JSONUnicode.suite suite << TC_JSONAddition.suite + suite << TC_JSONRails.suite suite << TC_JSONFixtures.suite end end diff --git a/test/json/test_json.rb b/test/json/test_json.rb index 2be7b4a9a3..2325c10063 100755 --- a/test/json/test_json.rb +++ b/test/json/test_json.rb @@ -7,7 +7,6 @@ class TC_JSON < Test::Unit::TestCase include JSON def setup - $KCODE = 'UTF8' @ary = [1, "foo", 3.14, 4711.0, 2.718, nil, [1,-2,3], false, true].map do |x| [x] end diff --git a/test/json/test_json_addition.rb b/test/json/test_json_addition.rb index e527f70a11..2ae0ce47c5 100755 --- a/test/json/test_json_addition.rb +++ b/test/json/test_json_addition.rb @@ -1,7 +1,8 @@ #!/usr/bin/env ruby require 'test/unit' -require 'json' +require 'json/add/core' +require 'date' class TC_JSONAddition < Test::Unit::TestCase include JSON @@ -23,7 +24,7 @@ class TC_JSONAddition < Test::Unit::TestCase def to_json(*args) { - 'json_class' => self.class, + 'json_class' => self.class.name, 'args' => [ @a ], }.to_json(*args) end @@ -32,12 +33,16 @@ class TC_JSONAddition < Test::Unit::TestCase class B def to_json(*args) { - 'json_class' => self.class, + 'json_class' => self.class.name, }.to_json(*args) end end class C + def self.json_creatable? + false + end + def to_json(*args) { 'json_class' => 'TC_JSONAddition::Nix', @@ -46,7 +51,6 @@ class TC_JSONAddition < Test::Unit::TestCase end def setup - $KCODE = 'UTF8' end def test_extended_json @@ -58,6 +62,21 @@ class TC_JSONAddition < Test::Unit::TestCase assert_equal a, a_again end + def test_extended_json_disabled + a = A.new(666) + assert A.json_creatable? + json = generate(a) + a_again = JSON.parse(json, :create_additions => true) + assert_kind_of a.class, a_again + assert_equal a, a_again + a_hash = JSON.parse(json, :create_additions => false) + assert_kind_of Hash, a_hash + assert_equal( + {"args"=>[666], "json_class"=>"TC_JSONAddition::A"}.sort_by { |k,| k }, + a_hash.sort_by { |k,| k } + ) + end + def test_extended_json_fail b = B.new assert !B.json_creatable? @@ -91,4 +110,34 @@ EOT raw_again = JSON.parse(json) assert_equal raw, raw_again end + + def test_core + t = Time.now + assert_equal t, JSON(JSON(t)) + d = Date.today + assert_equal d, JSON(JSON(d)) + d = DateTime.civil(2007, 6, 14, 14, 57, 10, Rational(1, 12), 2299161) + assert_equal d, JSON(JSON(d)) + assert_equal 1..10, JSON(JSON(1..10)) + assert_equal 1...10, JSON(JSON(1...10)) + assert_equal "a".."c", JSON(JSON("a".."c")) + assert_equal "a"..."c", JSON(JSON("a"..."c")) + struct = Struct.new 'MyStruct', :foo, :bar + s = struct.new 4711, 'foot' + assert_equal s, JSON(JSON(s)) + struct = Struct.new :foo, :bar + s = struct.new 4711, 'foot' + assert_raises(JSONError) { JSON(s) } + begin + raise TypeError, "test me" + rescue TypeError => e + e_json = JSON.generate e + e_again = JSON e_json + assert_kind_of TypeError, e_again + assert_equal e.message, e_again.message + assert_equal e.backtrace, e_again.backtrace + end + assert_equal /foo/, JSON(JSON(/foo/)) + assert_equal /foo/i, JSON(JSON(/foo/i)) + end end diff --git a/test/json/test_json_fixtures.rb b/test/json/test_json_fixtures.rb index 665dcbd5ea..33573cd300 100755 --- a/test/json/test_json_fixtures.rb +++ b/test/json/test_json_fixtures.rb @@ -5,7 +5,6 @@ require 'json' class TC_JSONFixtures < Test::Unit::TestCase def setup - $KCODE = 'UTF8' fixtures = File.join(File.dirname(__FILE__), 'fixtures/*.json') passed, failed = Dir[fixtures].partition { |f| f['pass'] } @passed = passed.inject([]) { |a, f| a << [ f, File.read(f) ] }.sort diff --git a/test/json/test_json_generate.rb b/test/json/test_json_generate.rb index 82d8c3d286..e720b2d862 100644 --- a/test/json/test_json_generate.rb +++ b/test/json/test_json_generate.rb @@ -5,7 +5,6 @@ class TC_JSONGenerate < Test::Unit::TestCase include JSON def setup - $KCODE = 'UTF8' @hash = { 'a' => 2, 'b' => 3.141, diff --git a/test/json/test_json_unicode.rb b/test/json/test_json_unicode.rb index a91f4b576c..9e0d762f6d 100755 --- a/test/json/test_json_unicode.rb +++ b/test/json/test_json_unicode.rb @@ -7,7 +7,6 @@ class TC_JSONUnicode < Test::Unit::TestCase include JSON def setup - $KCODE = 'UTF8' end def test_unicode -- cgit v1.2.3