oj 3.10.16 → 3.11.2

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: 1c6cf97a6abc7ea8698d7a6937bdd9444ed8e2def9447411fc6f2f0aaaaf1c9a
4
- data.tar.gz: d7c34c8a8de00f25718e2b20a404cc1f929dd091571a49070dee8e7edb18aa6b
3
+ metadata.gz: 9deb076071bb73df196bc549faa4fc56d42eb8417b70c6a6d050ec086b04a89a
4
+ data.tar.gz: 0d6f76b98e0e44d639a32b48959ac8aec6316e9b7726190056adc1022b8dac00
5
5
  SHA512:
6
- metadata.gz: a89b9497d951820e4d0c3e8e1bc94119acd85efec15a152513e29dd7210e1fbb41153a2205638862199b94eb50b05cc67e1b2fa373c4e0cbb834b44f210bc776
7
- data.tar.gz: d6ff8fddb8a6bc3475eb6555bdd03794d41ae3c9c553d23d1af3622e5b4c9729001429827eef32e80e8a19c3fd95984ae97eeafa0bca3768f6779d3a0987686a
6
+ metadata.gz: 0f856c84593191e1eddb72f85187c68c961f248d7e6ecac817f8fbfbba5d6bfbcf46a2691d6eacd307f51ed91a8a8bf637d97f76ab428d11e72b8760c59a35cc
7
+ data.tar.gz: 18498cc7854a8aace3beaab7d603361acd43545c8dbb8e73dddccee0ebe96aff9d47ca6635b9a7198e37288aa62366f1d81364a4e4be88117866543c773c40ee
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # [![{}j](http://www.ohler.com/dev/images/oj_comet_64.svg)](http://www.ohler.com/oj) gem
2
2
 
