oj 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +17 -23
  3. data/README.md +74 -425
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +4 -0
  6. data/ext/oj/circarray.c +68 -0
  7. data/ext/oj/circarray.h +23 -0
  8. data/ext/oj/code.c +227 -0
  9. data/ext/oj/code.h +40 -0
  10. data/ext/oj/compat.c +243 -0
  11. data/ext/oj/custom.c +1097 -0
  12. data/ext/oj/dump.c +766 -1534
  13. data/ext/oj/dump.h +92 -0
  14. data/ext/oj/dump_compat.c +937 -0
  15. data/ext/oj/dump_leaf.c +254 -0
  16. data/ext/oj/dump_object.c +810 -0
  17. data/ext/oj/dump_rails.c +329 -0
  18. data/ext/oj/dump_strict.c +416 -0
  19. data/ext/oj/encode.h +51 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +17 -7
  23. data/ext/oj/fast.c +213 -180
  24. data/ext/oj/hash.c +163 -0
  25. data/ext/oj/hash.h +46 -0
  26. data/ext/oj/hash_test.c +512 -0
  27. data/ext/oj/mimic_json.c +817 -0
  28. data/ext/oj/mimic_rails.c +806 -0
  29. data/ext/oj/mimic_rails.h +17 -0
  30. data/ext/oj/object.c +752 -0
  31. data/ext/oj/odd.c +230 -0
  32. data/ext/oj/odd.h +44 -0
  33. data/ext/oj/oj.c +1288 -929
  34. data/ext/oj/oj.h +240 -69
  35. data/ext/oj/parse.c +1014 -0
  36. data/ext/oj/parse.h +92 -0
  37. data/ext/oj/reader.c +223 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +127 -0
  40. data/ext/oj/{cache.h → resolve.h} +6 -13
  41. data/ext/oj/rxclass.c +133 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +77 -175
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +911 -0
  46. data/ext/oj/stream_writer.c +301 -0
  47. data/ext/oj/strict.c +162 -0
  48. data/ext/oj/string_writer.c +480 -0
  49. data/ext/oj/val_stack.c +98 -0
  50. data/ext/oj/val_stack.h +188 -0
  51. data/lib/oj/active_support_helper.rb +41 -0
  52. data/lib/oj/bag.rb +6 -10
  53. data/lib/oj/easy_hash.rb +52 -0
  54. data/lib/oj/json.rb +172 -0
  55. data/lib/oj/mimic.rb +260 -5
  56. data/lib/oj/saj.rb +13 -10
  57. data/lib/oj/schandler.rb +142 -0
  58. data/lib/oj/state.rb +131 -0
  59. data/lib/oj/version.rb +1 -1
  60. data/lib/oj.rb +11 -23
  61. data/pages/Advanced.md +22 -0
  62. data/pages/Compatibility.md +25 -0
  63. data/pages/Custom.md +23 -0
  64. data/pages/Encoding.md +65 -0
  65. data/pages/JsonGem.md +79 -0
  66. data/pages/Modes.md +140 -0
  67. data/pages/Options.md +250 -0
  68. data/pages/Rails.md +60 -0
  69. data/pages/Security.md +20 -0
  70. data/test/_test_active.rb +76 -0
  71. data/test/_test_active_mimic.rb +96 -0
  72. data/test/_test_mimic_rails.rb +126 -0
  73. data/test/activesupport4/decoding_test.rb +105 -0
  74. data/test/activesupport4/encoding_test.rb +531 -0
  75. data/test/activesupport4/test_helper.rb +41 -0
  76. data/test/activesupport5/decoding_test.rb +125 -0
  77. data/test/activesupport5/encoding_test.rb +483 -0
  78. data/test/activesupport5/encoding_test_cases.rb +90 -0
  79. data/test/activesupport5/test_helper.rb +50 -0
  80. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  81. data/test/helper.rb +27 -0
  82. data/test/isolated/shared.rb +310 -0
  83. data/test/isolated/test_mimic_after.rb +13 -0
  84. data/test/isolated/test_mimic_alone.rb +12 -0
  85. data/test/isolated/test_mimic_as_json.rb +45 -0
  86. data/test/isolated/test_mimic_before.rb +13 -0
  87. data/test/isolated/test_mimic_define.rb +28 -0
  88. data/test/isolated/test_mimic_rails_after.rb +22 -0
  89. data/test/isolated/test_mimic_rails_before.rb +21 -0
  90. data/test/isolated/test_mimic_redefine.rb +15 -0
  91. data/test/json_gem/json_addition_test.rb +216 -0
  92. data/test/json_gem/json_common_interface_test.rb +143 -0
  93. data/test/json_gem/json_encoding_test.rb +109 -0
  94. data/test/json_gem/json_ext_parser_test.rb +20 -0
  95. data/test/json_gem/json_fixtures_test.rb +35 -0
  96. data/test/json_gem/json_generator_test.rb +383 -0
  97. data/test/json_gem/json_generic_object_test.rb +90 -0
  98. data/test/json_gem/json_parser_test.rb +470 -0
  99. data/test/json_gem/json_string_matching_test.rb +42 -0
  100. data/test/json_gem/test_helper.rb +18 -0
  101. data/test/perf_compat.rb +130 -0
  102. data/test/perf_fast.rb +9 -9
  103. data/test/perf_file.rb +64 -0
  104. data/test/{perf_obj.rb → perf_object.rb} +24 -10
  105. data/test/perf_scp.rb +151 -0
  106. data/test/perf_strict.rb +32 -113
  107. data/test/sample.rb +2 -3
  108. data/test/test_compat.rb +474 -0
  109. data/test/test_custom.rb +355 -0
  110. data/test/test_debian.rb +53 -0
  111. data/test/test_fast.rb +66 -16
  112. data/test/test_file.rb +237 -0
  113. data/test/test_gc.rb +49 -0
  114. data/test/test_hash.rb +29 -0
  115. data/test/test_null.rb +376 -0
  116. data/test/test_object.rb +1010 -0
  117. data/test/test_saj.rb +16 -16
  118. data/test/test_scp.rb +417 -0
  119. data/test/test_strict.rb +410 -0
  120. data/test/test_various.rb +815 -0
  121. data/test/test_writer.rb +308 -0
  122. data/test/tests.rb +9 -902
  123. data/test/tests_mimic.rb +14 -0
  124. data/test/tests_mimic_addition.rb +7 -0
  125. metadata +253 -38
  126. data/ext/oj/cache.c +0 -148
  127. data/ext/oj/foo.rb +0 -6
  128. data/ext/oj/load.c +0 -1049
  129. data/test/a.rb +0 -38
  130. data/test/perf1.rb +0 -64
  131. data/test/perf2.rb +0 -76
  132. data/test/perf_obj_old.rb +0 -213
  133. data/test/test_mimic.rb +0 -208
