json 2.18.1 → 2.19.4

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.
data/ext/json/ext/json.h CHANGED
@@ -54,9 +54,24 @@ typedef unsigned char _Bool;
54
54
  # define RUBY_TYPED_FROZEN_SHAREABLE 0
55
55
  #endif
56
56
 
57
+ #ifdef RUBY_TYPED_EMBEDDABLE
58
+ # define HAVE_RUBY_TYPED_EMBEDDABLE 1
59
+ #else
60
+ # ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
61
+ # define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
62
+ # define HAVE_RUBY_TYPED_EMBEDDABLE 1
63
+ # else
64
+ # define RUBY_TYPED_EMBEDDABLE 0
65
+ # endif
66
+ #endif
67
+
57
68
  #ifndef NORETURN
69
+ #if defined(__has_attribute) && __has_attribute(noreturn)
70
+ #define NORETURN(x) __attribute__((noreturn)) x
71
+ #else
58
72
  #define NORETURN(x) x
59
73
  #endif
74
+ #endif
60
75
 
61
76
  #ifndef NOINLINE
62
77
  #if defined(__has_attribute) && __has_attribute(noinline)
@@ -7,6 +7,10 @@ have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
7
7
  have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2
8
8
  have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby
9
9
 
10
+ if RUBY_ENGINE == "ruby"
11
+ have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
12
+ end
13
+
10
14
  append_cflags("-std=c99")
11
15
 
