oj 3.11.5 → 3.12.3

Sign up to get free protection for your applications and to get access to all the features.
data/ext/oj/oj.h CHANGED
@@ -143,6 +143,8 @@ typedef struct _options {
143
143
  char safe; // YesNo
144
144
  char sec_prec_set; // boolean (0 or 1)
145
145
  char ignore_under; // YesNo - ignore attrs starting with _ if true in object and custom modes
146
+ char cache_keys; // YexNo
147
+ char cache_str; // string short than or equal to this are cache
146
148
  int64_t int_range_min; // dump numbers below as string
147
149
  int64_t int_range_max; // dump numbers above as string
148
150
  const char * create_id; // 0 or string
@@ -243,6 +245,7 @@ extern VALUE oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len)
243
245
  extern VALUE oj_object_parse_cstr(int argc, VALUE *argv, char *json, size_t len);
244
246
  extern VALUE oj_custom_parse_cstr(int argc, VALUE *argv, char *json, size_t len);
245
247
 
248
+ extern bool oj_hash_has_key(VALUE hash, VALUE key);
246
249
  extern void oj_parse_options(VALUE ropts, Options copts);
247
250
 
248
251
  extern void oj_dump_obj_to_json(VALUE obj, Options copts, Out out);
@@ -325,7 +328,6 @@ extern ID oj_exclude_end_id;
325
328
  extern ID oj_file_id;
326
329
  extern ID oj_fileno_id;
327
330
  extern ID oj_ftype_id;
328
- extern ID oj_has_key_id;
329
331
  extern ID oj_hash_end_id;
330
332
  extern ID oj_hash_key_id;
331
333
  extern ID oj_hash_set_id;
data/ext/oj/parse.c CHANGED
@@ -1129,7 +1129,7 @@ CLEANUP:
1129
1129
  if (Qnil != pi->err_class) {
1130
1130
  pi->err.clas = pi->err_class;
1131
1131
  }
1132
- if (CompatMode == pi->options.mode && Yes != pi->options.safe) {
1132
+ if ((CompatMode == pi->options.mode || RailsMode == pi->options.mode) && Yes != pi->options.safe) {
1133
1133
  // The json gem requires the error message be UTF-8 encoded. In
1134
1134
  // additional the complete JSON source must be returned. There
1135
1135
  // does not seem to be a size limit.
data/ext/oj/parse.h CHANGED
@@ -90,6 +90,9 @@ extern void oj_set_wab_callbacks(ParseInfo pi);
90
90
  extern void oj_sparse2(ParseInfo pi);
91
91
  extern VALUE oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd);
92
92
 
93
+ extern VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str);
94
+ extern VALUE oj_calc_hash_key(ParseInfo pi, Val parent);
95
+
93
96
  static inline void parse_info_init(ParseInfo pi) {
94
97
  memset(pi, 0, sizeof(struct _parseInfo));
95
98
  }
data/ext/oj/rails.c CHANGED
@@ -828,7 +828,8 @@ rails_mimic_json(VALUE self) {
828
828
  json = rb_define_module("JSON");
829
829
  }
830
830
  oj_mimic_json_methods(json);
831
- // oj_default_options.mode = RailsMode;
831
+ // Setting the default mode breaks the prmoise in the docs not to.
832
+ //oj_default_options.mode = RailsMode;
832
833
 
833
834
  return Qnil;
834
835
  }
data/ext/oj/scp.c CHANGED
@@ -9,6 +9,7 @@
9
9
  #include <unistd.h>
10
10
 
11
11
  #include "encode.h"
12
+ #include "hash.h"
12
13
  #include "oj.h"
13
14
  #include "parse.h"
14
15
 
@@ -82,19 +83,6 @@ static void end_array(ParseInfo pi) {
82
83
  rb_funcall(pi->handler, oj_array_end_id, 0);
83
84
  }
84
85
 
