json 2.6.2 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +39 -0
- data/README.md +4 -4
- data/VERSION +1 -1
- data/ext/json/ext/generator/generator.c +86 -21
- data/ext/json/ext/generator/generator.h +8 -5
- data/ext/json/ext/parser/parser.c +1828 -2964
- data/ext/json/ext/parser/parser.rl +85 -100
- data/json.gemspec +3 -3
- data/lib/json/add/bigdecimal.rb +5 -2
- data/lib/json/add/range.rb +22 -7
- data/lib/json/common.rb +11 -27
- data/lib/json/pure/generator.rb +62 -28
- data/lib/json/pure/parser.rb +1 -1
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +9 -0
- metadata +6 -6
|
@@ -222,14 +222,14 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
|
222
222
|
if (json->allow_nan) {
|
|
223
223
|
*result = CNaN;
|
|
224
224
|
} else {
|
|
225
|
-
rb_enc_raise(EXC_ENCODING eParserError, "
|
|
225
|
+
rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 2);
|
|
226
226
|
}
|
|
227
227
|
}
|
|
228
228
|
action parse_infinity {
|
|
229
229
|
if (json->allow_nan) {
|
|
230
230
|
*result = CInfinity;
|
|
231
231
|
} else {
|
|
232
|
-
rb_enc_raise(EXC_ENCODING eParserError, "
|
|
232
|
+
rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 7);
|
|
233
233
|
}
|
|
234
234
|
}
|
|
235
235
|
action parse_string {
|
|
@@ -245,7 +245,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
|
245
245
|
fexec p + 10;
|
|
246
246
|
fhold; fbreak;
|
|
247
247
|
} else {
|
|
248
|
-
rb_enc_raise(EXC_ENCODING eParserError, "
|
|
248
|
+
rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
251
|
np = JSON_parse_float(json, fpc, pe, result);
|
|
@@ -447,7 +447,7 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
|
447
447
|
if(cs >= JSON_array_first_final) {
|
|
448
448
|
return p + 1;
|
|
449
449
|
} else {
|
|
450
|
-
rb_enc_raise(EXC_ENCODING eParserError, "
|
|
450
|
+
rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
|
|
451
451
|
return NULL;
|
|
452
452
|
}
|
|
453
453
|
}
|
|
@@ -508,11 +508,11 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
|
|
|
508
508
|
case 'u':
|
|
509
509
|
if (pe > stringEnd - 4) {
|
|
510
510
|
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
|
511
|
-
|
|
511
|
+
ruby_xfree(bufferStart);
|
|
512
512
|
}
|
|
513
513
|
rb_enc_raise(
|
|
514
514
|
EXC_ENCODING eParserError,
|
|
515
|
-
"
|
|
515
|
+
"incomplete unicode character escape sequence at '%s'", p
|
|
516
516
|
);
|
|
517
517
|
} else {
|
|
518
518
|
UTF32 ch = unescape_unicode((unsigned char *) ++pe);
|
|
@@ -521,11 +521,11 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
|
|
|
521
521
|
pe++;
|
|
522
522
|
if (pe > stringEnd - 6) {
|
|
523
523
|
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
|
524
|
-
|
|
524
|
+
ruby_xfree(bufferStart);
|
|
525
525
|
}
|
|
526
526
|
rb_enc_raise(
|
|
527
527
|
EXC_ENCODING eParserError,
|
|
528
|
-
"
|
|
528
|
+
"incomplete surrogate pair at '%s'", p
|
|
529
529
|
);
|
|
530
530
|
}
|
|
531
531
|
if (pe[0] == '\\' && pe[1] == 'u') {
|
|
@@ -566,13 +566,13 @@ static VALUE json_string_unescape(char *string, char *stringEnd, int intern, int
|
|
|
566
566
|
result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
|
|
567
567
|
}
|
|
568
568
|
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
|
569
|
-
|
|
569
|
+
ruby_xfree(bufferStart);
|
|
570
570
|
}
|
|
571
571
|
# else
|
|
572
572
|
result = rb_utf8_str_new(bufferStart, (long)(buffer - bufferStart));
|
|
573
573
|
|
|
574
574
|
if (bufferSize > MAX_STACK_BUFFER_SIZE) {
|
|
575
|
-
|
|
575
|
+
ruby_xfree(bufferStart);
|
|
576
576
|
}
|
|
577
577
|
|
|
578
578
|
if (intern) {
|
|
@@ -691,8 +691,6 @@ static VALUE convert_encoding(VALUE source)
|
|
|
691
691
|
*
|
|
692
692
|
* Creates a new JSON::Ext::Parser instance for the string _source_.
|
|
693
693
|
*
|
|
694
|
-
* Creates a new JSON::Ext::Parser instance for the string _source_.
|
|
695
|
-
*
|
|
696
694
|
* It will be configured by the _opts_ hash. _opts_ can have the following
|
|
697
695
|
* keys:
|
|
698
696
|
*
|
|
@@ -721,98 +719,85 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
|
|
|
721
719
|
if (json->Vsource) {
|
|
722
720
|
rb_raise(rb_eTypeError, "already initialized instance");
|
|
723
721
|
}
|
|
724
|
-
#ifdef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
|
|
725
722
|
rb_scan_args(argc, argv, "1:", &source, &opts);
|
|
726
|
-
#else
|
|
727
|
-
rb_scan_args(argc, argv, "11", &source, &opts);
|
|
728
|
-
#endif
|
|
729
723
|
if (!NIL_P(opts)) {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
if (option_given_p(opts, tmp)) {
|
|
803
|
-
VALUE match_string = rb_hash_aref(opts, tmp);
|
|
804
|
-
json->match_string = RTEST(match_string) ? match_string : Qnil;
|
|
805
|
-
} else {
|
|
806
|
-
json->match_string = Qnil;
|
|
807
|
-
}
|
|
808
|
-
#ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
|
|
809
|
-
}
|
|
810
|
-
#endif
|
|
724
|
+
VALUE tmp = ID2SYM(i_max_nesting);
|
|
725
|
+
if (option_given_p(opts, tmp)) {
|
|
726
|
+
VALUE max_nesting = rb_hash_aref(opts, tmp);
|
|
727
|
+
if (RTEST(max_nesting)) {
|
|
728
|
+
Check_Type(max_nesting, T_FIXNUM);
|
|
729
|
+
json->max_nesting = FIX2INT(max_nesting);
|
|
730
|
+
} else {
|
|
731
|
+
json->max_nesting = 0;
|
|
732
|
+
}
|
|
733
|
+
} else {
|
|
734
|
+
json->max_nesting = 100;
|
|
735
|
+
}
|
|
736
|
+
tmp = ID2SYM(i_allow_nan);
|
|
737
|
+
if (option_given_p(opts, tmp)) {
|
|
738
|
+
json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
|
|
739
|
+
} else {
|
|
740
|
+
json->allow_nan = 0;
|
|
741
|
+
}
|
|
742
|
+
tmp = ID2SYM(i_symbolize_names);
|
|
743
|
+
if (option_given_p(opts, tmp)) {
|
|
744
|
+
json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
|
|
745
|
+
} else {
|
|
746
|
+
json->symbolize_names = 0;
|
|
747
|
+
}
|
|
748
|
+
tmp = ID2SYM(i_freeze);
|
|
749
|
+
if (option_given_p(opts, tmp)) {
|
|
750
|
+
json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
|
|
751
|
+
} else {
|
|
752
|
+
json->freeze = 0;
|
|
753
|
+
}
|
|
754
|
+
tmp = ID2SYM(i_create_additions);
|
|
755
|
+
if (option_given_p(opts, tmp)) {
|
|
756
|
+
json->create_additions = RTEST(rb_hash_aref(opts, tmp));
|
|
757
|
+
} else {
|
|
758
|
+
json->create_additions = 0;
|
|
759
|
+
}
|
|
760
|
+
if (json->symbolize_names && json->create_additions) {
|
|
761
|
+
rb_raise(rb_eArgError,
|
|
762
|
+
"options :symbolize_names and :create_additions cannot be "
|
|
763
|
+
" used in conjunction");
|
|
764
|
+
}
|
|
765
|
+
tmp = ID2SYM(i_create_id);
|
|
766
|
+
if (option_given_p(opts, tmp)) {
|
|
767
|
+
json->create_id = rb_hash_aref(opts, tmp);
|
|
768
|
+
} else {
|
|
769
|
+
json->create_id = rb_funcall(mJSON, i_create_id, 0);
|
|
770
|
+
}
|
|
771
|
+
tmp = ID2SYM(i_object_class);
|
|
772
|
+
if (option_given_p(opts, tmp)) {
|
|
773
|
+
json->object_class = rb_hash_aref(opts, tmp);
|
|
774
|
+
} else {
|
|
775
|
+
json->object_class = Qnil;
|
|
776
|
+
}
|
|
777
|
+
tmp = ID2SYM(i_array_class);
|
|
778
|
+
if (option_given_p(opts, tmp)) {
|
|
779
|
+
json->array_class = rb_hash_aref(opts, tmp);
|
|
780
|
+
} else {
|
|
781
|
+
json->array_class = Qnil;
|
|
782
|
+
}
|
|
783
|
+
tmp = ID2SYM(i_decimal_class);
|
|
784
|
+
if (option_given_p(opts, tmp)) {
|
|
785
|
+
json->decimal_class = rb_hash_aref(opts, tmp);
|
|
786
|
+
} else {
|
|
787
|
+
json->decimal_class = Qnil;
|
|
788
|
+
}
|
|
789
|
+
tmp = ID2SYM(i_match_string);
|
|
790
|
+
if (option_given_p(opts, tmp)) {
|
|
791
|
+
VALUE match_string = rb_hash_aref(opts, tmp);
|
|
792
|
+
json->match_string = RTEST(match_string) ? match_string : Qnil;
|
|
793
|
+
} else {
|
|
794
|
+
json->match_string = Qnil;
|
|
795
|
+
}
|
|
811
796
|
} else {
|
|
812
797
|
json->max_nesting = 100;
|
|
813
798
|
json->allow_nan = 0;
|
|
814
799
|
json->create_additions = 0;
|
|
815
|
-
json->create_id =
|
|
800
|
+
json->create_id = Qnil;
|
|
816
801
|
json->object_class = Qnil;
|
|
817
802
|
json->array_class = Qnil;
|
|
818
803
|
json->decimal_class = Qnil;
|
|
@@ -847,7 +832,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
|
|
|
847
832
|
*
|
|
848
833
|
* Parses the current JSON text _source_ and returns the complete data
|
|
849
834
|
* structure as a result.
|
|
850
|
-
* It raises JSON::
|
|
835
|
+
* It raises JSON::ParserError if fail to parse.
|
|
851
836
|
*/
|
|
852
837
|
static VALUE cParser_parse(VALUE self)
|
|
853
838
|
{
|
|
@@ -864,7 +849,7 @@ static VALUE cParser_parse(VALUE self)
|
|
|
864
849
|
if (cs >= JSON_first_final && p == pe) {
|
|
865
850
|
return result;
|
|
866
851
|
} else {
|
|
867
|
-
rb_enc_raise(EXC_ENCODING eParserError, "
|
|
852
|
+
rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p);
|
|
868
853
|
return Qnil;
|
|
869
854
|
}
|
|
870
855
|
}
|
data/json.gemspec
CHANGED
|
@@ -53,12 +53,12 @@ Gem::Specification.new do |s|
|
|
|
53
53
|
"lib/json/pure/parser.rb",
|
|
54
54
|
"lib/json/version.rb",
|
|
55
55
|
]
|
|
56
|
-
s.homepage = "
|
|
56
|
+
s.homepage = "https://flori.github.io/json"
|
|
57
57
|
s.metadata = {
|
|
58
58
|
'bug_tracker_uri' => 'https://github.com/flori/json/issues',
|
|
59
59
|
'changelog_uri' => 'https://github.com/flori/json/blob/master/CHANGES.md',
|
|
60
|
-
'documentation_uri' => '
|
|
61
|
-
'homepage_uri' =>
|
|
60
|
+
'documentation_uri' => 'https://flori.github.io/json/doc/index.html',
|
|
61
|
+
'homepage_uri' => s.homepage,
|
|
62
62
|
'source_code_uri' => 'https://github.com/flori/json',
|
|
63
63
|
'wiki_uri' => 'https://github.com/flori/json/wiki'
|
|
64
64
|
}
|
data/lib/json/add/bigdecimal.rb
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
|
|
3
3
|
require 'json'
|
|
4
4
|
end
|
|
5
|
-
|
|
5
|
+
begin
|
|
6
|
+
require 'bigdecimal'
|
|
7
|
+
rescue LoadError
|
|
8
|
+
end
|
|
6
9
|
|
|
7
10
|
class BigDecimal
|
|
8
11
|
# Import a JSON Marshalled object.
|
|
@@ -26,4 +29,4 @@ class BigDecimal
|
|
|
26
29
|
def to_json(*args)
|
|
27
30
|
as_json.to_json(*args)
|
|
28
31
|
end
|
|
29
|
-
end
|
|
32
|
+
end if defined?(::BigDecimal)
|
data/lib/json/add/range.rb
CHANGED
|
@@ -5,14 +5,25 @@ end
|
|
|
5
5
|
|
|
6
6
|
class Range
|
|
7
7
|
|
|
8
|
-
#
|
|
9
|
-
#
|
|
8
|
+
# Returns a new \Range object constructed from <tt>object['a']</tt>,
|
|
9
|
+
# which must be an array of values suitable for a call to Range.new:
|
|
10
|
+
#
|
|
11
|
+
# require 'json/add/range'
|
|
12
|
+
# Range.json_create({"a"=>[1, 4]}) # => 1..4
|
|
13
|
+
# Range.json_create({"a"=>[1, 4, true]}) # => 1...4
|
|
14
|
+
# Range.json_create({"a" => ['a', 'd']}) # => "a".."d"
|
|
15
|
+
#
|
|
10
16
|
def self.json_create(object)
|
|
11
17
|
new(*object['a'])
|
|
12
18
|
end
|
|
13
19
|
|
|
14
|
-
# Returns a hash
|
|
15
|
-
#
|
|
20
|
+
# Returns a 2-element hash representing +self+:
|
|
21
|
+
#
|
|
22
|
+
# require 'json/add/range'
|
|
23
|
+
# (1..4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, false]}
|
|
24
|
+
# (1...4).as_json # => {"json_class"=>"Range", "a"=>[1, 4, true]}
|
|
25
|
+
# ('a'..'d').as_json # => {"json_class"=>"Range", "a"=>["a", "d", false]}
|
|
26
|
+
#
|
|
16
27
|
def as_json(*)
|
|
17
28
|
{
|
|
18
29
|
JSON.create_id => self.class.name,
|
|
@@ -20,9 +31,13 @@ class Range
|
|
|
20
31
|
}
|
|
21
32
|
end
|
|
22
33
|
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
34
|
+
# Returns a JSON string representing +self+:
|
|
35
|
+
#
|
|
36
|
+
# require 'json/add/range'
|
|
37
|
+
# (1..4).to_json # => "{\"json_class\":\"Range\",\"a\":[1,4,false]}"
|
|
38
|
+
# (1...4).to_json # => "{\"json_class\":\"Range\",\"a\":[1,4,true]}"
|
|
39
|
+
# ('a'..'d').to_json # => "{\"json_class\":\"Range\",\"a\":[\"a\",\"d\",false]}"
|
|
40
|
+
#
|
|
26
41
|
def to_json(*args)
|
|
27
42
|
as_json.to_json(*args)
|
|
28
43
|
end
|
data/lib/json/common.rb
CHANGED
|
@@ -3,6 +3,9 @@ require 'json/version'
|
|
|
3
3
|
require 'json/generic_object'
|
|
4
4
|
|
|
5
5
|
module JSON
|
|
6
|
+
NOT_SET = Object.new.freeze
|
|
7
|
+
private_constant :NOT_SET
|
|
8
|
+
|
|
6
9
|
class << self
|
|
7
10
|
# :call-seq:
|
|
8
11
|
# JSON[object] -> new_array or new_string
|
|
@@ -295,19 +298,9 @@ module JSON
|
|
|
295
298
|
#
|
|
296
299
|
def generate(obj, opts = nil)
|
|
297
300
|
if State === opts
|
|
298
|
-
state
|
|
301
|
+
state = opts
|
|
299
302
|
else
|
|
300
|
-
state = State.new
|
|
301
|
-
end
|
|
302
|
-
if opts
|
|
303
|
-
if opts.respond_to? :to_hash
|
|
304
|
-
opts = opts.to_hash
|
|
305
|
-
elsif opts.respond_to? :to_h
|
|
306
|
-
opts = opts.to_h
|
|
307
|
-
else
|
|
308
|
-
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
309
|
-
end
|
|
310
|
-
state = state.configure(opts)
|
|
303
|
+
state = State.new(opts)
|
|
311
304
|
end
|
|
312
305
|
state.generate(obj)
|
|
313
306
|
end
|
|
@@ -334,19 +327,9 @@ module JSON
|
|
|
334
327
|
# JSON.fast_generate(a)
|
|
335
328
|
def fast_generate(obj, opts = nil)
|
|
336
329
|
if State === opts
|
|
337
|
-
state
|
|
330
|
+
state = opts
|
|
338
331
|
else
|
|
339
|
-
state = JSON.create_fast_state
|
|
340
|
-
end
|
|
341
|
-
if opts
|
|
342
|
-
if opts.respond_to? :to_hash
|
|
343
|
-
opts = opts.to_hash
|
|
344
|
-
elsif opts.respond_to? :to_h
|
|
345
|
-
opts = opts.to_h
|
|
346
|
-
else
|
|
347
|
-
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
348
|
-
end
|
|
349
|
-
state.configure(opts)
|
|
332
|
+
state = JSON.create_fast_state.configure(opts)
|
|
350
333
|
end
|
|
351
334
|
state.generate(obj)
|
|
352
335
|
end
|
|
@@ -592,13 +575,13 @@ module JSON
|
|
|
592
575
|
# Sets or returns the default options for the JSON.dump method.
|
|
593
576
|
# Initially:
|
|
594
577
|
# opts = JSON.dump_default_options
|
|
595
|
-
# opts # => {:max_nesting=>false, :allow_nan=>true, :
|
|
578
|
+
# opts # => {:max_nesting=>false, :allow_nan=>true, :script_safe=>false}
|
|
596
579
|
attr_accessor :dump_default_options
|
|
597
580
|
end
|
|
598
581
|
self.dump_default_options = {
|
|
599
582
|
:max_nesting => false,
|
|
600
583
|
:allow_nan => true,
|
|
601
|
-
:
|
|
584
|
+
:script_safe => false,
|
|
602
585
|
}
|
|
603
586
|
|
|
604
587
|
# :call-seq:
|
|
@@ -628,7 +611,7 @@ module JSON
|
|
|
628
611
|
# puts File.read(path)
|
|
629
612
|
# Output:
|
|
630
613
|
# {"foo":[0,1],"bar":{"baz":2,"bat":3},"bam":"bad"}
|
|
631
|
-
def dump(obj, anIO = nil, limit = nil)
|
|
614
|
+
def dump(obj, anIO = nil, limit = nil, strict: NOT_SET)
|
|
632
615
|
if anIO and limit.nil?
|
|
633
616
|
anIO = anIO.to_io if anIO.respond_to?(:to_io)
|
|
634
617
|
unless anIO.respond_to?(:write)
|
|
@@ -638,6 +621,7 @@ module JSON
|
|
|
638
621
|
end
|
|
639
622
|
opts = JSON.dump_default_options
|
|
640
623
|
opts = opts.merge(:max_nesting => limit) if limit
|
|
624
|
+
opts[:strict] = strict if NOT_SET != strict
|
|
641
625
|
result = generate(obj, opts)
|
|
642
626
|
if anIO
|
|
643
627
|
anIO.write result
|
data/lib/json/pure/generator.rb
CHANGED
|
@@ -37,25 +37,34 @@ module JSON
|
|
|
37
37
|
'\\' => '\\\\',
|
|
38
38
|
} # :nodoc:
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
ESCAPE_PATTERN = /[\/"\\\x0-\x1f]/n # :nodoc:
|
|
41
|
+
|
|
42
|
+
SCRIPT_SAFE_MAP = MAP.merge(
|
|
41
43
|
'/' => '\\/',
|
|
44
|
+
"\u2028".b => '\u2028',
|
|
45
|
+
"\u2029".b => '\u2029',
|
|
42
46
|
)
|
|
43
47
|
|
|
48
|
+
SCRIPT_SAFE_ESCAPE_PATTERN = Regexp.union(ESCAPE_PATTERN, "\u2028".b, "\u2029".b)
|
|
49
|
+
|
|
44
50
|
# Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
|
|
45
51
|
# UTF16 big endian characters as \u????, and return it.
|
|
46
|
-
def utf8_to_json(string,
|
|
52
|
+
def utf8_to_json(string, script_safe = false) # :nodoc:
|
|
47
53
|
string = string.dup
|
|
48
54
|
string.force_encoding(::Encoding::ASCII_8BIT)
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
if script_safe
|
|
56
|
+
string.gsub!(SCRIPT_SAFE_ESCAPE_PATTERN) { SCRIPT_SAFE_MAP[$&] || $& }
|
|
57
|
+
else
|
|
58
|
+
string.gsub!(ESCAPE_PATTERN) { MAP[$&] || $& }
|
|
59
|
+
end
|
|
51
60
|
string.force_encoding(::Encoding::UTF_8)
|
|
52
61
|
string
|
|
53
62
|
end
|
|
54
63
|
|
|
55
|
-
def utf8_to_json_ascii(string,
|
|
64
|
+
def utf8_to_json_ascii(string, script_safe = false) # :nodoc:
|
|
56
65
|
string = string.dup
|
|
57
66
|
string.force_encoding(::Encoding::ASCII_8BIT)
|
|
58
|
-
map =
|
|
67
|
+
map = script_safe ? SCRIPT_SAFE_MAP : MAP
|
|
59
68
|
string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
|
|
60
69
|
string.gsub!(/(
|
|
61
70
|
(?:
|
|
@@ -115,7 +124,8 @@ module JSON
|
|
|
115
124
|
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
|
116
125
|
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
|
117
126
|
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
|
118
|
-
# * *
|
|
127
|
+
# * *script_safe*: true if U+2028, U+2029 and forward slash (/) should be escaped
|
|
128
|
+
# as to make the JSON object safe to interpolate in a script tag (default: false).
|
|
119
129
|
# * *check_circular*: is deprecated now, use the :max_nesting option instead,
|
|
120
130
|
# * *max_nesting*: sets the maximum level of data structure nesting in
|
|
121
131
|
# the generated JSON, max_nesting = 0 if no maximum should be checked.
|
|
@@ -130,7 +140,8 @@ module JSON
|
|
|
130
140
|
@array_nl = ''
|
|
131
141
|
@allow_nan = false
|
|
132
142
|
@ascii_only = false
|
|
133
|
-
@
|
|
143
|
+
@script_safe = false
|
|
144
|
+
@strict = false
|
|
134
145
|
@buffer_initial_length = 1024
|
|
135
146
|
configure opts
|
|
136
147
|
end
|
|
@@ -158,7 +169,11 @@ module JSON
|
|
|
158
169
|
|
|
159
170
|
# If this attribute is set to true, forward slashes will be escaped in
|
|
160
171
|
# all json strings.
|
|
161
|
-
attr_accessor :
|
|
172
|
+
attr_accessor :script_safe
|
|
173
|
+
|
|
174
|
+
# If this attribute is set to true, attempting to serialize types not
|
|
175
|
+
# supported by the JSON spec will raise a JSON::GeneratorError
|
|
176
|
+
attr_accessor :strict
|
|
162
177
|
|
|
163
178
|
# :stopdoc:
|
|
164
179
|
attr_reader :buffer_initial_length
|
|
@@ -200,8 +215,13 @@ module JSON
|
|
|
200
215
|
end
|
|
201
216
|
|
|
202
217
|
# Returns true, if forward slashes are escaped. Otherwise returns false.
|
|
203
|
-
def
|
|
204
|
-
@
|
|
218
|
+
def script_safe?
|
|
219
|
+
@script_safe
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Returns true, if forward slashes are escaped. Otherwise returns false.
|
|
223
|
+
def strict?
|
|
224
|
+
@strict
|
|
205
225
|
end
|
|
206
226
|
|
|
207
227
|
# Configure this State instance with the Hash _opts_, and return
|
|
@@ -214,7 +234,7 @@ module JSON
|
|
|
214
234
|
else
|
|
215
235
|
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
216
236
|
end
|
|
217
|
-
|
|
237
|
+
opts.each do |key, value|
|
|
218
238
|
instance_variable_set "@#{key}", value
|
|
219
239
|
end
|
|
220
240
|
@indent = opts[:indent] if opts.key?(:indent)
|
|
@@ -226,7 +246,16 @@ module JSON
|
|
|
226
246
|
@ascii_only = opts[:ascii_only] if opts.key?(:ascii_only)
|
|
227
247
|
@depth = opts[:depth] || 0
|
|
228
248
|
@buffer_initial_length ||= opts[:buffer_initial_length]
|
|
229
|
-
|
|
249
|
+
|
|
250
|
+
@script_safe = if opts.key?(:script_safe)
|
|
251
|
+
!!opts[:script_safe]
|
|
252
|
+
elsif opts.key?(:escape_slash)
|
|
253
|
+
!!opts[:escape_slash]
|
|
254
|
+
else
|
|
255
|
+
false
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
@strict = !!opts[:strict] if opts.key?(:strict)
|
|
230
259
|
|
|
231
260
|
if !opts.key?(:max_nesting) # defaults to 100
|
|
232
261
|
@max_nesting = 100
|
|
@@ -243,7 +272,7 @@ module JSON
|
|
|
243
272
|
# passed to the configure method.
|
|
244
273
|
def to_h
|
|
245
274
|
result = {}
|
|
246
|
-
|
|
275
|
+
instance_variables.each do |iv|
|
|
247
276
|
iv = iv.to_s[1..-1]
|
|
248
277
|
result[iv.to_sym] = self[iv]
|
|
249
278
|
end
|
|
@@ -287,7 +316,13 @@ module JSON
|
|
|
287
316
|
# Converts this object to a string (calling #to_s), converts
|
|
288
317
|
# it to a JSON string, and returns the result. This is a fallback, if no
|
|
289
318
|
# special method #to_json was defined for some object.
|
|
290
|
-
def to_json(
|
|
319
|
+
def to_json(generator_state)
|
|
320
|
+
if generator_state.strict?
|
|
321
|
+
raise GeneratorError, "#{self.class} not allowed in JSON"
|
|
322
|
+
else
|
|
323
|
+
to_s.to_json
|
|
324
|
+
end
|
|
325
|
+
end
|
|
291
326
|
end
|
|
292
327
|
|
|
293
328
|
module Hash
|
|
@@ -310,21 +345,18 @@ module JSON
|
|
|
310
345
|
end
|
|
311
346
|
|
|
312
347
|
def json_transform(state)
|
|
313
|
-
delim =
|
|
314
|
-
|
|
315
|
-
result = '{'
|
|
316
|
-
result << state.object_nl
|
|
348
|
+
delim = ",#{state.object_nl}"
|
|
349
|
+
result = "{#{state.object_nl}"
|
|
317
350
|
depth = state.depth += 1
|
|
318
351
|
first = true
|
|
319
352
|
indent = !state.object_nl.empty?
|
|
320
|
-
each { |key,value|
|
|
353
|
+
each { |key, value|
|
|
321
354
|
result << delim unless first
|
|
322
355
|
result << state.indent * depth if indent
|
|
323
|
-
result
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
if value.respond_to?(:to_json)
|
|
356
|
+
result = "#{result}#{key.to_s.to_json(state)}#{state.space_before}:#{state.space}"
|
|
357
|
+
if state.strict?
|
|
358
|
+
raise GeneratorError, "#{value.class} not allowed in JSON"
|
|
359
|
+
elsif value.respond_to?(:to_json)
|
|
328
360
|
result << value.to_json(state)
|
|
329
361
|
else
|
|
330
362
|
result << %{"#{String(value)}"}
|
|
@@ -365,7 +397,9 @@ module JSON
|
|
|
365
397
|
each { |value|
|
|
366
398
|
result << delim unless first
|
|
367
399
|
result << state.indent * depth if indent
|
|
368
|
-
if
|
|
400
|
+
if state.strict?
|
|
401
|
+
raise GeneratorError, "#{value.class} not allowed in JSON"
|
|
402
|
+
elsif value.respond_to?(:to_json)
|
|
369
403
|
result << value.to_json(state)
|
|
370
404
|
else
|
|
371
405
|
result << %{"#{String(value)}"}
|
|
@@ -419,9 +453,9 @@ module JSON
|
|
|
419
453
|
string = encode(::Encoding::UTF_8)
|
|
420
454
|
end
|
|
421
455
|
if state.ascii_only?
|
|
422
|
-
'"' << JSON.utf8_to_json_ascii(string, state.
|
|
456
|
+
'"' << JSON.utf8_to_json_ascii(string, state.script_safe) << '"'
|
|
423
457
|
else
|
|
424
|
-
'"' << JSON.utf8_to_json(string, state.
|
|
458
|
+
'"' << JSON.utf8_to_json(string, state.script_safe) << '"'
|
|
425
459
|
end
|
|
426
460
|
end
|
|
427
461
|
|
data/lib/json/pure/parser.rb
CHANGED
|
@@ -179,7 +179,7 @@ module JSON
|
|
|
179
179
|
bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
|
|
180
180
|
i += 1
|
|
181
181
|
end
|
|
182
|
-
JSON.iconv('utf-8', 'utf-16be', bytes)
|
|
182
|
+
JSON.iconv('utf-8', 'utf-16be', bytes).force_encoding(::Encoding::ASCII_8BIT)
|
|
183
183
|
end
|
|
184
184
|
end
|
|
185
185
|
if string.respond_to?(:force_encoding)
|
data/lib/json/version.rb
CHANGED