json 2.12.0 → 2.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e71f977a9d4c1316007814d62236fd185f5aaade7a79f3e5d48a9ffde32f520
4
- data.tar.gz: f1be8ac3136a6dcf48aa15c7ec08fa4dfcedb6f89b1b6ad8944727708a16e074
3
+ metadata.gz: 7a3ab7a1c1427b28a1f9cd6b82a23afeefa4f1b5c10cda70ac8f63c7f54849b1
4
+ data.tar.gz: ae21fc70a6e8e82c22b75570602d65fdd91b0d10f5eaf38cc8fbed26f5cba009
5
5
  SHA512:
6
- metadata.gz: 23f2d490dfb7ea60b189f8227787fde0c53844f62c8e9023ba1d413a72b46b7a3b77836d1a6050dd0a2fa925370bd260da0a52d738bd1231c81ad1ef4a17adda
7
- data.tar.gz: 22326ad3f75f99e20c7f1ad3cc0f519ffc56b7c85c94aa124a2ea47c8d0c86f604307fe504f216b347651d3c82df83623798dbdbabc45be78a1e4721cc7b8cbe
6
+ metadata.gz: bc18c29f53460965d3cdadb2b2f864e3a13999d58316cfa7046d142fdb2b8cce2e6d0d45a9f09ab3beb346f1fac78cd9ba9901f66d76bd74c6a1c4d30a4f08e2
7
+ data.tar.gz: a9d76ce65491f9e1d76f70a686d2edc606f9b2bc3797dc0daa8f23b2caeecbf48dd7ed042e9e813bcc37d4157863782afd543a8f667dd5d6890795b4cd44b012
data/CHANGES.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ### Unreleased
4
4
 
5
+ ### 2025-05-23 (2.12.1)
6
+
7
+ * Fix a potential crash in large negative floating point number generation.
8
+ * Fix for JSON.pretty_generate to use passed state object's generate instead of state class as the required parameters aren't available.
9
+
5
10
  ### 2025-05-12 (2.12.0)
6
11
 
7
12
  * Improve floating point generation to not use scientific notation as much.
data/README.md CHANGED
@@ -233,6 +233,19 @@ the `pp` library's `pp` methods.
233
233
 
234
234
  ## Development
235
235
 
236
+ ### Prerequisites
237
+
238
+ 1. Clone the repository
239
+ 2. Install dependencies with `bundle install`
240
+
241
+ ### Testing
242
+
243
+ The full test suite can be run with:
244
+
245
+ ```bash
246
+ bundle exec rake test
247
+ ```
248
+
236
249
  ### Release
237
250
 
238
251
  Update the `lib/json/version.rb` file.
@@ -36,6 +36,12 @@ typedef unsigned char _Bool;
36
36
  # define MAYBE_UNUSED(x) x
37
37
  #endif
38
38
 
39
+ #ifdef RUBY_DEBUG
40
+ #ifndef JSON_DEBUG
41
+ #define JSON_DEBUG RUBY_DEBUG
42
+ #endif
43
+ #endif
44
+
39
45
  enum fbuffer_type {
40
46
  FBUFFER_HEAP_ALLOCATED = 0,
41
47
  FBUFFER_STACK_ALLOCATED = 1,
@@ -46,6 +52,9 @@ typedef struct FBufferStruct {
46
52
  unsigned long initial_length;
47
53
  unsigned long len;
48
54
  unsigned long capa;
55
+ #ifdef JSON_DEBUG
56
+ unsigned long requested;
57
+ #endif
49
58
  char *ptr;
50
59
  VALUE io;
51
60
  } FBuffer;
@@ -74,6 +83,20 @@ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *
74
83
  fb->ptr = stack_buffer;
75
84
  fb->capa = stack_buffer_size;
76
85
  }
86
+ #ifdef JSON_DEBUG
87
+ fb->requested = 0;
88
+ #endif
89
+ }
90
+
91
+ static inline void fbuffer_consumed(FBuffer *fb, unsigned long consumed)
92
+ {
93
+ #ifdef JSON_DEBUG
94
+ if (consumed > fb->requested) {
95
+ rb_bug("fbuffer: Out of bound write");
96
+ }
97
+ fb->requested = 0;
98
+ #endif
99
+ fb->len += consumed;
77
100
  }
78
101
 
79
102
  static void fbuffer_free(FBuffer *fb)