85
- static VALUE calc_hash_key(ParseInfo pi, Val kval) {
86
- volatile VALUE rkey = kval->key_val;
87
-
88
- if (Qundef == rkey) {
89
- rkey = rb_str_new(kval->key, kval->klen);
90
- rkey = oj_encode(rkey);
91
- if (Yes == pi->options.sym_key) {
92
- rkey = rb_str_intern(rkey);
93
- }
94
- }
95
- return rkey;
96
- }
97
-
98
86
  static VALUE hash_key(ParseInfo pi, const char *key, size_t klen) {
99
87
  return rb_funcall(pi->handler, oj_hash_key_id, 1, rb_str_new(key, klen));
100
88
  }
@@ -107,7 +95,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
107
95
  oj_hash_set_id,
108
96
  3,
109
97
  stack_peek(&pi->stack)->val,
110
- calc_hash_key(pi, kval),
98
+ oj_calc_hash_key(pi, kval),
111
99
  rstr);
112
100
  }
113
101
 
@@ -116,7 +104,7 @@ static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
116
104
  oj_hash_set_id,
117
105
  3,
118
106
  stack_peek(&pi->stack)->val,
119
- calc_hash_key(pi, kval),
107
+ oj_calc_hash_key(pi, kval),
120
108
  oj_num_as_value(ni));
121
109
  }
122
110
 
@@ -125,7 +113,7 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
125
113
  oj_hash_set_id,
126
114
  3,
127
115
  stack_peek(&pi->stack)->val,
128
- calc_hash_key(pi, kval),
116
+ oj_calc_hash_key(pi, kval),
129
117
  value);
130
118
  }
131
119
 
data/ext/oj/strict.c CHANGED
@@ -8,10 +8,65 @@
8
8
 
9
9
  #include "encode.h"
10
10
  #include "err.h"
11
+ #include "hash.h"
11
12
  #include "oj.h"
12
13
  #include "parse.h"
13
14
  #include "trace.h"
14
15
 
16
+ VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) {
17
+ volatile VALUE rstr = Qnil;
18
+
19
+ if (len <= cache_str) {
20
+ VALUE *slot;
21
+
22
+ if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) {
23
+ rstr = rb_str_new(str, len);
24
+ rstr = oj_encode(rstr);
25
+ *slot = rstr;
26
+ rb_gc_register_address(slot);
27
+ }
28
+ } else {
29
+ rstr = rb_str_new(str, len);
30
+ rstr = oj_encode(rstr);
31
+ }
32
+ return rstr;
33
+ }
34
+
35
+ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
36
+ volatile VALUE rkey = parent->key_val;
37
+
38
+ if (Qundef != rkey) {
39
+ return rkey;
40
+ }
41
+ if (Yes != pi->options.cache_keys) {
42
+ rkey = rb_str_new(parent->key, parent->klen);
43
+ rkey = oj_encode(rkey);
44
+ if (Yes == pi->options.sym_key) {
45
+ rkey = rb_str_intern(rkey);
46
+ }
47
+ return rkey;
48
+ }
49
+ VALUE *slot;
50
+
51
+ if (Yes == pi->options.sym_key) {
52
+ if (Qnil == (rkey = oj_sym_hash_get(parent->key, parent->klen, &slot))) {
53
+ rkey = rb_str_new(parent->key, parent->klen);
54
+ rkey = oj_encode(rkey);
55
+ rkey = rb_str_intern(rkey);
56
+ *slot = rkey;
57
+ rb_gc_register_address(slot);
58
+ }
59
+ } else {
60
+ if (Qnil == (rkey = oj_str_hash_get(parent->key, parent->klen, &slot))) {
61
+ rkey = rb_str_new(parent->key, parent->klen);
62
+ rkey = oj_encode(rkey);
63
+ *slot = rkey;
64
+ rb_gc_register_address(slot);
65
+ }
66
+ }
67
+ return rkey;
68
+ }
69
+
15
70
  static void hash_end(ParseInfo pi) {
16
71
  if (Yes == pi->options.trace) {
17
72
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
@@ -36,9 +91,8 @@ static void add_value(ParseInfo pi, VALUE val) {
36
91
  }
37
92
 
38
93
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
39
- volatile VALUE rstr = rb_str_new(str, len);
94
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
40
95
 
41
- rstr = oj_encode(rstr);
42
96
  pi->stack.head->val = rstr;
43
97
  if (Yes == pi->options.trace) {
44
98
  oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
@@ -65,24 +119,12 @@ static VALUE start_hash(ParseInfo pi) {
65
119
  return rb_hash_new();
66
120
  }
67
121
 
68
- static VALUE calc_hash_key(ParseInfo pi, Val parent) {
69
- volatile VALUE rkey = parent->key_val;
70
-
71
- if (Qundef == rkey) {
72
- rkey = rb_str_new(parent->key, parent->klen);
73
- }
74
- rkey = oj_encode(rkey);
75
- if (Yes == pi->options.sym_key) {
76
- rkey = rb_str_intern(rkey);
77
- }
78
- return rkey;
79
- }
80
-
81
122
  static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
82
- volatile VALUE rstr = rb_str_new(str, len);
123
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
83
124
 
84
- rstr = oj_encode(rstr);
85
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rstr);
125
+ rb_hash_aset(stack_peek(&pi->stack)->val,
126
+ oj_calc_hash_key(pi, parent),
127
+ rstr);
86
128
  if (Yes == pi->options.trace) {
87
129
  oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
88
130
  }
@@ -95,14 +137,18 @@ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
95
137
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
96
138
  }
97
139
  v = oj_num_as_value(ni);
98
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), v);
140
+ rb_hash_aset(stack_peek(&pi->stack)->val,
141
+ oj_calc_hash_key(pi, parent),
142
+ v);
99
143
  if (Yes == pi->options.trace) {
100
144
  oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
101
145
  }