12
16
  if enable_config('parser-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
@@ -7,8 +7,9 @@ static VALUE CNaN, CInfinity, CMinusInfinity;
7
7
 
8
8
  static ID i_new, i_try_convert, i_uminus, i_encode;
9
9
 
10
- static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters, sym_symbolize_names, sym_freeze,
11
- sym_decimal_class, sym_on_load, sym_allow_duplicate_key;
10
+ static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters,
11
+ sym_allow_invalid_escape, sym_symbolize_names, sym_freeze, sym_decimal_class, sym_on_load,
12
+ sym_allow_duplicate_key;
12
13
 
13
14
  static int binary_encindex;
14
15
  static int utf8_encindex;
@@ -240,17 +241,27 @@ static void rvalue_stack_mark(void *ptr)
240
241
  {
241
242
  rvalue_stack *stack = (rvalue_stack *)ptr;
242
243
  long index;
243
- for (index = 0; index < stack->head; index++) {
244
- rb_gc_mark(stack->ptr[index]);
244
+ if (stack && stack->ptr) {
245
+ for (index = 0; index < stack->head; index++) {
246
+ rb_gc_mark(stack->ptr[index]);
247
+ }
245
248
  }
246
249
  }
247
250
 
251
+ static void rvalue_stack_free_buffer(rvalue_stack *stack)
252
+ {
253
+ ruby_xfree(stack->ptr);
254
+ stack->ptr = NULL;
255
+ }
256
+
248
257
  static void rvalue_stack_free(void *ptr)
249
258
  {
250
259
  rvalue_stack *stack = (rvalue_stack *)ptr;
251
260
  if (stack) {
252
- ruby_xfree(stack->ptr);
261
+ rvalue_stack_free_buffer(stack);
262
+ #ifndef HAVE_RUBY_TYPED_EMBEDDABLE
253
263
  ruby_xfree(stack);
264
+ #endif
254
265
  }
255
266
  }
256
267
 
@@ -261,14 +272,13 @@ static size_t rvalue_stack_memsize(const void *ptr)
261
272
  }
262
273
 
263
274
  static const rb_data_type_t JSON_Parser_rvalue_stack_type = {
264
- "JSON::Ext::Parser/rvalue_stack",
265
- {
275
+ .wrap_struct_name = "JSON::Ext::Parser/rvalue_stack",
276
+ .function = {
266
277
  .dmark = rvalue_stack_mark,
267
278
  .dfree = rvalue_stack_free,
268
279
  .dsize = rvalue_stack_memsize,
269
280
  },
270
- 0, 0,
271
- RUBY_TYPED_FREE_IMMEDIATELY,
281
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE,
272
282
  };
273
283
 
274
284
  static rvalue_stack *rvalue_stack_spill(rvalue_stack *old_stack, VALUE *handle, rvalue_stack **stack_ref)
@@ -290,8 +300,12 @@ static void rvalue_stack_eagerly_release(VALUE handle)
290
300
  if (handle) {
291
301
  rvalue_stack *stack;
292
302
  TypedData_Get_Struct(handle, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack);
293
- RTYPEDDATA_DATA(handle) = NULL;
303
+ #ifdef HAVE_RUBY_TYPED_EMBEDDABLE
304
+ rvalue_stack_free_buffer(stack);
305
+ #else
294
306
  rvalue_stack_free(stack);
307
+ RTYPEDDATA_DATA(handle) = NULL;
308
+ #endif
295
309
  }
296
310
  }
297
311
 
@@ -336,12 +350,13 @@ typedef struct JSON_ParserStruct {
336
350
  bool allow_nan;
337
351
  bool allow_trailing_comma;
338
352
  bool allow_control_characters;
353
+ bool allow_invalid_escape;
339
354
  bool symbolize_names;
340
355
  bool freeze;
341
356
  } JSON_ParserConfig;
342
357
 
343
358
  typedef struct JSON_ParserStateStruct {
344
- VALUE stack_handle;
359
+ VALUE *stack_handle;
345
360
  const char *start;
346
361
  const char *cursor;
347
362
  const char *end;
@@ -400,14 +415,9 @@ static void emit_parse_warning(const char *message, JSON_ParserState *state)
400
415
 
401
416
  #define PARSE_ERROR_FRAGMENT_LEN 32
402
417
 
403
- #ifdef RBIMPL_ATTR_NORETURN
404
- RBIMPL_ATTR_NORETURN()
405
- #endif
406
- static void raise_parse_error(const char *format, JSON_ParserState *state)
418
+ static VALUE build_parse_error_message(const char *format, JSON_ParserState *state, long line, long column)
407
419
  {
408
420
  unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
409
- long line, column;
410
- cursor_position(state, &line, &column);
411
421
 
412
422
  const char *ptr = "EOF";
413
423
  if (state->cursor && state->cursor < state->end) {
@@ -439,20 +449,28 @@ static void raise_parse_error(const char *format, JSON_ParserState *state)
439
449
  }
440
450
  }
441
451
 
442
- VALUE msg = rb_sprintf(format, ptr);
443
- VALUE message = rb_enc_sprintf(enc_utf8, "%s at line %ld column %ld", RSTRING_PTR(msg), line, column);
444
- RB_GC_GUARD(msg);
452
+ VALUE message = rb_enc_sprintf(enc_utf8, format, ptr);
453
+ rb_str_catf(message, " at line %ld column %ld", line, column);
454
+ return message;
455
+ }
445
456
 
457
+ static VALUE parse_error_new(VALUE message, long line, long column)
458
+ {
446
459
  VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
447
460
  rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
448
461
  rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
449
- rb_exc_raise(exc);
462
+ return exc;
450
463
  }
451
464
 
452
- #ifdef RBIMPL_ATTR_NORETURN
453
- RBIMPL_ATTR_NORETURN()
454
- #endif
455
- static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
465
+ NORETURN(static) void raise_parse_error(const char *format, JSON_ParserState *state)
466
+ {
467
+ long line, column;
468
+ cursor_position(state, &line, &column);
469
+ VALUE message = build_parse_error_message(format, state, line, column);
470
+ rb_exc_raise(parse_error_new(message, line, column));
471
+ }
472
+
473
+ NORETURN(static) void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
456
474
  {
457
475
  state->cursor = at;
458
476
  raise_parse_error(format, state);
@@ -752,6 +770,10 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
752
770
  }
753
771
  raise_parse_error_at("invalid ASCII control character in string: %s", state, pe - 1);
754
772
  }