@@ -137,6 +160,10 @@ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
137
160
 
138
161
  static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
139
162
  {
163
+ #ifdef JSON_DEBUG
164
+ fb->requested = requested;
165
+ #endif
166
+
140
167
  if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
141
168
  fbuffer_do_inc_capa(fb, requested);
142
169
  }
@@ -147,15 +174,22 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
147
174
  if (len > 0) {
148
175
  fbuffer_inc_capa(fb, len);
149
176
  MEMCPY(fb->ptr + fb->len, newstr, char, len);
150
- fb->len += len;
177
+ fbuffer_consumed(fb, len);
151
178
  }
152
179
  }
153
180
 
154
181
  /* Appends a character into a buffer. The buffer needs to have sufficient capacity, via fbuffer_inc_capa(...). */
155
182
  static inline void fbuffer_append_reserved_char(FBuffer *fb, char chr)
156
183
  {
184
+ #ifdef JSON_DEBUG
185
+ if (fb->requested < 1) {
186
+ rb_bug("fbuffer: unreserved write");
187
+ }
188
+ fb->requested--;
189
+ #endif
190
+
157
191
  fb->ptr[fb->len] = chr;
158
- fb->len += 1;
192
+ fb->len++;
159
193
  }
160
194
 
161
195
  static void fbuffer_append_str(FBuffer *fb, VALUE str)
@@ -172,7 +206,7 @@ static inline void fbuffer_append_char(FBuffer *fb, char newchr)
172
206
  {
173
207
  fbuffer_inc_capa(fb, 1);
174
208
  *(fb->ptr + fb->len) = newchr;
175
- fb->len++;
209
+ fbuffer_consumed(fb, 1);
176
210
  }
177
211
 
178
212
  static inline char *fbuffer_cursor(FBuffer *fb)
@@ -182,7 +216,7 @@ static inline char *fbuffer_cursor(FBuffer *fb)
182
216
 
183
217
  static inline void fbuffer_advance_to(FBuffer *fb, char *end)
184
218
  {
185
- fb->len = end - fb->ptr;
219
+ fbuffer_consumed(fb, (end - fb->ptr) - fb->len);
186
220
  }
187
221
 
188
222
  /*
@@ -4,8 +4,9 @@ if RUBY_ENGINE == 'truffleruby'
4
4
  # The pure-Ruby generator is faster on TruffleRuby, so skip compiling the generator extension
5
5
  File.write('Makefile', dummy_makefile("").join)
6
6
  else
7
- append_cflags("-std=c99")
7
+ append_cflags("-std=c99 -O0")
8
8
  $defs << "-DJSON_GENERATOR"
9
+ $defs << "-DJSON_DEBUG" if ENV["JSON_DEBUG"]
9
10
 
10
11
  if enable_config('generator-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
11
12
  if RbConfig::CONFIG['host_cpu'] =~ /^(arm.*|aarch64.*)/
@@ -404,7 +404,7 @@ static inline unsigned char search_escape_basic_neon(search_state *search)
404
404
  if (!mask) {
405
405
  // Nothing to escape, ensure search_flush doesn't do anything by setting
406
406
  // search->cursor to search->ptr.
407
- search->buffer->len += remaining;
407
+ fbuffer_consumed(search->buffer, remaining);
408
408
  search->ptr = search->end;
409
409
  search->cursor = search->end;
410
410
  return 0;
@@ -511,7 +511,7 @@ static inline TARGET_SSE2 FORCE_INLINE unsigned char search_escape_basic_sse2(se
511
511
  if (needs_escape_mask == 0) {
512
512
  // Nothing to escape, ensure search_flush doesn't do anything by setting
513
513
  // search->cursor to search->ptr.
514
- search->buffer->len += remaining;
514
+ fbuffer_consumed(search->buffer, remaining);
515
515
  search->ptr = search->end;
516
516
  search->cursor = search->end;
517
517
  return 0;
@@ -1406,17 +1406,16 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
1406
1406
  }
1407
1407
 
1408
1408
  /* This implementation writes directly into the buffer. We reserve
1409
- * the 24 characters that fpconv_dtoa states as its maximum, plus
1410
- * 2 more characters for the potential ".0" suffix.
1409
+ * the 28 characters that fpconv_dtoa states as its maximum.
1411
1410
  */