102
146
  }
103
147
 
104
148
  static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
105
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
149
+ rb_hash_aset(stack_peek(&pi->stack)->val,
150
+ oj_calc_hash_key(pi, parent),
151
+ value);
106
152
  if (Yes == pi->options.trace) {
107
153
  oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
108
154
  }
@@ -116,9 +162,8 @@ static VALUE start_array(ParseInfo pi) {
116
162
  }
117
163
 
118
164
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
119
- volatile VALUE rstr = rb_str_new(str, len);
165
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
120
166
 
121
- rstr = oj_encode(rstr);
122
167
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
123
168
  if (Yes == pi->options.trace) {
124
169
  oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
data/ext/oj/wab.c CHANGED
@@ -10,6 +10,7 @@
10
10
  #include "dump.h"
11
11
  #include "encode.h"
12
12
  #include "err.h"
13
+ #include "hash.h"
13
14
  #include "oj.h"
14
15
  #include "parse.h"
15
16
  #include "trace.h"
@@ -292,6 +293,34 @@ void oj_dump_wab_val(VALUE obj, int depth, Out out) {
292
293
 
293
294
  ///// load functions /////
294
295
 
296
+ static VALUE calc_hash_key(ParseInfo pi, Val parent) {
297
+ volatile VALUE rkey = parent->key_val;
298
+
299
+ if (Qundef != rkey) {
300
+ rkey = oj_encode(rkey);
301
+ rkey = rb_str_intern(rkey);
302
+
303
+ return rkey;
304
+ }
305
+ if (Yes != pi->options.cache_keys) {
306
+ rkey = rb_str_new(parent->key, parent->klen);
307
+ rkey = oj_encode(rkey);
308
+ rkey = rb_str_intern(rkey);
309
+
310
+ return rkey;
311
+ }
312
+ VALUE *slot;
313
+
314
+ if (Qnil == (rkey = oj_sym_hash_get(parent->key, parent->klen, &slot))) {
315
+ rkey = rb_str_new(parent->key, parent->klen);
316
+ rkey = oj_encode(rkey);
317
+ rkey = rb_str_intern(rkey);
318
+ *slot = rkey;
319
+ rb_gc_register_address(slot);
320
+ }
321
+ return rkey;
322
+ }
323
+
295
324
  static void hash_end(ParseInfo pi) {
296
325
  if (Yes == pi->options.trace) {
297
326
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
@@ -432,7 +461,7 @@ static VALUE protect_uri(VALUE rstr) {
432
461
  return rb_funcall(resolve_uri_class(), oj_parse_id, 1, rstr);
433
462
  }
434
463
 
435
- static VALUE cstr_to_rstr(const char *str, size_t len) {
464
+ static VALUE cstr_to_rstr(ParseInfo pi, const char *str, size_t len) {
436
465
  volatile VALUE v = Qnil;
437
466
 
438
467
  if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] &&
@@ -445,20 +474,20 @@ static VALUE cstr_to_rstr(const char *str, size_t len) {
445
474
  uuid_check(str, (int)len) && Qnil != resolve_wab_uuid_class()) {
446
475
  return rb_funcall(wab_uuid_clas, oj_new_id, 1, rb_str_new(str, len));
447
476
  }
448
- v = rb_str_new(str, len);
449
477
  if (7 < len && 0 == strncasecmp("http://", str, 7)) {
450
478
  int err = 0;
479
+ v = rb_str_new(str, len);
451
480
  volatile VALUE uri = rb_protect(protect_uri, v, &err);
452
481
 
453
482
  if (0 == err) {
454
483
  return uri;
455
484
  }
456
485
  }
457
- return oj_encode(v);
486
+ return oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
458
487
  }
459
488
 
460
489
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
461
- pi->stack.head->val = cstr_to_rstr(str, len);
490
+ pi->stack.head->val = cstr_to_rstr(pi, str, len);
462
491
  if (Yes == pi->options.trace) {
463
492
  oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
464
493
  }
@@ -484,20 +513,8 @@ static VALUE start_hash(ParseInfo pi) {
484
513
  return rb_hash_new();
485
514
  }
486
515
 
487
- static VALUE calc_hash_key(ParseInfo pi, Val parent) {
488
- volatile VALUE rkey = parent->key_val;
489
-
490
- if (Qundef == rkey) {
491
- rkey = rb_str_new(parent->key, parent->klen);
492
- }
493
- rkey = oj_encode(rkey);
494
- rkey = rb_str_intern(rkey);
495
-
496
- return rkey;
497
- }
498
-
499
516
  static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
500
- volatile VALUE rval = cstr_to_rstr(str, len);
517
+ volatile VALUE rval = cstr_to_rstr(pi, str, len);
501
518
 
502
519
  rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
503
520
  if (Yes == pi->options.trace) {
@@ -533,7 +550,7 @@ static VALUE start_array(ParseInfo pi) {
533
550
  }
534
551
 
535
552
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
536
- volatile VALUE rval = cstr_to_rstr(str, len);
553
+ volatile VALUE rval = cstr_to_rstr(pi, str, len);
537
554
 
538
555
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
539
556
  if (Yes == pi->options.trace) {
data/lib/oj/mimic.rb CHANGED
@@ -23,6 +23,8 @@ module Oj
23
23
  bigdecimal_load: :auto,
24
24
  circular: false,
25
25
  class_cache: false,
26
+ cache_keys: true,
27
+ cache_str: 5,
26
28
  create_additions: false,
27
29
  create_id: "json_class",
28
30
  empty_string: false,
data/lib/oj/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '3.11.5'
4
+ VERSION = '3.12.3'
5
5
  end
data/pages/Modes.md CHANGED
@@ -97,6 +97,8 @@ information.
97
97
  | :bigdecimal_as_decimal | Boolean | | | | 3 | x | x | |
98
98
  | :bigdecimal_load | Boolean | | | | | | x | |
99
99
  | :compat_bigdecimal | Boolean | | | x | | | x | |
100
+ | :cache_keys | Boolean | x | x | x | x | | x | |
101
+ | :cache_strings | Fixnum | x | x | x | x | | x | |
100
102
  | :circular | Boolean | x | x | x | x | x | x | |
101
103
  | :class_cache | Boolean | | | | | x | x | |
102
104
  | :create_additions | Boolean | | | x | x | | x | |
data/pages/Options.md CHANGED
@@ -70,13 +70,17 @@ This can also be set with `:decimal_class` when used as a load or
70
70
  parse option to match the JSON gem. In that case either `Float`,
71
71
  `BigDecimal`, or `nil` can be provided.
72
72
 
73
- ### :compat_bigdecimal [Boolean]
73
+ ### :cache_keys [Boolean]
74
74
 
75
- Determines how to load decimals when in `:compat` mode.
75
+ If true Hash keys are cached or interned. There are trade-offs with
76
+ caching keys. Large caches will use more memory and in extreme cases
77
+ (like over a million) the cache may be slower than not using
78
+ it. Repeated parsing of similar JSON docs is where cache_keys shines.
76
79
 
77
- - `true` convert all decimal numbers to BigDecimal.
80
+ ### :cache_strings [Int]
78
81
 
79
- - `false` convert all decimal numbers to Float.
82
+ Shorter strings can be cached for better performance. A limit,
83
+ cache_strings, defines the upper limit on what strings are cached.
80
84
 
81
85
  ### :circular [Boolean]
82
86
 
@@ -90,6 +94,14 @@ recreate the looped references on load.
90
94
  Cache classes for faster parsing. This option should not be used if
91
95
  dynamically modifying classes or reloading classes then don't use this.
92
96
 
97
+ ### :compat_bigdecimal [Boolean]
98
+
99
+ Determines how to load decimals when in `:compat` mode.
100
+
101
+ - `true` convert all decimal numbers to BigDecimal.
102
+
103
+ - `false` convert all decimal numbers to Float.
104
+
93
105
  ### :create_additions
94
106
 
95
107
  A flag indicating that the :create_id key, when encountered during parsing,
@@ -251,7 +263,13 @@ compatibility. Using just indent as an integer gives better performance.
251
263
 
252
264
  ### :symbol_keys [Boolean]
253
265
 
254
- Use symbols instead of strings for hash keys. :symbolize_names is an alias.
266
+ Use symbols instead of strings for hash keys.
267
+
268
+ ### :symbolize_names [Boolean]
269
+
270
+ Like :symbol_keys has keys are made into symbols but only when
271
+ mimicing the JSON gem and then only as the JSON gem honors it so
272
+ JSON.parse honors the option but JSON.load does not.
255
273
 
256
274
  ### :trace
257
275
 
data/test/foo.rb CHANGED
@@ -8,48 +8,6 @@ end
8
8
 
9
9
  require 'oj'
10
10
 
11
- class Foo
12
- def initialize
13
- @x = 123
14
- end
11
+ p = Oj::Parser.new(:debug)
15
12
 
16
- def xto_json(opt=nil, options=nil)
17
- "---to_json---"
18
- end
19
- end
20
-
21
- class Bar < Foo
22
- def initialize
23
- @x = 321
24
- end
25
- end
26
-
27
- foo = Foo.new
28
- bar = Bar.new
29
-
30
- require 'json'
31
-
32
- puts "JSON: #{JSON.generate(foo)}"
33
- puts "to_json: #{foo.to_json}"
34
- puts "bar JSON: #{JSON.generate(bar)}"
35
- puts "bar to_json: #{bar.to_json}"
36
-
37
- m = bar.method('to_json')
38
- puts "*** method: #{m} owner: #{m.owner.name}"
39
-
40
- puts "---- rails"
41
- require 'rails'
42
-
43
- m = bar.method('to_json')
44
- puts "*** method: #{m} owner: #{m.owner} params: #{m.parameters}"
45
-
46
- puts "JSON: #{JSON.generate(foo)}"
47
- puts "to_json: #{foo.to_json}"
48
-
49
- puts "---- Oj.mimic_JSON"
50
- Oj.mimic_JSON()
51
- puts "Oj JSON: #{JSON.generate(foo)}"
52
- puts "Oj to_json: #{foo.to_json}"
53
-
54
- m = bar.method('to_json')
55
- puts "*** method: #{m} owner: #{m.owner} params: #{m.parameters}"
13
+ p.parse("[true, false]")