oj 3.11.5 → 3.16.5

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.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +19 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +20 -6
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +10 -9
  9. data/ext/oj/circarray.c +8 -6
  10. data/ext/oj/circarray.h +2 -2
  11. data/ext/oj/code.c +19 -33
  12. data/ext/oj/code.h +2 -2
  13. data/ext/oj/compat.c +27 -77
  14. data/ext/oj/custom.c +86 -179
  15. data/ext/oj/debug.c +126 -0
  16. data/ext/oj/dump.c +256 -249
  17. data/ext/oj/dump.h +26 -12
  18. data/ext/oj/dump_compat.c +565 -642
  19. data/ext/oj/dump_leaf.c +17 -63
  20. data/ext/oj/dump_object.c +65 -187
  21. data/ext/oj/dump_strict.c +27 -51
  22. data/ext/oj/encoder.c +43 -0
  23. data/ext/oj/err.c +2 -13
  24. data/ext/oj/err.h +24 -8
  25. data/ext/oj/extconf.rb +21 -6
  26. data/ext/oj/fast.c +149 -149
  27. data/ext/oj/intern.c +313 -0
  28. data/ext/oj/intern.h +22 -0
  29. data/ext/oj/mem.c +318 -0
  30. data/ext/oj/mem.h +53 -0
  31. data/ext/oj/mimic_json.c +121 -106
  32. data/ext/oj/object.c +85 -162
  33. data/ext/oj/odd.c +89 -67
  34. data/ext/oj/odd.h +15 -15
  35. data/ext/oj/oj.c +542 -411
  36. data/ext/oj/oj.h +99 -73
  37. data/ext/oj/parse.c +175 -187
  38. data/ext/oj/parse.h +26 -24
  39. data/ext/oj/parser.c +1600 -0
  40. data/ext/oj/parser.h +101 -0
  41. data/ext/oj/rails.c +112 -159
  42. data/ext/oj/rails.h +1 -1
  43. data/ext/oj/reader.c +11 -14
  44. data/ext/oj/reader.h +4 -2
  45. data/ext/oj/resolve.c +5 -24
  46. data/ext/oj/rxclass.c +7 -6
  47. data/ext/oj/rxclass.h +1 -1
  48. data/ext/oj/saj.c +22 -33
  49. data/ext/oj/saj2.c +584 -0
  50. data/ext/oj/saj2.h +23 -0
  51. data/ext/oj/scp.c +5 -28
  52. data/ext/oj/sparse.c +28 -72
  53. data/ext/oj/stream_writer.c +50 -40
  54. data/ext/oj/strict.c +56 -61
  55. data/ext/oj/string_writer.c +72 -39
  56. data/ext/oj/trace.h +31 -4
  57. data/ext/oj/usual.c +1218 -0
  58. data/ext/oj/usual.h +69 -0
  59. data/ext/oj/util.h +1 -1
  60. data/ext/oj/val_stack.c +14 -3
  61. data/ext/oj/val_stack.h +8 -7
  62. data/ext/oj/validate.c +46 -0
  63. data/ext/oj/wab.c +63 -88
  64. data/lib/oj/active_support_helper.rb +1 -3
  65. data/lib/oj/bag.rb +7 -1
  66. data/lib/oj/easy_hash.rb +4 -5
  67. data/lib/oj/error.rb +1 -2
  68. data/lib/oj/json.rb +162 -150
  69. data/lib/oj/mimic.rb +9 -7
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/schandler.rb +5 -4
  72. data/lib/oj/state.rb +12 -8
  73. data/lib/oj/version.rb +1 -2
  74. data/lib/oj.rb +2 -0
  75. data/pages/Compatibility.md +1 -1
  76. data/pages/InstallOptions.md +20 -0
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +8 -3
  79. data/pages/Options.md +43 -5
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +14 -2
  82. data/test/_test_active.rb +8 -9
  83. data/test/_test_active_mimic.rb +7 -8
  84. data/test/_test_mimic_rails.rb +17 -20
  85. data/test/activerecord/result_test.rb +5 -6
  86. data/test/activesupport6/encoding_test.rb +63 -28
  87. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  88. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  89. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  90. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  91. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  92. data/test/files.rb +15 -15
  93. data/test/foo.rb +16 -45
  94. data/test/helper.rb +11 -8
  95. data/test/isolated/shared.rb +3 -2
  96. data/test/json_gem/json_addition_test.rb +2 -2
  97. data/test/json_gem/json_common_interface_test.rb +8 -6
  98. data/test/json_gem/json_encoding_test.rb +0 -0
  99. data/test/json_gem/json_ext_parser_test.rb +1 -0
  100. data/test/json_gem/json_fixtures_test.rb +3 -2
  101. data/test/json_gem/json_generator_test.rb +56 -38
  102. data/test/json_gem/json_generic_object_test.rb +11 -11
  103. data/test/json_gem/json_parser_test.rb +54 -47
  104. data/test/json_gem/json_string_matching_test.rb +9 -9
  105. data/test/json_gem/test_helper.rb +7 -3
  106. data/test/mem.rb +34 -0
  107. data/test/perf.rb +22 -27
  108. data/test/perf_compat.rb +31 -33
  109. data/test/perf_dump.rb +50 -0
  110. data/test/perf_fast.rb +80 -82
  111. data/test/perf_file.rb +27 -29
  112. data/test/perf_object.rb +65 -69
  113. data/test/perf_once.rb +59 -0
  114. data/test/perf_parser.rb +183 -0
  115. data/test/perf_saj.rb +46 -54
  116. data/test/perf_scp.rb +58 -69
  117. data/test/perf_simple.rb +41 -39
  118. data/test/perf_strict.rb +74 -82
  119. data/test/perf_wab.rb +67 -69
  120. data/test/prec.rb +5 -5
  121. data/test/sample/change.rb +0 -1
  122. data/test/sample/dir.rb +0 -1
  123. data/test/sample/doc.rb +0 -1
  124. data/test/sample/file.rb +0 -1
  125. data/test/sample/group.rb +0 -1
  126. data/test/sample/hasprops.rb +0 -1
  127. data/test/sample/layer.rb +0 -1
  128. data/test/sample/rect.rb +0 -1
  129. data/test/sample/shape.rb +0 -1
  130. data/test/sample/text.rb +0 -1
  131. data/test/sample.rb +16 -16
  132. data/test/sample_json.rb +8 -8
  133. data/test/test_compat.rb +95 -43
  134. data/test/test_custom.rb +73 -51
  135. data/test/test_debian.rb +7 -10
  136. data/test/test_fast.rb +135 -79
  137. data/test/test_file.rb +41 -30
  138. data/test/test_gc.rb +16 -5
  139. data/test/test_generate.rb +5 -5
  140. data/test/test_hash.rb +5 -5
  141. data/test/test_integer_range.rb +9 -9
  142. data/test/test_null.rb +20 -20
  143. data/test/test_object.rb +99 -96
  144. data/test/test_parser.rb +11 -0
  145. data/test/test_parser_debug.rb +27 -0
  146. data/test/test_parser_saj.rb +337 -0
  147. data/test/test_parser_usual.rb +251 -0
  148. data/test/test_rails.rb +2 -2
  149. data/test/test_saj.rb +10 -8
  150. data/test/test_scp.rb +37 -39
  151. data/test/test_strict.rb +40 -32
  152. data/test/test_various.rb +165 -84
  153. data/test/test_wab.rb +48 -44
  154. data/test/test_writer.rb +47 -47
  155. data/test/tests.rb +13 -5
  156. data/test/tests_mimic.rb +12 -3
  157. data/test/tests_mimic_addition.rb +12 -3
  158. metadata +74 -128
  159. data/ext/oj/hash.c +0 -131
  160. data/ext/oj/hash.h +0 -19
  161. data/ext/oj/hash_test.c +0 -491
  162. data/test/activesupport4/decoding_test.rb +0 -108
  163. data/test/activesupport4/encoding_test.rb +0 -531
  164. data/test/activesupport4/test_helper.rb +0 -41
  165. data/test/activesupport5/test_helper.rb +0 -72
  166. data/test/bar.rb +0 -35
  167. data/test/baz.rb +0 -16
  168. data/test/zoo.rb +0 -13