1412
- fbuffer_inc_capa(buffer, 26);
1411
+ fbuffer_inc_capa(buffer, 28);
1413
1412
  char* d = buffer->ptr + buffer->len;
1414
1413
  int len = fpconv_dtoa(value, d);
1415
1414
 
1416
1415
  /* fpconv_dtoa converts a float to its shortest string representation,
1417
1416
  * but it adds a ".0" if this is a plain integer.
1418
1417
  */
1419
- buffer->len += len;
1418
+ fbuffer_consumed(buffer, len);
1420
1419
  }
1421
1420
 
1422
1421
  static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
@@ -393,7 +393,7 @@ RBIMPL_ATTR_NORETURN()
393
393
  #endif
394
394
  static void raise_parse_error(const char *format, JSON_ParserState *state)
395
395
  {
396
- unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
396
+ unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
397
397
 
398
398
  const char *cursor = state->cursor;
399
399
  long column = 0;
@@ -412,22 +412,34 @@ static void raise_parse_error(const char *format, JSON_ParserState *state)
412
412
  }
413
413
  }
414
414
 
415
- const char *ptr = state->cursor;
416
- size_t len = ptr ? strnlen(ptr, PARSE_ERROR_FRAGMENT_LEN) : 0;
415
+ const char *ptr = "EOF";
416
+ if (state->cursor && state->cursor < state->end) {
417
+ ptr = state->cursor;
418
+ size_t len = 0;
419
+ while (len < PARSE_ERROR_FRAGMENT_LEN) {
420
+ char ch = ptr[len];
421
+ if (!ch || ch == '\n' || ch == ' ' || ch == '\t' || ch == '\r') {
422
+ break;
423
+ }
424
+ len++;
425
+ }
417
426
 
418
- if (len == PARSE_ERROR_FRAGMENT_LEN) {
419
- MEMCPY(buffer, ptr, char, PARSE_ERROR_FRAGMENT_LEN);
427
+ if (len) {
428
+ buffer[0] = '\'';
429
+ MEMCPY(buffer + 1, ptr, char, len);
420
430
 
421
- while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte
422
- len--;
423
- }
431
+ while (buffer[len] >= 0x80 && buffer[len] < 0xC0) { // Is continuation byte
432
+ len--;
433
+ }
424
434
 
425
- if (buffer[len - 1] >= 0xC0) { // multibyte character start
426
- len--;
427
- }
435
+ if (buffer[len] >= 0xC0) { // multibyte character start
436
+ len--;
437
+ }
428
438
 
429
- buffer[len] = '\0';
430
- ptr = (const char *)buffer;
439
+ buffer[len + 1] = '\'';
440
+ buffer[len + 2] = '\0';
441
+ ptr = (const char *)buffer;
442
+ }
431
443
  }
432
444
 
433
445
  VALUE msg = rb_sprintf(format, ptr);
@@ -473,16 +485,16 @@ static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p
473
485
  signed char b;
474
486
  uint32_t result = 0;
475
487
  b = digit_values[p[0]];
476
- if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
488
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
477
489
  result = (result << 4) | (unsigned char)b;
478
490
  b = digit_values[p[1]];
479
- if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
491
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
480
492
  result = (result << 4) | (unsigned char)b;
481
493
  b = digit_values[p[2]];
482
- if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
494
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
483
495
  result = (result << 4) | (unsigned char)b;
484
496
  b = digit_values[p[3]];
485
- if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
497
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
486
498
  result = (result << 4) | (unsigned char)b;
487
499
  return result;
488
500
  }
@@ -532,11 +544,11 @@ json_eat_comments(JSON_ParserState *state)
532
544
  break;
533
545
  }
534
546
  default:
535
- raise_parse_error("unexpected token '%s'", state);
547
+ raise_parse_error("unexpected token %s", state);
536
548
  break;
537
549
  }
538
550
  } else {
539
- raise_parse_error("unexpected token '%s'", state);
551
+ raise_parse_error("unexpected token %s", state);
540
552
  }
541
553
  }
542
554
 
@@ -655,7 +667,7 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
655
667
  break;
656
668
  case 'u':
