json 2.8.1 → 2.9.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.
@@ -26,19 +26,6 @@ static const char deprecated_create_additions_warning[] =
26
26
  "and will be removed in 3.0, use JSON.unsafe_load or explicitly "
27
27
  "pass `create_additions: true`";
28
28
 
29
- #ifndef HAVE_RB_GC_MARK_LOCATIONS
30
- // For TruffleRuby
31
- void rb_gc_mark_locations(const VALUE *start, const VALUE *end)
32
- {
33
- VALUE *value = start;
34
-
35
- while (value < end) {
36
- rb_gc_mark(*value);
37
- value++;
38
- }
39
- }
40
- #endif
41
-
42
29
  #ifndef HAVE_RB_HASH_BULK_INSERT
43
30
  // For TruffleRuby
44
31
  void rb_hash_bulk_insert(long count, const VALUE *pairs, VALUE hash)
@@ -264,7 +251,10 @@ static inline void rvalue_stack_pop(rvalue_stack *stack, long count)
264
251
  static void rvalue_stack_mark(void *ptr)
265
252
  {
266
253
  rvalue_stack *stack = (rvalue_stack *)ptr;
267
- rb_gc_mark_locations(stack->ptr, stack->ptr + stack->head);
254
+ long index;
255
+ for (index = 0; index < stack->head; index++) {
256
+ rb_gc_mark(stack->ptr[index]);
257
+ }
268
258
  }
269
259
 
270
260
  static void rvalue_stack_free(void *ptr)
@@ -392,6 +382,7 @@ typedef struct JSON_ParserStruct {
392
382
  VALUE decimal_class;
393
383
  VALUE match_string;
394
384
  FBuffer fbuffer;
385
+ int in_array;
395
386
  int max_nesting;
396
387
  bool allow_nan;
397
388
  bool allow_trailing_comma;
@@ -420,8 +411,7 @@ static const rb_data_type_t JSON_Parser_type;
420
411
  static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
421
412
  static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
422
413
  static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
423
- static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result);
424
- static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result);
414
+ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result);
425
415
  static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
426
416
 
427
417
 
@@ -627,11 +617,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
627
617
  raise_parse_error("unexpected token at '%s'", p);
628
618
  }
629
619
  }
630
- np = JSON_parse_float(json, fpc, pe, result);
631
- if (np != NULL) {
632
- fexec np;
633
- }
634
- np = JSON_parse_integer(json, fpc, pe, result);
620
+ np = JSON_parse_number(json, fpc, pe, result);
635
621
  if (np != NULL) {
636
622
  fexec np;
637
623
  }
@@ -640,7 +626,9 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
640
626
 
641
627
  action parse_array {
642
628
  char *np;
629
+ json->in_array++;
643
630
  np = JSON_parse_array(json, fpc, pe, result, current_nesting + 1);
631
+ json->in_array--;
644
632
  if (np == NULL) { fhold; fbreak; } else fexec np;
645
633
  }
646
634
 
@@ -716,15 +704,8 @@ static inline VALUE fast_parse_integer(char *p, char *pe)
716
704
  return LL2NUM(memo);
717
705
  }
718
706
 
719
- static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result)
707
+ static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result)
720
708
  {
721
- int cs = EVIL;
722
-
723
- %% write init;
724
- json->memo = p;
725
- %% write exec;
726
-
727
- if (cs >= JSON_integer_first_final) {
728
709
  long len = p - json->memo;
729
710
  if (RB_LIKELY(len < MAX_FAST_INTEGER_SIZE)) {
730
711
  *result = fast_parse_integer(json->memo, p);
@@ -735,9 +716,6 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
735
716
  *result = rb_cstr2inum(FBUFFER_PTR(&json->fbuffer), 10);
736
717
  }
737
718
  return p + 1;
738
- } else {
739
- return NULL;
740
- }
741
719
  }
742
720
 