773
+ }
774
+
775
+ if (config->allow_invalid_escape) {
776
+ APPEND_CHAR(*pe);
755
777
  } else {
756
778
  raise_parse_error_at("invalid escape character in string: %s", state, pe - 1);
757
779
  }
@@ -776,20 +798,39 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
776
798
  }
777
799
 
778
800
  #define MAX_FAST_INTEGER_SIZE 18
801
+ #define MAX_NUMBER_STACK_BUFFER 128
802
+
803
+ typedef VALUE (*json_number_decode_func_t)(const char *ptr);
804
+
805
+ static inline VALUE json_decode_large_number(const char *start, long len, json_number_decode_func_t func)
806
+ {
807
+ if (RB_LIKELY(len < MAX_NUMBER_STACK_BUFFER)) {
808
+ char buffer[MAX_NUMBER_STACK_BUFFER];
809
+ MEMCPY(buffer, start, char, len);
810
+ buffer[len] = '\0';
811
+ return func(buffer);
812
+ } else {
813
+ VALUE buffer_v = rb_str_tmp_new(len);
814
+ char *buffer = RSTRING_PTR(buffer_v);
815
+ MEMCPY(buffer, start, char, len);
816
+ buffer[len] = '\0';
817
+ VALUE number = func(buffer);
818
+ RB_GC_GUARD(buffer_v);
819
+ return number;
820
+ }
821
+ }
779
822
 
780
- static VALUE json_decode_large_integer(const char *start, long len)
823
+ static VALUE json_decode_inum(const char *buffer)
781
824
  {
782
- VALUE buffer_v;
783
- char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1);
784
- MEMCPY(buffer, start, char, len);
785
- buffer[len] = '\0';
786
- VALUE number = rb_cstr2inum(buffer, 10);
787
- RB_ALLOCV_END(buffer_v);
788
- return number;
825
+ return rb_cstr2inum(buffer, 10);
789
826
  }
790
827
 
791
- static inline VALUE
792
- json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
828
+ NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len)
829
+ {
830
+ return json_decode_large_number(start, len, json_decode_inum);
831
+ }
832
+
833
+ static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
793
834
  {
794
835
  if (RB_LIKELY(mantissa_digits < MAX_FAST_INTEGER_SIZE)) {
795
836
  if (negative) {
@@ -801,28 +842,20 @@ json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const
801
842
  return json_decode_large_integer(start, end - start);
802
843
  }
803
844
 
804
- static VALUE json_decode_large_float(const char *start, long len)
845
+ static VALUE json_decode_dnum(const char *buffer)
805
846
  {
806
- if (RB_LIKELY(len < 64)) {
807
- char buffer[64];
808
- MEMCPY(buffer, start, char, len);
809
- buffer[len] = '\0';
810
- return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
811
- }
847
+ return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
848
+ }
812
849
 
813
- VALUE buffer_v;
814
- char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1);
815
- MEMCPY(buffer, start, char, len);
816
- buffer[len] = '\0';
817
- VALUE number = DBL2NUM(rb_cstr_to_dbl(buffer, 1));
818
- RB_ALLOCV_END(buffer_v);
819
- return number;
850
+ NOINLINE(static) VALUE json_decode_large_float(const char *start, long len)
851
+ {
852
+ return json_decode_large_number(start, len, json_decode_dnum);
820
853
  }
821
854
 
822
855
  /* Ruby JSON optimized float decoder using vendored Ryu algorithm
823
856
  * Accepts pre-extracted mantissa and exponent from first-pass validation
824
857
  */
825
- static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits, int32_t exponent, bool negative,
858
+ static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits, int64_t exponent, bool negative,
826
859
  const char *start, const char *end)