657
669
  if (pe > stringEnd - 5) {
658
- raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, p);
670
+ raise_parse_error_at("incomplete unicode character escape sequence at %s", state, p);
659
671
  } else {
660
672
  uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
661
673
  pe += 3;
@@ -672,7 +684,7 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
672
684
  if ((ch & 0xFC00) == 0xD800) {
673
685
  pe++;
674
686
  if (pe > stringEnd - 6) {
675
- raise_parse_error_at("incomplete surrogate pair at '%s'", state, p);
687
+ raise_parse_error_at("incomplete surrogate pair at %s", state, p);
676
688
  }
677
689
  if (pe[0] == '\\' && pe[1] == 'u') {
678
690
  uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
@@ -894,7 +906,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
894
906
  return json_push_value(state, config, Qnil);
895
907
  }
896
908
 
897
- raise_parse_error("unexpected token '%s'", state);
909
+ raise_parse_error("unexpected token %s", state);
898
910
  break;
899
911
  case 't':
900
912
  if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
@@ -902,7 +914,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
902
914
  return json_push_value(state, config, Qtrue);
903
915
  }
904
916
 
905
- raise_parse_error("unexpected token '%s'", state);
917
+ raise_parse_error("unexpected token %s", state);
906
918
  break;
907
919
  case 'f':
908
920
  // Note: memcmp with a small power of two compile to an integer comparison
@@ -911,7 +923,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
911
923
  return json_push_value(state, config, Qfalse);
912
924
  }
913
925
 
914
- raise_parse_error("unexpected token '%s'", state);
926
+ raise_parse_error("unexpected token %s", state);
915
927
  break;
916
928
  case 'N':
917
929
  // Note: memcmp with a small power of two compile to an integer comparison
@@ -920,7 +932,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
920
932
  return json_push_value(state, config, CNaN);
921
933
  }
922
934
 
923
- raise_parse_error("unexpected token '%s'", state);
935
+ raise_parse_error("unexpected token %s", state);
924
936
  break;
925
937
  case 'I':
926
938
  if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
@@ -928,7 +940,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
928
940
  return json_push_value(state, config, CInfinity);
929
941
  }
930
942
 
931
- raise_parse_error("unexpected token '%s'", state);
943
+ raise_parse_error("unexpected token %s", state);
932
944
  break;
933
945
  case '-':
934
946
  // Note: memcmp with a small power of two compile to an integer comparison
@@ -937,7 +949,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
937
949
  state->cursor += 9;
938
950
  return json_push_value(state, config, CMinusInfinity);
939
951
  } else {
940
- raise_parse_error("unexpected token '%s'", state);
952
+ raise_parse_error("unexpected token %s", state);
941
953
  }
942
954
  }
943
955
  // Fallthrough
@@ -1062,7 +1074,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1062
1074
  }
1063
1075
 
1064
1076
  if (*state->cursor != '"') {
1065
- raise_parse_error("expected object key, got '%s", state);
1077
+ raise_parse_error("expected object key, got %s", state);
1066
1078
  }
1067
1079
  json_parse_string(state, config, true);
1068
1080
 
@@ -1097,13 +1109,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1097
1109
  }
1098
1110
 
1099
1111
  if (*state->cursor != '"') {
1100
- raise_parse_error("expected object key, got: '%s'", state);
1112
+ raise_parse_error("expected object key, got: %s", state);
1101
1113
  }
1102
1114
  json_parse_string(state, config, true);
1103
1115
 
1104
1116
  json_eat_whitespace(state);
1105
1117
  if ((state->cursor >= state->end) || (*state->cursor != ':')) {
1106
- raise_parse_error("expected ':' after object key, got: '%s", state);
1118
+ raise_parse_error("expected ':' after object key, got: %s", state);
1107
1119
  }
1108
1120
  state->cursor++;
1109
1121
 
@@ -1113,24 +1125,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1113
1125
  }
1114
1126
  }
1115
1127
 
1116
- raise_parse_error("expected ',' or '}' after object value, got: '%s'", state);
1128
+ raise_parse_error("expected ',' or '}' after object value, got: %s", state);
1117
1129
  }
1118
1130
  break;
1119
1131
  }
1120
1132
 
1121
1133
  default:
1122
- raise_parse_error("unexpected character: '%s'", state);
1134
+ raise_parse_error("unexpected character: %s", state);
1123
1135
  break;
1124
1136
  }
1125
1137
 
1126
- raise_parse_error("unreacheable: '%s'", state);
1138
+ raise_parse_error("unreacheable: %s", state);
1127
1139
  }
1128
1140
 
1129
1141
  static void json_ensure_eof(JSON_ParserState *state)
