oj 3.16.11 → 3.17.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/oj/sparse.c CHANGED
@@ -290,13 +290,13 @@ static void read_escaped_str(ParseInfo pi) {
290
290
  case NEXT_HASH_NEW:
291
291
  case NEXT_HASH_KEY:
292
292
  if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
293
- parent->klen = buf_len(&buf);
294
- parent->key = malloc(parent->klen + 1);
295
- memcpy((char *)parent->key, buf.head, parent->klen);
296
- *(char *)(parent->key + parent->klen) = '\0';
293
+ parent->klen = buf_len(&buf);
294
+ parent->key = oj_strndup(buf.head, parent->klen);
295
+ parent->kalloc = 1;
297
296
  } else {
298
- parent->key = "";
299
- parent->klen = 0;
297
+ parent->key = "";
298
+ parent->klen = 0;
299
+ parent->kalloc = 0;
300
300
  }
301
301
  parent->k1 = *pi->rd.str;
302
302
  parent->next = NEXT_HASH_COLON;
@@ -399,6 +399,7 @@ static void read_num(ParseInfo pi) {
399
399
  char c;
400
400
 
401
401
  reader_protect(&pi->rd);
402
+ ni.pi = pi;
402
403
  ni.i = 0;
403
404
  ni.num = 0;
404
405
  ni.div = 1;
@@ -415,7 +416,7 @@ static void read_num(ParseInfo pi) {
415
416
  ni.bigdec_load = pi->options.compat_bigdec;
416
417
  } else {
417
418
  ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
418
- RubyDec == pi->options.bigdec_load);
419
+ RubyDec == pi->options.bigdec_load);
419
420
  ni.bigdec_load = pi->options.bigdec_load;
420
421
  }
421
422
 
@@ -549,6 +550,7 @@ static void read_nan(ParseInfo pi) {
549
550
  struct _numInfo ni;
550
551
  char c;
551
552
 
553
+ ni.pi = pi;
552
554
  ni.str = pi->rd.str;
553
555
  ni.i = 0;
554
556
  ni.num = 0;
@@ -565,7 +567,7 @@ static void read_nan(ParseInfo pi) {
565
567
  ni.bigdec_load = pi->options.compat_bigdec;
566
568
  } else {
567
569
  ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
568
- RubyDec == pi->options.bigdec_load);
570
+ RubyDec == pi->options.bigdec_load);
569
571
  ni.bigdec_load = pi->options.bigdec_load;
570
572
  }
571
573
 
@@ -745,6 +747,7 @@ void oj_sparse2(ParseInfo pi) {
745
747
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "expected NaN");
746
748
  return;
747
749
  }
750
+ ni.pi = pi;
748
751
  ni.str = pi->rd.str;
749
752
  ni.i = 0;
750
753
  ni.num = 0;
@@ -761,7 +764,7 @@ void oj_sparse2(ParseInfo pi) {
761
764
  ni.bigdec_load = pi->options.compat_bigdec;
762
765
  } else {
763
766
  ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
764
- RubyDec == pi->options.bigdec_load);
767
+ RubyDec == pi->options.bigdec_load);
765
768
  ni.bigdec_load = pi->options.bigdec_load;
766
769
  }
767
770
  add_num_value(pi, &ni);
@@ -903,7 +906,17 @@ CLEANUP:
903
906
  if (0 != pi->circ_array) {
904
907
  oj_circ_array_free(pi->circ_array);
905
908
  }
909
+ reader_cleanup(&pi->rd);
906
910
  stack_cleanup(&pi->stack);
911
+ // A :match_string option builds a chain of regexps for this call that has to
912
+ // be freed. Without the option the member aliases the chain owned by the
913
+ // defaults and must be left alone.
914
+ if (pi->options.str_rx.head != oj_default_options.str_rx.head) {
915
+ oj_rxclass_cleanup(&pi->options.str_rx);
916
+ pi->options.str_rx.head = NULL;
917
+ pi->options.str_rx.tail = NULL;
918
+ }
919
+ oj_free_call_options(&pi->options);
907
920
  if (0 != fd) {
908
921
  #ifdef _WIN32
909
922
  rb_w32_close(fd);
@@ -16,15 +16,29 @@ static void stream_writer_free(void *ptr) {
16
16
  return;
17
17
  }
18
18
  sw = (StreamWriter)ptr;
19
+ oj_options_release(&sw->sw.opts);
19
20
  OJ_R_FREE(sw->sw.out.buf);
20
21
  OJ_R_FREE(sw->sw.types);
21
22
  OJ_R_FREE(ptr);
22
23
  }
