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.
@@ -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, "%u: unexpected token at '%s'", __LINE__, p - 2);
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, "%u: unexpected token at '%s'", __LINE__, p - 8);
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, "%u: unexpected token at '%s'", __LINE__, p);
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, "%u: unexpected token at '%s'", __LINE__, p);
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
- free(bufferStart);
511
+ ruby_xfree(bufferStart);
512
512
  }
513
513
  rb_enc_raise(
514
514
  EXC_ENCODING eParserError,
515
- "%u: incomplete unicode character escape sequence at '%s'", __LINE__, p
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
- free(bufferStart);
524
+ ruby_xfree(bufferStart);
525
525
  }
526
526
  rb_enc_raise(
527
527
  EXC_ENCODING eParserError,
528
- "%u: incomplete surrogate pair at '%s'", __LINE__, p
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
- free(bufferStart);
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
- free(bufferStart);
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
- #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
731
- opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
732
- if (NIL_P(opts)) {
733
- rb_raise(rb_eArgError, "opts needs to be like a hash");
734
- } else {
735
- #endif
736
- VALUE tmp = ID2SYM(i_max_nesting);
737
- if (option_given_p(opts, tmp)) {
738
- VALUE max_nesting = rb_hash_aref(opts, tmp);
739
- if (RTEST(max_nesting)) {
740
- Check_Type(max_nesting, T_FIXNUM);
741
- json->max_nesting = FIX2INT(max_nesting);
742
- } else {
743
- json->max_nesting = 0;
744
- }
745
- } else {
746
- json->max_nesting = 100;
747
- }
748
- tmp = ID2SYM(i_allow_nan);
749
- if (option_given_p(opts, tmp)) {
750
- json->allow_nan = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
751
- } else {
752
- json->allow_nan = 0;
753
- }
754
- tmp = ID2SYM(i_symbolize_names);
755
- if (option_given_p(opts, tmp)) {
756
- json->symbolize_names = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
757
- } else {
758
- json->symbolize_names = 0;
759
- }
760
- tmp = ID2SYM(i_freeze);
761
- if (option_given_p(opts, tmp)) {
762
- json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
763
- } else {
764
- json->freeze = 0;
765
- }
766
- tmp = ID2SYM(i_create_additions);
767
- if (option_given_p(opts, tmp)) {
768
- json->create_additions = RTEST(rb_hash_aref(opts, tmp));
769
- } else {
770
- json->create_additions = 0;
771
- }
772
- if (json->symbolize_names && json->create_additions) {
773
- rb_raise(rb_eArgError,
774
- "options :symbolize_names and :create_additions cannot be "
775
- " used in conjunction");
776
- }
777
- tmp = ID2SYM(i_create_id);
778
- if (option_given_p(opts, tmp)) {
779
- json->create_id = rb_hash_aref(opts, tmp);
780
- } else {
781
- json->create_id = rb_funcall(mJSON, i_create_id, 0);
782
- }
783
- tmp = ID2SYM(i_object_class);
784
- if (option_given_p(opts, tmp)) {
785
- json->object_class = rb_hash_aref(opts, tmp);
786
- } else {
787
- json->object_class = Qnil;
788
- }
789
- tmp = ID2SYM(i_array_class);
790
- if (option_given_p(opts, tmp)) {
791
- json->array_class = rb_hash_aref(opts, tmp);
792
- } else {
793
- json->array_class = Qnil;
794
- }
795
- tmp = ID2SYM(i_decimal_class);
796
- if (option_given_p(opts, tmp)) {
797
- json->decimal_class = rb_hash_aref(opts, tmp);
798
- } else {
799
- json->decimal_class = Qnil;
800
- }
801
- tmp = ID2SYM(i_match_string);
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 = rb_funcall(mJSON, i_create_id, 0);
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::ParseError if fail to parse.
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, "%u: unexpected token at '%s'", __LINE__, p);
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 = "http://flori.github.com/json"
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' => 'http://flori.github.io/json/doc/index.html',
61
- 'homepage_uri' => 'http://flori.github.io/json/',
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
  }
@@ -2,7 +2,10 @@
2
2
  unless defined?(::JSON::JSON_LOADED) and ::JSON::JSON_LOADED
3
3
  require 'json'
4
4
  end
5
- defined?(::BigDecimal) or require 'bigdecimal'
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)
@@ -5,14 +5,25 @@ end
5
5
 
6
6
  class Range
7
7
 
8
- # Deserializes JSON string by constructing new Range object with arguments
9
- # <tt>a</tt> serialized by <tt>to_json</tt>.
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, that will be turned into a JSON object and represent this
15
- # object.
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
- # Stores class name (Range) with JSON array of arguments <tt>a</tt> which
24
- # include <tt>first</tt> (integer), <tt>last</tt> (integer), and
25
- # <tt>exclude_end?</tt> (boolean) as JSON string.
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, opts = opts, nil
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, opts = opts, nil
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, :escape_slash=>false}
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
- :escape_slash => false,
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
@@ -37,25 +37,34 @@ module JSON
37
37
  '\\' => '\\\\',
38
38
  } # :nodoc:
39
39
 
40
- ESCAPE_SLASH_MAP = MAP.merge(
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, escape_slash = false) # :nodoc:
52
+ def utf8_to_json(string, script_safe = false) # :nodoc:
47
53
  string = string.dup
48
54
  string.force_encoding(::Encoding::ASCII_8BIT)
49
- map = escape_slash ? ESCAPE_SLASH_MAP : MAP
50
- string.gsub!(/[\/"\\\x0-\x1f]/) { map[$&] || $& }
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, escape_slash = false) # :nodoc:
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 = escape_slash ? ESCAPE_SLASH_MAP : 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
- # * *escape_slash*: true if forward slash (/) should be escaped (default: false)
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
- @escape_slash = false
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 :escape_slash
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 escape_slash?
204
- @escape_slash
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
- for key, value in opts
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
- @escape_slash = !!opts[:escape_slash] if opts.key?(:escape_slash)
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
- for iv in instance_variables
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(*) to_s.to_json end
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
- delim << state.object_nl
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 << key.to_s.to_json(state)
324
- result << state.space_before
325
- result << ':'
326
- result << state.space
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 value.respond_to?(:to_json)
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.escape_slash) << '"'
456
+ '"' << JSON.utf8_to_json_ascii(string, state.script_safe) << '"'
423
457
  else
424
- '"' << JSON.utf8_to_json(string, state.escape_slash) << '"'
458
+ '"' << JSON.utf8_to_json(string, state.script_safe) << '"'
425
459
  end
426
460
  end
427
461
 
@@ -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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
  module JSON
3
3
  # JSON version
4
- VERSION = '2.6.2'
4
+ VERSION = '2.7.0'
5
5
  VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
6
6
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
7
7
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc: