oj 3.13.11 → 3.15.0

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 (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -0
  3. data/README.md +4 -2
  4. data/ext/oj/buf.h +11 -6
  5. data/ext/oj/cache.c +25 -24
  6. data/ext/oj/cache8.c +10 -9
  7. data/ext/oj/circarray.c +8 -6
  8. data/ext/oj/circarray.h +2 -2
  9. data/ext/oj/code.c +17 -24
  10. data/ext/oj/code.h +2 -2
  11. data/ext/oj/compat.c +17 -44
  12. data/ext/oj/custom.c +70 -141
  13. data/ext/oj/debug.c +3 -9
  14. data/ext/oj/dump.c +128 -118
  15. data/ext/oj/dump.h +12 -8
  16. data/ext/oj/dump_compat.c +564 -641
  17. data/ext/oj/dump_leaf.c +17 -63
  18. data/ext/oj/dump_object.c +70 -199
  19. data/ext/oj/dump_strict.c +22 -46
  20. data/ext/oj/encoder.c +1 -1
  21. data/ext/oj/err.c +2 -13
  22. data/ext/oj/err.h +9 -12
  23. data/ext/oj/extconf.rb +14 -5
  24. data/ext/oj/fast.c +75 -103
  25. data/ext/oj/intern.c +52 -50
  26. data/ext/oj/intern.h +4 -8
  27. data/ext/oj/mem.c +318 -0
  28. data/ext/oj/mem.h +53 -0
  29. data/ext/oj/mimic_json.c +75 -47
  30. data/ext/oj/object.c +49 -66
  31. data/ext/oj/odd.c +89 -67
  32. data/ext/oj/odd.h +15 -15
  33. data/ext/oj/oj.c +140 -99
  34. data/ext/oj/oj.h +80 -51
  35. data/ext/oj/parse.c +162 -184
  36. data/ext/oj/parse.h +7 -10
  37. data/ext/oj/parser.c +89 -34
  38. data/ext/oj/parser.h +18 -7
  39. data/ext/oj/rails.c +82 -146
  40. data/ext/oj/rails.h +1 -1
  41. data/ext/oj/reader.c +11 -12
  42. data/ext/oj/reader.h +4 -2
  43. data/ext/oj/resolve.c +3 -4
  44. data/ext/oj/rxclass.c +6 -5
  45. data/ext/oj/rxclass.h +1 -1
  46. data/ext/oj/saj.c +20 -31
  47. data/ext/oj/saj2.c +329 -93
  48. data/ext/oj/saj2.h +23 -0
  49. data/ext/oj/scp.c +3 -14
  50. data/ext/oj/sparse.c +26 -70
  51. data/ext/oj/stream_writer.c +12 -22
  52. data/ext/oj/strict.c +20 -52
  53. data/ext/oj/string_writer.c +21 -21
  54. data/ext/oj/trace.h +31 -4
  55. data/ext/oj/usual.c +105 -150
  56. data/ext/oj/usual.h +68 -0
  57. data/ext/oj/util.h +1 -1
  58. data/ext/oj/val_stack.c +1 -1
  59. data/ext/oj/val_stack.h +8 -7
  60. data/ext/oj/validate.c +21 -26
  61. data/ext/oj/wab.c +31 -68
  62. data/lib/oj/active_support_helper.rb +0 -1
  63. data/lib/oj/bag.rb +7 -1
  64. data/lib/oj/easy_hash.rb +4 -5
  65. data/lib/oj/error.rb +0 -1
  66. data/lib/oj/json.rb +4 -2
  67. data/lib/oj/mimic.rb +4 -2
  68. data/lib/oj/saj.rb +20 -6
  69. data/lib/oj/state.rb +9 -6
  70. data/lib/oj/version.rb +1 -2
  71. data/lib/oj.rb +2 -0
  72. data/pages/Compatibility.md +1 -1
  73. data/pages/InstallOptions.md +20 -0
  74. data/pages/Options.md +10 -0
  75. data/test/_test_active.rb +8 -9
  76. data/test/_test_active_mimic.rb +7 -8
  77. data/test/_test_mimic_rails.rb +17 -20
  78. data/test/activerecord/result_test.rb +5 -6
  79. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  80. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  81. data/test/{activesupport5 → activesupport7}/encoding_test.rb +20 -34
  82. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  83. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  84. data/test/files.rb +15 -15
  85. data/test/foo.rb +9 -71
  86. data/test/helper.rb +11 -8
  87. data/test/isolated/shared.rb +3 -2
  88. data/test/json_gem/json_addition_test.rb +2 -2
  89. data/test/json_gem/json_common_interface_test.rb +4 -4
  90. data/test/json_gem/json_encoding_test.rb +0 -0
  91. data/test/json_gem/json_ext_parser_test.rb +1 -0
  92. data/test/json_gem/json_fixtures_test.rb +3 -2
  93. data/test/json_gem/json_generator_test.rb +48 -36
  94. data/test/json_gem/json_generic_object_test.rb +11 -11
  95. data/test/json_gem/json_parser_test.rb +54 -47
  96. data/test/json_gem/json_string_matching_test.rb +9 -9
  97. data/test/json_gem/test_helper.rb +7 -3
  98. data/test/mem.rb +13 -12
  99. data/test/perf.rb +21 -26
  100. data/test/perf_compat.rb +31 -33
  101. data/test/perf_dump.rb +50 -0
  102. data/test/perf_fast.rb +80 -82
  103. data/test/perf_file.rb +27 -29
  104. data/test/perf_object.rb +65 -69
  105. data/test/perf_once.rb +12 -11
  106. data/test/perf_parser.rb +42 -48
  107. data/test/perf_saj.rb +46 -54
  108. data/test/perf_scp.rb +57 -69
  109. data/test/perf_simple.rb +41 -39
  110. data/test/perf_strict.rb +68 -70
  111. data/test/perf_wab.rb +67 -69
  112. data/test/prec.rb +3 -3
  113. data/test/sample/change.rb +0 -1
  114. data/test/sample/dir.rb +0 -1
  115. data/test/sample/doc.rb +0 -1
  116. data/test/sample/file.rb +0 -1
  117. data/test/sample/group.rb +0 -1
  118. data/test/sample/hasprops.rb +0 -1
  119. data/test/sample/layer.rb +0 -1
  120. data/test/sample/rect.rb +0 -1
  121. data/test/sample/shape.rb +0 -1
  122. data/test/sample/text.rb +0 -1
  123. data/test/sample.rb +16 -16
  124. data/test/sample_json.rb +8 -8
  125. data/test/test_compat.rb +76 -42
  126. data/test/test_custom.rb +72 -51
  127. data/test/test_debian.rb +7 -10
  128. data/test/test_fast.rb +86 -90
  129. data/test/test_file.rb +41 -30
  130. data/test/test_gc.rb +16 -5
  131. data/test/test_generate.rb +5 -5
  132. data/test/test_hash.rb +4 -4
  133. data/test/test_integer_range.rb +9 -9
  134. data/test/test_null.rb +20 -20
  135. data/test/test_object.rb +85 -96
  136. data/test/test_parser.rb +6 -22
  137. data/test/test_parser_debug.rb +27 -0
  138. data/test/test_parser_saj.rb +115 -23
  139. data/test/test_parser_usual.rb +6 -6
  140. data/test/test_rails.rb +2 -2
  141. data/test/test_saj.rb +10 -8
  142. data/test/test_scp.rb +37 -39
  143. data/test/test_strict.rb +30 -32
  144. data/test/test_various.rb +147 -99
  145. data/test/test_wab.rb +48 -44
  146. data/test/test_writer.rb +47 -47
  147. data/test/tests.rb +13 -4
  148. data/test/tests_mimic.rb +12 -3
  149. data/test/tests_mimic_addition.rb +12 -3
  150. metadata +33 -144
  151. data/test/activesupport4/decoding_test.rb +0 -108
  152. data/test/activesupport4/encoding_test.rb +0 -531
  153. data/test/activesupport4/test_helper.rb +0 -41
  154. data/test/activesupport5/test_helper.rb +0 -72
  155. data/test/bar.rb +0 -16
  156. data/test/baz.rb +0 -16
  157. data/test/bug.rb +0 -16
  158. data/test/zoo.rb +0 -13
data/ext/oj/mem.c ADDED
@@ -0,0 +1,318 @@
1
+ // Copyright (c) 2018, Peter Ohler, All rights reserved.
2
+
3
+ #include "mem.h"
4
+
5
+ #include <pthread.h>
6
+ #include <ruby.h>
7
+ #include <stdbool.h>
8
+ #include <stdint.h>
9
+ #include <stdio.h>
10
+ #include <stdlib.h>
11
+ #include <string.h>
12
+
13
+ typedef struct _rec {
14
+ struct _rec *next;
15
+ const void *ptr;
16
+ size_t size;
17
+ const char *file;
18
+ int line;
19
+ bool ruby;
20
+ } *Rec;
21
+
22
+ typedef struct _rep {
23
+ struct _rep *next;
24
+ size_t size;
25
+ const char *file;
26
+ int line;
27
+ int cnt;
28
+ } *Rep;
29
+
30
+ #ifdef MEM_DEBUG
31
+
32
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
33
+ static Rec recs = NULL;
34
+ static const char mem_pad[] = "--- This is a memory pad and should not change until being freed. ---";
35
+
36
+ void *oj_malloc(size_t size, const char *file, int line) {
37
+ void *ptr = malloc(size + sizeof(mem_pad));
38
+
39
+ if (NULL != ptr) {
40
+ Rec r = (Rec)malloc(sizeof(struct _rec));
41
+
42
+ if (NULL != r) {
43
+ strcpy(((char *)ptr) + size, mem_pad);
44
+ r->ptr = ptr;
45
+ r->size = size;
46
+ r->file = file;
47
+ r->line = line;
48
+ r->ruby = false;
49
+ pthread_mutex_lock(&lock);
50
+ r->next = recs;
51
+ recs = r;
52
+ pthread_mutex_unlock(&lock);
53
+ } else {
54
+ free(ptr);
55
+ ptr = NULL;
56
+ }
57
+ }
58
+ return ptr;
59
+ }
60
+
61
+ void *oj_realloc(void *orig, size_t size, const char *file, int line) {
62
+ void *ptr = realloc(orig, size + sizeof(mem_pad));
63
+ Rec r;
64
+
65
+ if (NULL != ptr) {
66
+ strcpy(((char *)ptr) + size, mem_pad);
67
+ pthread_mutex_lock(&lock);
68
+ for (r = recs; NULL != r; r = r->next) {
69
+ if (orig == r->ptr) {
70
+ r->ptr = ptr;
71
+ r->size = size;
72
+ r->file = file;
73
+ r->line = line;
74
+ r->ruby = false;
75
+ break;
76
+ }
77
+ }
78
+ pthread_mutex_unlock(&lock);
79
+ if (NULL == r) {
80
+ printf("Realloc at %s:%d (%p) not allocated.\n", file, line, orig);
81
+ }
82
+ }
83
+ return ptr;
84
+ }
85
+
86
+ void *oj_calloc(size_t count, size_t size, const char *file, int line) {
87
+ void *ptr;
88
+
89
+ size *= count;
90
+ if (NULL != (ptr = malloc(size + sizeof(mem_pad)))) {
91
+ Rec r = (Rec)malloc(sizeof(struct _rec));
92
+
93
+ if (NULL != r) {
94
+ memset(ptr, 0, size);
95
+ strcpy(((char *)ptr) + size, mem_pad);
96
+ r->ptr = ptr;
97
+ r->size = size;
98
+ r->file = file;
99
+ r->line = line;
100
+ r->ruby = false;
101
+ pthread_mutex_lock(&lock);
102
+ r->next = recs;
103
+ recs = r;
104
+ pthread_mutex_unlock(&lock);
105
+ } else {
106
+ free(ptr);
107
+ ptr = NULL;
108
+ }
109
+ }
110
+ return ptr;
111
+ }
112
+
113
+ void *oj_r_alloc(size_t size, const char *file, int line) {
114
+ void *ptr = ruby_xmalloc(size + sizeof(mem_pad));
115
+
116
+ if (NULL != ptr) {
117
+ Rec r = (Rec)malloc(sizeof(struct _rec));
118
+
119
+ if (NULL != r) {
120
+ strcpy(((char *)ptr) + size, mem_pad);
121
+ r->ptr = ptr;
122
+ r->size = size;
123
+ r->file = file;
124
+ r->line = line;
125
+ r->ruby = true;
126
+ pthread_mutex_lock(&lock);
127
+ r->next = recs;
128
+ recs = r;
129
+ pthread_mutex_unlock(&lock);
130
+ } else {
131
+ free(ptr);
132
+ ptr = NULL;
133
+ }
134
+ }
135
+ return ptr;
136
+ }
137
+
138
+ void *oj_r_realloc(void *orig, size_t size, const char *file, int line) {
139
+ void *ptr = ruby_xrealloc2(orig, 1, size + sizeof(mem_pad));
140
+ Rec r;
141
+
142
+ if (NULL != ptr) {
143
+ strcpy(((char *)ptr) + size, mem_pad);
144
+ pthread_mutex_lock(&lock);
145
+ for (r = recs; NULL != r; r = r->next) {
146
+ if (orig == r->ptr) {
147
+ r->ptr = ptr;
148
+ r->size = size;
149
+ r->file = file;
150
+ r->line = line;
151
+ r->ruby = true;
152
+ break;
153
+ }
154
+ }
155
+ pthread_mutex_unlock(&lock);
156
+ if (NULL == r) {
157
+ printf("Realloc at %s:%d (%p) not allocated.\n", file, line, orig);
158
+ }
159
+ }
160
+ return ptr;
161
+ }
162
+
163
+ void oj_freed(void *ptr, const char *file, int line, bool ruby) {
164
+ if (NULL != ptr) {
165
+ Rec r = NULL;
166
+ Rec prev = NULL;
167
+
168
+ pthread_mutex_lock(&lock);
169
+ for (r = recs; NULL != r; r = r->next) {
170
+ if (ptr == r->ptr) {
171
+ if (NULL == prev) {
172
+ recs = r->next;
173
+ } else {
174
+ prev->next = r->next;
175
+ }
176
+ break;
177
+ }
178
+ prev = r;
179
+ }
180
+ pthread_mutex_unlock(&lock);
181
+ if (NULL == r) {
182
+ printf("Free at %s:%d (%p) not allocated or already freed.\n", file, line, ptr);
183
+ } else {
184
+ char *pad = (char *)r->ptr + r->size;
185
+
186
+ if (r->ruby != ruby) {
187
+ if (r->ruby) {
188
+ printf("Memory at %s:%d (%p) allocated with Ruby allocator and freed with stdlib free.\n",
189
+ file,
190
+ line,
191
+ ptr);
192
+ } else {
193
+ printf("Memory at %s:%d (%p) allocated with stdlib allocator and freed with Ruby free.\n",
194
+ file,
195
+ line,
196
+ ptr);
197
+ }
198
+ }
199
+ if (0 != strcmp(mem_pad, pad)) {
200
+ uint8_t *p;
201
+ uint8_t *end = (uint8_t *)pad + sizeof(mem_pad);
202
+
203
+ printf("Memory at %s:%d (%p) write outside allocated.\n", file, line, ptr);
204
+ for (p = (uint8_t *)pad; p < end; p++) {
205
+ if (0x20 < *p && *p < 0x7f) {
206
+ printf("%c ", *p);
207
+ } else {
208
+ printf("%02x ", *(uint8_t *)p);
209
+ }
210
+ }
211
+ printf("\n");
212
+ }
213
+ free(r);
214
+ }
215
+ }
216
+ }
217
+
218
+ void oj_r_free(void *ptr, const char *file, int line) {
219
+ oj_freed(ptr, file, line, true);
220
+ xfree(ptr);
221
+ }
222
+
223
+ void oj_free(void *ptr, const char *file, int line) {
224
+ oj_freed(ptr, file, line, false);
225
+ free(ptr);
226
+ }
227
+
228
+ char *oj_mem_strdup(const char *str, const char *file, int line) {
229
+ size_t size = strlen(str) + 1;
230
+ char *ptr = (char *)malloc(size + sizeof(mem_pad));
231
+
232
+ if (NULL != ptr) {
233
+ Rec r = (Rec)malloc(sizeof(struct _rec));
234
+
235
+ if (NULL != r) {
236
+ strcpy(ptr, str);
237
+ strcpy(((char *)ptr) + size, mem_pad);
238
+ r->ptr = (void *)ptr;
239
+ r->size = size;
240
+ r->file = file;
241
+ r->line = line;
242
+ r->ruby = false;
243
+ pthread_mutex_lock(&lock);
244
+ r->next = recs;
245
+ recs = r;
246
+ pthread_mutex_unlock(&lock);
247
+ } else {
248
+ free(ptr);
249
+ ptr = NULL;
250
+ }
251
+ }
252
+ return ptr;
253
+ }
254
+
255
+ #endif
256
+
257
+ #ifdef MEM_DEBUG
258
+
259
+ static Rep update_reps(Rep reps, Rec r) {
260
+ Rep rp = reps;
261
+
262
+ for (; NULL != rp; rp = rp->next) {
263
+ if (rp->line == r->line && (rp->file == r->file || 0 == strcmp(rp->file, r->file))) {
264
+ rp->size += r->size;
265
+ rp->cnt++;
266
+ break;
267
+ }
268
+ }
269
+ if (NULL == rp && NULL != (rp = (Rep)malloc(sizeof(struct _rep)))) {
270
+ rp->size = r->size;
271
+ rp->file = r->file;
272
+ rp->line = r->line;
273
+ rp->cnt = 1;
274
+ rp->next = reps;
275
+ reps = rp;
276
+ }
277
+ return reps;
278
+ }
279
+
280
+ static void print_stats() {
281
+ printf("\n--- Memory Usage Report --------------------------------------------------------\n");
282
+ pthread_mutex_lock(&lock);
283
+
284
+ if (NULL == recs) {
285
+ printf("No memory leaks\n");
286
+ } else {
287
+ Rep reps = NULL;
288
+ Rep rp;
289
+ Rec r;
290
+ size_t leaked = 0;
291
+
292
+ for (r = recs; NULL != r; r = r->next) {
293
+ reps = update_reps(reps, r);
294
+ }
295
+ while (NULL != (rp = reps)) {
296
+ reps = rp->next;
297
+ printf("%16s:%3d %8lu bytes over %d occurances allocated and not freed.\n",
298
+ rp->file,
299
+ rp->line,
300
+ rp->size,
301
+ rp->cnt);
302
+ leaked += rp->size;
303
+ free(rp);
304
+ }
305
+ printf("%lu bytes leaked\n", leaked);
306
+ }
307
+ pthread_mutex_unlock(&lock);
308
+ printf("--------------------------------------------------------------------------------\n");
309
+ }
310
+
311
+ #endif
312
+
313
+ void oj_mem_report(void) {
314
+ #ifdef MEM_DEBUG
315
+ rb_gc();
316
+ print_stats();
317
+ #endif
318
+ }
data/ext/oj/mem.h ADDED
@@ -0,0 +1,53 @@
1
+ // Copyright (c) 2018, Peter Ohler, All rights reserved.
2
+
3
+ #ifndef OJ_MEM_H
4
+ #define OJ_MEM_H
5
+
6
+ #include <stdio.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+
10
+ #ifdef MEM_DEBUG
11
+
12
+ #define OJ_MALLOC(size) oj_malloc(size, __FILE__, __LINE__)
13
+ #define OJ_REALLOC(ptr, size) oj_realloc(ptr, size, __FILE__, __LINE__)
14
+ #define OJ_CALLOC(count, size) oj_calloc(count, size, __FILE__, __LINE__)
15
+ #define OJ_FREE(ptr) oj_free(ptr, __FILE__, __LINE__)
16
+
17
+ #define OJ_R_ALLOC(type) oj_r_alloc(sizeof(type), __FILE__, __LINE__)
18
+ #define OJ_R_ALLOC_N(type, n) (type *)oj_r_alloc(sizeof(type) * (n), __FILE__, __LINE__)
19
+ #define OJ_R_REALLOC_N(ptr, type, n) ((ptr) = (type *)oj_r_realloc(ptr, (sizeof(type) * (n)), __FILE__, __LINE__))
20
+ #define OJ_R_FREE(ptr) oj_r_free(ptr, __FILE__, __LINE__)
21
+
22
+ #define OJ_STRDUP(str) oj_mem_strdup(str, __FILE__, __LINE__)
23
+
24
+ extern void *oj_malloc(size_t size, const char *file, int line);
25
+ extern void *oj_realloc(void *ptr, size_t size, const char *file, int line);
26
+ extern void *oj_calloc(size_t count, size_t size, const char *file, int line);
27
+ extern void oj_free(void *ptr, const char *file, int line);
28
+
29
+ extern void *oj_r_alloc(size_t size, const char *file, int line);
30
+ extern void *oj_r_realloc(void *ptr, size_t size, const char *file, int line);
31
+ extern void oj_r_free(void *ptr, const char *file, int line);
32
+
33
+ extern char *oj_mem_strdup(const char *str, const char *file, int line);
34
+
35
+ #else
36
+
37
+ #define OJ_MALLOC(size) malloc(size)
38
+ #define OJ_REALLOC(ptr, size) realloc(ptr, size)
39
+ #define OJ_CALLOC(count, size) calloc(count, size)
40
+ #define OJ_FREE(ptr) free(ptr)
41
+
42
+ #define OJ_R_ALLOC(type) RB_ALLOC(type)
43
+ #define OJ_R_ALLOC_N(type, n) RB_ALLOC_N(type, n)
44
+ #define OJ_R_REALLOC_N(ptr, type, n) RB_REALLOC_N(ptr, type, n)
45
+ #define OJ_R_FREE(ptr) xfree(ptr)
46
+
47
+ #define OJ_STRDUP(str) strdup(str)
48
+
49
+ #endif
50
+
51
+ extern void oj_mem_report();
52
+
53
+ #endif /* OJ_MEM_H */
data/ext/oj/mimic_json.c CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include "dump.h"
5
5
  #include "encode.h"
6
+ #include "mem.h"
6
7
  #include "oj.h"
7
8
  #include "parse.h"
8
9
 
@@ -198,7 +199,6 @@ static int mimic_limit_arg(VALUE a) {
198
199
  * Returns [_String_] a JSON string.
199
200
  */
200
201
  static VALUE mimic_dump(int argc, VALUE *argv, VALUE self) {
201
- char buf[4096];
202
202
  struct _out out;
203
203
  struct _options copts = oj_default_options;
204
204
  VALUE rstr;
@@ -206,9 +206,9 @@ static VALUE mimic_dump(int argc, VALUE *argv, VALUE self) {
206
206
 
207
207
  copts.str_rx.head = NULL;
208
208
  copts.str_rx.tail = NULL;
209
- out.buf = buf;
210
- out.end = buf + sizeof(buf) - 10;
211
- out.allocated = false;
209
+
210
+ oj_out_init(&out);
211
+
212
212
  out.caller = CALLER_DUMP;
213
213
  copts.escape_mode = JXEsc;
214
214
  copts.mode = CompatMode;
@@ -257,9 +257,9 @@ static VALUE mimic_dump(int argc, VALUE *argv, VALUE self) {
257
257
  rb_funcall2(io, oj_write_id, 1, args);
258
258
  rstr = io;
259
259
  }
260
- if (out.allocated) {
261
- xfree(out.buf);
262
- }
260
+
261
+ oj_out_free(&out);
262
+
263
263
  return rstr;
264
264
  }
265
265
 
@@ -349,26 +349,26 @@ static VALUE mimic_load(int argc, VALUE *argv, VALUE self) {
349
349
  static VALUE mimic_dump_load(int argc, VALUE *argv, VALUE self) {
350
350
  if (1 > argc) {
351
351
  rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
352
- } else if (T_STRING == rb_type(*argv)) {
352
+ }
353
+ if (T_STRING == rb_type(*argv)) {
353
354
  return mimic_load(argc, argv, self);
354
- } else {
355
- return mimic_dump(argc, argv, self);
356
355
  }
357
- return Qnil;
356
+ return mimic_dump(argc, argv, self);
358
357
  }
359
358
 
360
359
  static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
361
- char buf[4096];
362
360
  struct _out out;
363
361
  VALUE rstr;
364
362
 
365
- memset(buf, 0, sizeof(buf));
363
+ if (0 == argc) {
364
+ rb_raise(rb_eArgError, "wrong number of arguments (0))");
365
+ }
366
+ memset(out.stack_buffer, 0, sizeof(out.stack_buffer));
367
+
368
+ oj_out_init(&out);
366
369
 
367
- out.buf = buf;
368
- out.end = buf + sizeof(buf) - 10;
369
- out.allocated = false;
370
- out.omit_nil = copts->dump_opts.omit_nil;
371
- out.caller = CALLER_GENERATE;
370
+ out.omit_nil = copts->dump_opts.omit_nil;
371
+ out.caller = CALLER_GENERATE;
372
372
  // For obj.to_json or generate nan is not allowed but if called from dump
373
373
  // it is.
374
374
  copts->dump_opts.nan_dump = RaiseNan;
@@ -388,6 +388,8 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
388
388
  VALUE active_hack[1];
389
389
 
390
390
  if (Qundef == state_class) {
391
+ rb_warn("Oj::Rails.mimic_JSON was called implicitly. "
392
+ "Call it explicitly beforehand if you want to remove this warning.");
391
393
  oj_define_mimic_json(0, NULL, Qnil);
392
394
  }
393
395
  active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
@@ -398,9 +400,9 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
398
400
  }
399
401
  rstr = rb_str_new2(out.buf);
400
402
  rstr = oj_encode(rstr);
401
- if (out.allocated) {
402
- xfree(out.buf);
403
- }
403
+
404
+ oj_out_free(&out);
405
+
404
406
  return rstr;
405
407
  }
406
408
 
@@ -457,7 +459,10 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
457
459
  // a Hash. I haven't dug deep enough to find out why but using a State
458
460
  // instance and not a Hash gives the desired behavior.
459
461
  *rargs = *argv;
460
- if (1 == argc) {
462
+ if (0 == argc) {
463
+ rb_raise(rb_eArgError, "wrong number of arguments (0))");
464
+ }
465
+ if (1 == argc || Qnil == argv[1]) {
461
466
  h = rb_hash_new();
462
467
  } else {
463
468
  h = argv[1];
@@ -478,6 +483,8 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
478
483
  rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
479
484
  }
480
485
  if (Qundef == state_class) {
486
+ rb_warn("Oj::Rails.mimic_JSON was called implicitly. "
487
+ "Call it explicitly beforehand if you want to remove this warning.");
481
488
  oj_define_mimic_json(0, NULL, Qnil);
482
489
  }
483
490
  rargs[1] = rb_funcall(state_class, oj_new_id, 1, h);
@@ -533,14 +540,6 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE info) {
533
540
  }
534
541
  } else if (oj_decimal_class_sym == k) {
535
542
  pi->options.compat_bigdec = (oj_bigdecimal_class == v);
536
- } else if (oj_max_nesting_sym == k) {
537
- if (Qtrue == v) {
538
- pi->max_depth = 100;
539
- } else if (Qfalse == v || Qnil == v) {
540
- pi->max_depth = 0;
541
- } else if (T_FIXNUM == rb_type(v)) {
542
- pi->max_depth = NUM2INT(v);
543
- }
544
543
  }
545
544
  return ST_CONTINUE;
546
545
  }
