json 2.4.1 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
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