data/ext/oj/usual.h ADDED
@@ -0,0 +1,69 @@
1
+ // Copyright (c) 2022, Peter Ohler, All rights reserved.
2
+
3
+ #include <ruby.h>
4
+ #include <stdbool.h>
5
+ #include <stdint.h>
6
+
7
+ struct _cache;
8
+ struct _ojParser;
9
+
10
+ // Used to mark the start of each Hash, Array, or Object. The members point at
11
+ // positions of the start in the value stack and if not an Array into the key
12
+ // stack.
13
+ typedef struct _col {
14
+ long vi; // value stack index
15
+ long ki; // key stack index if an hash else -1 for an array
16
+ } *Col;
17
+
18
+ typedef union _key {
19
+ struct {
20
+ int16_t len;
21
+ char buf[30];
22
+ };
23
+ struct {
24
+ int16_t xlen; // should be the same as len
25
+ char *key;
26
+ };
27
+ } *Key;
28
+
29
+ #define MISS_AUTO 'A'
30
+ #define MISS_RAISE 'R'
31
+ #define MISS_IGNORE 'I'
32
+
33
+ typedef struct _usual {
34
+ VALUE *vhead;
35
+ VALUE *vtail;
36
+ VALUE *vend;
37
+
38
+ Col chead;
39
+ Col ctail;
40
+ Col cend;
41
+
42
+ Key khead;
43
+ Key ktail;
44
+ Key kend;
45
+
46
+ VALUE (*get_key)(struct _ojParser *p, Key kp);
47
+ struct _cache *key_cache; // same as str_cache or sym_cache
48
+ struct _cache *str_cache;
49
+ struct _cache *sym_cache;
50
+ struct _cache *class_cache;
51
+ struct _cache *attr_cache;
52
+
53
+ VALUE array_class;
54
+ VALUE hash_class;
55
+
56
+ char *create_id;
57
+ uint8_t create_id_len;
58
+ uint8_t cache_str;
59
+ uint8_t cache_xrate;
60
+ uint8_t miss_class;
61
+ bool cache_keys;
62
+ bool ignore_json_create;
63
+ bool raise_on_empty;
64
+ } *Usual;
65
+
66
+ // Initialize the parser with the usual delegate. If the usual delegate is
67
+ // wrapped then this function is called first and then the parser functions
68
+ // can be replaced.
69
+ extern void oj_init_usual(struct _ojParser *p, Usual d);
data/ext/oj/util.h CHANGED
@@ -13,7 +13,7 @@ typedef struct _timeInfo {
13
13
  int day;
14
14
  int mon;
15
15
  int year;
16
- } * TimeInfo;
16
+ }* TimeInfo;
17
17
 