@@ -570,11 +569,21 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
570
569
  pi.max_depth = 100;
571
570
 
572
571
  if (Qnil != ropts) {
572
+ VALUE v;
573
+
573
574
  if (T_HASH != rb_type(ropts)) {
574
575
  rb_raise(rb_eArgError, "options must be a hash.");
575
576
  }
576
577
 
577
578
  rb_hash_foreach(ropts, parse_options_cb, (VALUE)&pi);
579
+ v = rb_hash_lookup(ropts, oj_max_nesting_sym);
580
+ if (Qtrue == v) {
581
+ pi.max_depth = 100;
582
+ } else if (Qfalse == v || Qnil == v) {
583
+ pi.max_depth = 0;
584
+ } else if (T_FIXNUM == rb_type(v)) {
585
+ pi.max_depth = NUM2INT(v);
586
+ }
578
587
  oj_parse_opt_match_string(&pi.options.str_rx, ropts);
579
588
  if (Yes == pi.options.create_ok && Yes == pi.options.sym_key) {
580
589
  rb_raise(rb_eArgError, ":symbolize_names and :create_additions can not both be true.");
@@ -644,23 +653,22 @@ static VALUE mimic_recurse_proc(VALUE self, VALUE obj) {
644
653
  *
645
654
  * - *id* [_nil_|String] new create_id
646
655
  *
647
- * Returns [_String_] the id.
656
+ * Returns [_nil_|_String_] the id.
648
657
  */
649
658
  static VALUE mimic_set_create_id(VALUE self, VALUE id) {
650
- Check_Type(id, T_STRING);
651
-
652
659
  if (NULL != oj_default_options.create_id) {
653
660
  if (oj_json_class != oj_default_options.create_id) {
654
- xfree((char *)oj_default_options.create_id);
661
+ OJ_R_FREE((char *)oj_default_options.create_id);
655
662
  }
656
663
  oj_default_options.create_id = NULL;
657
664
  oj_default_options.create_id_len = 0;
658
665
  }
659
666
  if (Qnil != id) {
660
- size_t len = RSTRING_LEN(id) + 1;
667
+ const char *ptr = StringValueCStr(id);
668
+ size_t len = RSTRING_LEN(id) + 1;
661
669
 
662
- oj_default_options.create_id = ALLOC_N(char, len);
663
- strcpy((char *)oj_default_options.create_id, StringValuePtr(id));
670
+ oj_default_options.create_id = OJ_R_ALLOC_N(char, len);
671
+ strcpy((char *)oj_default_options.create_id, ptr);
664
672
  oj_default_options.create_id_len = len - 1;
665
673
  }
666
674
  return id;
@@ -730,6 +738,7 @@ static struct _options mimic_object_to_json_options = {0, // indent
730
738
  0, // array_size
731
739
  RaiseNan, // nan_dump
732
740
  false, // omit_nil
741
+ false, // omit_null_byte
733
742
  100, // max_depth
734
743
  },
735
744
  {
@@ -740,19 +749,18 @@ static struct _options mimic_object_to_json_options = {0, // indent
740
749
  }};
741
750
 
742
751
  static VALUE mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
743
- char buf[4096];
744
752
  struct _out out;
745
753
  VALUE rstr;
746
754
  struct _options copts = oj_default_options;
747
755
 
748
756
  copts.str_rx.head = NULL;
749
757
  copts.str_rx.tail = NULL;
750
- out.buf = buf;
751
- out.end = buf + sizeof(buf) - 10;
752
- out.allocated = false;
753
- out.omit_nil = copts.dump_opts.omit_nil;
754
- copts.mode = CompatMode;
755
- copts.to_json = No;
758
+
759
+ oj_out_init(&out);
760
+
761
+ out.omit_nil = copts.dump_opts.omit_nil;
762
+ copts.mode = CompatMode;
763
+ copts.to_json = No;
756
764
  if (1 <= argc && Qnil != argv[0]) {
757
765
  oj_parse_mimic_dump_options(argv[0], &copts);
758
766
  }
@@ -765,9 +773,9 @@ static VALUE mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
765
773
  }
766
774
  rstr = rb_str_new2(out.buf);
767
775
  rstr = oj_encode(rstr);
768
- if (out.allocated) {
769
- xfree(out.buf);
770
- }
776
+
777
+ oj_out_free(&out);
778
+
771
779
  return rstr;
772
780
  }
773
781
 
@@ -784,28 +792,48 @@ void oj_mimic_json_methods(VALUE json) {
784
792
  VALUE json_error;
785
793
  VALUE generator;
786
794
  VALUE ext;
795
+ VALUE verbose;
787
796
 
797
+ // rb_undef_method doesn't work for modules or maybe sometimes
798
+ // doesn't. Anyway setting verbose should hide the warning.
799
+ verbose = rb_gv_get("$VERBOSE");
800
+ rb_gv_set("$VERBOSE", Qfalse);
801
+
802
+ rb_undef_method(json, "create_id=");
788
803
  rb_define_module_function(json, "create_id=", mimic_set_create_id, 1);
804
+ rb_undef_method(json, "create_id");
789
805
  rb_define_module_function(json, "create_id", mimic_create_id, 0);
790
806
 
807
+ rb_undef_method(json, "dump");
791
808
  rb_define_module_function(json, "dump", mimic_dump, -1);
809
+ rb_undef_method(json, "load");
792
810
  rb_define_module_function(json, "load", mimic_load, -1);
793
811
  rb_define_module_function(json, "restore", mimic_load, -1);
812
+ rb_undef_method(json, "recurse_proc");
794
813
  rb_define_module_function(json, "recurse_proc", mimic_recurse_proc, 1);
814
+ rb_undef_method(json, "[]");
795
815
  rb_define_module_function(json, "[]", mimic_dump_load, -1);
796
816
 
817
+ rb_undef_method(json, "generate");
797
818
  rb_define_module_function(json, "generate", oj_mimic_generate, -1);
819
+ rb_undef_method(json, "fast_generate");
798
820
  rb_define_module_function(json, "fast_generate", oj_mimic_generate, -1);
821
+ rb_undef_method(json, "pretty_generate");
799
822
  rb_define_module_function(json, "pretty_generate", oj_mimic_pretty_generate, -1);
800
823
  // For older versions of JSON, the deprecated unparse methods.
824
+ rb_undef_method(json, "unparse");
801
825
  rb_define_module_function(json, "unparse", oj_mimic_generate, -1);
802
826
  rb_define_module_function(json, "fast_unparse", oj_mimic_generate, -1);
803
827
  rb_define_module_function(json, "pretty_unparse", oj_mimic_pretty_generate, -1);
804
828
 
829
+ rb_undef_method(json, "parse");
805
830
  rb_define_module_function(json, "parse", oj_mimic_parse, -1);
831
+ rb_undef_method(json, "parse!");
806
832
  rb_define_module_function(json, "parse!", mimic_parse_bang, -1);
807
833
 
834
+ rb_undef_method(json, "state");
808
835
  rb_define_module_function(json, "state", mimic_state, 0);
836
+ rb_gv_set("$VERBOSE", verbose);
809
837
 
810
838
  if (rb_const_defined_at(json, rb_intern("JSONError"))) {
811
839
  json_error = rb_const_get(json, rb_intern("JSONError"));