json 2.6.3 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -229,7 +229,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
229
229
  if (json->allow_nan) {
230
230
  *result = CInfinity;
231
231
  } else {
232
- rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 8);
232
+ rb_enc_raise(EXC_ENCODING eParserError, "unexpected token at '%s'", p - 7);
233
233
  }
234
234
  }
235
235
  action parse_string {
@@ -508,7 +508,7 @@ 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,
@@ -521,7 +521,7 @@ 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,
@@ -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
  {
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
 
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.3'
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:
data/lib/json.rb CHANGED
@@ -285,6 +285,15 @@ require 'json/common'
285
285
  # # Raises JSON::NestingError (nesting of 2 is too deep):
286
286
  # JSON.generate(obj, max_nesting: 2)
287
287
  #
288
+ # ====== Escaping Options
289
+ #
290
+ # Options +script_safe+ (boolean) specifies wether <tt>'\u2028'</tt>, <tt>'\u2029'</tt>
291
+ # and <tt>'/'</tt> should be escaped as to make the JSON object safe to interpolate in script
292
+ # tags.
293
+ #
294
+ # Options +ascii_only+ (boolean) specifies wether all characters outside the ASCII range
295
+ # should be escaped.
296
+ #
288
297
  # ====== Output Options
289
298
  #
290
299
  # The default formatting options generate the most compact
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.3
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-05 00:00:00.000000000 Z
11
+ date: 2023-12-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: This is a JSON implementation as a Ruby extension in C.
14
14
  email: flori@ping.de
@@ -58,14 +58,14 @@ files:
58
58
  - lib/json/pure/generator.rb
59
59
  - lib/json/pure/parser.rb
60
60
  - lib/json/version.rb
61
- homepage: http://flori.github.com/json
61
+ homepage: https://flori.github.io/json
62
62
  licenses:
63
63
  - Ruby
64
64
  metadata:
65
65
  bug_tracker_uri: https://github.com/flori/json/issues
66
66
  changelog_uri: https://github.com/flori/json/blob/master/CHANGES.md
67
- documentation_uri: http://flori.github.io/json/doc/index.html
68
- homepage_uri: http://flori.github.io/json/
67
+ documentation_uri: https://flori.github.io/json/doc/index.html
68
+ homepage_uri: https://flori.github.io/json
69
69
  source_code_uri: https://github.com/flori/json
70
70
  wiki_uri: https://github.com/flori/json/wiki
71
71
  post_install_message:
@@ -87,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
87
87
  - !ruby/object:Gem::Version
88
88
  version: '0'
89
89
  requirements: []
90
- rubygems_version: 3.4.0.dev
90
+ rubygems_version: 3.5.0.dev
91
91
  signing_key:
92
92
  specification_version: 4
93
93
  summary: JSON Implementation for Ruby