827
860
  {
828
861
  if (RB_UNLIKELY(config->decimal_class)) {
@@ -830,13 +863,21 @@ static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantis
830
863
  return rb_funcallv(config->decimal_class, config->decimal_method_id, 1, &text);
831
864
  }
832
865
 
866
+ if (RB_UNLIKELY(exponent > INT32_MAX)) {
867
+ return negative ? CMinusInfinity : CInfinity;
868
+ }
869
+
870
+ if (RB_UNLIKELY(exponent < INT32_MIN)) {
871
+ return rb_float_new(negative ? -0.0 : 0.0);
872
+ }
873
+
833
874
  // Fall back to rb_cstr_to_dbl for potential subnormals (rare edge case)
834
875
  // Ryu has rounding issues with subnormals around 1e-310 (< 2.225e-308)
835
876
  if (RB_UNLIKELY(mantissa_digits > 17 || mantissa_digits + exponent < -307)) {
836
877
  return json_decode_large_float(start, end - start);
837
878
  }
838
879
 
839
- return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, exponent, negative));
880
+ return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, (int32_t)exponent, negative));
840
881
  }
841
882
 
842
883
  static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
@@ -868,7 +909,7 @@ static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
868
909
  return Qfalse;
869
910
  }
870
911
 
871
- static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
912
+ NOINLINE(static) void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
872
913
  {
873
914
  VALUE message = rb_sprintf(
874
915
  "detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
@@ -879,18 +920,17 @@ static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_
879
920
  RB_GC_GUARD(message);
880
921
  }
881
922
 
882
- #ifdef RBIMPL_ATTR_NORETURN
883
- RBIMPL_ATTR_NORETURN()
884
- #endif
885
- static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
923
+ NORETURN(static) void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
886
924
  {
887
925
  VALUE message = rb_sprintf(
888
926
  "duplicate key %"PRIsVALUE,
889
927
  rb_inspect(duplicate_key)
890
928
  );
891
929
 
892
- raise_parse_error(RSTRING_PTR(message), state);
893
- RB_GC_GUARD(message);
930
+ long line, column;
931
+ cursor_position(state, &line, &column);
932
+ rb_str_concat(message, build_parse_error_message("", state, line, column)) ;
933
+ rb_exc_raise(parse_error_new(message, line, column));
894
934
  }
895
935
 
896
936
  static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
@@ -927,7 +967,7 @@ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *
927
967
  if (RB_UNLIKELY(config->on_load_proc)) {
928
968
  value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
929
969
  }
930
- rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
970
+ rvalue_stack_push(state->stack, value, state->stack_handle, &state->stack);
931
971
  return value;
932
972
  }
933
973
 
@@ -1112,7 +1152,7 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig
1112
1152
  const char first_digit = *state->cursor;
1113
1153
 
1114
1154
  // Variables for Ryu optimization - extract digits during parsing
1115
- int32_t exponent = 0;
1155
+ int64_t exponent = 0;
1116
1156
  int decimal_point_pos = -1;
1117
1157
  uint64_t mantissa = 0;
1118
1158
 
@@ -1156,7 +1196,7 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig
1156
1196
  raise_parse_error_at("invalid number: %s", state, start);
1157
1197
  }
1158
1198
 
1159
- exponent = negative_exponent ? -((int32_t)abs_exponent) : ((int32_t)abs_exponent);
1199
+ exponent = negative_exponent ? -abs_exponent : abs_exponent;
1160
1200
  }
1161
1201
 
1162
1202
  if (integer) {
@@ -1433,6 +1473,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
1433
1473
  else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
1434
1474
  else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
1435
1475
  else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
1476
+ else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
1436
1477
  else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
1437
1478
  else if (key == sym_freeze) { config->freeze = RTEST(val); }
1438
1479
  else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
@@ -1536,11 +1577,13 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
1536
1577
  const char *start;
1537
1578
  RSTRING_GETMEM(Vsource, start, len);
1538
1579
 
1580
+ VALUE stack_handle = 0;
1539
1581
  JSON_ParserState _state = {
1540
1582
  .start = start,
1541
1583
  .cursor = start,
1542
1584
  .end = start + len,
1543
1585
  .stack = &stack,
1586
+ .stack_handle = &stack_handle,
1544
1587
  };
1545
1588
  JSON_ParserState *state = &_state;
1546
1589
 
@@ -1548,8 +1591,8 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
1548
1591
 
1549
1592
  // This may be skipped in case of exception, but
1550
1593
  // it won't cause a leak.
1551
- rvalue_stack_eagerly_release(state->stack_handle);
1552
-
1594
+ rvalue_stack_eagerly_release(stack_handle);
1595
+ RB_GC_GUARD(stack_handle);
1553
1596
  json_ensure_eof(state);
1554
1597
 
1555
1598
  return result;
@@ -1587,26 +1630,19 @@ static void JSON_ParserConfig_mark(void *ptr)
1587
1630
  rb_gc_mark(config->decimal_class);
1588
1631
  }