743
721
  %%{
@@ -747,22 +725,28 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
747
725
  write data;
748
726
 
749
727
  action exit { fhold; fbreak; }
728
+ action isFloat { is_float = true; }
750
729
 
751
730
  main := '-'? (
752
- (('0' | [1-9][0-9]*) '.' [0-9]+ ([Ee] [+\-]?[0-9]+)?)
753
- | (('0' | [1-9][0-9]*) ([Ee] [+\-]?[0-9]+))
754
- ) (^[0-9Ee.\-]? @exit );
731
+ (('0' | [1-9][0-9]*)
732
+ ((('.' [0-9]+ ([Ee] [+\-]?[0-9]+)?) |
733
+ ([Ee] [+\-]?[0-9]+)) > isFloat)?
734
+ ) (^[0-9Ee.\-]? @exit ));
755
735
  }%%
756
736
 
757
- static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
737
+ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result)
758
738
  {
759
739
  int cs = EVIL;
740
+ bool is_float = false;
760
741
 
761
742
  %% write init;
762
743
  json->memo = p;
763
744
  %% write exec;
764
745
 
765
746
  if (cs >= JSON_float_first_final) {
747
+ if (!is_float) {
748
+ return JSON_decode_integer(json, p, result);
749
+ }
766
750
  VALUE mod = Qnil;
767
751
  ID method_id = 0;
768
752
  if (json->decimal_class) {
@@ -906,7 +890,7 @@ static VALUE json_string_fastpath(JSON_Parser *json, char *string, char *stringE
906
890
  {
907
891
  size_t bufferSize = stringEnd - string;
908
892
 
909
- if (is_name) {
893
+ if (is_name && json->in_array) {
910
894
  VALUE cached_key;
911
895
  if (RB_UNLIKELY(symbolize)) {
912
896
  cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize);
@@ -929,7 +913,7 @@ static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringE
929
913
  int unescape_len;
930
914
  char buf[4];
931
915
 
932
- if (is_name) {
916
+ if (is_name && json->in_array) {
933
917
  VALUE cached_key;
934
918
  if (RB_UNLIKELY(symbolize)) {
935
919
  cached_key = rsymbol_cache_fetch(&json->name_cache, string, bufferSize);
@@ -1355,8 +1339,10 @@ static void JSON_mark(void *ptr)
1355
1339
  rb_gc_mark(json->match_string);
1356
1340
  rb_gc_mark(json->stack_handle);
1357
1341
 
1358
- const VALUE *name_cache_entries = &json->name_cache.entries[0];
1359
- rb_gc_mark_locations(name_cache_entries, name_cache_entries + json->name_cache.length);
1342
+ long index;
1343
+ for (index = 0; index < json->name_cache.length; index++) {
1344
+ rb_gc_mark(json->name_cache.entries[index]);
1345
+ }
1360
1346
  }
1361
1347
 
1362
1348
  static void JSON_free(void *ptr)
data/lib/json/common.rb CHANGED
@@ -1,4 +1,5 @@
1
- #frozen_string_literal: true
1
+ # frozen_string_literal: true
2
+
2
3
  require 'json/version'
3
4
 
4
5
  module JSON
@@ -25,7 +26,7 @@ module JSON
25
26
  elsif object.respond_to?(:to_str)
26
27
  str = object.to_str
27
28
  if str.is_a?(String)
28
- return JSON.parse(object.to_str, opts)
29
+ return JSON.parse(str, opts)
29
30
  end
30
31
  end
31
32
 
@@ -142,7 +143,23 @@ module JSON
142
143
  # :startdoc:
143
144
 
144
145
  # This exception is raised if a generator or unparser error occurs.
145
- class GeneratorError < JSONError; end
146
+ class GeneratorError < JSONError
147
+ attr_reader :invalid_object
148
+
149
+ def initialize(message, invalid_object = nil)
150
+ super(message)
151
+ @invalid_object = invalid_object
152
+ end
153
+
154
+ def detailed_message(...)
155
+ if @invalid_object.nil?
156
+ super
157
+ else
158
+ "#{super}\nInvalid object: #{@invalid_object.inspect}"
159
+ end
160
+ end
161
+ end
162
+
146
163
  # For backwards compatibility
147
164
  UnparserError = GeneratorError # :nodoc:
148
165
 
@@ -230,8 +247,8 @@ module JSON
230
247
  # parse(File.read(path), opts)
231
248
  #
232
249
  # See method #parse.
233
- def load_file(filespec, opts = {})
234
- parse(File.read(filespec), opts)
250
+ def load_file(filespec, opts = nil)
251
+ parse(File.read(filespec, encoding: Encoding::UTF_8), opts)
235
252
  end
236
253
 
237
254
  # :call-seq:
@@ -242,7 +259,7 @@ module JSON
242
259
  #
243
260
  # See method #parse!
244
261
  def load_file!(filespec, opts = {})
245
- parse!(File.read(filespec), opts)
262
+ parse!(File.read(filespec, encoding: Encoding::UTF_8), opts)
246
263
  end
247
264
 
248
265
  # :call-seq:
@@ -285,7 +302,7 @@ module JSON
285
302
  if State === opts
286
303
  opts.generate(obj)
287
304
  else
288
- State.generate(obj, opts)
305
+ State.generate(obj, opts, nil)
289
306
  end
290
307
  end
291
308
 
@@ -410,6 +427,10 @@ module JSON
410
427
  #
411
428
  # Returns the Ruby objects created by parsing the given +source+.
412
429
  #
430
+ # BEWARE: This method is meant to serialise data from trusted user input,
431
+ # like from your own database server or clients under your control, it could
432
+ # be dangerous to allow untrusted users to pass JSON sources into it.
433
+ #
413
434
  # - Argument +source+ must be, or be convertible to, a \String:
414
435
  # - If +source+ responds to instance method +to_str+,
415
436
  # <tt>source.to_str</tt> becomes the source.
@@ -424,9 +445,6 @@ module JSON
424
445
  # - Argument +proc+, if given, must be a \Proc that accepts one argument.
425
446
  # It will be called recursively with each result (depth-first order).
426
447
  # See details below.
427
- # BEWARE: This method is meant to serialise data from trusted user input,
428
- # like from your own database server or clients under your control, it could
429
- # be dangerous to allow untrusted users to pass JSON sources into it.
430
448
  # - Argument +opts+, if given, contains a \Hash of options for the parsing.
431
449
  # See {Parsing Options}[#module-JSON-label-Parsing+Options].
432
450
  # The default options can be changed via method JSON.unsafe_load_default_options=.
@@ -563,6 +581,16 @@ module JSON
563
581
  #
564
582
  # Returns the Ruby objects created by parsing the given +source+.
565
583
  #
584
+ # BEWARE: This method is meant to serialise data from trusted user input,
585
+ # like from your own database server or clients under your control, it could
586
+ # be dangerous to allow untrusted users to pass JSON sources into it.
587
+ # If you must use it, use JSON.unsafe_load instead to make it clear.
588
+ #
589
+ # Since JSON version 2.8.0, `load` emits a deprecation warning when a
590
+ # non native type is deserialized, without `create_additions` being explicitly
591
+ # enabled, and in JSON version 3.0, `load` will have `create_additions` disabled
592
+ # by default.
593
+ #
566
594
  # - Argument +source+ must be, or be convertible to, a \String:
567
595
  # - If +source+ responds to instance method +to_str+,
568
596
  # <tt>source.to_str</tt> becomes the source.
@@ -577,10 +605,6 @@ module JSON
577
605
  # - Argument +proc+, if given, must be a \Proc that accepts one argument.
578
606
  # It will be called recursively with each result (depth-first order).
579
607
  # See details below.
580
- # BEWARE: This method is meant to serialise data from trusted user input,
581
- # like from your own database server or clients under your control, it could
582
- # be dangerous to allow untrusted users to pass JSON sources into it.
583
- # If you must use it, use JSON.unsafe_load instead to make it clear.
584
608
  # - Argument +opts+, if given, contains a \Hash of options for the parsing.
585
609
  # See {Parsing Options}[#module-JSON-label-Parsing+Options].
586
610
  # The default options can be changed via method JSON.load_default_options=.
@@ -793,18 +817,15 @@ module JSON
793
817
  opts = opts.merge(:max_nesting => limit) if limit
794
818
  opts = merge_dump_options(opts, **kwargs) if kwargs
795
819
 
796
- result = begin
797
- generate(obj, opts)
820
+ begin
821
+ if State === opts
822
+ opts.generate(obj, anIO)
823
+ else
824
+ State.generate(obj, opts, anIO)
825
+ end
798
826
  rescue JSON::NestingError
799
827
  raise ArgumentError, "exceed depth limit"
800
828
  end
801
-
802
- if anIO.nil?
803
- result
804
- else
805
- anIO.write result
806
- anIO
807
- end
808
829
  end
809
830
 
810
831
  # Encodes string using String.encode.
@@ -47,6 +47,17 @@ module JSON
47
47
 
48
48
  alias_method :merge, :configure
49
49
 
50
+ # call-seq:
51
+ # generate(obj) -> String
52
+ # generate(obj, anIO) -> anIO
53
+ #
54
+ # Generates a valid JSON document from object +obj+ and returns the
55
+ # result. If no valid JSON document can be created this method raises a
56
+ # GeneratorError exception.
57
+ def generate(obj, io = nil)
58
+ _generate(obj, io)
59
+ end
60
+
50
61
  # call-seq: to_h
51
62
  #
52
63
  # Returns the configuration instance variables as a hash, that can be
@@ -62,8 +62,8 @@ module JSON
62
62
  string
63
63
  end
64
64
 
65
- def utf8_to_json_ascii(string, script_safe = false) # :nodoc:
66
- string = string.b
65
+ def utf8_to_json_ascii(original_string, script_safe = false) # :nodoc:
66
+ string = original_string.b
67
67
  map = script_safe ? SCRIPT_SAFE_MAP : MAP
68
68
  string.gsub!(/[\/"\\\x0-\x1f]/n) { map[$&] || $& }
69
69
  string.gsub!(/(
@@ -74,7 +74,7 @@ module JSON
74
74
  )+ |
75
75
  [\x80-\xc1\xf5-\xff] # invalid
76
76
  )/nx) { |c|
77
- c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
77
+ c.size == 1 and raise GeneratorError.new("invalid utf8 byte: '#{c}'", original_string)
78
78
  s = c.encode(::Encoding::UTF_16BE, ::Encoding::UTF_8).unpack('H*')[0]
79
79
  s.force_encoding(::Encoding::BINARY)
80
80
  s.gsub!(/.{4}/n, '\\\\u\&')
@@ -83,7 +83,7 @@ module JSON
83
83
  string.force_encoding(::Encoding::UTF_8)
84
84
  string
85
85
  rescue => e
86
- raise GeneratorError.wrap(e)
86
+ raise GeneratorError.new(e.message, original_string)
87
87
  end
88
88
 
89
89
  def valid_utf8?(string)
@@ -96,8 +96,14 @@ module JSON
96
96
  # This class is used to create State instances, that are use to hold data
97
97
  # while generating a JSON text from a Ruby data structure.
98
98
  class State
99
- def self.generate(obj, opts = nil)
100
- new(opts).generate(obj)
99
+ def self.generate(obj, opts = nil, io = nil)
100
+ string = new(opts).generate(obj)
101
+ if io
102
+ io.write(string)
103
+ io
104
+ else
105
+ string
106
+ end
101
107
  end
102
108
 
103
109
  # Creates a State object from _opts_, which ought to be Hash to create
@@ -300,8 +306,10 @@ module JSON
300
306
  else
301
307
  result = obj.to_json(self)
302
308
  end
303
- JSON::TruffleRuby::Generator.valid_utf8?(result) or raise GeneratorError,
304
- "source sequence #{result.inspect} is illegal/malformed utf-8"
309
+ JSON::TruffleRuby::Generator.valid_utf8?(result) or raise GeneratorError.new(
310
+ "source sequence #{result.inspect} is illegal/malformed utf-8",
311
+ obj
312
+ )
305
313
  result
306
314
  end
307
315
 
@@ -358,10 +366,10 @@ module JSON
358
366
  begin
359
367
  string = string.encode(::Encoding::UTF_8)
360
368
  rescue Encoding::UndefinedConversionError => error
361
- raise GeneratorError, error.message
369
+ raise GeneratorError.new(error.message, string)
362
370
  end
363
371
  end
364
- raise GeneratorError, "source sequence is illegal/malformed utf-8" unless string.valid_encoding?
372
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", string) unless string.valid_encoding?
365
373
 
366
374
  if /["\\\x0-\x1f]/n.match?(string)
367
375
  buf << string.gsub(/["\\\x0-\x1f]/n, MAP)
@@ -397,7 +405,7 @@ module JSON
397
405
  # special method #to_json was defined for some object.
398
406
  def to_json(state = nil, *)
399
407
  if state && State.from_state(state).strict?
400
- raise GeneratorError, "#{self.class} not allowed in JSON"
408
+ raise GeneratorError.new("#{self.class} not allowed in JSON", self)
401
409
  else
402
410
  to_s.to_json
403
411
  end
@@ -448,7 +456,7 @@ module JSON
448
456
 
449
457
  result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
450
458
  if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
451
- raise GeneratorError, "#{value.class} not allowed in JSON"
459
+ raise GeneratorError.new("#{value.class} not allowed in JSON", value)
452
460
  elsif value.respond_to?(:to_json)
453
461
  result << value.to_json(state)
454
462
  else
@@ -501,7 +509,7 @@ module JSON
501
509
  result << delim unless first
502
510
  result << state.indent * depth if indent
503
511
  if state.strict? && !(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value)
504
- raise GeneratorError, "#{value.class} not allowed in JSON"
512
+ raise GeneratorError.new("#{value.class} not allowed in JSON", value)
505
513
  elsif value.respond_to?(:to_json)
506
514
  result << value.to_json(state)
507
515
  else
@@ -530,13 +538,13 @@ module JSON
530
538
  if state.allow_nan?
531
539
  to_s
532
540
  else
533
- raise GeneratorError, "#{self} not allowed in JSON"
541
+ raise GeneratorError.new("#{self} not allowed in JSON", self)
534
542
  end
535
543
  when nan?
536
544
  if state.allow_nan?
537
545
  to_s
538
546
  else
539
- raise GeneratorError, "#{self} not allowed in JSON"
547
+ raise GeneratorError.new("#{self} not allowed in JSON", self)
540
548
  end
541
549
  else
542
550
  to_s
@@ -552,7 +560,7 @@ module JSON
552
560
  state = State.from_state(state)
553
561
  if encoding == ::Encoding::UTF_8
554
562
  unless valid_encoding?
555
- raise GeneratorError, "source sequence is illegal/malformed utf-8"
563
+ raise GeneratorError.new("source sequence is illegal/malformed utf-8", self)
556
564
  end
557
565
  string = self
558
566
  else
@@ -564,7 +572,7 @@ module JSON
564
572
  %("#{JSON::TruffleRuby::Generator.utf8_to_json(string, state.script_safe)}")
565
573
  end
566
574
  rescue Encoding::UndefinedConversionError => error
567
- raise ::JSON::GeneratorError, error.message
575
+ raise ::JSON::GeneratorError.new(error.message, self)
568
576
  end
569
577
 
570
578
  # Module that holds the extending methods if, the String module is
data/lib/json/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSON
4
- VERSION = '2.8.1'
4
+ VERSION = '2.9.0'
5
5
  end
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.8.1
4
+ version: 2.9.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: 2024-11-06 00:00:00.000000000 Z
11
+ date: 2024-12-03 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