1130
1142
  {
1131
1143
  json_eat_whitespace(state);
1132
1144
  if (state->cursor != state->end) {
1133
- raise_parse_error("unexpected token at end of stream '%s'", state);
1145
+ raise_parse_error("unexpected token at end of stream %s", state);
1134
1146
  }
1135
1147
  }
1136
1148
 
@@ -92,7 +92,7 @@ static Fp find_cachedpow10(int exp, int* k)
92
92
  {
93
93
  const double one_log_ten = 0.30102999566398114;
94
94
 
95
- int approx = -(exp + npowers) * one_log_ten;
95
+ int approx = (int)(-(exp + npowers) * one_log_ten);
96
96
  int idx = (approx - firstpower) / steppowers;
97
97
 
98
98
  while(1) {
@@ -432,8 +432,8 @@ static int filter_special(double fp, char* dest)
432
432
  *
433
433
  * Input:
434
434
  * fp -> the double to convert, dest -> destination buffer.
435
- * The generated string will never be longer than 24 characters.
436
- * Make sure to pass a pointer to at least 24 bytes of memory.
435
+ * The generated string will never be longer than 28 characters.
436
+ * Make sure to pass a pointer to at least 28 bytes of memory.
437
437
  * The emitted string will not be null terminated.
438
438
  *
439
439
  * Output:
@@ -443,7 +443,7 @@ static int filter_special(double fp, char* dest)
443
443
  *
444
444
  * void print(double d)
445
445
  * {
446
- * char buf[24 + 1] // plus null terminator
446
+ * char buf[28 + 1] // plus null terminator
447
447
  * int str_len = fpconv_dtoa(d, buf);
448
448
  *
449
449
  * buf[str_len] = '\0';
@@ -451,7 +451,7 @@ static int filter_special(double fp, char* dest)
451
451
  * }
452
452
  *
453
453
  */
454
- static int fpconv_dtoa(double d, char dest[24])
454
+ static int fpconv_dtoa(double d, char dest[28])
455
455
  {
456
456
  char digits[18];
457
457
 
data/lib/json/common.rb CHANGED
@@ -172,7 +172,7 @@ module JSON
172
172
  end
173
173
  end
174
174
  self.state = generator::State
175
- const_set :State, self.state
175
+ const_set :State, state
176
176
  ensure
177
177
  $VERBOSE = old
178
178
  end
@@ -490,7 +490,7 @@ module JSON
490
490
  # }
491
491
  #
492
492
  def pretty_generate(obj, opts = nil)
493
- return state.generate(obj) if State === opts
493
+ return opts.generate(obj) if State === opts
494
494
 
495
495
  options = PRETTY_GENERATE_OPTIONS
496
496
 
@@ -1072,7 +1072,7 @@ module ::Kernel
1072
1072
  end
1073
1073
 
1074
1074
  objs.each do |obj|
1075
- puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
1075
+ puts JSON.generate(obj, :allow_nan => true, :max_nesting => false)
1076
1076
  end
1077
1077
  nil
1078
1078
  end
@@ -1087,7 +1087,7 @@ module ::Kernel
1087
1087
  end
1088
1088
 
1089
1089
  objs.each do |obj|
1090
- puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
1090
+ puts JSON.pretty_generate(obj, :allow_nan => true, :max_nesting => false)
1091
1091
  end
1092
1092
  nil
1093
1093
  end
data/lib/json/ext.rb CHANGED
@@ -34,12 +34,12 @@ module JSON
34
34
 
35
35
  if RUBY_ENGINE == 'truffleruby'
36
36
  require 'json/truffle_ruby/generator'
37
- JSON.generator = ::JSON::TruffleRuby::Generator
37
+ JSON.generator = JSON::TruffleRuby::Generator
38
38
  else
39
39
  require 'json/ext/generator'
40
40
  JSON.generator = Generator
41
41
  end
42
42
  end
43
43
 
44
- JSON_LOADED = true unless defined?(::JSON::JSON_LOADED)
44
+ JSON_LOADED = true unless defined?(JSON::JSON_LOADED)
45
45
  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.12.0'
4
+ VERSION = '2.12.1'
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.12.0
4
+ version: 2.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Florian Frank
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-05-12 00:00:00.000000000 Z
10
+ date: 2025-05-23 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: This is a JSON implementation as a Ruby extension in C.
13
13
  email: flori@ping.de