1589
1632
 
1590
- static void JSON_ParserConfig_free(void *ptr)
1591
- {
1592
- JSON_ParserConfig *config = ptr;
1593
- ruby_xfree(config);
1594
- }
1595
-
1596
1633
  static size_t JSON_ParserConfig_memsize(const void *ptr)
1597
1634
  {
1598
1635
  return sizeof(JSON_ParserConfig);
1599
1636
  }
1600
1637
 
1601
1638
  static const rb_data_type_t JSON_ParserConfig_type = {
1602
- "JSON::Ext::Parser/ParserConfig",
1603
- {
1639
+ .wrap_struct_name = "JSON::Ext::Parser/ParserConfig",
1640
+ .function = {
1604
1641
  JSON_ParserConfig_mark,
1605
- JSON_ParserConfig_free,
1642
+ RUBY_DEFAULT_FREE,
1606
1643
  JSON_ParserConfig_memsize,
1607
1644
  },
1608
- 0, 0,
1609
- RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
1645
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
1610
1646
  };
1611
1647
 
1612
1648
  static VALUE cJSON_parser_s_allocate(VALUE klass)
@@ -1651,6 +1687,7 @@ void Init_parser(void)
1651
1687
  sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
1652
1688
  sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
1653
1689
  sym_allow_control_characters = ID2SYM(rb_intern("allow_control_characters"));
1690
+ sym_allow_invalid_escape = ID2SYM(rb_intern("allow_invalid_escape"));
1654
1691
  sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
1655
1692
  sym_freeze = ID2SYM(rb_intern("freeze"));
1656
1693
  sym_on_load = ID2SYM(rb_intern("on_load"));
@@ -133,16 +133,6 @@ ALWAYS_INLINE(static) int string_scan_simd_neon(const char **ptr, const char *en
133
133
  return 0;
134
134
  }
135
135
 
136
- static inline uint8x16x4_t load_uint8x16_4(const unsigned char *table)
137
- {
138
- uint8x16x4_t tab;
139
- tab.val[0] = vld1q_u8(table);
140
- tab.val[1] = vld1q_u8(table+16);
141
- tab.val[2] = vld1q_u8(table+32);
142
- tab.val[3] = vld1q_u8(table+48);
143
- return tab;
144
- }
145
-
146
136
  #endif /* ARM Neon Support.*/
147
137
 
148
138
  #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
data/lib/json/common.rb CHANGED
@@ -156,15 +156,17 @@ module JSON
156
156
  def generator=(generator) # :nodoc:
157
157
  old, $VERBOSE = $VERBOSE, nil
158
158
  @generator = generator
159
- generator_methods = generator::GeneratorMethods
160
- for const in generator_methods.constants
161
- klass = const_get(const)
162
- modul = generator_methods.const_get(const)
163
- klass.class_eval do
164
- instance_methods(false).each do |m|
165
- m.to_s == 'to_json' and remove_method m
159
+ if generator.const_defined?(:GeneratorMethods)
160
+ generator_methods = generator::GeneratorMethods
161
+ for const in generator_methods.constants
162
+ klass = const_get(const)
163
+ modul = generator_methods.const_get(const)
164
+ klass.class_eval do
165
+ instance_methods(false).each do |m|
166
+ m.to_s == 'to_json' and remove_method m
167
+ end
168
+ include modul
166
169
  end
167
- include modul
168
170
  end
169
171
  end
170
172
  self.state = generator::State
@@ -878,7 +880,7 @@ module JSON
878
880
  end
879
881
  end
880
882
 
881
- if opts[:allow_blank] && (source.nil? || source.empty?)
883
+ if opts[:allow_blank] && (source.nil? || (String === source && source.empty?))
882
884
  source = 'null'
883
885
  end
884
886
 
@@ -1036,7 +1038,8 @@ module JSON
1036
1038
  # JSON.new(options = nil, &block)
1037
1039
  #
1038
1040
  # Argument +options+, if given, contains a \Hash of options for both parsing and generating.
1039
- # See {Parsing Options}[#module-JSON-label-Parsing+Options], and {Generating Options}[#module-JSON-label-Generating+Options].
1041
+ # See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
1042
+ # and {Generating Options}[rdoc-ref:JSON@Generating+Options].
1040
1043
  #
1041
1044
  # For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
1042
1045
  # encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
@@ -1095,6 +1098,30 @@ module JSON
1095
1098
  load(File.read(path, encoding: Encoding::UTF_8))
1096
1099
  end
1097
1100
  end
1101
+
1102
+ module GeneratorMethods
1103
+ # call-seq: to_json(*)
1104
+ #
1105
+ # Converts this object into a JSON string.
1106
+ # If this object doesn't directly maps to a JSON native type,
1107
+ # first convert it to a string (calling #to_s), then converts
1108
+ # it to a JSON string, and returns the result.
1109
+ # This is a fallback, if no special method #to_json was defined for some object.
1110
+ def to_json(state = nil, *)
1111
+ obj = case self
1112
+ when nil, false, true, Integer, Float, Array, Hash
1113
+ self
1114
+ else
1115
+ "#{self}"
1116
+ end
1117
+
1118
+ if state.nil?
1119
+ JSON::State._generate_no_fallback(obj, nil, nil)
1120
+ else
1121
+ JSON::State.from_state(state)._generate_no_fallback(obj)
1122
+ end
1123
+ end
1124
+ end
1098
1125
  end
1099
1126
 
1100
1127
  module ::Kernel
@@ -1140,3 +1167,7 @@ module ::Kernel
1140
1167
  JSON[object, opts]
1141
1168
  end
1142
1169
  end
1170
+
1171
+ class Object
1172
+ include JSON::GeneratorMethods
1173
+ end
@@ -9,7 +9,7 @@ module JSON
9
9
  # Instantiates a new State object, configured by _opts_.
10
10
  #
11
11
  # Argument +opts+, if given, contains a \Hash of options for the generation.
12
- # See {Generating Options}[#module-JSON-label-Generating+Options].
12
+ # See {Generating Options}[rdoc-ref:JSON@Generating+Options].
13
13
  def initialize(opts = nil)
14
14
  if opts && !opts.empty?
15
15
  configure(opts)
@@ -48,7 +48,7 @@ module JSON
48
48
  SCRIPT_SAFE_ESCAPE_PATTERN = /[\/"\\\x0-\x1f\u2028-\u2029]/
49
49
 
50
50
  def self.native_type?(value) # :nodoc:
51
- (false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
51
+ (false == value || true == value || nil == value || String === value || Symbol === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
52
52
  end
53
53
 
54
54
  def self.native_key?(key) # :nodoc:
@@ -211,7 +211,14 @@ module JSON
211
211
 
212
212
  # This integer returns the current depth data structure nesting in the
213
213
  # generated JSON.
214
- attr_accessor :depth
214
+ attr_reader :depth
215
+
216
+ def depth=(depth)
217
+ if depth.negative?
218
+ raise ArgumentError, "depth must be >= 0 (got #{depth})"
219
+ end
220
+ @depth = depth
221
+ end
215
222
 
216
223
  def check_max_nesting # :nodoc:
217
224
  return if @max_nesting.zero?
@@ -260,6 +267,11 @@ module JSON
260
267
  else
261
268
  raise TypeError, "can't convert #{opts.class} into Hash"
262
269
  end
270
+
271
+ if opts[:depth]&.negative?
272
+ raise ArgumentError, "depth must be >= 0 (got #{opts[:depth]})"
273
+ end
274
+
263
275
  opts.each do |key, value|
264
276
  instance_variable_set "@#{key}", value
265
277
  end
@@ -505,11 +517,11 @@ module JSON
505
517
 
506
518
  if empty?
507
519
  state.depth -= 1
508
- return '{}'
520
+ return +'{}'
509
521
  end
510
522
 
511
523
  delim = ",#{state.object_nl}"
512
- result = +"{#{state.object_nl}"
524
+ result = "{#{state.object_nl}"
513
525
  first = true
514
526
  key_type = nil
515
527
  indent = !state.object_nl.empty?
@@ -546,7 +558,7 @@ module JSON
546
558
  raise TypeError, "#{key.class}#to_s returns an instance of #{key_str.class}, expected a String"
547
559
  end
548
560
 
549
- result = +"#{result}#{key_json}#{state.space_before}:#{state.space}"
561
+ result = "#{result}#{key_json}#{state.space_before}:#{state.space}"
550
562
  if state.strict? && !Generator.native_type?(value)
551
563
  if state.as_json
552
564
  value = state.as_json.call(value, false)
@@ -597,7 +609,7 @@ module JSON
597
609
 
598
610
  if empty?
599
611
  state.depth -= 1
600
- return '[]'
612
+ return +'[]'
601
613
  end
602
614
 
603
615
  result = '['.dup
@@ -722,17 +734,17 @@ module JSON
722
734
 
723
735
  module TrueClass
724
736
  # Returns a JSON string for true: 'true'.
725
- def to_json(*) 'true' end
737
+ def to_json(*) +'true' end
726
738
  end
727
739
 
728
740
  module FalseClass
729
741
  # Returns a JSON string for false: 'false'.
730
- def to_json(*) 'false' end
742
+ def to_json(*) +'false' end
731
743
  end
732
744
 
733
745
  module NilClass
734
746
  # Returns a JSON string for nil: 'null'.
735
- def to_json(*) 'null' end
747
+ def to_json(*) +'null' end
736
748
  end
737
749
  end
738
750
  end
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.18.1'
4
+ VERSION = '2.19.4'
5
5
  end
data/lib/json.rb CHANGED
@@ -194,6 +194,18 @@ require 'json/common'
194
194
  # When enabled:
195
195
  # JSON.parse(%{"Hello\nWorld"}, allow_control_characters: true) # => "Hello\nWorld"
196
196
  #
197
+ # ---
198
+ #
199
+ # Option +allow_invalid_escape+ (boolean) specifies whether to ignore backslahes that are followed
200
+ # by an invalid escape character in strings;
201
+ # defaults to +false+.
202
+ #
203
+ # With the default, +false+:
204
+ # JSON.parse('"Hell\o"') # invalid escape character in string (JSON::ParserError)
205
+ #
206
+ # When enabled:
207
+ # JSON.parse('"Hell\o"', allow_invalid_escape: true) # => "Hello"
208
+ #
197
209
  # ====== Output Options
198
210
  #
199
211
  # Option +freeze+ (boolean) specifies whether the returned objects will be frozen;
@@ -323,8 +335,8 @@ require 'json/common'
323
335
  # JSON.generate(JSON::MinusInfinity)
324
336
  #
325
337
  # Allow:
326
- # ruby = [Float::NaN, Float::Infinity, Float::MinusInfinity]
327
- # JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
338
+ # ruby = [Float::NAN, Float::INFINITY, JSON::NaN, JSON::Infinity, JSON::MinusInfinity]
339
+ # JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,NaN,Infinity,-Infinity]'
328
340
  #
329
341
  # ---
330
342
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.18.1
4
+ version: 2.19.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
@@ -84,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
84
  - !ruby/object:Gem::Version
85
85
  version: '0'
86
86
  requirements: []
87
- rubygems_version: 4.1.0.dev
87
+ rubygems_version: 4.0.6
88
88
  specification_version: 4
89
89
  summary: JSON Implementation for Ruby
90
90
  test_files: []