oj 3.7.4 → 3.13.23

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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1360 -0
  3. data/README.md +31 -8
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +53 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -43
  11. data/ext/oj/circarray.h +16 -17
  12. data/ext/oj/code.c +165 -179
  13. data/ext/oj/code.h +27 -29
  14. data/ext/oj/compat.c +174 -194
  15. data/ext/oj/custom.c +790 -866
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +848 -863
  18. data/ext/oj/dump.h +81 -67
  19. data/ext/oj/dump_compat.c +85 -123
  20. data/ext/oj/dump_leaf.c +100 -188
  21. data/ext/oj/dump_object.c +527 -656
  22. data/ext/oj/dump_strict.c +315 -338
  23. data/ext/oj/encode.h +7 -34
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -29
  26. data/ext/oj/err.h +48 -48
  27. data/ext/oj/extconf.rb +17 -4
  28. data/ext/oj/fast.c +1073 -1088
  29. data/ext/oj/intern.c +298 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +469 -436
  32. data/ext/oj/object.c +532 -599
  33. data/ext/oj/odd.c +154 -138
  34. data/ext/oj/odd.h +37 -38
  35. data/ext/oj/oj.c +1333 -986
  36. data/ext/oj/oj.h +336 -316
  37. data/ext/oj/parse.c +1002 -846
  38. data/ext/oj/parse.h +92 -87
  39. data/ext/oj/parser.c +1587 -0
  40. data/ext/oj/parser.h +102 -0
  41. data/ext/oj/rails.c +888 -878
  42. data/ext/oj/rails.h +11 -14
  43. data/ext/oj/reader.c +141 -147
  44. data/ext/oj/reader.h +73 -89
  45. data/ext/oj/resolve.c +41 -62
  46. data/ext/oj/resolve.h +7 -9
  47. data/ext/oj/rxclass.c +71 -75
  48. data/ext/oj/rxclass.h +18 -19
  49. data/ext/oj/saj.c +443 -486
  50. data/ext/oj/saj2.c +596 -0
  51. data/ext/oj/saj2.h +23 -0
  52. data/ext/oj/scp.c +88 -113
  53. data/ext/oj/sparse.c +787 -709
  54. data/ext/oj/stream_writer.c +133 -159
  55. data/ext/oj/strict.c +127 -118
  56. data/ext/oj/string_writer.c +230 -249
  57. data/ext/oj/trace.c +34 -41
  58. data/ext/oj/trace.h +19 -19
  59. data/ext/oj/usual.c +1207 -0
  60. data/ext/oj/usual.h +68 -0
  61. data/ext/oj/util.c +136 -0
  62. data/ext/oj/util.h +20 -0
  63. data/ext/oj/val_stack.c +60 -68
  64. data/ext/oj/val_stack.h +91 -129
  65. data/ext/oj/validate.c +46 -0
  66. data/ext/oj/wab.c +342 -353
  67. data/lib/oj/bag.rb +1 -0
  68. data/lib/oj/easy_hash.rb +5 -4
  69. data/lib/oj/error.rb +1 -1
  70. data/lib/oj/json.rb +1 -1
  71. data/lib/oj/mimic.rb +48 -14
  72. data/lib/oj/saj.rb +20 -6
  73. data/lib/oj/state.rb +9 -8
  74. data/lib/oj/version.rb +2 -2
  75. data/lib/oj.rb +0 -8
  76. data/pages/Compatibility.md +1 -1
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +53 -46
  79. data/pages/Options.md +78 -11
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +73 -22
  82. data/pages/Security.md +1 -1
  83. data/test/activerecord/result_test.rb +7 -2
  84. data/test/activesupport5/abstract_unit.rb +45 -0
  85. data/test/activesupport5/decoding_test.rb +68 -60
  86. data/test/activesupport5/encoding_test.rb +111 -96
  87. data/test/activesupport5/encoding_test_cases.rb +33 -25
  88. data/test/activesupport5/test_helper.rb +43 -21
  89. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  90. data/test/activesupport6/abstract_unit.rb +44 -0
  91. data/test/activesupport6/decoding_test.rb +133 -0
  92. data/test/activesupport6/encoding_test.rb +507 -0
  93. data/test/activesupport6/encoding_test_cases.rb +98 -0
  94. data/test/activesupport6/test_common.rb +17 -0
  95. data/test/activesupport6/test_helper.rb +163 -0
  96. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  97. data/test/activesupport7/abstract_unit.rb +49 -0
  98. data/test/activesupport7/decoding_test.rb +125 -0
  99. data/test/activesupport7/encoding_test.rb +486 -0
  100. data/test/activesupport7/encoding_test_cases.rb +104 -0
  101. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  102. data/test/bar.rb +6 -12
  103. data/test/baz.rb +16 -0
  104. data/test/bug.rb +16 -0
  105. data/test/foo.rb +69 -75
  106. data/test/helper.rb +16 -0
  107. data/test/json_gem/json_common_interface_test.rb +8 -3
  108. data/test/json_gem/json_generator_test.rb +21 -8
  109. data/test/json_gem/json_parser_test.rb +8 -1
  110. data/test/json_gem/test_helper.rb +12 -0
  111. data/test/mem.rb +33 -0
  112. data/test/perf.rb +1 -1
  113. data/test/perf_dump.rb +50 -0
  114. data/test/perf_once.rb +58 -0
  115. data/test/perf_parser.rb +189 -0
  116. data/test/perf_scp.rb +11 -10
  117. data/test/perf_strict.rb +17 -23
  118. data/test/prec.rb +23 -0
  119. data/test/sample_json.rb +1 -1
  120. data/test/test_compat.rb +46 -10
  121. data/test/test_custom.rb +145 -7
  122. data/test/test_fast.rb +62 -2
  123. data/test/test_file.rb +23 -7
  124. data/test/test_gc.rb +11 -0
  125. data/test/test_generate.rb +21 -0
  126. data/test/test_hash.rb +11 -1
  127. data/test/test_integer_range.rb +1 -2
  128. data/test/test_object.rb +43 -12
  129. data/test/test_parser.rb +11 -0
  130. data/test/test_parser_debug.rb +27 -0
  131. data/test/test_parser_saj.rb +335 -0
  132. data/test/test_parser_usual.rb +217 -0
  133. data/test/test_rails.rb +35 -0
  134. data/test/test_saj.rb +1 -1
  135. data/test/test_scp.rb +3 -5
  136. data/test/test_strict.rb +26 -1
  137. data/test/test_various.rb +86 -65
  138. data/test/test_wab.rb +2 -0
  139. data/test/test_writer.rb +19 -2
  140. data/test/tests.rb +10 -1
  141. data/test/tests_mimic.rb +9 -0
  142. data/test/tests_mimic_addition.rb +9 -0
  143. data/test/zoo.rb +13 -0
  144. metadata +63 -110
  145. data/ext/oj/hash.c +0 -163
  146. data/ext/oj/hash.h +0 -46
  147. data/ext/oj/hash_test.c +0 -512
data/ext/oj/mimic_json.c CHANGED
@@ -1,69 +1,65 @@
1
- /* mimic_json.c
2
- * Copyright (c) 2012, 2017, Peter Ohler
3
- * All rights reserved.
4
- */
1
+ // Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
5
3
 
6
- #include "oj.h"
7
- #include "encode.h"
8
4
  #include "dump.h"
5
+ #include "encode.h"
6
+ #include "oj.h"
9
7
  #include "parse.h"
10
8
 
11
- static VALUE symbolize_names_sym;
12
-
13
- extern const char oj_json_class[];
9
+ extern const char oj_json_class[];
14
10
 
15
- VALUE oj_array_nl_sym;
16
- VALUE oj_ascii_only_sym;
17
- VALUE oj_json_generator_error_class;
18
- VALUE oj_json_parser_error_class;
19
- VALUE oj_max_nesting_sym;
20
- VALUE oj_object_nl_sym;
21
- VALUE oj_space_before_sym;
22
- VALUE oj_space_sym;
11
+ VALUE oj_array_nl_sym;
12
+ VALUE oj_ascii_only_sym;
13
+ VALUE oj_json_generator_error_class;
14
+ VALUE oj_json_parser_error_class;
15
+ VALUE oj_max_nesting_sym;
16
+ VALUE oj_object_nl_sym;
17
+ VALUE oj_space_before_sym;
18
+ VALUE oj_space_sym;
23
19
 
24
- static VALUE state_class;
20
+ static VALUE state_class = Qundef;
25
21
 
26
22
  // mimic JSON documentation
27
23
 
28
24
  /* Document-module: JSON::Ext
29
- *
25
+ *
30
26
  * The Ext module is a placeholder in the mimic JSON module used for
31
27
  * compatibility only.
32
28
  */
33
29
  /* Document-class: JSON::Ext::Parser
34
- *
30
+ *
35
31
  * The JSON::Ext::Parser is a placeholder in the mimic JSON module used for
36
32
  * compatibility only.
37
33
  */
38
34
  /* Document-class: JSON::Ext::Generator
39
- *
35
+ *
40
36
  * The JSON::Ext::Generator is a placeholder in the mimic JSON module used for
41
37
  * compatibility only.
42
38
  */
43
39
 
44
40
  /* Document-method: parser=
45
41
  * call-seq: parser=(parser)
46
- *
42
+ *
47
43
  * Does nothing other than provide compatibility.
48
44
  * - *parser* [_Object_] ignored
49
45
  */
50
46
  /* Document-method: generator=
51
47
  * call-seq: generator=(generator)
52
- *
48
+ *
53
49
  * Does nothing other than provide compatibility.
54
50
  * - *generator* [_Object_] ignored
55
51
  */
56
52
 
57
53
  VALUE
58
54
  oj_get_json_err_class(const char *err_classname) {
59
- volatile VALUE json_module;
60
- volatile VALUE clas;
61
- volatile VALUE json_error_class;
55
+ volatile VALUE json_module;
56
+ volatile VALUE clas;
57
+ volatile VALUE json_error_class;
62
58
 
63
59
  if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
64
- json_module = rb_const_get_at(rb_cObject, rb_intern("JSON"));
60
+ json_module = rb_const_get_at(rb_cObject, rb_intern("JSON"));
65
61
  } else {
66
- json_module = rb_define_module("JSON");
62
+ json_module = rb_define_module("JSON");
67
63
  }
68
64
  if (rb_const_defined_at(json_module, rb_intern("JSONError"))) {
69
65
  json_error_class = rb_const_get(json_module, rb_intern("JSONError"));
@@ -71,225 +67,236 @@ oj_get_json_err_class(const char *err_classname) {
71
67
  json_error_class = rb_define_class_under(json_module, "JSONError", rb_eStandardError);
72
68
  }
73
69
  if (0 == strcmp(err_classname, "JSONError")) {
74
- clas = json_error_class;
70
+ clas = json_error_class;
75
71
  } else {
76
- if (rb_const_defined_at(json_module, rb_intern(err_classname))) {
77
- clas = rb_const_get(json_module, rb_intern(err_classname));
78
- } else {
79
- clas = rb_define_class_under(json_module, err_classname, json_error_class);
80
- }
72
+ if (rb_const_defined_at(json_module, rb_intern(err_classname))) {
73
+ clas = rb_const_get(json_module, rb_intern(err_classname));
74
+ } else {
75
+ clas = rb_define_class_under(json_module, err_classname, json_error_class);
76
+ }
81
77
  }
82
78
  return clas;
83
79
  }
84
80
 