18
18
  extern void sec_as_time(int64_t secs, TimeInfo ti);
19
19
 
data/ext/oj/val_stack.c CHANGED
@@ -8,11 +8,11 @@
8
8
  #include "odd.h"
9
9
  #include "oj.h"
10
10
 
11
- static void mark(void *ptr) {
11
+ static void stack_mark(void *ptr) {
12
12
  ValStack stack = (ValStack)ptr;
13
13
  Val v;
14
14
 
15
- if (0 == ptr) {
15
+ if (NULL == ptr) {
16
16
  return;
17
17
  }
18
18
  #ifdef HAVE_PTHREAD_MUTEX_INIT
@@ -46,6 +46,17 @@ static void mark(void *ptr) {
46
46
  #endif
47
47
  }
48
48
 
49
+ static const rb_data_type_t oj_stack_type = {
50
+ "Oj/stack",
51
+ {
52
+ stack_mark,
53
+ NULL,
54
+ NULL,
55
+ },
56
+ 0,
57
+ 0,
58
+ };
59
+
49
60
  VALUE
50
61
  oj_stack_init(ValStack stack) {
51
62
  #ifdef HAVE_PTHREAD_MUTEX_INIT
@@ -70,7 +81,7 @@ oj_stack_init(ValStack stack) {
70
81
  stack->head->clen = 0;
71
82
  stack->head->next = NEXT_NONE;
72
83
 
73
- return Data_Wrap_Struct(oj_cstack_class, mark, 0, stack);
84
+ return TypedData_Wrap_Struct(oj_cstack_class, &oj_stack_type, stack);
74
85
  }
75
86
 
76
87
  const char *oj_stack_next_string(ValNext n) {
data/ext/oj/val_stack.h CHANGED
@@ -6,6 +6,7 @@
6
6
 
7
7
  #include <stdint.h>
8
8
 
9
+ #include "mem.h"
9
10
  #include "odd.h"
10
11
  #include "ruby.h"
11
12
  #ifdef HAVE_PTHREAD_MUTEX_INIT
@@ -28,10 +29,10 @@ typedef enum {
28
29
 
29
30
  typedef struct _val {
30
31
  volatile VALUE val;
31
- const char * key;
32
+ const char *key;
32
33
  char karray[32];
33
34
  volatile VALUE key_val;
34
- const char * classname;
35
+ const char *classname;
35
36
  VALUE clas;
36
37
  OddArgs odd_args;
37
38
  uint16_t klen;
@@ -39,7 +40,7 @@ typedef struct _val {
39
40
  char next; // ValNext
40
41
  char k1; // first original character in the key
41
42
  char kalloc;
42
- } * Val;
43
+ } *Val;
43
44
 
44
45
  typedef struct _valStack {
45
46
  struct _val base[STACK_INC];
@@ -52,7 +53,7 @@ typedef struct _valStack {
52
53
  VALUE mutex;
53
54
  #endif
54
55
 
55
- } * ValStack;
56
+ } *ValStack;
56
57
 
57
58
  extern VALUE oj_stack_init(ValStack stack);
58
59
 
@@ -62,7 +63,7 @@ inline static int stack_empty(ValStack stack) {
62
63
 
63
64
  inline static void stack_cleanup(ValStack stack) {
64
65
  if (stack->base != stack->head) {
65
- xfree(stack->head);
66
+ OJ_R_FREE(stack->head);
66
67
  stack->head = NULL;
67
68
  }
68
69
  }
@@ -76,10 +77,10 @@ inline static void stack_push(ValStack stack, VALUE val, ValNext next) {
76
77
  // A realloc can trigger a GC so make sure it happens outside the lock
77
78
  // but lock before changing pointers.
78
79
  if (stack->base == stack->head) {
79
- head = ALLOC_N(struct _val, len + STACK_INC);
80
+ head = OJ_R_ALLOC_N(struct _val, len + STACK_INC);
80
81
  memcpy(head, stack->base, sizeof(struct _val) * len);
81
82
  } else {
82
- REALLOC_N(head, struct _val, len + STACK_INC);
83
+ OJ_R_REALLOC_N(head, struct _val, len + STACK_INC);
83
84
  }
84
85
  #ifdef HAVE_PTHREAD_MUTEX_INIT
85
86
  pthread_mutex_lock(&stack->mutex);
data/ext/oj/validate.c ADDED
@@ -0,0 +1,46 @@
1
+ // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
+
3
+ #include "parser.h"
4
+
5
+ static void noop(ojParser p) {
6
+ }
7
+
8
+ static VALUE option(ojParser p, const char *key, VALUE value) {
9
+ rb_raise(rb_eArgError, "%s is not an option for the validate delegate", key);
10
+ return Qnil;
11
+ }
12
+
13
+ static VALUE result(ojParser p) {
14
+ return Qnil;
15
+ }
16
+
17
+ static void dfree(ojParser p) {
18
+ }
19
+
20
+ static void mark(ojParser p) {
21
+ }
22
+
23
+ void oj_set_parser_validator(ojParser p) {
24
+ Funcs end = p->funcs + 3;
25
+ Funcs f;
26
+ p->ctx = NULL;
27
+
28
+ for (f = p->funcs; f < end; f++) {
29
+ f->add_null = noop;
30
+ f->add_true = noop;
31
+ f->add_false = noop;
32
+ f->add_int = noop;
33
+ f->add_float = noop;
34
+ f->add_big = noop;
35
+ f->add_str = noop;
36
+ f->open_array = noop;
37
+ f->close_array = noop;
38
+ f->open_object = noop;
39
+ f->close_object = noop;
40
+ }
41
+ p->option = option;
42
+ p->result = result;
43
+ p->free = dfree;
44
+ p->mark = mark;
45
+ p->start = noop;
46
+ }
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 "intern.h"
13
14
  #include "oj.h"
14
15
  #include "parse.h"
15
16
  #include "trace.h"
@@ -34,7 +35,7 @@ static VALUE uri_http_clas = Qundef;
34
35
 
35
36
  ///// dump functions /////
36
37
 
37
- static VALUE resolve_wab_uuid_class() {
38
+ static VALUE resolve_wab_uuid_class(void) {
38
39
  if (Qundef == wab_uuid_clas) {
39
40
  volatile VALUE wab_module;
40
41
 
@@ -49,7 +50,7 @@ static VALUE resolve_wab_uuid_class() {
49
50
  return wab_uuid_clas;
50
51
  }
51
52
 
52
- static VALUE resolve_uri_class() {
53
+ static VALUE resolve_uri_class(void) {
53
54
  if (Qundef == uri_clas) {
54
55
  uri_clas = Qnil;
55
56
  if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
@@ -59,7 +60,7 @@ static VALUE resolve_uri_class() {
59
60
  return uri_clas;
60
61
  }
61
62
 
62
- static VALUE resolve_uri_http_class() {
63
+ static VALUE resolve_uri_http_class(void) {
63
64
  if (Qundef == uri_http_clas) {
64
65
  volatile VALUE uri_module;
65
66
 
@@ -75,15 +76,13 @@ static VALUE resolve_uri_http_class() {
75
76
  }
76
77
 
77
78
  static void raise_wab(VALUE obj) {
78
- rb_raise(rb_eTypeError,
79
- "Failed to dump %s Object to JSON in wab mode.\n",
80
- rb_class2name(rb_obj_class(obj)));
79
+ rb_raise(rb_eTypeError, "Failed to dump %s Object to JSON in wab mode.\n", rb_class2name(rb_obj_class(obj)));
81
80
  }
82
81
 
83
82
  // Removed dependencies on math due to problems with CentOS 5.4.
84
83
  static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
85
84
  char buf[64];
86
- char * b;
85
+ char *b;
87
86
  double d = rb_num2dbl(obj);
88
87
  int cnt = 0;
89
88
 
@@ -123,11 +122,11 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
123
122
  *out->cur++ = ']';
124
123
  } else {
125
124
  size = d2 * out->indent + 2;
125
+ assure_size(out, size * cnt);
126
126
  cnt--;
127
127
  for (i = 0; i <= cnt; i++) {
128
- assure_size(out, size);
129
128
  fill_indent(out, d2);
130
- oj_dump_wab_val(rb_ary_entry(a, i), d2, out);
129
+ oj_dump_wab_val(RARRAY_AREF(a, i), d2, out);
131
130
  if (i < cnt) {
132
131
  *out->cur++ = ',';
133
132
  }
@@ -193,20 +192,15 @@ static void dump_time(VALUE obj, Out out) {
193
192
  time_t sec;
194
193
  long long nsec;
195
194
 
196
- #ifdef HAVE_RB_TIME_TIMESPEC
197
195
  if (16 <= sizeof(struct timespec)) {
198
196
  struct timespec ts = rb_time_timespec(obj);
199
197
 
200
198
  sec = ts.tv_sec;
201
199
  nsec = ts.tv_nsec;
202
200
  } else {
203
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
204
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
201
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
202
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
205
203
  }
206
- #else
207
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
208
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
209
- #endif
210
204
 
211
205
  assure_size(out, 36);
212
206
  // 2012-01-05T23:58:07.123456000Z
@@ -230,13 +224,13 @@ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
230
224
  if (rb_cTime == clas) {
231
225
  dump_time(obj, out);
232
226
  } else if (oj_bigdecimal_class == clas) {
233
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
227
+ volatile VALUE rstr = oj_safe_string_convert(obj);
234
228
 
235
- oj_dump_raw(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), out);
229
+ oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
236
230
  } else if (resolve_wab_uuid_class() == clas) {
237
- oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false);
231
+ oj_dump_str(oj_safe_string_convert(obj), depth, out, false);
238
232
  } else if (resolve_uri_http_class() == clas) {
239
- oj_dump_str(rb_funcall(obj, oj_to_s_id, 0), depth, out, false);
233
+ oj_dump_str(oj_safe_string_convert(obj), depth, out, false);
240
234
  } else {
241
235
  raise_wab(obj);
242
236
  }
@@ -270,9 +264,7 @@ static DumpFunc wab_funcs[] = {
270
264
  void oj_dump_wab_val(VALUE obj, int depth, Out out) {
271
265
  int type = rb_type(obj);
272
266
 
273
- if (Yes == out->opts->trace) {
274
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
275
- }
267
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
276
268
  if (MAX_DEPTH < depth) {
277
269
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
278
270
  }
@@ -281,9 +273,7 @@ void oj_dump_wab_val(VALUE obj, int depth, Out out) {
281
273
 
282
274
  if (NULL != f) {
283
275
  f(obj, depth, out, false);
284
- if (Yes == out->opts->trace) {
285
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
286
- }
276
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
287
277
  return;
288
278
  }
289
279
  }
@@ -292,16 +282,35 @@ void oj_dump_wab_val(VALUE obj, int depth, Out out) {
292
282
 
293
283
  ///// load functions /////
294
284
 
295
- static void hash_end(ParseInfo pi) {
296
- if (Yes == pi->options.trace) {
297
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
285
+ static VALUE calc_hash_key(ParseInfo pi, Val parent) {
286
+ volatile VALUE rkey = parent->key_val;
287
+
288
+ if (Qundef != rkey) {
289
+ rkey = oj_encode(rkey);
290
+ rkey = rb_str_intern(rkey);
291
+
292
+ return rkey;
298
293
  }
294
+ if (Yes == pi->options.cache_keys) {
295
+ rkey = oj_sym_intern(parent->key, parent->klen);
296
+ } else {
297
+ #if HAVE_RB_ENC_INTERNED_STR
298
+ rkey = rb_enc_interned_str(parent->key, parent->klen, oj_utf8_encoding);
299
+ #else
300
+ rkey = rb_utf8_str_new(parent->key, parent->klen);
301
+ rkey = rb_str_intern(rkey);
302
+ OBJ_FREEZE(rkey);
303
+ #endif
304
+ }
305
+ return rkey;
306
+ }
307
+
308
+ static void hash_end(ParseInfo pi) {
309
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
299
310
  }
300
311
 
301
312
  static void array_end(ParseInfo pi) {
302
- if (Yes == pi->options.trace) {
303
- oj_trace_parse_array_end(pi, __FILE__, __LINE__);
304
- }
313
+ TRACE_PARSE_ARRAY_END(pi->options.trace, pi);
305
314
  }
306
315
 
307
316
  static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
@@ -309,9 +318,7 @@ static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
309
318
  }
310
319
 
311
320
  static void add_value(ParseInfo pi, VALUE val) {
312
- if (Yes == pi->options.trace) {
313
- oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
314
- }
321
+ TRACE_PARSE_CALL(pi->options.trace, "add_value", pi, val);
315
322
  pi->stack.head->val = val;
316
323
  }
317
324
 
@@ -432,36 +439,34 @@ static VALUE protect_uri(VALUE rstr) {
432
439
  return rb_funcall(resolve_uri_class(), oj_parse_id, 1, rstr);
433
440
  }
434
441
 
435
- static VALUE cstr_to_rstr(const char *str, size_t len) {
442
+ static VALUE cstr_to_rstr(ParseInfo pi, const char *str, size_t len) {
436
443
  volatile VALUE v = Qnil;
437
444
 
438
- if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] &&
439
- ':' == str[16] && '.' == str[19] && 'Z' == str[29]) {
445
+ if (30 == len && '-' == str[4] && '-' == str[7] && 'T' == str[10] && ':' == str[13] && ':' == str[16] &&
446
+ '.' == str[19] && 'Z' == str[29]) {
440
447
  if (Qnil != (v = time_parse(str, (int)len))) {
441
448
  return v;
442
449
  }
443
450
  }
444
- if (36 == len && '-' == str[8] && '-' == str[13] && '-' == str[18] && '-' == str[23] &&
445
- uuid_check(str, (int)len) && Qnil != resolve_wab_uuid_class()) {
451
+ if (36 == len && '-' == str[8] && '-' == str[13] && '-' == str[18] && '-' == str[23] && uuid_check(str, (int)len) &&
452
+ Qnil != resolve_wab_uuid_class()) {
446
453
  return rb_funcall(wab_uuid_clas, oj_new_id, 1, rb_str_new(str, len));
447
454
  }
448
- v = rb_str_new(str, len);
449
455
  if (7 < len && 0 == strncasecmp("http://", str, 7)) {
450
- int err = 0;
456
+ int err = 0;
457
+ v = rb_str_new(str, len);
451
458
  volatile VALUE uri = rb_protect(protect_uri, v, &err);
452
459
 
453
460
  if (0 == err) {
454
461
  return uri;
455
462
  }
456
463
  }
457
- return oj_encode(v);
464
+ return oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
458
465
  }
459
466
 
460
467
  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);
462
- if (Yes == pi->options.trace) {
463
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
464
- }
468
+ pi->stack.head->val = cstr_to_rstr(pi, str, len);
469
+ TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, pi->stack.head->val);
465
470
  }
466
471
 
467
472
  static void add_num(ParseInfo pi, NumInfo ni) {
@@ -469,40 +474,22 @@ static void add_num(ParseInfo pi, NumInfo ni) {
469
474
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
470
475
  }
471
476
  pi->stack.head->val = oj_num_as_value(ni);
472
- if (Yes == pi->options.trace) {
473
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
474
- }
477
+ TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, pi->stack.head->val);
475
478
  }
476
479
 
477
480
  static VALUE start_hash(ParseInfo pi) {
478
- if (Yes == pi->options.trace) {
479
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
480
- }
481
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
481
482
  if (Qnil != pi->options.hash_class) {
482
483
  return rb_class_new_instance(0, NULL, pi->options.hash_class);
483
484
  }
484
485
  return rb_hash_new();
485
486
  }
486
487
 
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
488
  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);
489
+ volatile VALUE rval = cstr_to_rstr(pi, str, len);
501
490
 
502
491
  rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
503
- if (Yes == pi->options.trace) {
504
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
505
- }
492
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rval);
506
493
  }
507
494
 
508
495
  static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
@@ -513,32 +500,24 @@ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
513
500
  }
514
501
  rval = oj_num_as_value(ni);
515
502
  rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
516
- if (Yes == pi->options.trace) {
517
- oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
518
- }
503
+ TRACE_PARSE_CALL(pi->options.trace, "set_number", pi, rval);
519
504
  }
520
505
 
521
506
  static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
522
507
  rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
523
- if (Yes == pi->options.trace) {
524
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
525
- }
508
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
526
509
  }
527
510
 
528
511
  static VALUE start_array(ParseInfo pi) {
529
- if (Yes == pi->options.trace) {
530
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
531
- }
512
+ TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
532
513
  return rb_ary_new();
533
514
  }
534
515
 
535
516
  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);
517
+ volatile VALUE rval = cstr_to_rstr(pi, str, len);
537
518
 
538
519
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
539
- if (Yes == pi->options.trace) {
540
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, rval);
541
- }
520
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, rval);
542
521
  }
543
522
 
544
523
  static void array_append_num(ParseInfo pi, NumInfo ni) {
@@ -549,16 +528,12 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
549
528
  }
550
529
  rval = oj_num_as_value(ni);
551
530
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
552
- if (Yes == pi->options.trace) {
553
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
554
- }
531
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
555
532
  }
556
533
 
557
534
  static void array_append_value(ParseInfo pi, VALUE value) {
558
535
  rb_ary_push(stack_peek(&pi->stack)->val, value);
559
- if (Yes == pi->options.trace) {
560
- oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
561
- }
536
+ TRACE_PARSE_CALL(pi->options.trace, "append_value", pi, value);
562
537
  }
563
538
 
564
539
  void oj_set_wab_callbacks(ParseInfo pi) {
@@ -1,16 +1,14 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  require 'active_support/time'
3
4
 
4
5
  module Oj
5
-
6
6
  # Exists only to handle the ActiveSupport::TimeWithZone.
7
7
  class ActiveSupportHelper
8
-
9
8
  def self.createTimeWithZone(utc, zone)
10
9
  ActiveSupport::TimeWithZone.new(utc - utc.gmt_offset, ActiveSupport::TimeZone[zone])
11
10
  end
12
11
  end
13
-
14
12
  end
15
13
 
16
14
  Oj.register_odd(ActiveSupport::TimeWithZone, Oj::ActiveSupportHelper, :createTimeWithZone, :utc, 'time_zone.name')
data/lib/oj/bag.rb CHANGED
@@ -15,7 +15,7 @@ module Oj
15
15
  # @example Oj::Bag.new(:@x => 42, :@y => 57)
16
16
  # @param [Hash] args instance variable symbols and their values
17
17
  def initialize(args = {})
18
- args.each do |k,v|
18
+ args.each do |k, v|
19
19
  self.instance_variable_set(k, v)
20
20
  end
21
21
  end
@@ -26,6 +26,7 @@ module Oj
26
26
  # variable reader, otherwise false.
27
27
  def respond_to?(m)
28
28
  return true if super
29
+
29
30
  instance_variables.include?(:"@#{m}")
30
31
  end
31
32
 
@@ -37,8 +38,10 @@ module Oj
37
38
  # @raise [NoMethodError] if the instance variable is not defined.
38
39
  def method_missing(m, *args, &block)
39
40
  raise ArgumentError.new("wrong number of arguments (#{args.size} for 0) to method #{m}") unless args.nil? or args.empty?
41
+
40
42
  at_m = :"@#{m}"
41
43
  raise NoMethodError.new("undefined method #{m}", m) unless instance_variable_defined?(at_m)
44
+
42
45
  instance_variable_get(at_m)
43
46
  end
44
47
 
@@ -47,9 +50,11 @@ module Oj
47
50
  # @return [Boolean] true if each variable and value are the same, otherwise false.
48
51
  def eql?(other)
49
52
  return false if (other.nil? or self.class != other.class)
53
+
50
54
  ova = other.instance_variables
51
55
  iv = instance_variables
52
56
  return false if ova.size != iv.size
57
+
53
58
  iv.all? { |vid| instance_variable_get(vid) != other.instance_variable_get(vid) }
54
59
  end
55
60
  alias == eql?
@@ -65,6 +70,7 @@ module Oj
65
70
  classname = classname.to_s unless classname.is_a?(String)
66
71
  tokens = classname.split('::').map(&:to_sym)
67
72
  raise NameError.new("Invalid classname '#{classname}") if tokens.empty?
73
+
68
74
  m = Object
69
75
  tokens[0..-2].each do |sym|
70
76
  if m.const_defined?(sym)
data/lib/oj/easy_hash.rb CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  module Oj
3
2
 
4
3
  # A Hash subclass that normalizes the hash keys to allow lookup by the
@@ -6,10 +5,6 @@ module Oj
6
5
  # that match the keys.
7
6
  class EasyHash < Hash
8
7
 
9
- # Initializes the instance to an empty Hash.
10
- def initialize()
11
- end
12
-
13
8
  # Replaces the Object.respond_to?() method.
14
9
  # @param [Symbol] m method symbol
15
10
  # @param [Boolean] include_all whether to include private and protected methods in the search
@@ -19,12 +14,14 @@ module Oj
19
14
  return true if super
20
15
  return true if has_key?(m)
21
16
  return true if has_key?(m.to_s)
17
+
22
18
  has_key?(m.to_sym)
23
19
  end
24
20
 
25
21
  def [](key)
26
22
  return fetch(key, nil) if has_key?(key)
27
23
  return fetch(key.to_s, nil) if has_key?(key.to_s)
24
+
28
25
  fetch(key.to_sym, nil)
29
26
  end
30
27
 
@@ -36,9 +33,11 @@ module Oj
36
33
  def method_missing(m, *args, &block)
37
34
  if m.to_s.end_with?('=')
38
35
  raise ArgumentError.new("wrong number of arguments (#{args.size} for 1 with #{m}) to method #{m}") if args.nil? or 1 != args.length
36
+
39
37
  m = m[0..-2]
40
38
  return store(m.to_s, args[0]) if has_key?(m.to_s)
41
39
  return store(m.to_sym, args[0]) if has_key?(m.to_sym)
40
+
42
41
  return store(m, args[0])
43
42
  else
44
43
  raise ArgumentError.new("wrong number of arguments (#{args.size} for 0 with #{m}) to method #{m}") unless args.nil? or args.empty?
data/lib/oj/error.rb CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  module Oj
3
2
 
4
3
  # Inherit Error class from StandardError.
@@ -16,7 +15,7 @@ module Oj
16
15
  # An Exception that is raised if a file fails to load.
17
16
  LoadError = Class.new(Error)
18
17
 
19
- # An Exception that is raised if there is a conflict with mimicing JSON
18
+ # An Exception that is raised if there is a conflict with mimicking JSON
20
19
  MimicError = Class.new(Error)
21
20
 
22
21
  end # Oj