3
- [![Build Status](https://img.shields.io/travis/ohler55/oj/master.svg?logo=travis)](http://travis-ci.org/ohler55/oj?branch=master) [![AppVeyor](https://img.shields.io/appveyor/ci/ohler55/oj/master.svg?logo=appveyor)](https://ci.appveyor.com/project/ohler55/oj) ![Gem](https://img.shields.io/gem/v/oj.svg) ![Gem](https://img.shields.io/gem/dt/oj.svg) [![SemVer compatibility](https://api.dependabot.com/badges/compatibility_score?dependency-name=oj&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=oj&package-manager=bundler&version-scheme=semver) [![TideLift](https://tidelift.com/badges/github/ohler55/oj)](https://tidelift.com/subscription/pkg/rubygems-oj?utm_source=rubygems-oj&utm_medium=referral&utm_campaign=readme)
3
+ [![Build Status](https://img.shields.io/travis/ohler55/oj/master.svg?logo=travis)](http://travis-ci.org/ohler55/oj?branch=master) ![Gem](https://img.shields.io/gem/v/oj.svg) ![Gem](https://img.shields.io/gem/dt/oj.svg) [![SemVer compatibility](https://api.dependabot.com/badges/compatibility_score?dependency-name=oj&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=oj&package-manager=bundler&version-scheme=semver) [![TideLift](https://tidelift.com/badges/github/ohler55/oj)](https://tidelift.com/subscription/pkg/rubygems-oj?utm_source=rubygems-oj&utm_medium=referral&utm_campaign=readme)
4
4
 
5
5
  A *fast* JSON parser and Object marshaller as a Ruby gem.
6
6
 
@@ -174,15 +174,20 @@ hixss_friendly_size(const uint8_t *str, size_t len) {
174
174
  return size - len * (size_t)'0' + check;
175
175
  }
176
176
 
177
- inline static size_t
177
+ inline static long
178
178
  rails_xss_friendly_size(const uint8_t *str, size_t len) {
179
- size_t size = 0;
179
+ long size = 0;
180
180
  size_t i = len;
181
+ uint8_t hi = 0;
181
182
 
182
183
  for (; 0 < i; str++, i--) {
183
184
  size += rails_xss_friendly_chars[*str];
185
+ hi |= *str & 0x80;
184
186
  }
185
- return size - len * (size_t)'0';
187
+ if (0 == hi) {
188
+ return size - len * (size_t)'0';
189
+ }
190
+ return -(size - len * (size_t)'0');
186
191
  }
187
192
 
188
193
  inline static size_t
@@ -249,7 +254,6 @@ dump_hex(uint8_t c, Out out) {
249
254
 
250
255
  static void
251
256
  raise_invalid_unicode(const char *str, int len, int pos) {
252
- char buf[len + 1];
253
257
  char c;
254
258
  char code[32];
255
259
  char *cp = code;
@@ -268,8 +272,7 @@ raise_invalid_unicode(const char *str, int len, int pos) {
268
272
  cp--;
269
273
  *cp++ = ']';
270
274
  *cp = '\0';
271
- strncpy(buf, str, len);
272
- rb_raise(oj_json_generator_error_class, "Invalid Unicode %s at %d in '%s'", code, pos, buf);
275
+ rb_raise(oj_json_generator_error_class, "Invalid Unicode %s at %d", code, pos);
273
276
  }
274
277
 
275
278
  static const char*
@@ -767,6 +770,7 @@ oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
767
770
  size_t size;
768
771
  char *cmap;
769
772
  const char *orig = str;
773
+ bool has_hi = false;
770
774
 
771
775
  switch (out->opts->escape_mode) {
772
776
  case NLEsc:
@@ -785,10 +789,19 @@ oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
785
789
  cmap = hixss_friendly_chars;
786
790
  size = hixss_friendly_size((uint8_t*)str, cnt);
787
791
  break;
788
- case RailsXEsc:
792
+ case RailsXEsc: {
793
+ long sz;
794
+
789
795
  cmap = rails_xss_friendly_chars;
790
- size = rails_xss_friendly_size((uint8_t*)str, cnt);
796
+ sz = rails_xss_friendly_size((uint8_t*)str, cnt);
797
+ if (sz < 0) {
798
+ has_hi = true;
799
+ size = (size_t)-sz;
800
+ } else {
801
+ size = (size_t)sz;
802
+ }
791
803
  break;
804
+ }
792
805
  case RailsEsc:
793
806
  cmap = rails_friendly_chars;
794
807
  size = rails_friendly_size((uint8_t*)str, cnt);
@@ -812,7 +825,7 @@ oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
812
825
  str++;
813
826
  is_sym = 0; // just to make sure
814
827
  }
815
- if (cnt == size) {
828
+ if (cnt == size && !has_hi) {
816
829
  if (is_sym) {
817
830
  *out->cur++ = ':';
818
831
  }
@@ -364,7 +364,6 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
364
364
  struct _out out;
365
365
  VALUE rstr;
366
366
 
367
- // TBD
368
367
  memset(buf, 0, sizeof(buf));
369
368
 
370
369
  out.buf = buf;
@@ -510,7 +509,6 @@ mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
510
509
  pi.options.create_ok = No;
511
510
  pi.options.allow_nan = (bang ? Yes : No);
512
511
  pi.options.nilnil = No;
513
- //pi.options.bigdec_load = FloatDec;
514
512
  pi.options.bigdec_load = RubyDec;
515
513
  pi.options.mode = CompatMode;
516
514
  pi.max_depth = 100;
@@ -561,6 +559,9 @@ mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
561
559
  pi.options.array_class = v;
562
560
  }
563
561
  }
562
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_decimal_class_sym)) {
563
+ pi.options.compat_bigdec = (oj_bigdecimal_class == rb_hash_lookup(ropts, oj_decimal_class_sym));
564
+ }
564
565
  v = rb_hash_lookup(ropts, oj_max_nesting_sym);
565
566
  if (Qtrue == v) {
566
567
  pi.max_depth = 100;
@@ -685,6 +686,7 @@ static struct _options mimic_object_to_json_options = {
685
686
  RubyTime, // time_format
686
687
  No, // bigdec_as_num
687
688
  RubyDec, // bigdec_load
689
+ false, // compat_bigdec
688
690
  No, // to_hash
689
691
  No, // to_json
690
692
  No, // as_json
@@ -839,6 +841,7 @@ oj_mimic_json_methods(VALUE json) {
839
841
  }
840
842
  // Pull in the JSON::State mimic file.
841
843
  state_class = rb_const_get_at(generator, rb_intern("State"));
844
+ rb_gc_register_mark_object(state_class);
842
845
 
843
846
  symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym);
844
847
  }
@@ -88,6 +88,7 @@ VALUE oj_slash_string;
88
88
  VALUE oj_allow_nan_sym;
89
89
  VALUE oj_array_class_sym;
90
90
  VALUE oj_create_additions_sym;
91
+ VALUE oj_decimal_class_sym;
91
92
  VALUE oj_hash_class_sym;
92
93
  VALUE oj_indent_sym;
93
94
  VALUE oj_object_class_sym;
@@ -106,6 +107,7 @@ static VALUE bigdecimal_load_sym;
106
107
  static VALUE bigdecimal_sym;
107
108
  static VALUE circular_sym;
108
109
  static VALUE class_cache_sym;
110
+ static VALUE compat_bigdecimal_sym;
109
111
  static VALUE compat_sym;
110
112
  static VALUE create_id_sym;
111
113
  static VALUE custom_sym;
@@ -167,6 +169,7 @@ struct _options oj_default_options = {
167
169
  UnixTime, // time_format
168
170
  NotSet, // bigdec_as_num
169
171
  AutoDec, // bigdec_load
172
+ false, // compat_bigdec
170
173
  No, // to_hash
171
174
  No, // to_json
172
175
  No, // as_json
@@ -229,6 +232,7 @@ struct _options oj_default_options = {
229
232
  * - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
230
233
  * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
231
234
  * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits. :float should be the same as ruby. :fast may require rounding but is must faster.
235
+ * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as a Float when in compat or rails mode.
232
236
  * - *:create_id* [_String_|_nil_] create id for json compatible object encoding, default is 'json_class'
233
237
  * - *:create_additions* [_Boolean_|_nil_] if true allow creation of instances using create_id on load.
234
238
  * - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal when dumping the seconds portion of time
@@ -333,6 +337,7 @@ get_def_opts(VALUE self) {
333
337
  case AutoDec:
334
338
  default: rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); break;
335
339
  }
340
+ rb_hash_aset(opts, compat_bigdecimal_sym, oj_default_options.compat_bigdec ? Qtrue : Qfalse);
336
341
  rb_hash_aset(opts, create_id_sym, (NULL == oj_default_options.create_id) ? Qnil : rb_str_new2(oj_default_options.create_id));
337
342
  rb_hash_aset(opts, oj_space_sym, (0 == oj_default_options.dump_opts.after_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.after_sep));
338
343
  rb_hash_aset(opts, oj_space_before_sym, (0 == oj_default_options.dump_opts.before_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.before_sep));
@@ -378,6 +383,7 @@ get_def_opts(VALUE self) {
378
383
  * - *:escape* [_:newline_|_:json_|_:xss_safe_|_:ascii_|_unicode_xss_|_nil_] mode encodes all high-bit characters as escaped sequences if :ascii, :json is standand UTF-8 JSON encoding, :newline is the same as :json but newlines are not escaped, :unicode_xss allows unicode but escapes &, <, and >, and any \u20xx characters along with some others, and :xss_safe escapes &, <, and >, and some others.
379
384
  * - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String.
380
385
  * - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_nil_] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
386
+ * - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as a Float in compat mode.
381
387
  * - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_|_:wab_] load and dump mode to use for JSON :strict raises an exception when a non-supported Object is encountered. :compat attempts to extract variable values from an Object using to_json() or to_hash() then it walks the Object's variables if neither is found. The :object mode ignores to_hash() and to_json() methods and encodes variables using code internal to the Oj gem. The :null mode ignores non-supported Objects and replaces them with a null. The :custom mode honors all dump options. The :rails more mimics rails and Active behavior.
382
388
  * - *:time_format* [_:unix_|_:xmlschema_|_:ruby_] time format when dumping in :compat mode :unix decimal number denoting the number of seconds since 1/1/1970, :unix_zone decimal number denoting the number of seconds since 1/1/1970 plus the utc_offset in the exponent, :xmlschema date-time format taken from XML Schema as a String, :ruby Time.to_s formatted String.
383
389
  * - *:create_id* [_String_|_nil_] create id for json compatible object encoding
@@ -581,6 +587,19 @@ oj_parse_options(VALUE ropts, Options copts) {
581
587
  rb_raise(rb_eArgError, ":bigdecimal_load must be :bigdecimal, :float, or :auto.");
582
588
  }
583
589
  }
590
+ if (Qnil != (v = rb_hash_lookup(ropts, compat_bigdecimal_sym))) {
591
+ copts->compat_bigdec = (Qtrue == v);
592
+ }
593
+ if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_decimal_class_sym)) {
594
+ v = rb_hash_lookup(ropts, oj_decimal_class_sym);
595
+ if (rb_cFloat == v) {
596
+ copts->compat_bigdec = false;
597
+ } else if (oj_bigdecimal_class == v) {
598
+ copts->compat_bigdec = true;
599
+ } else {
600
+ rb_raise(rb_eArgError, ":decimal_class must be BigDecimal or Float.");
601
+ }
602
+ }
584
603
  if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, create_id_sym)) {
585
604
  v = rb_hash_lookup(ropts, create_id_sym);
586
605
  if (Qnil == v) {
@@ -1628,13 +1647,21 @@ Init_oj() {
1628
1647
  rb_require("oj/schandler");
1629
1648
 
1630
1649
  oj_bag_class = rb_const_get_at(Oj, rb_intern("Bag"));
1650
+ rb_gc_register_mark_object(oj_bag_class);
1631
1651
  oj_bigdecimal_class = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
1652
+ rb_gc_register_mark_object(oj_bigdecimal_class);
1632
1653
  oj_date_class = rb_const_get(rb_cObject, rb_intern("Date"));
1654
+ rb_gc_register_mark_object(oj_date_class);
1633
1655
  oj_datetime_class = rb_const_get(rb_cObject, rb_intern("DateTime"));
1656
+ rb_gc_register_mark_object(oj_datetime_class);
1634
1657
  oj_enumerable_class = rb_const_get(rb_cObject, rb_intern("Enumerable"));
1658
+ rb_gc_register_mark_object(oj_enumerable_class);
1635
1659
  oj_parse_error_class = rb_const_get_at(Oj, rb_intern("ParseError"));
1660
+ rb_gc_register_mark_object(oj_parse_error_class);
1636
1661
  oj_stringio_class = rb_const_get(rb_cObject, rb_intern("StringIO"));
1662
+ rb_gc_register_mark_object(oj_stringio_class);
1637
1663
  oj_struct_class = rb_const_get(rb_cObject, rb_intern("Struct"));
1664
+ rb_gc_register_mark_object(oj_struct_class);
1638
1665
  oj_json_parser_error_class = rb_eEncodingError; // replaced if mimic is called
1639
1666
  oj_json_generator_error_class = rb_eEncodingError; // replaced if mimic is called
1640
1667
 
@@ -1649,6 +1676,7 @@ Init_oj() {
1649
1676
  bigdecimal_sym = ID2SYM(rb_intern("bigdecimal")); rb_gc_register_address(&bigdecimal_sym);
1650
1677
  circular_sym = ID2SYM(rb_intern("circular")); rb_gc_register_address(&circular_sym);
1651
1678
  class_cache_sym = ID2SYM(rb_intern("class_cache")); rb_gc_register_address(&class_cache_sym);
1679
+ compat_bigdecimal_sym = ID2SYM(rb_intern("compat_bigdecimal"));rb_gc_register_address(&compat_bigdecimal_sym);
1652
1680
  compat_sym = ID2SYM(rb_intern("compat")); rb_gc_register_address(&compat_sym);
1653
1681
  create_id_sym = ID2SYM(rb_intern("create_id")); rb_gc_register_address(&create_id_sym);
1654
1682
  custom_sym = ID2SYM(rb_intern("custom")); rb_gc_register_address(&custom_sym);
@@ -1674,6 +1702,7 @@ Init_oj() {
1674
1702
  oj_array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&oj_array_nl_sym);
1675
1703
  oj_ascii_only_sym = ID2SYM(rb_intern("ascii_only")); rb_gc_register_address(&oj_ascii_only_sym);
1676
1704
  oj_create_additions_sym = ID2SYM(rb_intern("create_additions"));rb_gc_register_address(&oj_create_additions_sym);
1705
+ oj_decimal_class_sym = ID2SYM(rb_intern("decimal_class")); rb_gc_register_address(&oj_decimal_class_sym);
1677
1706
  oj_hash_class_sym = ID2SYM(rb_intern("hash_class")); rb_gc_register_address(&oj_hash_class_sym);
1678
1707
  oj_indent_sym = ID2SYM(rb_intern("indent")); rb_gc_register_address(&oj_indent_sym);
1679
1708
  oj_max_nesting_sym = ID2SYM(rb_intern("max_nesting")); rb_gc_register_address(&oj_max_nesting_sym);
@@ -135,6 +135,7 @@ typedef struct _options {
135
135
  char time_format; // TimeFormat
136
136
  char bigdec_as_num; // YesNo
137
137
  char bigdec_load; // BigLoad
138
+ char compat_bigdec; // boolean (0 or 1)
138
139
  char to_hash; // YesNo
139
140
  char to_json; // YesNo
140
141
  char as_json; // YesNo
@@ -310,6 +311,7 @@ extern VALUE oj_array_class_sym;
310
311
  extern VALUE oj_array_nl_sym;
311
312
  extern VALUE oj_ascii_only_sym;
312
313
  extern VALUE oj_create_additions_sym;
314
+ extern VALUE oj_decimal_class_sym;
313
315
  extern VALUE oj_hash_class_sym;
314
316
  extern VALUE oj_indent_sym;
315
317
  extern VALUE oj_max_nesting_sym;
@@ -385,8 +385,13 @@ read_num(ParseInfo pi) {
385
385
  ni.nan = 0;
386
386
  ni.neg = 0;
387
387
  ni.has_exp = 0;
388
- ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
389
- ni.bigdec_load = pi->options.bigdec_load;
388
+ if (CompatMode == pi->options.mode) {
389
+ ni.no_big = !pi->options.compat_bigdec;
390
+ ni.bigdec_load = pi->options.compat_bigdec;
391
+ } else {
392
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
393
+ ni.bigdec_load = pi->options.bigdec_load;
394
+ }
390
395
 
391
396
  if ('-' == *pi->cur) {
392
397
  pi->cur++;
@@ -511,7 +516,11 @@ read_num(ParseInfo pi) {
511
516
  ni.nan = 1;
512
517
  }
513
518
  }
514
- if (BigDec == pi->options.bigdec_load) {
519
+ if (CompatMode == pi->options.mode) {
520
+ if (pi->options.compat_bigdec) {
521
+ ni.big = 1;
522
+ }
523
+ } else if (BigDec == pi->options.bigdec_load) {
515
524
  ni.big = 1;
516
525
  }
517
526
  if (0 == parent) {
@@ -400,8 +400,13 @@ read_num(ParseInfo pi) {
400
400
  ni.nan = 0;
401
401
  ni.neg = 0;
402
402
  ni.has_exp = 0;
403
- ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
404
- ni.bigdec_load = pi->options.bigdec_load;
403
+ if (CompatMode == pi->options.mode) {
404
+ ni.no_big = !pi->options.compat_bigdec;
405
+ ni.bigdec_load = pi->options.compat_bigdec;
406
+ } else {
407
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
408
+ ni.bigdec_load = pi->options.bigdec_load;
409
+ }
405
410
 
406
411
  c = reader_get(&pi->rd);
407
412
  if ('-' == c) {
@@ -518,7 +523,11 @@ read_num(ParseInfo pi) {
518
523
  ni.nan = 1;
519
524
  }
520
525
  }
521
- if (BigDec == pi->options.bigdec_load) {
526
+ if (CompatMode == pi->options.mode) {
527
+ if (pi->options.compat_bigdec) {
528
+ ni.big = 1;
529
+ }
530
+ } else if (BigDec == pi->options.bigdec_load) {
522
531
  ni.big = 1;
523
532
  }
524
533
  add_num_value(pi, &ni);
@@ -541,15 +550,24 @@ read_nan(ParseInfo pi) {
541
550
  ni.infinity = 0;
542
551
  ni.nan = 1;
543
552
  ni.neg = 0;
544
- ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
545
- ni.bigdec_load = pi->options.bigdec_load;
553
+ if (CompatMode == pi->options.mode) {
554
+ ni.no_big = !pi->options.compat_bigdec;
555
+ ni.bigdec_load = pi->options.compat_bigdec;
556
+ } else {
557
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
558
+ ni.bigdec_load = pi->options.bigdec_load;
559
+ }
546
560
 
547
561
  if ('a' != reader_get(&pi->rd) ||
548
562
  ('N' != (c = reader_get(&pi->rd)) && 'n' != c)) {
549
563
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
550
564
  return;
551
565
  }
552
- if (BigDec == pi->options.bigdec_load) {
566
+ if (CompatMode == pi->options.mode) {
567
+ if (pi->options.compat_bigdec) {
568
+ ni.big = 1;
569
+ }
570
+ } else if (BigDec == pi->options.bigdec_load) {
553
571
  ni.big = 1;
554
572
  }
555
573
  add_num_value(pi, &ni);
@@ -739,8 +757,15 @@ oj_sparse2(ParseInfo pi) {
739
757
  ni.infinity = 0;
740
758
  ni.nan = 1;
741
759
  ni.neg = 0;
742
- ni.no_big = (FloatDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load);
743
- ni.bigdec_load = pi->options.bigdec_load;
760
+ if (CompatMode == pi->options.mode) {
761
+ ni.no_big = !pi->options.compat_bigdec;
762
+ ni.bigdec_load = pi->options.compat_bigdec;
763
+ } else {
764
+ ni.no_big = (FloatDec == pi->options.bigdec_load ||
765
+ FastDec == pi->options.bigdec_load ||
766
+ RubyDec == pi->options.bigdec_load);
767
+ ni.bigdec_load = pi->options.bigdec_load;
768
+ }
744
769
  add_num_value(pi, &ni);
745
770
  } else {
746
771
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid token");
@@ -8,6 +8,50 @@ end
8
8
 
9
9
  module Oj
10
10
 
11
+ ##
12
+ # Custom mode can be used to emulate the compat mode with some minor
13
+ # differences. These are the options that setup the custom mode to be like
14
+ # the compat mode.
15
+ CUSTOM_MIMIC_JSON_OPTIONS = {
16
+ allow_gc: true,
17
+ allow_invalid_unicode: false,
18
+ allow_nan: false,
19
+ array_class: nil,
20
+ array_nl: nil,
21
+ auto_define: false,
22
+ bigdecimal_as_decimal: false,
23
+ bigdecimal_load: :auto,
24
+ circular: false,
25
+ class_cache: false,
26
+ create_additions: false,
27
+ create_id: "json_class",
28
+ empty_string: false,
29
+ escape_mode: :unicode_xss,
30
+ float_precision: 0,
31
+ hash_class: nil,
32
+ ignore: nil,
33
+ ignore_under: false,
34
+ indent: 0,
35
+ integer_range: nil,
36
+ mode: :custom,
37
+ nan: :raise,
38
+ nilnil: false,
39
+ object_nl: nil,
40
+ omit_nil: false,
41
+ quirks_mode: true,
42
+ safe: false,
43
+ second_precision: 3,
44
+ space: nil,
45
+ space_before: nil,
46
+ symbol_keys: false,
47
+ time_format: :ruby,
48
+ trace: false,
49
+ use_as_json: false,
50
+ use_raw_json: false,
51
+ use_to_hash: false,
52
+ use_to_json: true,
53
+ }
54
+
11
55
  # A bit hack-ish but does the trick. The JSON.dump_default_options is a Hash
12
56
  # but in mimic we use a C struct to store defaults. This class creates a view
13
57
  # onto that struct.
@@ -38,7 +82,7 @@ module Oj
38
82
 
39
83
  jfile = File.join(d, 'json.rb')
40
84
  $LOADED_FEATURES << jfile unless $LOADED_FEATURES.include?(jfile) if File.exist?(jfile)
41
-
85
+
42
86
  Dir.glob(File.join(d, 'json', '**', '*.rb')).each do |file|
43
87
  # allow json/add/xxx to be loaded. User can override with Oj.add_to_json(xxx).
44
88
  $LOADED_FEATURES << file unless $LOADED_FEATURES.include?(file) unless file.include?('add')
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '3.10.16'
4
+ VERSION = '3.11.2'
5
5
  end
@@ -96,6 +96,7 @@ information.
96
96
  | :auto_define | Boolean | | | | | x | x | |
97
97
  | :bigdecimal_as_decimal | Boolean | | | | 3 | x | x | |
98
98
  | :bigdecimal_load | Boolean | | | | | | x | |
99
+ | :compat_bigdecimal | Boolean | | | x | | | x | |
99
100
  | :circular | Boolean | x | x | x | x | x | x | |
100
101
  | :class_cache | Boolean | | | | | x | x | |
101
102
  | :create_additions | Boolean | | | x | x | | x | |
@@ -66,6 +66,18 @@ Determines how to load decimals.
66
66
 
67
67
  - `:auto` the most precise for the number of digits is used.
68
68
 
69
+ This can also be set with `:decimal_class` when used as a load or
70
+ parse option to match the JSON gem. In that case either `Float`,
71
+ `BigDecimal`, or `nil` can be provided.
72
+
73
+ ### :compat_bigdecimal [Boolean]
74
+
75
+ Determines how to load decimals when in `:compat` mode.
76
+
77
+ - `true` convert all decimal numbers to BigDecimal.
78
+
79
+ - `false` convert all decimal numbers to Float.
80
+
69
81
  ### :circular [Boolean]
70
82
 
71
83
  Detect circular references while dumping. In :compat mode raise a
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+ #
1
3
  # Ubuntu does not accept arguments to ruby when called using env. To get warnings to show up the -w options is
2
4
  # required. That can be set in the RUBYOPT environment variable.
3
5
  # export RUBYOPT=-w
@@ -16,6 +18,14 @@ require 'bigdecimal'
16
18
  require 'pp'
17
19
  require 'oj'
18
20
 
21
+
22
+ if defined?(GC.verify_compaction_references) == 'method'
23
+ # This method was added in Ruby 3.0.0. Calling it this way asks the GC to
24
+ # move objects around, helping to find object movement bugs.
25
+ GC.verify_compaction_references(double_heap: true, toward: :empty)
26
+ end
27
+
28
+
19
29
  $ruby = RUBY_DESCRIPTION.split(' ')[0]
20
30
  $ruby = 'ree' if 'ruby' == $ruby && RUBY_DESCRIPTION.include?('Ruby Enterprise Edition')
21
31
 
@@ -136,6 +136,10 @@ EOT
136
136
 
137
137
  def test_pretty_state
138
138
  state = JSON::PRETTY_STATE_PROTOTYPE.dup
139
+ # In come cases in Ruby 3.0 an :escape_slash is included in the state. It
140
+ # seems to occur on travis but not locally.
141
+ actual = state.to_h
142
+ actual.delete(:escape_slash)
139
143
  assert_equal({
140
144
  :allow_nan => false,
141
145
  :array_nl => "\n",
@@ -147,11 +151,15 @@ EOT
147
151
  :object_nl => "\n",
148
152
  :space => " ",
149
153
  :space_before => "",
150
- }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
154
+ }.sort_by { |n,| n.to_s }, actual.sort_by { |n,| n.to_s })
151
155
  end
152
156
 
153
157
  def test_safe_state
154
158
  state = JSON::SAFE_STATE_PROTOTYPE.dup
159
+ # In come cases in Ruby 3.0 an :escape_slash is included in the state. It
160
+ # seems to occur on travis but not locally.
161
+ actual = state.to_h
162
+ actual.delete(:escape_slash)
155
163
  assert_equal({
156
164
  :allow_nan => false,
157
165
  :array_nl => "",
@@ -163,11 +171,15 @@ EOT
163
171
  :object_nl => "",
164
172
  :space => "",
165
173
  :space_before => "",
166
- }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
174
+ }.sort_by { |n,| n.to_s }, actual.sort_by { |n,| n.to_s })
167
175
  end
168
176
 
169
177
  def test_fast_state
170
178
  state = JSON::FAST_STATE_PROTOTYPE.dup
179
+ # In come cases in Ruby 3.0 an :escape_slash is included in the state. It
180
+ # seems to occur on travis but not locally.
181
+ actual = state.to_h
182
+ actual.delete(:escape_slash)
171
183
  assert_equal({
172
184
  :allow_nan => false,
173
185
  :array_nl => "",
@@ -179,7 +191,7 @@ EOT
179
191
  :object_nl => "",
180
192
  :space => "",
181
193
  :space_before => "",
182
- }.sort_by { |n,| n.to_s }, state.to_h.sort_by { |n,| n.to_s })
194
+ }.sort_by { |n,| n.to_s }, actual.sort_by { |n,| n.to_s })
183
195
  end
184
196
 
185
197
  def test_allow_nan
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  $: << File.dirname(__FILE__)
2
4
  $oj_dir = File.dirname(File.dirname(File.expand_path(File.dirname(__FILE__))))
3
5
  %w(lib ext).each do |dir|
@@ -12,6 +14,12 @@ if ENV['REAL_JSON_GEM']
12
14
  else
13
15
  require 'oj'
14
16
  Oj.mimic_JSON
17
+
18
+ if defined?(GC.verify_compaction_references) == 'method'
19
+ # This method was added in Ruby 3.0.0. Calling it this way asks the GC to
20
+ # move objects around, helping to find object movement bugs.
21
+ GC.verify_compaction_references(double_heap: true, toward: :empty)
22
+ end
15
23
  end
16
24
 
17
25
  NaN = JSON::NaN if defined?(JSON::NaN)
@@ -178,7 +178,7 @@ class CompatJuice < Minitest::Test
178
178
  assert_equal('"abc"', json)
179
179
  end
180
180
 
181
- def test_time
181
+ def test_time_xml_schema
182
182
  t = Time.xmlschema("2012-01-05T23:58:07.123456000+09:00")
183
183
  #t = Time.local(2012, 1, 5, 23, 58, 7, 123456)
184
184
  json = Oj.dump(t, :mode => :compat)
@@ -277,12 +277,19 @@ class CompatJuice < Minitest::Test
277
277
  # BigDecimal
278
278
  def test_bigdecimal
279
279
  # BigDecimals are dumped as strings and can not be restored to the
280
- # original value.
280
+ # original value without using an undocumented feature of the JSON gem.
281
281
  json = Oj.dump(BigDecimal('3.14159265358979323846'))
282
282
  # 2.4.0 changes the exponent to lowercase
283
283
  assert_equal('"0.314159265358979323846e1"', json.downcase)
284
284
  end
285
285
 
286
+ def test_decimal_class
287
+ big = BigDecimal('3.14159265358979323846')
288
+ # :decimal_class is the undocumented feature.
289
+ json = Oj.load('3.14159265358979323846', mode: :compat, decimal_class: BigDecimal)
290
+ assert_equal(big, json)
291
+ end
292
+
286
293
  def test_infinity
287
294
  assert_raises(Oj::ParseError) { Oj.load('Infinity', :mode => :strict) }
288
295
  x = Oj.load('Infinity', :mode => :compat)
@@ -290,7 +297,7 @@ class CompatJuice < Minitest::Test
290
297
  end
291
298
 
292
299
  # Time
293
- def test_time
300
+ def test_time_from_time_object
294
301
  t = Time.new(2015, 1, 5, 21, 37, 7.123456, -8 * 3600)
295
302
  expect = '"' + t.to_s + '"'
296
303
  json = Oj.dump(t)
@@ -23,4 +23,13 @@ class RailsJuice < Minitest::Test
23
23
  assert_equal('0.123e3', json.downcase)
24
24
  end
25
25
 
26
+ def test_invalid_encoding
27
+ assert_raises(EncodingError) {
28
+ Oj.dump("\"\xf3j", mode: :rails)
29
+ }
30
+ assert_raises(EncodingError) {
31
+ Oj.dump("\xf3j", mode: :rails)
32
+ }
33
+ end
34
+
26
35
  end
@@ -120,6 +120,7 @@ class Juice < Minitest::Test
120
120
  escape_mode: :ascii,
121
121
  time_format: :unix_zone,
122
122
  bigdecimal_load: :float,
123
+ compat_bigdecimal: true,
123
124
  create_id: 'classy',
124
125
  create_additions: true,
125
126
  space: 'z',
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oj
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.10.16
4
+ version: 3.11.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Ohler
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-10 00:00:00.000000000 Z
11
+ date: 2021-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -79,16 +79,16 @@ extensions:
79
79
  - ext/oj/extconf.rb
80
80
  extra_rdoc_files:
81
81
  - README.md
82
- - pages/Rails.md
83
- - pages/JsonGem.md
84
- - pages/Encoding.md
85
- - pages/WAB.md
86
- - pages/Custom.md
87
82
  - pages/Advanced.md
88
- - pages/Options.md
89
83
  - pages/Compatibility.md
84
+ - pages/Custom.md
85
+ - pages/Encoding.md
86
+ - pages/JsonGem.md
90
87
  - pages/Modes.md
88
+ - pages/Options.md
89
+ - pages/Rails.md
91
90
  - pages/Security.md
91
+ - pages/WAB.md
92
92
  files:
93
93
  - LICENSE
94
94
  - README.md
@@ -265,7 +265,7 @@ metadata:
265
265
  homepage_uri: http://www.ohler.com/oj/
266
266
  source_code_uri: https://github.com/ohler55/oj
267
267
  wiki_uri: https://github.com/ohler55/oj/wiki
268
- post_install_message:
268
+ post_install_message:
269
269
  rdoc_options:
270
270
  - "--title"
271
271
  - Oj
@@ -284,98 +284,98 @@ required_rubygems_version: !ruby/object:Gem::Requirement
284
284
  - !ruby/object:Gem::Version
285
285
  version: '0'
286
286
  requirements: []
287
- rubygems_version: 3.1.2
288
- signing_key:
287
+ rubygems_version: 3.2.3
288
+ signing_key:
289
289
  specification_version: 4
290
290
  summary: A fast JSON parser and serializer.
291
291
  test_files:
292
+ - test/_test_active.rb
293
+ - test/_test_active_mimic.rb
294
+ - test/_test_mimic_rails.rb
295
+ - test/activerecord/result_test.rb
296
+ - test/activesupport4/decoding_test.rb
297
+ - test/activesupport4/encoding_test.rb
298
+ - test/activesupport4/test_helper.rb
299
+ - test/activesupport5/abstract_unit.rb
300
+ - test/activesupport5/decoding_test.rb
301
+ - test/activesupport5/encoding_test.rb
302
+ - test/activesupport5/encoding_test_cases.rb
303
+ - test/activesupport5/test_helper.rb
304
+ - test/activesupport5/time_zone_test_helpers.rb
305
+ - test/activesupport6/abstract_unit.rb
306
+ - test/activesupport6/decoding_test.rb
307
+ - test/activesupport6/encoding_test.rb
308
+ - test/activesupport6/encoding_test_cases.rb
309
+ - test/activesupport6/test_common.rb
310
+ - test/activesupport6/test_helper.rb
311
+ - test/activesupport6/time_zone_test_helpers.rb
312
+ - test/bar.rb
313
+ - test/baz.rb
314
+ - test/files.rb
292
315
  - test/foo.rb
293
- - test/prec.rb
294
- - test/test_integer_range.rb
295
- - test/test_strict.rb
296
- - test/perf_strict.rb
297
- - test/tests.rb
298
- - test/perf_saj.rb
299
- - test/test_compat.rb
300
316
  - test/helper.rb
301
- - test/perf_file.rb
302
- - test/test_scp.rb
303
- - test/perf_compat.rb
304
- - test/json_gem/json_common_interface_test.rb
317
+ - test/isolated/shared.rb
318
+ - test/isolated/test_mimic_after.rb
319
+ - test/isolated/test_mimic_alone.rb
320
+ - test/isolated/test_mimic_as_json.rb
321
+ - test/isolated/test_mimic_before.rb
322
+ - test/isolated/test_mimic_define.rb
323
+ - test/isolated/test_mimic_rails_after.rb
324
+ - test/isolated/test_mimic_rails_before.rb
325
+ - test/isolated/test_mimic_redefine.rb
305
326
  - test/json_gem/json_addition_test.rb
306
- - test/json_gem/json_fixtures_test.rb
327
+ - test/json_gem/json_common_interface_test.rb
328
+ - test/json_gem/json_encoding_test.rb
307
329
  - test/json_gem/json_ext_parser_test.rb
308
- - test/json_gem/json_string_matching_test.rb
309
- - test/json_gem/json_generic_object_test.rb
330
+ - test/json_gem/json_fixtures_test.rb
310
331
  - test/json_gem/json_generator_test.rb
311
- - test/json_gem/test_helper.rb
312
- - test/json_gem/json_encoding_test.rb
332
+ - test/json_gem/json_generic_object_test.rb
313
333
  - test/json_gem/json_parser_test.rb
314
- - test/perf_wab.rb
315
- - test/test_file.rb
316
- - test/test_object.rb
317
- - test/sample.rb
334
+ - test/json_gem/json_string_matching_test.rb
335
+ - test/json_gem/test_helper.rb
336
+ - test/perf.rb
337
+ - test/perf_compat.rb
338
+ - test/perf_fast.rb
339
+ - test/perf_file.rb
318
340
  - test/perf_object.rb
319
- - test/test_hash.rb
320
- - test/test_custom.rb
321
- - test/bar.rb
322
- - test/activesupport4/encoding_test.rb
323
- - test/activesupport4/test_helper.rb
324
- - test/activesupport4/decoding_test.rb
325
- - test/sample_json.rb
326
- - test/activesupport5/encoding_test_cases.rb
327
- - test/activesupport5/encoding_test.rb
328
- - test/activesupport5/abstract_unit.rb
329
- - test/activesupport5/time_zone_test_helpers.rb
330
- - test/activesupport5/test_helper.rb
331
- - test/activesupport5/decoding_test.rb
332
- - test/test_saj.rb
341
+ - test/perf_saj.rb
333
342
  - test/perf_scp.rb
334
- - test/test_wab.rb
335
- - test/test_null.rb
336
- - test/_test_active.rb
337
- - test/_test_mimic_rails.rb
338
- - test/test_fast.rb
339
- - test/perf_fast.rb
343
+ - test/perf_simple.rb
344
+ - test/perf_strict.rb
345
+ - test/perf_wab.rb
346
+ - test/prec.rb
340
347
  - test/sample/change.rb
341
- - test/sample/text.rb
348
+ - test/sample/dir.rb
342
349
  - test/sample/doc.rb
343
- - test/sample/shape.rb
344
- - test/sample/layer.rb
345
- - test/sample/group.rb
346
350
  - test/sample/file.rb
347
- - test/sample/rect.rb
351
+ - test/sample/group.rb
348
352
  - test/sample/hasprops.rb
353
+ - test/sample/layer.rb
349
354
  - test/sample/line.rb
350
- - test/sample/dir.rb
351
355
  - test/sample/oval.rb
352
- - test/tests_mimic.rb
353
- - test/perf_simple.rb
354
- - test/zoo.rb
355
- - test/activerecord/result_test.rb
356
- - test/_test_active_mimic.rb
357
- - test/baz.rb
358
- - test/tests_mimic_addition.rb
359
- - test/test_writer.rb
360
- - test/test_rails.rb
361
- - test/perf.rb
362
- - test/isolated/test_mimic_define.rb
363
- - test/isolated/test_mimic_after.rb
364
- - test/isolated/test_mimic_rails_after.rb
365
- - test/isolated/test_mimic_before.rb
366
- - test/isolated/test_mimic_rails_before.rb
367
- - test/isolated/test_mimic_redefine.rb
368
- - test/isolated/shared.rb
369
- - test/isolated/test_mimic_alone.rb
370
- - test/isolated/test_mimic_as_json.rb
356
+ - test/sample/rect.rb
357
+ - test/sample/shape.rb
358
+ - test/sample/text.rb
359
+ - test/sample.rb
360
+ - test/sample_json.rb
361
+ - test/test_compat.rb
362
+ - test/test_custom.rb
371
363
  - test/test_debian.rb
364
+ - test/test_fast.rb
365
+ - test/test_file.rb
372
366
  - test/test_gc.rb
373
- - test/files.rb
367
+ - test/test_hash.rb
368
+ - test/test_integer_range.rb
369
+ - test/test_null.rb
370
+ - test/test_object.rb
371
+ - test/test_rails.rb
372
+ - test/test_saj.rb
373
+ - test/test_scp.rb
374
+ - test/test_strict.rb
374
375
  - test/test_various.rb
375
- - test/activesupport6/encoding_test_cases.rb
376
- - test/activesupport6/encoding_test.rb
377
- - test/activesupport6/abstract_unit.rb
378
- - test/activesupport6/time_zone_test_helpers.rb
379
- - test/activesupport6/test_helper.rb
380
- - test/activesupport6/test_common.rb
381
- - test/activesupport6/decoding_test.rb
376
+ - test/test_wab.rb
377
+ - test/test_writer.rb
378
+ - test/tests.rb
379
+ - test/tests_mimic.rb
380
+ - test/tests_mimic_addition.rb
381
+ - test/zoo.rb