json 2.4.1 → 2.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69d9ea2a14a3aa9fdbbe8d44b02f9b9e1968c05a9312326e5277651a242f18da
4
- data.tar.gz: 9f5c2d99d45d8a187eacc0d2257c2402bccc535af476a5562ddd71f5fe21bbd1
3
+ metadata.gz: ae21d647db9c8291ae1fd3137d82feff3c0f7d575c244bd23902332179ef660b
4
+ data.tar.gz: d51e458a1de384797e9a11ca9413f74ff58f067e4478a4d54d220527387914fd
5
5
  SHA512:
6
- metadata.gz: 8865e45a1d7c71030ab0ce49399c474bf451d3542acd46bdacd063082f7b8be45b8d32dcbc04867bff2d2cc15545f1284a11a5c60e5da27f53bdee7936c34add
7
- data.tar.gz: 467b3e5615b29991d0c35889c4a7e86e69ea253c58d64a1a40d933ea5fa1bcf38b67e3d3941b109f972ce454bec4226119edafba1a3248a028c36a508cbbd4e4
6
+ metadata.gz: f7b8eaa3f4cb78f26cdb0a4629529372baa32b9e30f16bcfe8955581e6e886561f3da4b396fd711a1ffdad04dec9657f4f0953bf4283a99d9c5243353272ad11
7
+ data.tar.gz: fe145361cd4b6bfd2fdb038ae5ab373d9f641893f43dab26460bc085833687ce78e105f2b18cff2c11d4cf974a32da082954d0117fffbeb8f75548272392201b
data/CHANGES.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changes
2
2
 
3
+ ## 2020-12-22 (2.5.0)
4
+
5
+ * Ready to Ractor-safe at Ruby 3.0.
6
+
3
7
  ## 2020-12-17 (2.4.1)
4
8
 
5
9
  * Restore version.rb with 2.4.1
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.4.1
1
+ 2.5.0
@@ -15,8 +15,7 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
15
15
  #endif
16
16
  mFloat, mString, mString_Extend,
17
17
  mTrueClass, mFalseClass, mNilClass, eGeneratorError,
18
- eNestingError,
19
- i_SAFE_STATE_PROTOTYPE;
18
+ eNestingError;
20
19
 
21
20
  static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
22
21
  i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
@@ -620,13 +619,18 @@ static size_t State_memsize(const void *ptr)
620
619
  return size;
621
620
  }
622
621
 
622
+ #ifndef HAVE_RB_EXT_RACTOR_SAFE
623
+ # undef RUBY_TYPED_FROZEN_SHAREABLE
624
+ # define RUBY_TYPED_FROZEN_SHAREABLE 0
625
+ #endif
626
+
623
627
  #ifdef NEW_TYPEDDATA_WRAPPER
624
628
  static const rb_data_type_t JSON_Generator_State_type = {
625
629
  "JSON/Generator/State",
626
630
  {NULL, State_free, State_memsize,},
627
631
  #ifdef RUBY_TYPED_FREE_IMMEDIATELY
628
632
  0, 0,
629
- RUBY_TYPED_FREE_IMMEDIATELY,
633
+ RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
630
634
  #endif
631
635
  };
632
636
  #endif
@@ -1166,8 +1170,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
1166
1170
  } else if (rb_obj_is_kind_of(opts, rb_cHash)) {
1167
1171
  return rb_funcall(self, i_new, 1, opts);
1168
1172
  } else {
1169
- VALUE prototype = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
1170
- return rb_funcall(prototype, i_dup, 0);
1173
+ return rb_class_new_instance(0, NULL, cState);
1171
1174
  }
1172
1175
  }
1173
1176
 
@@ -1499,6 +1502,10 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
1499
1502
  */
1500
1503
  void Init_generator(void)
1501
1504
  {
1505
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
1506
+ rb_ext_ractor_safe(true);
1507
+ #endif
1508
+
1502
1509
  #undef rb_intern
1503
1510
  rb_require("json/common");
1504
1511
 
@@ -1608,5 +1615,4 @@ void Init_generator(void)
1608
1615
  i_encoding = rb_intern("encoding");
1609
1616
  i_encode = rb_intern("encode");
1610
1617
  #endif
1611
- i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
1612
1618
  }
