oj 3.7.4 → 3.13.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1352 -0
  3. data/README.md +29 -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 +809 -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 +1070 -1087
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +469 -436
  32. data/ext/oj/object.c +525 -593
  33. data/ext/oj/odd.c +154 -138
  34. data/ext/oj/odd.h +37 -38
  35. data/ext/oj/oj.c +1325 -986
  36. data/ext/oj/oj.h +333 -316
  37. data/ext/oj/parse.c +1002 -846
  38. data/ext/oj/parse.h +92 -87
  39. data/ext/oj/parser.c +1557 -0
  40. data/ext/oj/parser.h +91 -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 +602 -0
  51. data/ext/oj/scp.c +88 -113
  52. data/ext/oj/sparse.c +787 -709
  53. data/ext/oj/stream_writer.c +133 -159
  54. data/ext/oj/strict.c +127 -118
  55. data/ext/oj/string_writer.c +230 -249
  56. data/ext/oj/trace.c +34 -41
  57. data/ext/oj/trace.h +19 -19
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +59 -67
  62. data/ext/oj/val_stack.h +91 -129
  63. data/ext/oj/validate.c +46 -0
  64. data/ext/oj/wab.c +342 -353
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +5 -4
  67. data/lib/oj/error.rb +1 -1
  68. data/lib/oj/json.rb +1 -1
  69. data/lib/oj/mimic.rb +48 -14
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/state.rb +8 -7
  72. data/lib/oj/version.rb +2 -2
  73. data/lib/oj.rb +0 -8
  74. data/pages/Compatibility.md +1 -1
  75. data/pages/JsonGem.md +15 -0
  76. data/pages/Modes.md +53 -46
  77. data/pages/Options.md +72 -11
  78. data/pages/Parser.md +309 -0
  79. data/pages/Rails.md +73 -22
  80. data/pages/Security.md +1 -1
  81. data/test/activerecord/result_test.rb +7 -2
  82. data/test/activesupport5/abstract_unit.rb +45 -0
  83. data/test/activesupport5/decoding_test.rb +68 -60
  84. data/test/activesupport5/encoding_test.rb +111 -96
  85. data/test/activesupport5/encoding_test_cases.rb +33 -25
  86. data/test/activesupport5/test_helper.rb +43 -21
  87. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  88. data/test/activesupport6/abstract_unit.rb +44 -0
  89. data/test/activesupport6/decoding_test.rb +133 -0
  90. data/test/activesupport6/encoding_test.rb +507 -0
  91. data/test/activesupport6/encoding_test_cases.rb +98 -0
  92. data/test/activesupport6/test_common.rb +17 -0
  93. data/test/activesupport6/test_helper.rb +163 -0
  94. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  95. data/test/activesupport7/abstract_unit.rb +49 -0
  96. data/test/activesupport7/decoding_test.rb +125 -0
  97. data/test/activesupport7/encoding_test.rb +486 -0
  98. data/test/activesupport7/encoding_test_cases.rb +104 -0
  99. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  100. data/test/bar.rb +6 -12
  101. data/test/baz.rb +16 -0
  102. data/test/bug.rb +16 -0
  103. data/test/foo.rb +69 -75
  104. data/test/helper.rb +16 -0
  105. data/test/json_gem/json_common_interface_test.rb +8 -3
  106. data/test/json_gem/json_generator_test.rb +18 -4
  107. data/test/json_gem/json_parser_test.rb +9 -0
  108. data/test/json_gem/test_helper.rb +12 -0
  109. data/test/mem.rb +33 -0
  110. data/test/perf.rb +1 -1
  111. data/test/perf_dump.rb +50 -0
  112. data/test/perf_once.rb +58 -0
  113. data/test/perf_parser.rb +189 -0
  114. data/test/perf_scp.rb +11 -10
  115. data/test/perf_strict.rb +17 -23
  116. data/test/prec.rb +23 -0
  117. data/test/sample_json.rb +1 -1
  118. data/test/test_compat.rb +46 -10
  119. data/test/test_custom.rb +147 -8
  120. data/test/test_fast.rb +62 -2
  121. data/test/test_file.rb +25 -2
  122. data/test/test_gc.rb +13 -0
  123. data/test/test_generate.rb +21 -0
  124. data/test/test_hash.rb +11 -1
  125. data/test/test_integer_range.rb +7 -2
  126. data/test/test_object.rb +85 -9
  127. data/test/test_parser.rb +27 -0
  128. data/test/test_parser_saj.rb +335 -0
  129. data/test/test_parser_usual.rb +217 -0
  130. data/test/test_rails.rb +35 -0
  131. data/test/test_saj.rb +1 -1
  132. data/test/test_scp.rb +5 -5
  133. data/test/test_strict.rb +26 -1
  134. data/test/test_various.rb +87 -65
  135. data/test/test_wab.rb +2 -0
  136. data/test/test_writer.rb +19 -2
  137. data/test/tests.rb +1 -1
  138. data/test/zoo.rb +13 -0
  139. metadata +60 -110
  140. data/ext/oj/hash.c +0 -163
  141. data/ext/oj/hash.h +0 -46
  142. 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;