85
- void
86
- oj_parse_mimic_dump_options(VALUE ropts, Options copts) {
87
- VALUE v;
88
- size_t len;
81
+ void oj_parse_mimic_dump_options(VALUE ropts, Options copts) {
82
+ VALUE v;
83
+ size_t len;
89
84
 
90
85
  if (T_HASH != rb_type(ropts)) {
91
- if (rb_respond_to(ropts, oj_to_hash_id)) {
92
- ropts = rb_funcall(ropts, oj_to_hash_id, 0);
93
- } else if (rb_respond_to(ropts, oj_to_h_id)) {
94
- ropts = rb_funcall(ropts, oj_to_h_id, 0);
95
- } else if (Qnil == ropts) {
96
- return;
97
- } else {
98
- rb_raise(rb_eArgError, "options must be a hash.");
99
- }
86
+ if (rb_respond_to(ropts, oj_to_hash_id)) {
87
+ ropts = rb_funcall(ropts, oj_to_hash_id, 0);
88
+ } else if (rb_respond_to(ropts, oj_to_h_id)) {
89
+ ropts = rb_funcall(ropts, oj_to_h_id, 0);
90
+ } else if (Qnil == ropts) {
91
+ return;
92
+ } else {
93
+ rb_raise(rb_eArgError, "options must be a hash.");
94
+ }
100
95
  }
101
96
  v = rb_hash_lookup(ropts, oj_max_nesting_sym);
102
97
  if (Qtrue == v) {
103
- copts->dump_opts.max_depth = 100;
98
+ copts->dump_opts.max_depth = 100;
104
99
  } else if (Qfalse == v || Qnil == v) {
105
- copts->dump_opts.max_depth = MAX_DEPTH;
100
+ copts->dump_opts.max_depth = MAX_DEPTH;
106
101
  } else if (T_FIXNUM == rb_type(v)) {
107
- copts->dump_opts.max_depth = NUM2INT(v);
108
- if (0 >= copts->dump_opts.max_depth) {
109
- copts->dump_opts.max_depth = MAX_DEPTH;
110
- }
102
+ copts->dump_opts.max_depth = NUM2INT(v);
103
+ if (0 >= copts->dump_opts.max_depth) {
104
+ copts->dump_opts.max_depth = MAX_DEPTH;
105
+ }
111
106
  }
112
107
  if (Qnil != (v = rb_hash_lookup(ropts, oj_allow_nan_sym))) {
113
- if (Qtrue == v) {
114
- copts->dump_opts.nan_dump = WordNan;
115
- } else {
116
- copts->dump_opts.nan_dump = RaiseNan;
117
- }
108
+ if (Qtrue == v) {
109
+ copts->dump_opts.nan_dump = WordNan;
110
+ } else {
111
+ copts->dump_opts.nan_dump = RaiseNan;
112
+ }
118
113
  }
119
114
  if (Qnil != (v = rb_hash_lookup(ropts, oj_indent_sym))) {
120
- rb_check_type(v, T_STRING);
121
- if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) {
122
- rb_raise(rb_eArgError, "indent string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.indent_str));
123
- }
124
- strcpy(copts->dump_opts.indent_str, StringValuePtr(v));
125
- copts->dump_opts.indent_size = (uint8_t)len;
126
- copts->dump_opts.use = true;
115
+ rb_check_type(v, T_STRING);
116
+ if (sizeof(copts->dump_opts.indent_str) <= (len = RSTRING_LEN(v))) {
117
+ rb_raise(rb_eArgError,
118
+ "indent string is limited to %lu characters.",
119
+ (unsigned long)sizeof(copts->dump_opts.indent_str));
120
+ }
121
+ strcpy(copts->dump_opts.indent_str, StringValuePtr(v));
122
+ copts->dump_opts.indent_size = (uint8_t)len;
123
+ copts->dump_opts.use = true;
127
124
  }
128
125
  if (Qnil != (v = rb_hash_lookup(ropts, oj_space_sym))) {
129
- rb_check_type(v, T_STRING);
130
- if (sizeof(copts->dump_opts.after_sep) <= (len = RSTRING_LEN(v))) {
131
- rb_raise(rb_eArgError, "space string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.after_sep));
132
- }
133
- strcpy(copts->dump_opts.after_sep, StringValuePtr(v));
134
- copts->dump_opts.after_size = (uint8_t)len;
135
- copts->dump_opts.use = true;
126
+ rb_check_type(v, T_STRING);
127
+ if (sizeof(copts->dump_opts.after_sep) <= (len = RSTRING_LEN(v))) {
128
+ rb_raise(rb_eArgError,
129
+ "space string is limited to %lu characters.",
130
+ (unsigned long)sizeof(copts->dump_opts.after_sep));
131
+ }
132
+ strcpy(copts->dump_opts.after_sep, StringValuePtr(v));
133
+ copts->dump_opts.after_size = (uint8_t)len;
134
+ copts->dump_opts.use = true;
136
135
  }
137
136
  if (Qnil != (v = rb_hash_lookup(ropts, oj_space_before_sym))) {
138
- rb_check_type(v, T_STRING);
139
- if (sizeof(copts->dump_opts.before_sep) <= (len = RSTRING_LEN(v))) {
140
- rb_raise(rb_eArgError, "space_before string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.before_sep));
141
- }
142
- strcpy(copts->dump_opts.before_sep, StringValuePtr(v));
143
- copts->dump_opts.before_size = (uint8_t)len;
144
- copts->dump_opts.use = true;
137
+ rb_check_type(v, T_STRING);
138
+ if (sizeof(copts->dump_opts.before_sep) <= (len = RSTRING_LEN(v))) {
139
+ rb_raise(rb_eArgError,
140
+ "space_before string is limited to %lu characters.",
141
+ (unsigned long)sizeof(copts->dump_opts.before_sep));
142
+ }
143
+ strcpy(copts->dump_opts.before_sep, StringValuePtr(v));
144
+ copts->dump_opts.before_size = (uint8_t)len;
145
+ copts->dump_opts.use = true;
145
146
  }
146
147
  if (Qnil != (v = rb_hash_lookup(ropts, oj_object_nl_sym))) {
147
- rb_check_type(v, T_STRING);
148
- if (sizeof(copts->dump_opts.hash_nl) <= (len = RSTRING_LEN(v))) {
149
- rb_raise(rb_eArgError, "object_nl string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.hash_nl));
150
- }
151
- strcpy(copts->dump_opts.hash_nl, StringValuePtr(v));
152
- copts->dump_opts.hash_size = (uint8_t)len;
153
- copts->dump_opts.use = true;
148
+ rb_check_type(v, T_STRING);
149
+ if (sizeof(copts->dump_opts.hash_nl) <= (len = RSTRING_LEN(v))) {
150
+ rb_raise(rb_eArgError,
151
+ "object_nl string is limited to %lu characters.",
152
+ (unsigned long)sizeof(copts->dump_opts.hash_nl));
153
+ }
154
+ strcpy(copts->dump_opts.hash_nl, StringValuePtr(v));
155
+ copts->dump_opts.hash_size = (uint8_t)len;
156
+ copts->dump_opts.use = true;
154
157
  }
155
158
  if (Qnil != (v = rb_hash_lookup(ropts, oj_array_nl_sym))) {
156
- rb_check_type(v, T_STRING);
157
- if (sizeof(copts->dump_opts.array_nl) <= (len = RSTRING_LEN(v))) {
158
- rb_raise(rb_eArgError, "array_nl string is limited to %lu characters.", (unsigned long)sizeof(copts->dump_opts.array_nl));
159
- }
160
- strcpy(copts->dump_opts.array_nl, StringValuePtr(v));
161
- copts->dump_opts.array_size = (uint8_t)len;
162
- copts->dump_opts.use = true;
159
+ rb_check_type(v, T_STRING);
160
+ if (sizeof(copts->dump_opts.array_nl) <= (len = RSTRING_LEN(v))) {
161
+ rb_raise(rb_eArgError,
162
+ "array_nl string is limited to %lu characters.",
163
+ (unsigned long)sizeof(copts->dump_opts.array_nl));
164
+ }
165
+ strcpy(copts->dump_opts.array_nl, StringValuePtr(v));
166
+ copts->dump_opts.array_size = (uint8_t)len;
167
+ copts->dump_opts.use = true;
163
168
  }
164
169
  if (Qnil != (v = rb_hash_lookup(ropts, oj_quirks_mode_sym))) {
165
- copts->quirks_mode = (Qtrue == v) ? Yes : No;
170
+ copts->quirks_mode = (Qtrue == v) ? Yes : No;
166
171
  }
167
172
  if (Qnil != (v = rb_hash_lookup(ropts, oj_ascii_only_sym))) {
168
- // generate seems to assume anything except nil and false are true.
169
- if (Qfalse == v) {
170
- copts->escape_mode = JXEsc; // JSONEsc;
171
- } else {
172
- copts->escape_mode = ASCIIEsc;
173
- }
173
+ // generate seems to assume anything except nil and false are true.
174
+ if (Qfalse == v) {
175
+ copts->escape_mode = JXEsc;
176
+ } else {
177
+ copts->escape_mode = ASCIIEsc;
178
+ }
174
179
  }
175
180
  }
176
181
 
177
- static int
178
- mimic_limit_arg(VALUE a) {
182
+ static int mimic_limit_arg(VALUE a) {
179
183
  if (Qnil == a || T_FIXNUM != rb_type(a)) {
180
- return -1;
184
+ return -1;
181
185
  }
182
186
  return NUM2INT(a);
183
187
  }
184
188
 
185
189
  /* Document-method: dump
186
190
  * call-seq: dump(obj, anIO=nil, limit=nil)
187
- *
191
+ *
188
192
  * Encodes an object as a JSON String.
189
- *
193
+ *
190
194
  * - *obj* [_Object_] object to convert to encode as JSON
191
195
  * - *anIO* [_IO_] an IO that allows writing
192
196
  * - *limit* [_Fixnum_] ignored
193
197
  *
194
198
  * Returns [_String_] a JSON string.
195
199
  */
196
- static VALUE
197
- mimic_dump(int argc, VALUE *argv, VALUE self) {
198
- char buf[4096];
199
- struct _Out out;
200
- struct _Options copts = oj_default_options;
201
- VALUE rstr;
200
+ static VALUE mimic_dump(int argc, VALUE *argv, VALUE self) {
201
+ struct _out out;
202
+ struct _options copts = oj_default_options;
203
+ VALUE rstr;
204
+ VALUE active_hack[1];
202
205
 
203
206
  copts.str_rx.head = NULL;
204
207
  copts.str_rx.tail = NULL;
205
- out.buf = buf;
206
- out.end = buf + sizeof(buf) - 10;
207
- out.allocated = false;
208
- out.caller = CALLER_DUMP;
208
+
209
+ oj_out_init(&out);
210
+
211
+ out.caller = CALLER_DUMP;
209
212
  copts.escape_mode = JXEsc;
210
- copts.mode = CompatMode;
213
+ copts.mode = CompatMode;
211
214
 
212
215
  /* seems like this is not correct
213
216
  if (No == copts.nilnil && Qnil == *argv) {
214
- rb_raise(rb_eTypeError, "nil not allowed.");
217
+ rb_raise(rb_eTypeError, "nil not allowed.");
215
218
  }
216
219
  */
217
- copts.dump_opts.max_depth = MAX_DEPTH; // when using dump there is no limit
218
- out.omit_nil = copts.dump_opts.omit_nil;
220
+ copts.dump_opts.max_depth = MAX_DEPTH; // when using dump there is no limit
221
+ out.omit_nil = copts.dump_opts.omit_nil;
222
+
219
223
  if (2 <= argc) {
220
- int limit;
221
-
222
- // The json gem take a more liberal approach to optional
223
- // arguments. Expected are (obj, anIO=nil, limit=nil) yet the io
224
- // argument can be left off completely and the 2nd argument is then
225
- // the limit.
226
- if (0 <= (limit = mimic_limit_arg(argv[1]))) {
227
- copts.dump_opts.max_depth = limit;
228
- }
229
- if (3 <= argc && 0 <= (limit = mimic_limit_arg(argv[2]))) {
230
- copts.dump_opts.max_depth = limit;
231
- }
232
- }
233
- oj_dump_obj_to_json(*argv, &copts, &out);
224
+ int limit;
225
+
226
+ // The json gem take a more liberal approach to optional
227
+ // arguments. Expected are (obj, anIO=nil, limit=nil) yet the io
228
+ // argument can be left off completely and the 2nd argument is then
229
+ // the limit.
230
+ if (0 <= (limit = mimic_limit_arg(argv[1]))) {
231
+ copts.dump_opts.max_depth = limit;
232
+ }
233
+ if (3 <= argc && 0 <= (limit = mimic_limit_arg(argv[2]))) {
234
+ copts.dump_opts.max_depth = limit;
235
+ }
236
+ }
237
+ // ActiveSupport in active_support/core_ext/object/json.rb check the
238
+ // optional argument type to to_json and it the argument is a
239
+ // ::JSON::State it calls the JSON gem code otherwise it calls the active
240
+ // support encoder code. To make sure the desired branch is called a
241
+ // default ::JSON::State argument is passed in. Basically a hack to get
242
+ // around the active support hack so two wrongs make a right this time.
243
+ active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
244
+ oj_dump_obj_to_json_using_params(*argv, &copts, &out, 1, active_hack);
245
+
234
246
  if (0 == out.buf) {
235
- rb_raise(rb_eNoMemError, "Not enough memory.");
247
+ rb_raise(rb_eNoMemError, "Not enough memory.");
236
248
  }
237
249
  rstr = rb_str_new2(out.buf);
238
250
  rstr = oj_encode(rstr);
239
251
  if (2 <= argc && Qnil != argv[1] && rb_respond_to(argv[1], oj_write_id)) {
240
- VALUE io = argv[1];
241
- VALUE args[1];
252
+ VALUE io = argv[1];
253
+ VALUE args[1];
242
254
 
243
- *args = rstr;
244
- rb_funcall2(io, oj_write_id, 1, args);
245
- rstr = io;
246
- }
247
- if (out.allocated) {
248
- xfree(out.buf);
255
+ *args = rstr;
256
+ rb_funcall2(io, oj_write_id, 1, args);
257
+ rstr = io;
249
258
  }
259
+
260
+ oj_out_free(&out);
261
+
250
262
  return rstr;
251
263
  }
252
264
 
253
265
  // This is the signature for the hash_foreach callback also.
254
- static int
255
- mimic_walk(VALUE key, VALUE obj, VALUE proc) {
266
+ static int mimic_walk(VALUE key, VALUE obj, VALUE proc) {
256
267
  switch (rb_type(obj)) {
257
- case T_HASH:
258
- rb_hash_foreach(obj, mimic_walk, proc);
259
- break;
260
- case T_ARRAY:
261
- {
262
- size_t cnt = RARRAY_LEN(obj);
263
- size_t i;
264
-
265
- for (i = 0; i < cnt; i++) {
266
- mimic_walk(Qnil, rb_ary_entry(obj, i), proc);
267
- }
268
- break;
269
- }
270
- default:
271
- break;
268
+ case T_HASH: rb_hash_foreach(obj, mimic_walk, proc); break;
269
+ case T_ARRAY: {
270
+ size_t cnt = RARRAY_LEN(obj);
271
+ size_t i;
272
+
273
+ for (i = 0; i < cnt; i++) {
274
+ mimic_walk(Qnil, RARRAY_AREF(obj, i), proc);
275
+ }
276
+ break;
277
+ }
278
+ default: break;
272
279
  }
273
280
  if (Qnil == proc) {
274
- if (rb_block_given_p()) {
275
- rb_yield(obj);
276
- }
281
+ if (rb_block_given_p()) {
282
+ rb_yield(obj);
283
+ }
277
284
  } else {
278
- VALUE args[1];
285
+ VALUE args[1];
279
286
 
280
- *args = obj;
281
- rb_proc_call_with_block(proc, 1, args, Qnil);
287
+ *args = obj;
288
+ rb_proc_call_with_block(proc, 1, args, Qnil);
282
289
  }
283
290
  return ST_CONTINUE;
284
291
  }
285
292
 
286
293
  /* Document-method: restore
287
294
  * call-seq: restore(source, proc=nil)
288
- *
295
+ *
289
296
  * Loads a Ruby Object from a JSON source that can be either a String or an
290
- * IO. If Proc is given or a block is providedit is called with each nested
297
+ * IO. If Proc is given or a block is provided it is called with each nested
291
298
  * element of the loaded Object.
292
- *
299
+ *
293
300
  * - *source* [_String_|IO] JSON source
294
301
  * - *proc* [_Proc_] to yield to on each element or nil
295
302
  *
@@ -298,30 +305,29 @@ mimic_walk(VALUE key, VALUE obj, VALUE proc) {
298
305
 
299
306
  /* Document-method: load
300
307
  * call-seq: load(source, proc=nil)
301
- *
308
+ *
302
309
  * Loads a Ruby Object from a JSON source that can be either a String or an
303
- * IO. If Proc is given or a block is providedit is called with each nested
310
+ * IO. If Proc is given or a block is provided it is called with each nested
304
311
  * element of the loaded Object.
305
- *
312
+ *
306
313
  * - *source* [_String_|IO] JSON source
307
314
  * - *proc* [_Proc_] to yield to on each element or nil
308
315
  *
309
316
  * Returns [_Object_] the decode Object.
310
317
  */
311
- static VALUE
312
- mimic_load(int argc, VALUE *argv, VALUE self) {
313
- VALUE obj;
314
- VALUE p = Qnil;
318
+ static VALUE mimic_load(int argc, VALUE *argv, VALUE self) {
319
+ VALUE obj;
320
+ VALUE p = Qnil;
315
321
 
316
322
  obj = oj_compat_load(argc, argv, self);
317
323
  if (2 <= argc) {
318
- if (rb_cProc == rb_obj_class(argv[1])) {
319
- p = argv[1];
320
- } else if (3 <= argc) {
321
- if (rb_cProc == rb_obj_class(argv[2])) {
322
- p = argv[2];
323
- }
324
- }
324
+ if (rb_cProc == rb_obj_class(argv[1])) {
325
+ p = argv[1];
326
+ } else if (3 <= argc) {
327
+ if (rb_cProc == rb_obj_class(argv[2])) {
328
+ p = argv[2];
329
+ }
330
+ }
325
331
  }
326
332
  mimic_walk(Qnil, obj, p);
327
333
 
@@ -330,61 +336,75 @@ mimic_load(int argc, VALUE *argv, VALUE self) {
330
336
 
331
337
  /* Document-method: []
332
338
  * call-seq: [](obj, opts={})
333
- *
339
+ *
334
340
  * If the obj argument is a String then it is assumed to be a JSON String and
335
341
  * parsed otherwise the obj is encoded as a JSON String.
336
- *
342
+ *
337
343
  * - *obj* [_String_|Hash|Array] object to convert
338
344
  * - *opts* [_Hash_] same options as either generate or parse
339
345
  *
340
346
  * Returns [_Object_]
341
347
  */
342
- static VALUE
343
- mimic_dump_load(int argc, VALUE *argv, VALUE self) {
348
+ static VALUE mimic_dump_load(int argc, VALUE *argv, VALUE self) {
344
349
  if (1 > argc) {
345
- rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
350
+ rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
346
351
  } else if (T_STRING == rb_type(*argv)) {
347
- return mimic_load(argc, argv, self);
352
+ return mimic_load(argc, argv, self);
348
353
  } else {
349
- return mimic_dump(argc, argv, self);
354
+ return mimic_dump(argc, argv, self);
350
355
  }
351
356
  return Qnil;
352
357
  }
353
358
 
354
- static VALUE
355
- mimic_generate_core(int argc, VALUE *argv, Options copts) {
356
- char buf[4096];
357
- struct _Out out;
358
- VALUE rstr;
359
-
360
- out.buf = buf;
361
- out.end = buf + sizeof(buf) - 10;
362
- out.allocated = false;
363
- out.omit_nil = copts->dump_opts.omit_nil;
364
- out.caller = CALLER_GENERATE;
359
+ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
360
+ struct _out out;
361
+ VALUE rstr;
362
+
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);
369
+
370
+ out.omit_nil = copts->dump_opts.omit_nil;
371
+ out.caller = CALLER_GENERATE;
365
372
  // For obj.to_json or generate nan is not allowed but if called from dump
366
373
  // it is.
367
374
  copts->dump_opts.nan_dump = RaiseNan;
368
- copts->mode = CompatMode;
369
- copts->to_json = Yes;
375
+ copts->mode = CompatMode;
376
+ copts->to_json = Yes;
370
377
  if (2 == argc && Qnil != argv[1]) {
371
- oj_parse_mimic_dump_options(argv[1], copts);
378
+ oj_parse_mimic_dump_options(argv[1], copts);
372
379
  }
373
380
  /* seems like this is not correct
374
381
  if (No == copts->nilnil && Qnil == *argv) {
375
- rb_raise(rb_eTypeError, "nil not allowed.");
382
+ rb_raise(rb_eTypeError, "nil not allowed.");
376
383
  }
377
384
  */
378
- oj_dump_obj_to_json_using_params(*argv, copts, &out, argc - 1, argv + 1);
379
-
385
+ if (1 < argc) {
386
+ oj_dump_obj_to_json_using_params(*argv, copts, &out, argc - 1, argv + 1);
387
+ } else {
388
+ VALUE active_hack[1];
389
+
390
+ if (Qundef == state_class) {
391
+ rb_warn(
392
+ "Oj::Rails.mimic_JSON was called implicitly. "
393
+ "Call it explicitly beforehand if you want to remove this warning."
394
+ );
395
+ oj_define_mimic_json(0, NULL, Qnil);
396
+ }
397
+ active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
398
+ oj_dump_obj_to_json_using_params(*argv, copts, &out, 1, active_hack);
399
+ }
380
400
  if (0 == out.buf) {
381
- rb_raise(rb_eNoMemError, "Not enough memory.");
401
+ rb_raise(rb_eNoMemError, "Not enough memory.");
382
402
  }
383
403
  rstr = rb_str_new2(out.buf);
384
404
  rstr = oj_encode(rstr);
385
- if (out.allocated) {
386
- xfree(out.buf);
387
- }
405
+
406
+ oj_out_free(&out);
407
+
388
408
  return rstr;
389
409
  }
390
410
 
@@ -396,11 +416,11 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
396
416
 
397
417
  /* Document-method: generate
398
418
  * call-seq: generate(obj, opts=nil)
399
- *
419
+ *
400
420
  * Encode obj as a JSON String. The obj argument must be a Hash, Array, or
401
421
  * respond to to_h or to_json. Options other than those listed such as
402
422
  * +:allow_nan+ or +:max_nesting+ are ignored.
403
- *
423
+ *
404
424
  * - *obj* [_Object_|Hash|Array] object to convert to a JSON String
405
425
  * - *opts* [_Hash_] options
406
426
  * - - *:indent* [_String_] String to use for indentation.
@@ -408,13 +428,14 @@ mimic_generate_core(int argc, VALUE *argv, Options copts) {
408
428
  * - *:space_before* [_String_] String placed before a : delimiter
409
429
  * - *:object_nl* [_String_] String placed after a JSON object
410
430
  * - *:array_nl* [_String_] String placed after a JSON array
411
- * - *:ascii_only* [_Boolean_] if not nil or false then use only ascii characters in the output. Note JSON.generate does support this even if it is not documented.
431
+ * - *:ascii_only* [_Boolean_] if not nil or false then use only ascii characters in the output.
432
+ * Note JSON.generate does support this even if it is not documented.
412
433
  *
413
434
  * Returns [_String_] generated JSON.
414
435
  */
415
436
  VALUE
416
437
  oj_mimic_generate(int argc, VALUE *argv, VALUE self) {
417
- struct _Options copts = oj_default_options;
438
+ struct _options copts = oj_default_options;
418
439
 
419
440
  copts.str_rx.head = NULL;
420
441
  copts.str_rx.tail = NULL;
@@ -432,36 +453,46 @@ oj_mimic_generate(int argc, VALUE *argv, VALUE self) {
432
453
  */
433
454
  VALUE
434
455
  oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
435
- struct _Options copts = oj_default_options;
436
- VALUE rargs[2];
437
- volatile VALUE h;
456
+ struct _options copts = oj_default_options;
457
+ VALUE rargs[2];
458
+ volatile VALUE h;
438
459
 
439
460
  // Some (all?) json gem to_json methods need a State instance and not just
440
461
  // a Hash. I haven't dug deep enough to find out why but using a State
441
462
  // instance and not a Hash gives the desired behavior.
442
463
  *rargs = *argv;
443
- if (1 == argc) {
444
- h = rb_hash_new();
445
- } else {
446
- h = argv[1];
464
+ if (0 == argc) {
465
+ rb_raise(rb_eArgError, "wrong number of arguments (0))");
466
+ }
467
+ if (1 == argc || Qnil == argv[1]) {
468
+ h = rb_hash_new();
469
+ } else {
470
+ h = argv[1];
447
471
  }
448
- if (Qfalse == rb_funcall(h, oj_has_key_id, 1, oj_indent_sym)) {
449
- rb_hash_aset(h, oj_indent_sym, rb_str_new2(" "));
472
+ if (!oj_hash_has_key(h, oj_indent_sym)) {
473
+ rb_hash_aset(h, oj_indent_sym, rb_str_new2(" "));
450
474
  }
451
- if (Qfalse == rb_funcall(h, oj_has_key_id, 1, oj_space_before_sym)) {
452
- rb_hash_aset(h, oj_space_before_sym, rb_str_new2(""));
475
+ if (!oj_hash_has_key(h, oj_space_before_sym)) {
476
+ rb_hash_aset(h, oj_space_before_sym, rb_str_new2(""));
453
477
  }
454
- if (Qfalse == rb_funcall(h, oj_has_key_id, 1, oj_space_sym)) {
455
- rb_hash_aset(h, oj_space_sym, rb_str_new2(" "));
478
+ if (!oj_hash_has_key(h, oj_space_sym)) {
479
+ rb_hash_aset(h, oj_space_sym, rb_str_new2(" "));
456
480
  }
457
- if (Qfalse == rb_funcall(h, oj_has_key_id, 1, oj_object_nl_sym)) {
458
- rb_hash_aset(h, oj_object_nl_sym, rb_str_new2("\n"));
481
+ if (!oj_hash_has_key(h, oj_object_nl_sym)) {
482
+ rb_hash_aset(h, oj_object_nl_sym, rb_str_new2("\n"));
459
483
  }
460
- if (Qfalse == rb_funcall(h, oj_has_key_id, 1, oj_array_nl_sym)) {
461
- rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
484
+ if (!oj_hash_has_key(h, oj_array_nl_sym)) {
485
+ rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
486
+ }
487
+ if (Qundef == state_class) {
488
+ rb_warn(
489
+ "Oj::Rails.mimic_JSON was called implicitly. "
490
+ "Call it explicitly beforehand if you want to remove this warning."
491
+ );
492
+ oj_define_mimic_json(0, NULL, Qnil);
462
493
  }
463
494
  rargs[1] = rb_funcall(state_class, oj_new_id, 1, h);
464
-
495
+
465
496
  copts.str_rx.head = NULL;
466
497
  copts.str_rx.tail = NULL;
467
498
  strcpy(copts.dump_opts.indent_str, " ");
@@ -474,98 +505,100 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
474
505
  copts.dump_opts.hash_size = (uint8_t)strlen(copts.dump_opts.hash_nl);
475
506
  strcpy(copts.dump_opts.array_nl, "\n");
476
507
  copts.dump_opts.array_size = (uint8_t)strlen(copts.dump_opts.array_nl);
477
- copts.dump_opts.use = true;
508
+ copts.dump_opts.use = true;
478
509
 
479
510
  return mimic_generate_core(2, rargs, &copts);
480
511
  }
481
512
 
482
- static VALUE
483
- mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
484
- struct _ParseInfo pi;
485
- VALUE ropts;
486
- VALUE args[1];
513
+ static int parse_options_cb(VALUE k, VALUE v, VALUE info) {
514
+ struct _parseInfo *pi = (struct _parseInfo *)info;
515
+
516
+ if (oj_symbolize_names_sym == k) {
517
+ pi->options.sym_key = (Qtrue == v) ? Yes : No;
518
+ } else if (oj_quirks_mode_sym == k) {
519
+ pi->options.quirks_mode = (Qtrue == v) ? Yes : No;
520
+ } else if (oj_create_additions_sym == k) {
521
+ pi->options.create_ok = (Qtrue == v) ? Yes : No;
522
+ } else if (oj_allow_nan_sym == k) {
523
+ pi->options.allow_nan = (Qtrue == v) ? Yes : No;
524
+ } else if (oj_hash_class_sym == k) {
525
+ if (Qnil == v) {
526
+ pi->options.hash_class = Qnil;
527
+ } else {
528
+ rb_check_type(v, T_CLASS);
529
+ pi->options.hash_class = v;
530
+ }
531
+ } else if (oj_object_class_sym == k) {
532
+ if (Qnil == v) {
533
+ pi->options.hash_class = Qnil;
534
+ } else {
535
+ rb_check_type(v, T_CLASS);
536
+ pi->options.hash_class = v;
537
+ }
538
+ } else if (oj_array_class_sym == k) {
539
+ if (Qnil == v) {
540
+ pi->options.array_class = Qnil;
541
+ } else {
542
+ rb_check_type(v, T_CLASS);
543
+ pi->options.array_class = v;
544
+ }
545
+ } else if (oj_decimal_class_sym == k) {
546
+ pi->options.compat_bigdec = (oj_bigdecimal_class == v);
547
+ }
548
+ return ST_CONTINUE;
549
+ }
550
+
551
+ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
552
+ struct _parseInfo pi;
553
+ VALUE ropts;
554
+ VALUE args[1];
487
555
 
488
556
  rb_scan_args(argc, argv, "11", NULL, &ropts);
489
557
  parse_info_init(&pi);
490
558
  oj_set_compat_callbacks(&pi);
491
559
 
492
560
  pi.err_class = oj_json_parser_error_class;
493
- //pi.err_class = Qnil;
494
-
495
- pi.options = oj_default_options;
496
- pi.options.auto_define = No;
497
- pi.options.quirks_mode = Yes;
498
- pi.options.allow_invalid = No;
499
- pi.options.empty_string = No;
500
- pi.options.create_ok = No;
501
- pi.options.allow_nan = (bang ? Yes : No);
502
- pi.options.nilnil = No;
503
- pi.options.bigdec_load = FloatDec;
504
- pi.options.mode = CompatMode;
505
- pi.max_depth = 100;
561
+ // pi.err_class = Qnil;
562
+
563
+ pi.options = oj_default_options;
564
+ pi.options.auto_define = No;
565
+ pi.options.quirks_mode = Yes;
566
+ pi.options.allow_invalid = Yes;
567
+ pi.options.empty_string = No;
568
+ pi.options.create_ok = No;
569
+ pi.options.allow_nan = (bang ? Yes : No);
570
+ pi.options.nilnil = No;
571
+ pi.options.bigdec_load = RubyDec;
572
+ pi.options.mode = CompatMode;
573
+ pi.max_depth = 100;
506
574
 
507
575
  if (Qnil != ropts) {
508
- VALUE v;
509
-
510
- if (T_HASH != rb_type(ropts)) {
511
- rb_raise(rb_eArgError, "options must be a hash.");
512
- }
513
- if (Qnil != (v = rb_hash_lookup(ropts, symbolize_names_sym))) {
514
- pi.options.sym_key = (Qtrue == v) ? Yes : No;
515
- }
516
- if (Qnil != (v = rb_hash_lookup(ropts, oj_quirks_mode_sym))) {
517
- pi.options.quirks_mode = (Qtrue == v) ? Yes : No;
518
- }
519
- if (Qnil != (v = rb_hash_lookup(ropts, oj_create_additions_sym))) {
520
- pi.options.create_ok = (Qtrue == v) ? Yes : No;
521
- }
522
- if (Qnil != (v = rb_hash_lookup(ropts, oj_allow_nan_sym))) {
523
- pi.options.allow_nan = (Qtrue == v) ? Yes : No;
524
- }
525
-
526
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_hash_class_sym)) {
527
- if (Qnil == (v = rb_hash_lookup(ropts, oj_hash_class_sym))) {
528
- pi.options.hash_class = Qnil;
529
- } else {
530
- rb_check_type(v, T_CLASS);
531
- pi.options.hash_class = v;
532
- }
533
- }
534
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_object_class_sym)) {
535
- if (Qnil == (v = rb_hash_lookup(ropts, oj_object_class_sym))) {
536
- pi.options.hash_class = Qnil;
537
- } else {
538
- rb_check_type(v, T_CLASS);
539
- pi.options.hash_class = v;
540
- }
541
- }
542
- if (Qtrue == rb_funcall(ropts, oj_has_key_id, 1, oj_array_class_sym)) {
543
- if (Qnil == (v = rb_hash_lookup(ropts, oj_array_class_sym))) {
544
- pi.options.array_class = Qnil;
545
- } else {
546
- rb_check_type(v, T_CLASS);
547
- pi.options.array_class = v;
548
- }
549
- }
550
- v = rb_hash_lookup(ropts, oj_max_nesting_sym);
551
- if (Qtrue == v) {
552
- pi.max_depth = 100;
553
- } else if (Qfalse == v || Qnil == v) {
554
- pi.max_depth = 0;
555
- } else if (T_FIXNUM == rb_type(v)) {
556
- pi.max_depth = NUM2INT(v);
557
- }
558
- oj_parse_opt_match_string(&pi.options.str_rx, ropts);
559
- if (Yes == pi.options.create_ok && Yes == pi.options.sym_key) {
560
- rb_raise(rb_eArgError, ":symbolize_names and :create_additions can not both be true.");
561
- }
576
+ VALUE v;
577
+
578
+ if (T_HASH != rb_type(ropts)) {
579
+ rb_raise(rb_eArgError, "options must be a hash.");
580
+ }
581
+
582
+ rb_hash_foreach(ropts, parse_options_cb, (VALUE)&pi);
583
+ v = rb_hash_lookup(ropts, oj_max_nesting_sym);
584
+ if (Qtrue == v) {
585
+ pi.max_depth = 100;
586
+ } else if (Qfalse == v || Qnil == v) {
587
+ pi.max_depth = 0;
588
+ } else if (T_FIXNUM == rb_type(v)) {
589
+ pi.max_depth = NUM2INT(v);
590
+ }
591
+ oj_parse_opt_match_string(&pi.options.str_rx, ropts);
592
+ if (Yes == pi.options.create_ok && Yes == pi.options.sym_key) {
593
+ rb_raise(rb_eArgError, ":symbolize_names and :create_additions can not both be true.");
594
+ }
562
595
  }
563
596
  *args = *argv;
564
597
 
565
598
  if (T_STRING == rb_type(*args)) {
566
- return oj_pi_parse(1, args, &pi, 0, 0, false);
599
+ return oj_pi_parse(1, args, &pi, 0, 0, false);
567
600
  } else {
568
- return oj_pi_sparse(1, args, &pi, 0);
601
+ return oj_pi_sparse(1, args, &pi, 0);
569
602
  }
570
603
  }
571
604
 
@@ -578,8 +611,10 @@ mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
578
611
  *
579
612
  * - *source* [_String_|IO] source to parse
580
613
  * - *opts* [_Hash_] options
581
- * - *:symbolize* [Boolean] _names flag indicating JSON object keys should be Symbols instead of Strings
582
- * - *:create_additions* [Boolean] flag indicating a key matching +create_id+ in a JSON object should trigger the creation of Ruby Object
614
+ * - *:symbolize* [Boolean] _names flag indicating JSON object keys should be Symbols instead of
615
+ * Strings
616
+ * - *:create_additions* [Boolean] flag indicating a key matching +create_id+ in a JSON object
617
+ * should trigger the creation of Ruby Object
583
618
  *
584
619
  * Returns [Object]
585
620
  * @see create_id=
@@ -595,21 +630,19 @@ oj_mimic_parse(int argc, VALUE *argv, VALUE self) {
595
630
  * Same as parse().
596
631
  * @see parse
597
632
  */
598
- static VALUE
599
- mimic_parse_bang(int argc, VALUE *argv, VALUE self) {
633
+ static VALUE mimic_parse_bang(int argc, VALUE *argv, VALUE self) {
600
634
  return mimic_parse_core(argc, argv, self, true);
601
635
  }
602
636
 
603
637
  /* Document-method: recurse_proc
604
638
  * call-seq: recurse_proc(obj, &proc)
605
- *
639
+ *
606
640
  * Yields to the proc for every element in the obj recursively.
607
- *
641
+ *
608
642
  * - *obj* [_Hash_|Array] object to walk
609
643
  * - *proc* [_Proc_] to yield to on each element
610
644
  */
611
- static VALUE
612
- mimic_recurse_proc(VALUE self, VALUE obj) {
645
+ static VALUE mimic_recurse_proc(VALUE self, VALUE obj) {
613
646
  rb_need_block();
614
647
  mimic_walk(Qnil, obj, Qnil);
615
648
 
@@ -626,23 +659,22 @@ mimic_recurse_proc(VALUE self, VALUE obj) {
626
659
  *
627
660
  * Returns [_String_] the id.
628
661
  */
629
- static VALUE
630
- mimic_set_create_id(VALUE self, VALUE id) {
662
+ static VALUE mimic_set_create_id(VALUE self, VALUE id) {
631
663
  Check_Type(id, T_STRING);
632
664
 
633
665
  if (NULL != oj_default_options.create_id) {
634
- if (oj_json_class != oj_default_options.create_id && NULL != oj_default_options.create_id) {
635
- xfree((char*)oj_default_options.create_id);
636
- }
637
- oj_default_options.create_id = NULL;
638
- oj_default_options.create_id_len = 0;
666
+ if (oj_json_class != oj_default_options.create_id) {
667
+ xfree((char *)oj_default_options.create_id);
668
+ }
669
+ oj_default_options.create_id = NULL;
670
+ oj_default_options.create_id_len = 0;
639
671
  }
640
672
  if (Qnil != id) {
641
- size_t len = RSTRING_LEN(id) + 1;
673
+ size_t len = RSTRING_LEN(id) + 1;
642
674
 
643
- oj_default_options.create_id = ALLOC_N(char, len);
644
- strcpy((char*)oj_default_options.create_id, StringValuePtr(id));
645
- oj_default_options.create_id_len = len - 1;
675
+ oj_default_options.create_id = ALLOC_N(char, len);
676
+ strcpy((char *)oj_default_options.create_id, StringValuePtr(id));
677
+ oj_default_options.create_id_len = len - 1;
646
678
  }
647
679
  return id;
648
680
  }
@@ -652,98 +684,102 @@ mimic_set_create_id(VALUE self, VALUE id) {
652
684
  *
653
685
  * Returns [_String_] the create_id.
654
686
  */
655
- static VALUE
656
- mimic_create_id(VALUE self) {
687
+ static VALUE mimic_create_id(VALUE self) {
657
688
  if (NULL != oj_default_options.create_id) {
658
- return oj_encode(rb_str_new_cstr(oj_default_options.create_id));
689
+ return rb_utf8_str_new(oj_default_options.create_id, oj_default_options.create_id_len);
659
690
  }
660
691
  return rb_str_new_cstr(oj_json_class);
661
692
  }
662
693
 
663
- static struct _Options mimic_object_to_json_options = {
664
- 0, // indent
665
- No, // circular
666
- No, // auto_define
667
- No, // sym_key
668
- JXEsc, // escape_mode
669
- CompatMode, // mode
670
- No, // class_cache
671
- RubyTime, // time_format
672
- No, // bigdec_as_num
673
- FloatDec, // bigdec_load
674
- No, // to_hash
675
- No, // to_json
676
- No, // as_json
677
- No, // nilnil
678
- No, // empty_string
679
- Yes, // allow_gc
680
- Yes, // quirks_mode
681
- No, // allow_invalid
682
- No, // create_ok
683
- No, // allow_nan
684
- No, // trace
685
- 0, // integer_range_min
686
- 0, // integer_range_max
687
- oj_json_class,// create_id
688
- 10, // create_id_len
689
- 3, // sec_prec
690
- 16, // float_prec
691
- "%0.16g", // float_fmt
692
- Qnil, // hash_class
693
- Qnil, // array_class
694
- { // dump_opts
695
- false, //use
696
- "", // indent
697
- "", // before_sep
698
- "", // after_sep
699
- "", // hash_nl
700
- "", // array_nl
701
- 0, // indent_size
702
- 0, // before_size
703
- 0, // after_size
704
- 0, // hash_size
705
- 0, // array_size
706
- RaiseNan,// nan_dump
707
- false, // omit_nil
708
- 100, // max_depth
709
- },
710
- { // str_rx
711
- NULL, // head
712
- NULL, // tail
713
- { '\0' }, // err
714
- }
715
- };
716
-
717
- static VALUE
718
- mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
719
- char buf[4096];
720
- struct _Out out;
721
- VALUE rstr;
722
- struct _Options copts = oj_default_options;
694
+ static struct _options mimic_object_to_json_options = {0, // indent
695
+ No, // circular
696
+ No, // auto_define
697
+ No, // sym_key
698
+ JXEsc, // escape_mode
699
+ CompatMode, // mode
700
+ No, // class_cache
701
+ RubyTime, // time_format
702
+ No, // bigdec_as_num
703
+ RubyDec, // bigdec_load
704
+ false, // compat_bigdec
705
+ No, // to_hash
706
+ No, // to_json
707
+ No, // as_json
708
+ No, // raw_json
709
+ No, // nilnil
710
+ No, // empty_string
711
+ Yes, // allow_gc
712
+ Yes, // quirks_mode
713
+ Yes, // allow_invalid
714
+ No, // create_ok
715
+ No, // allow_nan
716
+ No, // trace
717
+ No, // safe
718
+ false, // sec_prec_set
719
+ No, // ignore_under
720
+ Yes, // cache_keys
721
+ 0, // cache_str
722
+ 0, // int_range_min
723
+ 0, // int_range_max
724
+ oj_json_class, // create_id
725
+ 10, // create_id_len
726
+ 3, // sec_prec
727
+ 0, // float_prec
728
+ "%0.16g", // float_fmt
729
+ Qnil, // hash_class
730
+ Qnil, // array_class
731
+ {
732
+ // dump_opts
733
+ false, // use
734
+ "", // indent
735
+ "", // before_sep
736
+ "", // after_sep
737
+ "", // hash_nl
738
+ "", // array_nl
739
+ 0, // indent_size
740
+ 0, // before_size
741
+ 0, // after_size
742
+ 0, // hash_size
743
+ 0, // array_size
744
+ RaiseNan, // nan_dump
745
+ false, // omit_nil
746
+ 100, // max_depth
747
+ },
748
+ {
749
+ // str_rx
750
+ NULL, // head
751
+ NULL, // tail
752
+ {'\0'}, // err
753
+ }};
754
+
755
+ static VALUE mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
756
+ struct _out out;
757
+ VALUE rstr;
758
+ struct _options copts = oj_default_options;
723
759
 
724
760
  copts.str_rx.head = NULL;
725
761
  copts.str_rx.tail = NULL;
726
- out.buf = buf;
727
- out.end = buf + sizeof(buf) - 10;
728
- out.allocated = false;
729
- out.omit_nil = copts.dump_opts.omit_nil;
730
- copts.mode = CompatMode;
731
- copts.to_json = No;
762
+
763
+ oj_out_init(&out);
764
+
765
+ out.omit_nil = copts.dump_opts.omit_nil;
766
+ copts.mode = CompatMode;
767
+ copts.to_json = No;
732
768
  if (1 <= argc && Qnil != argv[0]) {
733
- oj_parse_mimic_dump_options(argv[0], &copts);
769
+ oj_parse_mimic_dump_options(argv[0], &copts);
734
770
  }
735
771
  // To be strict the mimic_object_to_json_options should be used but people
736
772
  // seem to prefer the option of changing that.
737
- //oj_dump_obj_to_json(self, &mimic_object_to_json_options, &out);
773
+ // oj_dump_obj_to_json(self, &mimic_object_to_json_options, &out);
738
774
  oj_dump_obj_to_json_using_params(self, &copts, &out, argc, argv);
739
- if (0 == out.buf) {
740
- rb_raise(rb_eNoMemError, "Not enough memory.");
775
+ if (NULL == out.buf) {
776
+ rb_raise(rb_eNoMemError, "Not enough memory.");
741
777
  }
742
778
  rstr = rb_str_new2(out.buf);
743
779
  rstr = oj_encode(rstr);
744
- if (out.allocated) {
745
- xfree(out.buf);
746
- }
780
+
781
+ oj_out_free(&out);
782
+
747
783
  return rstr;
748
784
  }
749
785
 
@@ -752,16 +788,14 @@ mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
752
788
  *
753
789
  * Returns [_JSON::State_] the JSON::State class.
754
790
  */
755
- static VALUE
756
- mimic_state(VALUE self) {
791
+ static VALUE mimic_state(VALUE self) {
757
792
  return state_class;
758
793
  }
759
794
 
760
- void
761
- oj_mimic_json_methods(VALUE json) {
762
- VALUE json_error;
763
- VALUE generator;
764
- VALUE ext;
795
+ void oj_mimic_json_methods(VALUE json) {
796
+ VALUE json_error;
797
+ VALUE generator;
798
+ VALUE ext;
765
799
 
766
800
  rb_define_module_function(json, "create_id=", mimic_set_create_id, 1);
767
801
  rb_define_module_function(json, "create_id", mimic_create_id, 0);
@@ -793,36 +827,35 @@ oj_mimic_json_methods(VALUE json) {
793
827
  if (rb_const_defined_at(json, rb_intern("ParserError"))) {
794
828
  oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError"));
795
829
  } else {
796
- oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error);
830
+ oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error);
797
831
  }
798
832
  if (rb_const_defined_at(json, rb_intern("GeneratorError"))) {
799
833
  oj_json_generator_error_class = rb_const_get(json, rb_intern("GeneratorError"));
800
834
  } else {
801
- oj_json_generator_error_class = rb_define_class_under(json, "GeneratorError", json_error);
835
+ oj_json_generator_error_class = rb_define_class_under(json, "GeneratorError", json_error);
802
836
  }
803
837
  if (rb_const_defined_at(json, rb_intern("NestingError"))) {
804
838
  rb_const_get(json, rb_intern("NestingError"));
805
839
  } else {
806
- rb_define_class_under(json, "NestingError", json_error);
840
+ rb_define_class_under(json, "NestingError", json_error);
807
841
  }
808
842
 
809
843
  if (rb_const_defined_at(json, rb_intern("Ext"))) {
810
- ext = rb_const_get_at(json, rb_intern("Ext"));
811
- } else {
812
- ext = rb_define_module_under(json, "Ext");
844
+ ext = rb_const_get_at(json, rb_intern("Ext"));
845
+ } else {
846
+ ext = rb_define_module_under(json, "Ext");
813
847
  }
814
848
  if (rb_const_defined_at(ext, rb_intern("Generator"))) {
815
- generator = rb_const_get_at(ext, rb_intern("Generator"));
816
- } else {
817
- generator = rb_define_module_under(ext, "Generator");
849
+ generator = rb_const_get_at(ext, rb_intern("Generator"));
850
+ } else {
851
+ generator = rb_define_module_under(ext, "Generator");
818
852
  }
819
853
  if (!rb_const_defined_at(generator, rb_intern("State"))) {
820
- rb_require("oj/state");
854
+ rb_require("oj/state");
821
855
  }
822
856
  // Pull in the JSON::State mimic file.
823
857
  state_class = rb_const_get_at(generator, rb_intern("State"));
824
-
825
- symbolize_names_sym = ID2SYM(rb_intern("symbolize_names")); rb_gc_register_address(&symbolize_names_sym);
858
+ rb_gc_register_mark_object(state_class);
826
859
  }
827
860
 
828
861
  /* Document-module: JSON
@@ -831,31 +864,31 @@ oj_mimic_json_methods(VALUE json) {
831
864
  */
832
865
  VALUE
833
866
  oj_define_mimic_json(int argc, VALUE *argv, VALUE self) {
834
- VALUE dummy;
835
- VALUE verbose;
836
- VALUE json;
837
-
867
+ VALUE dummy;
868
+ VALUE verbose;
869
+ VALUE json;
870
+
838
871
  // Either set the paths to indicate JSON has been loaded or replaces the
839
872
  // methods if it has been loaded.
840
873
  if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
841
- json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
874
+ json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
842
875
  } else {
843
- json = rb_define_module("JSON");
876
+ json = rb_define_module("JSON");
844
877
  }
845
878
  verbose = rb_gv_get("$VERBOSE");
846
879
  rb_gv_set("$VERBOSE", Qfalse);
847
880
  rb_define_module_function(rb_cObject, "JSON", mimic_dump_load, -1);
848
881
  dummy = rb_gv_get("$LOADED_FEATURES");
849
882
  if (rb_type(dummy) == T_ARRAY) {
850
- rb_ary_push(dummy, rb_str_new2("json"));
851
- if (0 < argc) {
852
- VALUE mimic_args[1];
883
+ rb_ary_push(dummy, rb_str_new2("json"));
884
+ if (0 < argc) {
885
+ VALUE mimic_args[1];
853
886
 
854
- *mimic_args = *argv;
855
- rb_funcall2(Oj, rb_intern("mimic_loaded"), 1, mimic_args);
856
- } else {
857
- rb_funcall2(Oj, rb_intern("mimic_loaded"), 0, 0);
858
- }
887
+ *mimic_args = *argv;
888
+ rb_funcall2(Oj, rb_intern("mimic_loaded"), 1, mimic_args);
889
+ } else {
890
+ rb_funcall2(Oj, rb_intern("mimic_loaded"), 0, 0);
891
+ }
859
892
  }
860
893
  oj_mimic_json_methods(json);
861
894
 
@@ -863,7 +896,7 @@ oj_define_mimic_json(int argc, VALUE *argv, VALUE self) {
863
896
 
864
897
  rb_gv_set("$VERBOSE", verbose);
865
898
 
866
- oj_default_options = mimic_object_to_json_options;
899
+ oj_default_options = mimic_object_to_json_options;
867
900
  oj_default_options.to_json = Yes;
868
901
 
869
902
  return json;