@@ -91,13 +91,12 @@ static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
91
91
 
92
92
  static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
93
93
  static VALUE CNaN, CInfinity, CMinusInfinity;
94
- static VALUE cBigDecimal = Qundef;
95
94
 
96
95
  static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
97
96
  i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
98
97
  i_object_class, i_array_class, i_decimal_class, i_key_p,
99
98
  i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
100
- i_leftshift, i_new, i_BigDecimal, i_freeze, i_uminus;
99
+ i_leftshift, i_new, i_try_convert, i_freeze, i_uminus;
101
100
 
102
101
 
103
102
  #line 126 "parser.rl"
@@ -991,19 +990,6 @@ enum {JSON_float_en_main = 1};
991
990
  #line 346 "parser.rl"
992
991
 
993
992
 
994
- static int is_bigdecimal_class(VALUE obj)
995
- {
996
- if (cBigDecimal == Qundef) {
997
- if (rb_const_defined(rb_cObject, i_BigDecimal)) {
998
- cBigDecimal = rb_const_get_at(rb_cObject, i_BigDecimal);
999
- }
1000
- else {
1001
- return 0;
1002
- }
1003
- }
1004
- return obj == cBigDecimal;
1005
- }
1006
-
1007
993
  static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
1008
994
  {
1009
995
  int cs = EVIL;
@@ -1146,21 +1132,46 @@ case 7:
1146
1132
  #line 368 "parser.rl"
1147
1133
 
1148
1134
  if (cs >= JSON_float_first_final) {
1135
+ VALUE mod = Qnil;
1136
+ ID method_id = 0;
1137
+ if (rb_respond_to(json->decimal_class, i_try_convert)) {
1138
+ mod = json->decimal_class;
1139
+ method_id = i_try_convert;
1140
+ } else if (rb_respond_to(json->decimal_class, i_new)) {
1141
+ mod = json->decimal_class;
1142
+ method_id = i_new;
1143
+ } else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
1144
+ VALUE name = rb_class_name(json->decimal_class);
1145
+ const char *name_cstr = RSTRING_PTR(name);
1146
+ const char *last_colon = strrchr(name_cstr, ':');
1147
+ if (last_colon) {
1148
+ const char *mod_path_end = last_colon - 1;
1149
+ VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
1150
+ mod = rb_path_to_class(mod_path);
1151
+
1152
+ const char *method_name_beg = last_colon + 1;
1153
+ long before_len = method_name_beg - name_cstr;
1154
+ long len = RSTRING_LEN(name) - before_len;
1155
+ VALUE method_name = rb_str_substr(name, before_len, len);
1156
+ method_id = SYM2ID(rb_str_intern(method_name));
1157
+ } else {
1158
+ mod = rb_mKernel;
1159
+ method_id = SYM2ID(rb_str_intern(name));
1160
+ }
1161
+ }
1162
+
1149
1163
  long len = p - json->memo;
1150
1164
  fbuffer_clear(json->fbuffer);
1151
1165
  fbuffer_append(json->fbuffer, json->memo, len);
1152
1166
  fbuffer_append_char(json->fbuffer, '\0');
1153
- if (NIL_P(json->decimal_class)) {
1154
- *result = rb_float_new(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
1167
+
1168
+ if (method_id) {
1169
+ VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
1170
+ *result = rb_funcallv(mod, method_id, 1, &text);
1155
1171
  } else {
1156
- VALUE text;
1157
- text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
1158
- if (is_bigdecimal_class(json->decimal_class)) {
1159
- *result = rb_funcall(Qnil, i_BigDecimal, 1, text);
1160
- } else {
1161
- *result = rb_funcall(json->decimal_class, i_new, 1, text);
1162
- }
1172
+ *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
1163
1173
  }
1174
+
1164
1175
  return p + 1;
1165
1176
  } else {
1166
1177
  return NULL;
@@ -2108,6 +2119,10 @@ static VALUE cParser_source(VALUE self)
2108
2119
 
2109
2120
  void Init_parser(void)
2110
2121
  {
2122
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
2123
+ rb_ext_ractor_safe(true);
2124
+ #endif
2125
+
2111
2126
  #undef rb_intern
2112
2127
  rb_require("json/common");
2113
2128
  mJSON = rb_define_module("JSON");
@@ -2150,7 +2165,7 @@ void Init_parser(void)
2150
2165
  i_aref = rb_intern("[]");
2151
2166
  i_leftshift = rb_intern("<<");
2152
2167
  i_new = rb_intern("new");
2153
- i_BigDecimal = rb_intern("BigDecimal");
2168
+ i_try_convert = rb_intern("try_convert");
2154
2169
  i_freeze = rb_intern("freeze");
2155
2170
  i_uminus = rb_intern("-@");
2156
2171
  }
@@ -89,13 +89,12 @@ static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
89
89
 
90
90
  static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
91
91
  static VALUE CNaN, CInfinity, CMinusInfinity;
92
- static VALUE cBigDecimal = Qundef;
93
92
 
94
93
  static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
95
94
  i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
96
95
  i_object_class, i_array_class, i_decimal_class, i_key_p,
97
96
  i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
98
- i_leftshift, i_new, i_BigDecimal, i_freeze, i_uminus;
97
+ i_leftshift, i_new, i_try_convert, i_freeze, i_uminus;
99
98
 
100
99
  %%{
101
100
  machine JSON_common;
@@ -345,19 +344,6 @@ static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *res
345
344
  ) (^[0-9Ee.\-]? @exit );
346
345
  }%%
347
346
 
348
- static int is_bigdecimal_class(VALUE obj)
349
- {
350
- if (cBigDecimal == Qundef) {
351
- if (rb_const_defined(rb_cObject, i_BigDecimal)) {
352
- cBigDecimal = rb_const_get_at(rb_cObject, i_BigDecimal);
353
- }
354
- else {
355
- return 0;
356
- }
357
- }
358
- return obj == cBigDecimal;
359
- }
360
-
361
347
  static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result)
362
348
  {
363
349
  int cs = EVIL;
@@ -367,21 +353,46 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
367
353
  %% write exec;
368
354
 
369
355
  if (cs >= JSON_float_first_final) {
356
+ VALUE mod = Qnil;
357
+ ID method_id = 0;
358
+ if (rb_respond_to(json->decimal_class, i_try_convert)) {
359
+ mod = json->decimal_class;
360
+ method_id = i_try_convert;
361
+ } else if (rb_respond_to(json->decimal_class, i_new)) {
362
+ mod = json->decimal_class;
363
+ method_id = i_new;
364
+ } else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
365
+ VALUE name = rb_class_name(json->decimal_class);
366
+ const char *name_cstr = RSTRING_PTR(name);
367
+ const char *last_colon = strrchr(name_cstr, ':');
368
+ if (last_colon) {
369
+ const char *mod_path_end = last_colon - 1;
370
+ VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
371
+ mod = rb_path_to_class(mod_path);
372
+
373
+ const char *method_name_beg = last_colon + 1;
374
+ long before_len = method_name_beg - name_cstr;
375
+ long len = RSTRING_LEN(name) - before_len;
376
+ VALUE method_name = rb_str_substr(name, before_len, len);
377
+ method_id = SYM2ID(rb_str_intern(method_name));
378
+ } else {
379
+ mod = rb_mKernel;
380
+ method_id = SYM2ID(rb_str_intern(name));
381
+ }
382
+ }
383
+
370
384
  long len = p - json->memo;
371
385
  fbuffer_clear(json->fbuffer);
372
386
  fbuffer_append(json->fbuffer, json->memo, len);
373
387
  fbuffer_append_char(json->fbuffer, '\0');
374
- if (NIL_P(json->decimal_class)) {
375
- *result = rb_float_new(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
388
+
389
+ if (method_id) {
390
+ VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
391
+ *result = rb_funcallv(mod, method_id, 1, &text);
376
392
  } else {
377
- VALUE text;
378
- text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
379
- if (is_bigdecimal_class(json->decimal_class)) {
380
- *result = rb_funcall(Qnil, i_BigDecimal, 1, text);
381
- } else {
382
- *result = rb_funcall(json->decimal_class, i_new, 1, text);
383
- }
393
+ *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
384
394
  }
395
+
385
396
  return p + 1;
386
397
  } else {
387
398
  return NULL;
@@ -868,6 +879,10 @@ static VALUE cParser_source(VALUE self)
868
879
 
869
880
  void Init_parser(void)
870
881
  {
882
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
883
+ rb_ext_ractor_safe(true);
884
+ #endif
885
+
871
886
  #undef rb_intern
872
887
  rb_require("json/common");
873
888
  mJSON = rb_define_module("JSON");
@@ -910,7 +925,7 @@ void Init_parser(void)
910
925
  i_aref = rb_intern("[]");
911
926
  i_leftshift = rb_intern("<<");
912
927
  i_new = rb_intern("new");
913
- i_BigDecimal = rb_intern("BigDecimal");
928
+ i_try_convert = rb_intern("try_convert");
914
929
  i_freeze = rb_intern("freeze");
915
930
  i_uminus = rb_intern("-@");
916
931
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "json"
5
- s.version = File.read('VERSION').chomp
5
+ s.version = File.read(File.expand_path('../VERSION', __FILE__)).chomp
6
6
 
7
7
  s.summary = "JSON Implementation for Ruby"
8
8
  s.description = "This is a JSON implementation as a Ruby extension in C."
@@ -71,22 +71,28 @@ module JSON
71
71
  end
72
72
  self.state = generator::State
73
73
  const_set :State, self.state
74
- const_set :SAFE_STATE_PROTOTYPE, State.new
75
- const_set :FAST_STATE_PROTOTYPE, State.new(
74
+ const_set :SAFE_STATE_PROTOTYPE, State.new # for JRuby
75
+ ensure
76
+ $VERBOSE = old
77
+ end
78
+
79
+ def create_fast_state
80
+ State.new(
76
81
  :indent => '',
77
82
  :space => '',
78
83
  :object_nl => "",
79
84
  :array_nl => "",
80
85
  :max_nesting => false
81
86
  )
82
- const_set :PRETTY_STATE_PROTOTYPE, State.new(
87
+ end
88
+
89
+ def create_pretty_state
90
+ State.new(
83
91
  :indent => ' ',
84
92
  :space => ' ',
85
93
  :object_nl => "\n",
86
94
  :array_nl => "\n"
87
95
  )
88
- ensure
89
- $VERBOSE = old
90
96
  end
91
97
 
92
98
  # Returns the JSON generator module that is used by JSON. This is
@@ -98,13 +104,26 @@ module JSON
98
104
  # either JSON::Ext::Generator::State or JSON::Pure::Generator::State:
99
105
  # JSON.state # => JSON::Ext::Generator::State
100
106
  attr_accessor :state
107
+ end
108
+
109
+ DEFAULT_CREATE_ID = 'json_class'.freeze
110
+ private_constant :DEFAULT_CREATE_ID
111
+
112
+ CREATE_ID_TLS_KEY = "JSON.create_id".freeze
113
+ private_constant :CREATE_ID_TLS_KEY
114
+
115
+ # Sets create identifier, which is used to decide if the _json_create_
116
+ # hook of a class should be called; initial value is +json_class+:
117
+ # JSON.create_id # => 'json_class'
118
+ def self.create_id=(new_value)
119
+ Thread.current[CREATE_ID_TLS_KEY] = new_value.dup.freeze
120
+ end
101
121
 
102
- # Sets or returns create identifier, which is used to decide if the _json_create_
103
- # hook of a class should be called; initial value is +json_class+:
104
- # JSON.create_id # => 'json_class'
105
- attr_accessor :create_id
122
+ # Returns the current create identifier.
123
+ # See also JSON.create_id=.
124
+ def self.create_id
125
+ Thread.current[CREATE_ID_TLS_KEY] || DEFAULT_CREATE_ID
106
126
  end
107
- self.create_id = 'json_class'
108
127
 
109
128
  NaN = 0.0/0
110
129
 
@@ -276,7 +295,7 @@ module JSON
276
295
  if State === opts
277
296
  state, opts = opts, nil
278
297
  else
279
- state = SAFE_STATE_PROTOTYPE.dup
298
+ state = State.new
280
299
  end
281
300
  if opts
282
301
  if opts.respond_to? :to_hash
@@ -315,7 +334,7 @@ module JSON
315
334
  if State === opts
316
335
  state, opts = opts, nil
317
336
  else
318
- state = FAST_STATE_PROTOTYPE.dup
337
+ state = JSON.create_fast_state
319
338
  end
320
339
  if opts
321
340
  if opts.respond_to? :to_hash
@@ -370,7 +389,7 @@ module JSON
370
389
  if State === opts
371
390
  state, opts = opts, nil
372
391
  else
373
- state = PRETTY_STATE_PROTOTYPE.dup
392
+ state = JSON.create_pretty_state
374
393
  end
375
394
  if opts
376
395
  if opts.respond_to? :to_hash
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
  module JSON
3
3
  # JSON version
4
- VERSION = '2.4.1'
4
+ VERSION = '2.5.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:
@@ -48,35 +48,6 @@ EOT
48
48
  $VERBOSE = v
49
49
  end
50
50
 
51
- def test_remove_const_segv
52
- stress = GC.stress
53
- const = JSON::SAFE_STATE_PROTOTYPE.dup
54
-
55
- bignum_too_long_to_embed_as_string = 1234567890123456789012345
56
- expect = bignum_too_long_to_embed_as_string.to_s
57
- GC.stress = true
58
-
59
- 10.times do |i|
60
- tmp = bignum_too_long_to_embed_as_string.to_json
61
- raise "'\#{expect}' is expected, but '\#{tmp}'" unless tmp == expect
62
- end
63
-
64
- silence do
65
- JSON.const_set :SAFE_STATE_PROTOTYPE, nil
66
- end
67
-
68
- 10.times do |i|
69
- assert_raise TypeError do
70
- bignum_too_long_to_embed_as_string.to_json
71
- end
72
- end
73
- ensure
74
- GC.stress = stress
75
- silence do
76
- JSON.const_set :SAFE_STATE_PROTOTYPE, const
77
- end
78
- end if JSON.const_defined?("Ext") && RUBY_ENGINE != 'jruby'
79
-
80
51
  def test_generate
81
52
  json = generate(@hash)
82
53
  assert_equal(parse(@json2), parse(json))
@@ -171,7 +142,7 @@ EOT
171
142
  end
172
143
 
173
144
  def test_pretty_state
174
- state = PRETTY_STATE_PROTOTYPE.dup
145
+ state = JSON.create_pretty_state
175
146
  assert_equal({
176
147
  :allow_nan => false,
177
148
  :array_nl => "\n",
@@ -188,7 +159,7 @@ EOT
188
159
  end
189
160
 
190
161
  def test_safe_state
191
- state = SAFE_STATE_PROTOTYPE.dup
162
+ state = JSON::State.new
192
163
  assert_equal({
193
164
  :allow_nan => false,
194
165
  :array_nl => "",
@@ -205,7 +176,7 @@ EOT
205
176
  end
206
177
 
207
178
  def test_fast_state
208
- state = FAST_STATE_PROTOTYPE.dup
179
+ state = JSON.create_fast_state
209
180
  assert_equal({
210
181
  :allow_nan => false,
211
182
  :array_nl => "",
@@ -241,12 +212,8 @@ EOT
241
212
 
242
213
  def test_depth
243
214
  ary = []; ary << ary
244
- assert_equal 0, JSON::SAFE_STATE_PROTOTYPE.depth
245
215
  assert_raise(JSON::NestingError) { generate(ary) }
246
- assert_equal 0, JSON::SAFE_STATE_PROTOTYPE.depth
247
- assert_equal 0, JSON::PRETTY_STATE_PROTOTYPE.depth
248
216
  assert_raise(JSON::NestingError) { JSON.pretty_generate(ary) }
249
- assert_equal 0, JSON::PRETTY_STATE_PROTOTYPE.depth
250
217
  s = JSON.state.new
251
218
  assert_equal 0, s.depth
252
219
  assert_raise(JSON::NestingError) { ary.to_json(s) }
@@ -265,7 +232,7 @@ EOT
265
232
  end
266
233
 
267
234
  def test_gc
268
- if respond_to?(:assert_in_out_err)
235
+ if respond_to?(:assert_in_out_err) && !(RUBY_PLATFORM =~ /java/)
269
236
  assert_in_out_err(%w[-rjson --disable-gems], <<-EOS, [], [])
270
237
  bignum_too_long_to_embed_as_string = 1234567890123456789012345
271
238
  expect = bignum_too_long_to_embed_as_string.to_s