@@ -0,0 +1,329 @@
1
+ /* dump_object.c
2
+ * Copyright (c) 2012, 2017, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include "dump.h"
7
+ #include "encode.h"
8
+ #include "mimic_rails.h"
9
+
10
+ #define OJ_INFINITY (1.0/0.0)
11
+
12
+ bool oj_rails_hash_opt = false;
13
+ bool oj_rails_array_opt = false;
14
+
15
+ static void
16
+ dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
17
+ volatile VALUE ja;
18
+
19
+ if (0 < out->argc) {
20
+ ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
21
+ } else {
22
+ ja = rb_funcall(obj, oj_as_json_id, 0);
23
+ }
24
+ if (ja == obj || !as_ok) {
25
+ // Once as_json is call it should never be called again on the same
26
+ // object with as_ok.
27
+ oj_dump_rails_val(ja, depth, out, false);
28
+ } else {
29
+ int type = rb_type(ja);
30
+
31
+ if (T_HASH == type || T_ARRAY == type) {
32
+ oj_dump_rails_val(ja, depth, out, false);
33
+ } else {
34
+ oj_dump_rails_val(ja, depth, out, true);
35
+ }
36
+ }
37
+ }
38
+
39
+ static void
40
+ dump_to_hash(VALUE obj, int depth, Out out) {
41
+ oj_dump_rails_val(rb_funcall(obj, oj_to_hash_id, 0), depth, out, false);
42
+ }
43
+
44
+ static void
45
+ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
46
+ char buf[64];
47
+ char *b;
48
+ double d = rb_num2dbl(obj);
49
+ int cnt = 0;
50
+
51
+ if (0.0 == d) {
52
+ b = buf;
53
+ *b++ = '0';
54
+ *b++ = '.';
55
+ *b++ = '0';
56
+ *b++ = '\0';
57
+ cnt = 3;
58
+ } else {
59
+ if (isnan(d) || OJ_INFINITY == d || -OJ_INFINITY == d) {
60
+ strcpy(buf, "null");
61
+ cnt = 4;
62
+ } else if (d == (double)(long long int)d) {
63
+ cnt = snprintf(buf, sizeof(buf), "%.1f", d);
64
+ } else {
65
+ cnt = snprintf(buf, sizeof(buf), "%0.16g", d);
66
+ }
67
+ }
68
+ assure_size(out, cnt);
69
+ for (b = buf; '\0' != *b; b++) {
70
+ *out->cur++ = *b;
71
+ }
72
+ *out->cur = '\0';
73
+ }
74
+
75
+ static void
76
+ dump_array(VALUE a, int depth, Out out, bool as_ok) {
77
+ size_t size;
78
+ int i, cnt;
79
+ int d2 = depth + 1;
80
+
81
+ if (Yes == out->opts->circular) {
82
+ if (0 > oj_check_circular(a, out)) {
83
+ oj_dump_nil(Qnil, 0, out, false);
84
+ return;
85
+ }
86
+ }
87
+ if (as_ok && !oj_rails_array_opt && rb_respond_to(a, oj_as_json_id)) {
88
+ dump_as_json(a, depth, out, false);
89
+ return;
90
+ }
91
+ cnt = (int)RARRAY_LEN(a);
92
+ *out->cur++ = '[';
93
+ size = 2;
94
+ assure_size(out, size);
95
+ if (0 == cnt) {
96
+ *out->cur++ = ']';
97
+ } else {
98
+ if (out->opts->dump_opts.use) {
99
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
100
+ } else {
101
+ size = d2 * out->indent + 2;
102
+ }
103
+ cnt--;
104
+ for (i = 0; i <= cnt; i++) {
105
+ assure_size(out, size);
106
+ if (out->opts->dump_opts.use) {
107
+ if (0 < out->opts->dump_opts.array_size) {
108
+ strcpy(out->cur, out->opts->dump_opts.array_nl);
109
+ out->cur += out->opts->dump_opts.array_size;
110
+ }
111
+ if (0 < out->opts->dump_opts.indent_size) {
112
+ int i;
113
+ for (i = d2; 0 < i; i--) {
114
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
115
+ out->cur += out->opts->dump_opts.indent_size;
116
+ }
117
+ }
118
+ } else {
119
+ fill_indent(out, d2);
120
+ }
121
+ oj_dump_rails_val(rb_ary_entry(a, i), d2, out, as_ok);
122
+ if (i < cnt) {
123
+ *out->cur++ = ',';
124
+ }
125
+ }
126
+ size = depth * out->indent + 1;
127
+ assure_size(out, size);
128
+ if (out->opts->dump_opts.use) {
129
+ if (0 < out->opts->dump_opts.array_size) {
130
+ strcpy(out->cur, out->opts->dump_opts.array_nl);
131
+ out->cur += out->opts->dump_opts.array_size;
132
+ }
133
+ if (0 < out->opts->dump_opts.indent_size) {
134
+ int i;
135
+
136
+ for (i = depth; 0 < i; i--) {
137
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
138
+ out->cur += out->opts->dump_opts.indent_size;
139
+ }
140
+ }
141
+ } else {
142
+ fill_indent(out, depth);
143
+ }
144
+ *out->cur++ = ']';
145
+ }
146
+ *out->cur = '\0';
147
+ }
148
+
149
+ static int
150
+ hash_cb(VALUE key, VALUE value, Out out) {
151
+ int depth = out->depth;
152
+ long size;
153
+ int rtype = rb_type(key);
154
+
155
+ if (rtype != T_STRING && rtype != T_SYMBOL) {
156
+ key = rb_funcall(key, oj_to_s_id, 0);
157
+ rtype = rb_type(key);
158
+ }
159
+ if (!out->opts->dump_opts.use) {
160
+ size = depth * out->indent + 1;
161
+ assure_size(out, size);
162
+ fill_indent(out, depth);
163
+ if (rtype == T_STRING) {
164
+ oj_dump_str(key, 0, out, false);
165
+ } else {
166
+ oj_dump_sym(key, 0, out, false);
167
+ }
168
+ *out->cur++ = ':';
169
+ } else {
170
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
171
+ assure_size(out, size);
172
+ if (0 < out->opts->dump_opts.hash_size) {
173
+ strcpy(out->cur, out->opts->dump_opts.hash_nl);
174
+ out->cur += out->opts->dump_opts.hash_size;
175
+ }
176
+ if (0 < out->opts->dump_opts.indent_size) {
177
+ int i;
178
+ for (i = depth; 0 < i; i--) {
179
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
180
+ out->cur += out->opts->dump_opts.indent_size;
181
+ }
182
+ }
183
+ if (rtype == T_STRING) {
184
+ oj_dump_str(key, 0, out, false);
185
+ } else {
186
+ oj_dump_sym(key, 0, out, false);
187
+ }
188
+ size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
189
+ assure_size(out, size);
190
+ if (0 < out->opts->dump_opts.before_size) {
191
+ strcpy(out->cur, out->opts->dump_opts.before_sep);
192
+ out->cur += out->opts->dump_opts.before_size;
193
+ }
194
+ *out->cur++ = ':';
195
+ if (0 < out->opts->dump_opts.after_size) {
196
+ strcpy(out->cur, out->opts->dump_opts.after_sep);
197
+ out->cur += out->opts->dump_opts.after_size;
198
+ }
199
+ }
200
+ oj_dump_rails_val(value, depth, out, false);
201
+ out->depth = depth;
202
+ *out->cur++ = ',';
203
+
204
+ return ST_CONTINUE;
205
+ }
206
+
207
+ static void
208
+ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
209
+ int cnt;
210
+ size_t size;
211
+
212
+ if (Yes == out->opts->circular) {
213
+ if (0 > oj_check_circular(obj, out)) {
214
+ oj_dump_nil(Qnil, 0, out, false);
215
+ return;
216
+ }
217
+ }
218
+ if (as_ok && !oj_rails_hash_opt && rb_respond_to(obj, oj_as_json_id)) {
219
+ dump_as_json(obj, depth, out, false);
220
+ return;
221
+ }
222
+ cnt = (int)RHASH_SIZE(obj);
223
+ size = depth * out->indent + 2;
224
+ assure_size(out, 2);
225
+ *out->cur++ = '{';
226
+ if (0 == cnt) {
227
+ *out->cur++ = '}';
228
+ } else {
229
+ out->depth = depth + 1;
230
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
231
+ if (',' == *(out->cur - 1)) {
232
+ out->cur--; // backup to overwrite last comma
233
+ }
234
+ if (!out->opts->dump_opts.use) {
235
+ assure_size(out, size);
236
+ fill_indent(out, depth);
237
+ } else {
238
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
239
+ assure_size(out, size);
240
+ if (0 < out->opts->dump_opts.hash_size) {
241
+ strcpy(out->cur, out->opts->dump_opts.hash_nl);
242
+ out->cur += out->opts->dump_opts.hash_size;
243
+ }
244
+ if (0 < out->opts->dump_opts.indent_size) {
245
+ int i;
246
+
247
+ for (i = depth; 0 < i; i--) {
248
+ strcpy(out->cur, out->opts->dump_opts.indent_str);
249
+ out->cur += out->opts->dump_opts.indent_size;
250
+ }
251
+ }
252
+ }
253
+ *out->cur++ = '}';
254
+ }
255
+ *out->cur = '\0';
256
+ }
257
+
258
+ static void
259
+ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
260
+ if (as_ok) {
261
+ ROpt ro;
262
+
263
+ if (NULL != (ro = oj_rails_get_opt(out->ropts, rb_obj_class(obj))) && ro->on) {
264
+ ro->dump(obj, depth, out, as_ok);
265
+ } else if (rb_respond_to(obj, oj_as_json_id)) {
266
+ dump_as_json(obj, depth, out, true);
267
+ } else if (rb_respond_to(obj, oj_to_hash_id)) {
268
+ dump_to_hash(obj, depth, out);
269
+ } else {
270
+ oj_dump_obj_to_s(obj, out);
271
+ }
272
+ } else if (rb_respond_to(obj, oj_to_hash_id)) {
273
+ // Always attempt to_hash.
274
+ dump_to_hash(obj, depth, out);
275
+ } else {
276
+ oj_dump_obj_to_s(obj, out);
277
+ }
278
+ }
279
+
280
+ static void
281
+ dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
282
+ oj_dump_obj_to_s(obj, out);
283
+ }
284
+
285
+ static DumpFunc rails_funcs[] = {
286
+ NULL, // RUBY_T_NONE = 0x00,
287
+ dump_obj, // RUBY_T_OBJECT = 0x01,
288
+ oj_dump_class, // RUBY_T_CLASS = 0x02,
289
+ oj_dump_class, // RUBY_T_MODULE = 0x03,
290
+ dump_float, // RUBY_T_FLOAT = 0x04,
291
+ oj_dump_str, // RUBY_T_STRING = 0x05,
292
+ dump_as_string, // RUBY_T_REGEXP = 0x06,
293
+ dump_array, // RUBY_T_ARRAY = 0x07,
294
+ dump_hash, // RUBY_T_HASH = 0x08,
295
+ dump_obj, // RUBY_T_STRUCT = 0x09,
296
+ oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
297
+ NULL, // RUBY_T_FILE = 0x0b,
298
+ dump_obj, // RUBY_T_DATA = 0x0c,
299
+ NULL, // RUBY_T_MATCH = 0x0d,
300
+ // Rails raises a stack error on Complex and Rational. It also corrupts
301
+ // something whic causes a segfault on the next call. Oj will not mimic
302
+ // that behavior.
303
+ dump_as_string, // RUBY_T_COMPLEX = 0x0e,
304
+ dump_as_string, // RUBY_T_RATIONAL = 0x0f,
305
+ NULL, // 0x10
306
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
307
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
308
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
309
+ oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
310
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
311
+ };
312
+
313
+ void
314
+ oj_dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
315
+ int type = rb_type(obj);
316
+
317
+ if (MAX_DEPTH < depth) {
318
+ rb_raise(rb_eNoMemError, "Too deeply nested.\n");
319
+ }
320
+ if (0 < type && type <= RUBY_T_FIXNUM) {
321
+ DumpFunc f = rails_funcs[type];
322
+
323
+ if (NULL != f) {
324
+ f(obj, depth, out, as_ok);
325
+ return;
326
+ }
327
+ }
328
+ oj_dump_nil(Qnil, depth, out, false);
329
+ }