23
24
 
25
+ static void stream_writer_mark(void *ptr) {
26
+ if (NULL != ptr) {
27
+ StreamWriter sw = (StreamWriter)ptr;
28
+
29
+ oj_options_mark(&sw->sw.opts);
30
+ // The writer can be the only reference to the stream as in
31
+ // Oj::StreamWriter.new(StringIO.new) so it must be marked.
32
+ if (Qnil != sw->stream) {
33
+ rb_gc_mark(sw->stream);
34
+ }
35
+ }
36
+ }
37
+
24
38
  static const rb_data_type_t oj_stream_writer_type = {
25
39
  "Oj/stream_writer",
26
40
  {
27
- NULL,
41
+ stream_writer_mark,
28
42
  stream_writer_free,
29
43
  NULL,
30
44
  },
@@ -116,6 +130,7 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
116
130
  oj_str_writer_init(&sw->sw, 4096);
117
131
  sw->flush_limit = 0;
118
132
  }
133
+ oj_options_take_ownership(&sw->sw.opts);
119
134
  sw->sw.out.indent = sw->sw.opts.indent;
120
135
  sw->stream = stream;
121
136
  sw->type = type;
@@ -42,12 +42,18 @@ static void maybe_comma(StrWriter sw) {
42
42
 
43
43
  // Used by stream writer also.
44
44
  void oj_str_writer_init(StrWriter sw, int buf_size) {
45
- sw->opts = oj_default_options;
46
- sw->depth = 0;
47
- sw->types = OJ_R_ALLOC_N(char, 256);
48
- sw->types_end = sw->types + 256;
49
- *sw->types = '\0';
50
- sw->keyWritten = 0;
45
+ sw->opts = oj_default_options;
46
+ // Detach from the match_string regexps owned by the defaults before the
47
+ // options are parsed. A :match_string option then builds a chain of its own
48
+ // that is freed with the writer instead of being appended to the chain the
49
+ // defaults are using.
50
+ sw->opts.str_rx.head = NULL;
51
+ sw->opts.str_rx.tail = NULL;
52
+ sw->depth = 0;
53
+ sw->types = OJ_R_ALLOC_N(char, 256);
54
+ sw->types_end = sw->types + 256;
55
+ *sw->types = '\0';
56
+ sw->keyWritten = 0;
51
57
 
52
58
  if (0 == buf_size) {
53
59
  buf_size = 4096;
@@ -72,6 +78,8 @@ void oj_str_writer_init(StrWriter sw, int buf_size) {
72
78
  sw->out.argv = NULL;
73
79
  sw->out.ropts = NULL;
74
80
  sw->out.omit_nil = oj_default_options.dump_opts.omit_nil;
81
+ // oj_str_writer_init does not call oj_out_init, so clear this here too.
82
+ sw->out.key_filter_off = false;
75
83
  }
76
84
 
77
85
  void oj_str_writer_push_key(StrWriter sw, const char *key) {
@@ -234,15 +242,22 @@ static void string_writer_free(void *ptr) {
234
242
  sw = (StrWriter)ptr;
235
243
 
236
244
  oj_out_free(&sw->out);
245
+ oj_options_release(&sw->opts);
237
246
 
238
247
  OJ_R_FREE(sw->types);
239
248
  OJ_R_FREE(ptr);
240
249
  }
241
250
 
251
+ static void string_writer_mark(void *ptr) {
252
+ if (NULL != ptr) {
253
+ oj_options_mark(&((StrWriter)ptr)->opts);
254
+ }
255
+ }
256
+
242
257
  static const rb_data_type_t oj_string_writer_type = {
243
258
  "Oj/string_writer",
244
259
  {
245
- NULL,
260
+ string_writer_mark,
246
261
  string_writer_free,
247
262
  NULL,
248
263
  },
@@ -279,6 +294,7 @@ static VALUE str_writer_new(int argc, VALUE *argv, VALUE self) {
279
294
  if (1 == argc) {
280
295
  oj_parse_options(argv[0], &sw->opts);
281
296
  }
297
+ oj_options_take_ownership(&sw->opts);
282
298
  sw->out.argc = argc - 1;
283
299
  sw->out.argv = argv + 1;
284
300
  sw->out.indent = sw->opts.indent;
data/ext/oj/usual.c CHANGED
@@ -63,7 +63,7 @@ static VALUE form_attr(const char *str, size_t len) {
63
63
  memcpy(b + 1, str, len);
64
64
  b[len + 1] = '\0';
65
65
 
66
- id = rb_intern3(buf, len + 1, oj_utf8_encoding);
66
+ id = rb_intern3(b, len + 1, oj_utf8_encoding);
67
67
  OJ_R_FREE(b);
68
68
  return id;
69
69
  }
@@ -200,7 +200,10 @@ static void push_key(ojParser p) {
200
200
  d->ktail = d->khead + pos;
201
201
  d->kend = d->khead + cap;
202
202
  }
203
- d->ktail->len = klen;
203
+ if (32000 < klen) {
204
+ rb_raise(oj_json_parser_error_class, "Key too long. Keys are limited to 32,000 bytes.");
205
+ }
206
+ d->ktail->len = (int16_t)klen;
204
207
  if (klen < sizeof(d->ktail->buf)) {
205
208
  memcpy(d->ktail->buf, key, klen);
206
209
  d->ktail->buf[klen] = '\0';
@@ -608,12 +611,16 @@ static void dfree(ojParser p) {
608
611
  Usual d = (Usual)p->ctx;
609
612
 
610
613
  cache_free(d->str_cache);
614
+ d->str_cache = NULL;
611
615
  cache_free(d->attr_cache);
616
+ d->attr_cache = NULL;
612
617
  if (NULL != d->sym_cache) {
613
618
  cache_free(d->sym_cache);
619
+ d->sym_cache = NULL;
614
620
  }
615
621
  if (NULL != d->class_cache) {
616
622
  cache_free(d->class_cache);
623
+ d->class_cache = NULL;
617
624
  }
618
625
  OJ_R_FREE(d->vhead);
619
626
  OJ_R_FREE(d->chead);
@@ -640,6 +647,12 @@ static void mark(ojParser p) {
640
647
  if (NULL != d->class_cache) {
641
648
  cache_mark(d->class_cache);
642
649
  }
650
+ if (Qnil != d->hash_class) {
651
+ rb_gc_mark(d->hash_class);
652
+ }
653
+ if (Qnil != d->array_class) {
654
+ rb_gc_mark(d->array_class);
655
+ }
643
656
  for (vp = d->vhead; vp < d->vtail; vp++) {
644
657
  if (Qundef != *vp) {
645
658
  rb_gc_mark(*vp);
@@ -818,6 +831,7 @@ static VALUE opt_create_id_set(ojParser p, VALUE value) {
818
831
  Usual d = (Usual)p->ctx;
819
832
 
820
833
  if (Qnil == value) {
834
+ OJ_R_FREE(d->create_id);
821
835
  d->create_id = NULL;
822
836
  d->create_id_len = 0;
823
837
  p->funcs[OBJECT_FUN].add_str = add_str_key;
@@ -837,12 +851,15 @@ static VALUE opt_create_id_set(ojParser p, VALUE value) {
837
851
  if (1 << (8 * sizeof(d->create_id_len)) <= len) {
838
852
  rb_raise(rb_eArgError, "The create_id values is limited to %d bytes.", 1 << (8 * sizeof(d->create_id_len)));
839
853
  }
840
- d->create_id_len = (uint8_t)len;
854
+ char *prev = d->create_id;
855
+
841
856
  d->create_id = str_dup(RSTRING_PTR(value), len);
857
+ d->create_id_len = (uint8_t)len;
842
858
  p->funcs[OBJECT_FUN].add_str = add_str_key_create;
843
859
  p->funcs[TOP_FUN].close_object = close_object_create;
844
860
  p->funcs[ARRAY_FUN].close_object = close_object_create;
845
861
  p->funcs[OBJECT_FUN].close_object = close_object_create;
862
+ OJ_R_FREE(prev);
846
863
  }
847
864
  return opt_create_id(p, value);
848
865
  }
@@ -1050,10 +1067,10 @@ static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1050
1067
  if (NULL != d->sym_cache) {
1051
1068
  cache_free(d->sym_cache);
1052
1069
  d->sym_cache = NULL;
1070
+ d->key_cache = NULL;
1053
1071
  }
1054
- if (!d->cache_keys) {
1055
- d->get_key = str_key;
1056
- }
1072
+ d->cache_keys = false;
1073
+ d->get_key = str_key;
1057
1074
  }
1058
1075
  return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1059
1076
  }
data/ext/oj/util.c CHANGED
@@ -134,3 +134,30 @@ void sec_as_time(int64_t secs, TimeInfo ti) {
134
134
  secs = secs - (int64_t)ti->min * 60LL;
135
135
  ti->sec = (int)secs;
136
136
  }
137
+
138
+ // The inverse of sec_as_time(). The days are counted with the civil calendar
139
+ // algorithm from Howard Hinnant's date library so that no libc call is needed.
140
+ // timegm() is not available on Windows and the mktime() based replacement that
141
+ // was used there returned the wrong value in any timezone east of UTC.
142
+ int64_t time_as_sec(TimeInfo ti) {
143
+ int64_t year = (int64_t)ti->year;
144
+ int64_t mon = (int64_t)ti->mon;
145
+ int64_t era;
146
+ int64_t yoe; // year of the era, [0, 399]
147
+ int64_t doy; // day of the year, [0, 365]
148
+ int64_t doe; // day of the era, [0, 146096]
149
+ int64_t days; // days since 1970-01-01
150
+
151
+ // Start the year on March 1st so that a leap day falls on the last day of
152
+ // the year and the day of the year is a simple expression.
153
+ if (mon <= 2) {
154
+ year--;
155
+ }
156
+ era = (0 <= year ? year : year - 399) / 400;
157
+ yoe = year - era * 400;
158
+ doy = (153 * (mon + (2 < mon ? -3 : 9)) + 2) / 5 + (int64_t)ti->day - 1;
159
+ doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
160
+ days = era * 146097 + doe - 719468;
161
+
162
+ return days * SECS_PER_DAY + (int64_t)ti->hour * 3600LL + (int64_t)ti->min * 60LL + (int64_t)ti->sec;
163
+ }
data/ext/oj/util.h CHANGED
@@ -15,6 +15,7 @@ typedef struct _timeInfo {
15
15
  int year;
16
16
  }* TimeInfo;
17
17
 
18
- extern void sec_as_time(int64_t secs, TimeInfo ti);
18
+ extern void sec_as_time(int64_t secs, TimeInfo ti);
19
+ extern int64_t time_as_sec(TimeInfo ti);
19
20
 
20
21
  #endif /* OJ_UTIL_H */
data/ext/oj/val_stack.h CHANGED
@@ -35,8 +35,8 @@ typedef struct _val {
35
35
  const char *classname;
36
36
  VALUE clas;
37
37
  OddArgs odd_args;
38
- uint16_t klen;
39
- uint16_t clen;
38
+ size_t klen;
39
+ size_t clen;
40
40
  char next; // ValNext
41
41
  char k1; // first original character in the key
42
42
  char kalloc;
@@ -62,6 +62,16 @@ inline static int stack_empty(ValStack stack) {
62
62
  }
63
63
 
64
64
  inline static void stack_cleanup(ValStack stack) {
65
+ Val v;
66
+
67
+ // end_hash() frees the args of a completed odd class. Anything still here
68
+ // belongs to a parse that was abandoned part way through.
69
+ for (v = stack->head; v < stack->tail; v++) {
70
+ if (NULL != v->odd_args) {
71
+ oj_odd_free(v->odd_args);
72
+ v->odd_args = NULL;
73
+ }
74
+ }
65
75
  if (stack->base != stack->head) {
66
76
  OJ_R_FREE(stack->head);
67
77
  stack->head = NULL;
@@ -70,9 +80,11 @@ inline static void stack_cleanup(ValStack stack) {
70
80
 
71
81
  inline static void stack_push(ValStack stack, VALUE val, ValNext next) {
72
82
  if (stack->end <= stack->tail) {
73
- size_t len = stack->end - stack->head;
74
- size_t toff = stack->tail - stack->head;
75
- Val head = stack->head;
83
+ size_t len = stack->end - stack->head;
84
+ size_t toff = stack->tail - stack->head;
85
+ Val head = stack->head;
86
+ const char *old = (const char *)stack->head;
87
+ size_t i;
76
88
 
77
89
  // A realloc can trigger a GC so make sure it happens outside the lock
78
90
  // but lock before changing pointers.
@@ -82,6 +94,13 @@ inline static void stack_push(ValStack stack, VALUE val, ValNext next) {
82
94
  } else {
83
95
  OJ_R_REALLOC_N(head, struct _val, len + STACK_INC);
84
96
  }
97
+ // A key short enough to be kept in the Val itself points into the
98
+ // block that just moved.
99
+ for (i = 0; i < toff; i++) {
100
+ if (old <= head[i].key && head[i].key < old + sizeof(struct _val) * len) {
101
+ head[i].key = head[i].karray;
102
+ }
103
+ }
85
104
  #ifdef HAVE_PTHREAD_MUTEX_INIT
86
105
  pthread_mutex_lock(&stack->mutex);
87
106
  #else
data/ext/oj/wab.c CHANGED
@@ -19,7 +19,7 @@
19
19
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
20
20
  #define OJ_INFINITY (1.0 / 0.0)
21
21
 
22
- static char hex_chars[256] = "\
22
+ static char hex_chars[257] = "\
23
23
  ................................\
24
24
  ................xxxxxxxxxx......\
25
25
  .xxxxxx.........................\
@@ -375,44 +375,41 @@ static const char *read_num(const char *s, int len, int *vp) {
375
375
  }
376
376
 
377
377
  static VALUE time_parse(const char *s, int len) {
378
- struct tm tm;
379
- bool neg = false;
380
- long nsecs = 0;
381
- int i;
382
- time_t secs;
378
+ struct _timeInfo ti;
379
+ bool neg = false;
380
+ long nsecs = 0;
381
+ int i;
383
382
 
384
- memset(&tm, 0, sizeof(tm));
383
+ memset(&ti, 0, sizeof(ti));
385
384
  if ('-' == *s) {
386
385
  s++;
387
386
  neg = true;
388
387
  }
389
- if (NULL == (s = read_num(s, 4, &tm.tm_year))) {
388
+ if (NULL == (s = read_num(s, 4, &ti.year))) {
390
389
  return Qnil;
391
390
  }
392
391
  if (neg) {
393
- tm.tm_year = -tm.tm_year;
394
- neg = false;
392
+ ti.year = -ti.year;
393
+ neg = false;
395
394
  }
396
- tm.tm_year -= 1900;
397
395
  s++;
398
- if (NULL == (s = read_num(s, 2, &tm.tm_mon))) {
396
+ if (NULL == (s = read_num(s, 2, &ti.mon))) {
399
397
  return Qnil;
400
398
  }
401
- tm.tm_mon--;
402
399
  s++;
403
- if (NULL == (s = read_num(s, 2, &tm.tm_mday))) {
400
+ if (NULL == (s = read_num(s, 2, &ti.day))) {
404
401
  return Qnil;
405
402
  }
406
403
  s++;
407
- if (NULL == (s = read_num(s, 2, &tm.tm_hour))) {
404
+ if (NULL == (s = read_num(s, 2, &ti.hour))) {
408
405
  return Qnil;
409
406
  }
410
407
  s++;
411
- if (NULL == (s = read_num(s, 2, &tm.tm_min))) {
408
+ if (NULL == (s = read_num(s, 2, &ti.min))) {
412
409
  return Qnil;
413
410
  }
414
411
  s++;
415
- if (NULL == (s = read_num(s, 2, &tm.tm_sec))) {
412
+ if (NULL == (s = read_num(s, 2, &ti.sec))) {
416
413
  return Qnil;
417
414
  }
418
415
  s++;
@@ -424,16 +421,7 @@ static VALUE time_parse(const char *s, int len) {
424
421
  return Qnil;
425
422
  }
426
423
  }
427
- #if IS_WINDOWS
428
- secs = (time_t)mktime(&tm);
429
- memset(&tm, 0, sizeof(tm));
430
- tm.tm_year = 70;
431
- tm.tm_mday = 1;
432
- secs -= (time_t)mktime(&tm);
433
- #else
434
- secs = (time_t)timegm(&tm);
435
- #endif
436
- return rb_funcall(rb_time_nano_new(secs, nsecs), oj_utc_id, 0);
424
+ return rb_funcall(rb_time_nano_new((time_t)time_as_sec(&ti), nsecs), oj_utc_id, 0);
437
425
  }
438
426
 
439
427
  static VALUE protect_uri(VALUE rstr) {
data/lib/oj/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Oj
2
2
  # Current version of the module.
3
- VERSION = '3.16.11'
3
+ VERSION = '3.17.6'
4
4
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Ruby**
4
4
 
5
- Oj is compatible with Ruby 2.4+ and RBX.
5
+ Oj is compatible with Ruby 2.7+ and RBX.
6
6
  Support for JRuby has been removed as JRuby no longer supports C extensions and
7
7
  there are bugs in the older versions that are not being fixed.
8
8
 
data/pages/Custom.md CHANGED
@@ -8,9 +8,8 @@ for object dumping and loading. The `:compat` mode mimic the json gem
8
8
  including methods called for encoding and inconsistencies between
9
9
  `JSON.dump()`, `JSON.generate()`, and `JSON()`.
10
10
 
11
- The `:custom` mode is the default mode. It can be configured either by passing
12
- options to the `Oj.dump()` and `Oj.load()` methods or by modifying the default
13
- options.
11
+ The `:custom` mode can be configured either by passing options to the
12
+ `Oj.dump()` and `Oj.load()` methods or by modifying the default options.
14
13
 
15
14
  The ability to create objects from JSON object elements is supported and
16
15
  considers the `:create_additions` option. Special treatment is given to the
@@ -10,11 +10,13 @@ To enable Oj trace feature, it uses `--enable-trace-log` option when installing
10
10
  Then, the trace logs will be displayed when `:trace` option is set to `true`.
11
11
 
12
12
 
13
- ### Enable SIMD instructions
13
+ ### SIMD instructions
14
14
 
15
- ```
16
- $ gem install oj -- --with-sse42
17
- ```
15
+ SIMD optimizations are enabled automatically, so no install option is
16
+ required. At runtime Oj detects the CPU features that are available and
17
+ selects the best implementation: SSE4.2 or SSE2 on x86 / x86_64, NEON on ARM,
18
+ and a scalar fallback when none is available.
18
19
 
19
- To enable the use of SIMD instructions in Oj, it uses the `--with-sse42` option when installing the gem.
20
- This will enable the use of the SSE4.2 instructions in the internal.
20
+ Earlier versions required a `--with-sse42` option at install time to turn on
21
+ SSE4.2. That option has been removed (#982); SSE4.2 is now selected
22
+ automatically when the CPU supports it.
data/pages/Modes.md CHANGED
@@ -121,7 +121,7 @@ information.
121
121
  | :object_nl | String | | | x | x | | x | |
122
122
  | :omit_nil | Boolean | x | x | x | x | x | x | |
123
123
  | :quirks_mode | Boolean | | | 6 | | | x | |
124
- | :safe | String | | | x | | | | |
124
+ | :safe | Boolean | | | x | | | | |
125
125
  | :second_precision | Fixnum | | | | | x | x | |
126
126
  | :space | String | | | x | x | | x | |
127
127
  | :space_before | String | | | x | x | | x | |
data/pages/Options.md CHANGED
@@ -213,8 +213,7 @@ for json gem compatibility.
213
213
 
214
214
  Primary behavior for loading and dumping. The :mode option controls which
215
215
  other options are in effect. For more details see the {file:Modes.md} page. By
216
- default Oj uses the :custom mode which is provides the highest degree of
217
- customization.
216
+ default Oj uses the :object mode.
218
217
 
219
218
  ### :nan [Symbol]
220
219
 
@@ -249,6 +248,10 @@ integer gives better performance.
249
248
 
250
249
  If true, Hash and Object attributes with nil values are omitted.
251
250
 
251
+ ### :omit_null_byte [Boolean]
252
+
253
+ If true, null bytes in strings will be omitted when dumping.
254
+
252
255
  ### :quirks_mode [Boolean]
253
256
 
254
257
  Allow single JSON values instead of documents, default is true (allow). This
@@ -265,10 +268,6 @@ to true.
265
268
 
266
269
  The number of digits after the decimal when dumping the seconds of time.
267
270
 
268
- ### :skip_null_byte [Boolean]
269
-
270
- If true, null bytes in strings will be omitted when dumping.
271
-
272
271
  ### :space
273
272
 
274
273
  String inserted after the ':' character when dumping a JSON object. The
data/pages/Parser.md CHANGED
@@ -280,7 +280,7 @@ Oj::Parser.usual 0.452 110544.876
280
280
  JSON::Ext 1.009 49555.094
281
281
  ```
282
282
 
283
- The `Oj::Parser.new(:saj)` is **1.55** times faster than `Oj.load` and
283
+ The `Oj::Parser.new(:usual)` is **1.55** times faster than `Oj.load` and
284
284
  **2.23** times faster than the JSON gem.
285
285
 
286
286
  ### Object
@@ -298,7 +298,7 @@ Oj::Parser.usual 0.071 703502.033
298
298
  JSON::Ext 0.401 124638.859
299
299
  ```
300
300
 
301
- The `Oj::Parser.new(:saj)` is **3.17** times faster than
301
+ The `Oj::Parser.new(:usual)` is **3.17** times faster than
302
302
  `Oj.compat_load` and **5.64** times faster than the JSON gem.
303
303
 
304
304
  ## Summary
data/pages/Rails.md CHANGED
@@ -89,6 +89,12 @@ The classes that can be put in optimized mode and are optimized when
89
89
  * any class inheriting from ActiveRecord::Base
90
90
  * any other class where all attributes should be dumped
91
91
 
92
+ Both `Oj::Rails` and each `Oj::Rails::Encoder` have `optimize()`, `deoptimize()`, and `optimized?()` methods. The module level methods change the setting for the whole process. An encoder follows those process wide settings until `optimize()` or `deoptimize()` is called on the encoder itself. From then on the encoder keeps a set of its own and later module level changes do not reach it.
93
+
94
+ Options work the same way. An encoder reads `Oj.default_options` when it encodes, so later changes to the defaults reach it, unless it was given options of its own, in which case it keeps the copy it took when it was created. An encoder counts as having options of its own only if the hash it was built with names at least one option Oj knows. A hash of nothing but keys Oj does not have, such as the `escape: false` ActiveSupport 8.1 builds one of its cached encoders with, leaves the encoder on the defaults.
95
+
96
+ Once a class is optimized its `as_json()` method is no longer called, so an application that defines its own `as_json()` on an optimized class, `BigDecimal` for example, will not see it used. Call `Oj::Rails.deoptimize(BigDecimal)` after `Oj.optimize_rails` to put that one class back on the `as_json()` path and leave the rest optimized.
97
+
92
98
  The ActiveSupport decoder is the `JSON.parse()` method. Calling the
93
99
  `Oj::Rails.set_decoder()` method replaces that method with the Oj equivalent.
94
100
 
data/pages/Security.md CHANGED
@@ -11,10 +11,24 @@ auto defined is used with an untrusted source. The `Oj.safe_load()` method
11
11
  sets and uses the most strict and safest options. It should be used by
12
12
  developers who find it difficult to understand the options available in Oj.
13
13
 
14
- The options in Oj are designed to provide flexibility to the developer. This
15
- flexibility allows Objects to be serialized and deserialized. No methods are
16
- ever called on these created Objects but that does not stop the developer from
17
- calling methods on them. As in any system, check your inputs before working with
18
- them. Taking an arbitrary `String` from a user and evaluating it is never a good
19
- idea from an unsecure source. The same is true for `Object` attributes as they
20
- are not more than `String`s. Always check inputs from untrusted sources.
14
+ The options in Oj are designed to provide flexibility to the developer. This flexibility allows Objects to be serialized and deserialized. An Object is deserialized by allocating it without calling its initializer and then setting its instance variables. A few methods are called on what that builds: `exception` and `set_backtrace` on an `Exception`, and `replace` on a subclass of `Hash`, `Array` or `String` for a `self` key. As in any system, check your inputs before working with them. Taking an arbitrary `String` from a user and evaluating it is never a good idea from an unsecure source. The same is true for `Object` attributes as they are not more than `String`s. Always check inputs from untrusted sources.
15
+
16
+ ## The mode a document is loaded in
17
+
18
+ `Oj.load()` uses the `:object` mode unless the mode is changed. That mode takes the class of an Object from the document, so the document decides which of the classes already loaded in the process is allocated and what its instance variables are. Classes are looked up and not created unless `:auto_define` is turned on.
19
+
20
+ For a document from an untrusted source, ask for a mode that does not do that:
21
+
22
+ ```ruby
23
+ Oj.load(json, mode: :strict)
24
+ Oj.strict_load(json)
25
+ Oj.safe_load(json)
26
+ ```
27
+
28
+ or set it for the process:
29
+
30
+ ```ruby
31
+ Oj.default_options = {mode: :strict}
32
+ ```
33
+
34
+ `Oj.object_load()` is the explicit form of the current default and stays in `:object` mode whatever the default is set to.