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
@@ -1,255 +1,240 @@
1
- /* strwriter.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
4
  #include "dump.h"
7
5
  #include "encode.h"
8
6
 
9
- extern VALUE Oj;
7
+ extern VALUE Oj;
8
+
9
+ bool string_writer_optimized = false;
10
10
 
11
- static void
12
- key_check(StrWriter sw, const char *key) {
13
- DumpType type = sw->types[sw->depth];
11
+ static void key_check(StrWriter sw, const char *key) {
12
+ DumpType type = sw->types[sw->depth];
14
13
 
15
14
  if (0 == key && (ObjectNew == type || ObjectType == type)) {
16
- rb_raise(rb_eStandardError, "Can not push onto an Object without a key.");
15
+ rb_raise(rb_eStandardError, "Can not push onto an Object without a key.");
17
16
  }
18
17
  }
19
18
 
20
- static void
21
- push_type(StrWriter sw, DumpType type) {
19
+ static void push_type(StrWriter sw, DumpType type) {
22
20
  if (sw->types_end <= sw->types + sw->depth + 1) {
23
- size_t size = (sw->types_end - sw->types) * 2;
21
+ size_t size = (sw->types_end - sw->types) * 2;
24
22
 
25
- REALLOC_N(sw->types, char, size);
26
- sw->types_end = sw->types + size;
23
+ REALLOC_N(sw->types, char, size);
24
+ sw->types_end = sw->types + size;
27
25
  }
28
26
  sw->depth++;
29
27
  sw->types[sw->depth] = type;
30
28
  }
31
29
 
32
- static void
33
- maybe_comma(StrWriter sw) {
30
+ static void maybe_comma(StrWriter sw) {
34
31
  switch (sw->types[sw->depth]) {
35
- case ObjectNew:
36
- sw->types[sw->depth] = ObjectType;
37
- break;
38
- case ArrayNew:
39
- sw->types[sw->depth] = ArrayType;
40
- break;
32
+ case ObjectNew: sw->types[sw->depth] = ObjectType; break;
33
+ case ArrayNew: sw->types[sw->depth] = ArrayType; break;
41
34
  case ObjectType:
42
35
  case ArrayType:
43
- // Always have a few characters available in the out.buf.
44
- *sw->out.cur++ = ',';
45
- break;
36
+ // Always have a few characters available in the out.buf.
37
+ *sw->out.cur++ = ',';
38
+ break;
46
39
  }
47
40
  }
48
41
 
49
42
  // Used by stream writer also.
50
- void
51
- oj_str_writer_init(StrWriter sw, int buf_size) {
52
- sw->opts = oj_default_options;
53
- sw->depth = 0;
54
- sw->types = ALLOC_N(char, 256);
55
- sw->types_end = sw->types + 256;
56
- *sw->types = '\0';
43
+ void oj_str_writer_init(StrWriter sw, int buf_size) {
44
+ sw->opts = oj_default_options;
45
+ sw->depth = 0;
46
+ sw->types = ALLOC_N(char, 256);
47
+ sw->types_end = sw->types + 256;
48
+ *sw->types = '\0';
57
49
  sw->keyWritten = 0;
58
50
 
59
51
  if (0 == buf_size) {
60
- buf_size = 4096;
52
+ buf_size = 4096;
61
53
  } else if (buf_size < 1024) {
62
- buf_size = 1024;
54
+ buf_size = 1024;
63
55
  }
64
- sw->out.buf = ALLOC_N(char, buf_size);
65
- sw->out.end = sw->out.buf + buf_size - 10;
66
- sw->out.allocated = true;
67
- sw->out.cur = sw->out.buf;
68
- *sw->out.cur = '\0';
56
+ // Must be allocated. Using the out.stack_buffer results in double frees
57
+ // and I haven't figured out why yet.
58
+ sw->out.buf = ALLOC_N(char, buf_size);
59
+ sw->out.cur = sw->out.buf;
60
+ sw->out.end = sw->out.buf + buf_size - BUFFER_EXTRA;
61
+ sw->out.allocated = true;
62
+
63
+ *sw->out.cur = '\0';
69
64
  sw->out.circ_cache = NULL;
70
- sw->out.circ_cnt = 0;
71
- sw->out.hash_cnt = 0;
72
- sw->out.opts = &sw->opts;
73
- sw->out.indent = sw->opts.indent;
74
- sw->out.depth = 0;
75
- sw->out.argc = 0;
76
- sw->out.argv = NULL;
77
- sw->out.caller = 0;
78
- sw->out.ropts = NULL;
79
- sw->out.omit_nil = oj_default_options.dump_opts.omit_nil;
65
+ sw->out.circ_cnt = 0;
66
+ sw->out.hash_cnt = 0;
67
+ sw->out.opts = &sw->opts;
68
+ sw->out.indent = sw->opts.indent;
69
+ sw->out.depth = 0;
70
+ sw->out.argc = 0;
71
+ sw->out.argv = NULL;
72
+ sw->out.caller = 0;
73
+ sw->out.ropts = NULL;
74
+ sw->out.omit_nil = oj_default_options.dump_opts.omit_nil;
80
75
  }
81
76
 
82
- void
83
- oj_str_writer_push_key(StrWriter sw, const char *key) {
84
- DumpType type = sw->types[sw->depth];
85
- long size;
77
+ void oj_str_writer_push_key(StrWriter sw, const char *key) {
78
+ DumpType type = sw->types[sw->depth];
79
+ long size;
86
80
 
87
81
  if (sw->keyWritten) {
88
- rb_raise(rb_eStandardError, "Can not push more than one key before pushing a non-key.");
82
+ rb_raise(rb_eStandardError, "Can not push more than one key before pushing a non-key.");
89
83
  }
90
84
  if (ObjectNew != type && ObjectType != type) {
91
- rb_raise(rb_eStandardError, "Can only push a key onto an Object.");
85
+ rb_raise(rb_eStandardError, "Can only push a key onto an Object.");
92
86
  }
93
87
  size = sw->depth * sw->out.indent + 3;
94
88
  assure_size(&sw->out, size);
95
89
  maybe_comma(sw);
96
90
  if (0 < sw->depth) {
97
- fill_indent(&sw->out, sw->depth);
91
+ fill_indent(&sw->out, sw->depth);
98
92
  }
99
93
  oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
100
94
  *sw->out.cur++ = ':';
101
95
  sw->keyWritten = 1;
102
96
  }
103
97
 
104
- void
105
- oj_str_writer_push_object(StrWriter sw, const char *key) {
98
+ void oj_str_writer_push_object(StrWriter sw, const char *key) {
106
99
  if (sw->keyWritten) {
107
- sw->keyWritten = 0;
108
- assure_size(&sw->out, 1);
100
+ sw->keyWritten = 0;
101
+ assure_size(&sw->out, 1);
109
102
  } else {
110
- long size;
111
-
112
- key_check(sw, key);
113
- size = sw->depth * sw->out.indent + 3;
114
- assure_size(&sw->out, size);
115
- maybe_comma(sw);
116
- if (0 < sw->depth) {
117
- fill_indent(&sw->out, sw->depth);
118
- }
119
- if (0 != key) {
120
- oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
121
- *sw->out.cur++ = ':';
122
- }
103
+ long size;
104
+
105
+ key_check(sw, key);
106
+ size = sw->depth * sw->out.indent + 3;
107
+ assure_size(&sw->out, size);
108
+ maybe_comma(sw);
109
+ if (0 < sw->depth) {
110
+ fill_indent(&sw->out, sw->depth);
111
+ }
112
+ if (0 != key) {
113
+ oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
114
+ *sw->out.cur++ = ':';
115
+ }
123
116
  }
124
117
  *sw->out.cur++ = '{';
125
118
  push_type(sw, ObjectNew);
126
119
  }
127
120
 
128
- void
129
- oj_str_writer_push_array(StrWriter sw, const char *key) {
121
+ void oj_str_writer_push_array(StrWriter sw, const char *key) {
130
122
  if (sw->keyWritten) {
131
- sw->keyWritten = 0;
132
- assure_size(&sw->out, 1);
123
+ sw->keyWritten = 0;
124
+ assure_size(&sw->out, 1);
133
125
  } else {
134
- long size;
135
-
136
- key_check(sw, key);
137
- size = sw->depth * sw->out.indent + 3;
138
- assure_size(&sw->out, size);
139
- maybe_comma(sw);
140
- if (0 < sw->depth) {
141
- fill_indent(&sw->out, sw->depth);
142
- }
143
- if (0 != key) {
144
- oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
145
- *sw->out.cur++ = ':';
146
- }
126
+ long size;
127
+
128
+ key_check(sw, key);
129
+ size = sw->depth * sw->out.indent + 3;
130
+ assure_size(&sw->out, size);
131
+ maybe_comma(sw);
132
+ if (0 < sw->depth) {
133
+ fill_indent(&sw->out, sw->depth);
134
+ }
135
+ if (0 != key) {
136
+ oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
137
+ *sw->out.cur++ = ':';
138
+ }
147
139
  }
148
140
  *sw->out.cur++ = '[';
149
141
  push_type(sw, ArrayNew);
150
142
  }
151
143
 
152
- void
153
- oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key) {
154
- Out out = &sw->out;
155
-
144
+ void oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key) {
145
+ Out out = &sw->out;
146
+
156
147
  if (sw->keyWritten) {
157
- sw->keyWritten = 0;
148
+ sw->keyWritten = 0;
158
149
  } else {
159
- long size;
160
-
161
- key_check(sw, key);
162
- size = sw->depth * out->indent + 3;
163
- assure_size(out, size);
164
- maybe_comma(sw);
165
- if (0 < sw->depth) {
166
- fill_indent(&sw->out, sw->depth);
167
- }
168
- if (0 != key) {
169
- oj_dump_cstr(key, strlen(key), 0, 0, out);
170
- *out->cur++ = ':';
171
- }
150
+ long size;
151
+
152
+ key_check(sw, key);
153
+ size = sw->depth * out->indent + 3;
154
+ assure_size(out, size);
155
+ maybe_comma(sw);
156
+ if (0 < sw->depth) {
157
+ fill_indent(&sw->out, sw->depth);
158
+ }
159
+ if (0 != key) {
160
+ oj_dump_cstr(key, strlen(key), 0, 0, out);
161
+ *out->cur++ = ':';
162
+ }
172
163
  }
173
164
  switch (out->opts->mode) {
174
- case StrictMode: oj_dump_strict_val(val, sw->depth, out); break;
175
- case NullMode: oj_dump_null_val(val, sw->depth, out); break;
176
- case ObjectMode: oj_dump_obj_val(val, sw->depth, out); break;
177
- case CompatMode: oj_dump_compat_val(val, sw->depth, out, Yes == out->opts->to_json); break;
178
- case RailsMode: oj_dump_rails_val(val, sw->depth, out); break;
179
- case CustomMode: oj_dump_custom_val(val, sw->depth, out, true); break;
180
- default: oj_dump_custom_val(val, sw->depth, out, true); break;
165
+ case StrictMode: oj_dump_strict_val(val, sw->depth, out); break;
166
+ case NullMode: oj_dump_null_val(val, sw->depth, out); break;
167
+ case ObjectMode: oj_dump_obj_val(val, sw->depth, out); break;
168
+ case CompatMode: oj_dump_compat_val(val, sw->depth, out, Yes == out->opts->to_json); break;
169
+ case RailsMode: oj_dump_rails_val(val, sw->depth, out); break;
170
+ case CustomMode: oj_dump_custom_val(val, sw->depth, out, true); break;
171
+ default: oj_dump_custom_val(val, sw->depth, out, true); break;
181
172
  }
182
173
  }
183
174
 
184
- void
185
- oj_str_writer_push_json(StrWriter sw, const char *json, const char *key) {
175
+ void oj_str_writer_push_json(StrWriter sw, const char *json, const char *key) {
186
176
  if (sw->keyWritten) {
187
- sw->keyWritten = 0;
177
+ sw->keyWritten = 0;
188
178
  } else {
189
- long size;
190
-
191
- key_check(sw, key);
192
- size = sw->depth * sw->out.indent + 3;
193
- assure_size(&sw->out, size);
194
- maybe_comma(sw);
195
- if (0 < sw->depth) {
196
- fill_indent(&sw->out, sw->depth);
197
- }
198
- if (0 != key) {
199
- oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
200
- *sw->out.cur++ = ':';
201
- }
179
+ long size;
180
+
181
+ key_check(sw, key);
182
+ size = sw->depth * sw->out.indent + 3;
183
+ assure_size(&sw->out, size);
184
+ maybe_comma(sw);
185
+ if (0 < sw->depth) {
186
+ fill_indent(&sw->out, sw->depth);
187
+ }
188
+ if (0 != key) {
189
+ oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
190
+ *sw->out.cur++ = ':';
191
+ }
202
192
  }
203
193
  oj_dump_raw(json, strlen(json), &sw->out);
204
194
  }
205
195
 
206
- void
207
- oj_str_writer_pop(StrWriter sw) {
208
- long size;
209
- DumpType type = sw->types[sw->depth];
196
+ void oj_str_writer_pop(StrWriter sw) {
197
+ long size;
198
+ DumpType type = sw->types[sw->depth];
210
199
 
211
200
  if (sw->keyWritten) {
212
- sw->keyWritten = 0;
213
- rb_raise(rb_eStandardError, "Can not pop after writing a key but no value.");
201
+ sw->keyWritten = 0;
202
+ rb_raise(rb_eStandardError, "Can not pop after writing a key but no value.");
214
203
  }
215
204
  sw->depth--;
216
205
  if (0 > sw->depth) {
217
- rb_raise(rb_eStandardError, "Can not pop with no open array or object.");
206
+ rb_raise(rb_eStandardError, "Can not pop with no open array or object.");
218
207
  }
219
208
  size = sw->depth * sw->out.indent + 2;
220
209
  assure_size(&sw->out, size);
221
210
  fill_indent(&sw->out, sw->depth);
222
211
  switch (type) {
223
212
  case ObjectNew:
224
- case ObjectType:
225
- *sw->out.cur++ = '}';
226
- break;
213
+ case ObjectType: *sw->out.cur++ = '}'; break;
227
214
  case ArrayNew:
228
- case ArrayType:
229
- *sw->out.cur++ = ']';
230
- break;
215
+ case ArrayType: *sw->out.cur++ = ']'; break;
231
216
  }
232
217
  if (0 == sw->depth && 0 <= sw->out.indent) {
233
- *sw->out.cur++ = '\n';
218
+ *sw->out.cur++ = '\n';
234
219
  }
235
220
  }
236
221
 
237
- void
238
- oj_str_writer_pop_all(StrWriter sw) {
222
+ void oj_str_writer_pop_all(StrWriter sw) {
239
223
  while (0 < sw->depth) {
240
- oj_str_writer_pop(sw);
224
+ oj_str_writer_pop(sw);
241
225
  }
242
226
  }
243
227
 
244
- static void
245
- str_writer_free(void *ptr) {
246
- StrWriter sw;
228
+ static void str_writer_free(void *ptr) {
229
+ StrWriter sw;
247
230
 
248
231
  if (0 == ptr) {
249
- return;
232
+ return;
250
233
  }
251
234
  sw = (StrWriter)ptr;
252
- xfree(sw->out.buf);
235
+
236
+ oj_out_free(&sw->out);
237
+
253
238
  xfree(sw->types);
254
239
  xfree(ptr);
255
240
  }
@@ -268,18 +253,17 @@ str_writer_free(void *ptr) {
268
253
  * should be.
269
254
  *
270
255
  * - *io* [_IO_] stream to write to
271
- * - *options* [_Hash_] formating options
256
+ * - *options* [_Hash_] formatting options
272
257
  */
273
- static VALUE
274
- str_writer_new(int argc, VALUE *argv, VALUE self) {
275
- StrWriter sw = ALLOC(struct _StrWriter);
276
-
258
+ static VALUE str_writer_new(int argc, VALUE *argv, VALUE self) {
259
+ StrWriter sw = ALLOC(struct _strWriter);
260
+
277
261
  oj_str_writer_init(sw, 0);
278
262
  if (1 == argc) {
279
- oj_parse_options(argv[0], &sw->opts);
263
+ oj_parse_options(argv[0], &sw->opts);
280
264
  }
281
- sw->out.argc = argc - 1;
282
- sw->out.argv = argv + 1;
265
+ sw->out.argc = argc - 1;
266
+ sw->out.argv = argv + 1;
283
267
  sw->out.indent = sw->opts.indent;
284
268
 
285
269
  return Data_Wrap_Struct(oj_string_writer_class, 0, str_writer_free, sw);
@@ -293,9 +277,8 @@ str_writer_new(int argc, VALUE *argv, VALUE self) {
293
277
  * the next push then that new key will be ignored.
294
278
  * - *key* [_String_] the key pending for the next push
295
279
  */
296
- static VALUE
297
- str_writer_push_key(VALUE self, VALUE key) {
298
- StrWriter sw = (StrWriter)DATA_PTR(self);
280
+ static VALUE str_writer_push_key(VALUE self, VALUE key) {
281
+ StrWriter sw = (StrWriter)DATA_PTR(self);
299
282
 
300
283
  rb_check_type(key, T_STRING);
301
284
  oj_str_writer_push_key(sw, StringValuePtr(key));
@@ -310,29 +293,24 @@ str_writer_push_key(VALUE self, VALUE key) {
310
293
  * until a pop() is called.
311
294
  * - *key* [_String_] the key if adding to an object in the JSON document
312
295
  */
313
- static VALUE
314
- str_writer_push_object(int argc, VALUE *argv, VALUE self) {
315
- StrWriter sw = (StrWriter)DATA_PTR(self);
296
+ static VALUE str_writer_push_object(int argc, VALUE *argv, VALUE self) {
297
+ StrWriter sw = (StrWriter)DATA_PTR(self);
316
298
 
317
299
  switch (argc) {
318
- case 0:
319
- oj_str_writer_push_object(sw, 0);
320
- break;
300
+ case 0: oj_str_writer_push_object(sw, 0); break;
321
301
  case 1:
322
- if (Qnil == argv[0]) {
323
- oj_str_writer_push_object(sw, 0);
324
- } else {
325
- rb_check_type(argv[0], T_STRING);
326
- oj_str_writer_push_object(sw, StringValuePtr(argv[0]));
327
- }
328
- break;
329
- default:
330
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
331
- break;
302
+ if (Qnil == argv[0]) {
303
+ oj_str_writer_push_object(sw, 0);
304
+ } else {
305
+ rb_check_type(argv[0], T_STRING);
306
+ oj_str_writer_push_object(sw, StringValuePtr(argv[0]));
307
+ }
308
+ break;
309
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); break;
332
310
  }
333
311
  if (rb_block_given_p()) {
334
- rb_yield(Qnil);
335
- oj_str_writer_pop(sw);
312
+ rb_yield(Qnil);
313
+ oj_str_writer_pop(sw);
336
314
  }
337
315
  return Qnil;
338
316
  }
@@ -344,29 +322,24 @@ str_writer_push_object(int argc, VALUE *argv, VALUE self) {
344
322
  * until a pop() is called.
345
323
  * - *key* [_String_] the key if adding to an object in the JSON document
346
324
  */
347
- static VALUE
348
- str_writer_push_array(int argc, VALUE *argv, VALUE self) {
349
- StrWriter sw = (StrWriter)DATA_PTR(self);
325
+ static VALUE str_writer_push_array(int argc, VALUE *argv, VALUE self) {
326
+ StrWriter sw = (StrWriter)DATA_PTR(self);
350
327
 
351
328
  switch (argc) {
352
- case 0:
353
- oj_str_writer_push_array(sw, 0);
354
- break;
329
+ case 0: oj_str_writer_push_array(sw, 0); break;
355
330
  case 1:
356
- if (Qnil == argv[0]) {
357
- oj_str_writer_push_array(sw, 0);
358
- } else {
359
- rb_check_type(argv[0], T_STRING);
360
- oj_str_writer_push_array(sw, StringValuePtr(argv[0]));
361
- }
362
- break;
363
- default:
364
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
365
- break;
331
+ if (Qnil == argv[0]) {
332
+ oj_str_writer_push_array(sw, 0);
333
+ } else {
334
+ rb_check_type(argv[0], T_STRING);
335
+ oj_str_writer_push_array(sw, StringValuePtr(argv[0]));
336
+ }
337
+ break;
338
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); break;
366
339
  }
367
340
  if (rb_block_given_p()) {
368
- rb_yield(Qnil);
369
- oj_str_writer_pop(sw);
341
+ rb_yield(Qnil);
342
+ oj_str_writer_pop(sw);
370
343
  }
371
344
  return Qnil;
372
345
  }
@@ -378,23 +351,18 @@ str_writer_push_array(int argc, VALUE *argv, VALUE self) {
378
351
  * - *value* [_Object_] value to add to the JSON document
379
352
  * - *key* [_String_] the key if adding to an object in the JSON document
380
353
  */
381
- static VALUE
382
- str_writer_push_value(int argc, VALUE *argv, VALUE self) {
354
+ static VALUE str_writer_push_value(int argc, VALUE *argv, VALUE self) {
383
355
  switch (argc) {
384
- case 1:
385
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
386
- break;
356
+ case 1: oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); break;
387
357
  case 2:
388
- if (Qnil == argv[1]) {
389
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
390
- } else {
391
- rb_check_type(argv[1], T_STRING);
392
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
393
- }
394
- break;
395
- default:
396
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'.");
397
- break;
358
+ if (Qnil == argv[1]) {
359
+ oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
360
+ } else {
361
+ rb_check_type(argv[1], T_STRING);
362
+ oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
363
+ }
364
+ break;
365
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); break;
398
366
  }
399
367
  return Qnil;
400
368
  }
@@ -408,24 +376,21 @@ str_writer_push_value(int argc, VALUE *argv, VALUE self) {
408
376
  * - *value* [_Object_] value to add to the JSON document
409
377
  * - *key* [_String_] the key if adding to an object in the JSON document
410
378
  */
411
- static VALUE
412
- str_writer_push_json(int argc, VALUE *argv, VALUE self) {
379
+ static VALUE str_writer_push_json(int argc, VALUE *argv, VALUE self) {
413
380
  rb_check_type(argv[0], T_STRING);
414
381
  switch (argc) {
415
- case 1:
416
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
417
- break;
382
+ case 1: oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); break;
418
383
  case 2:
419
- if (Qnil == argv[1]) {
420
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
421
- } else {
422
- rb_check_type(argv[1], T_STRING);
423
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
424
- }
425
- break;
426
- default:
427
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'.");
428
- break;
384
+ if (Qnil == argv[1]) {
385
+ oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
386
+ } else {
387
+ rb_check_type(argv[1], T_STRING);
388
+ oj_str_writer_push_json((StrWriter)DATA_PTR(self),
389
+ StringValuePtr(*argv),
390
+ StringValuePtr(argv[1]));
391
+ }
392
+ break;
393
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); break;
429
394
  }
430
395
  return Qnil;
431
396
  }
@@ -435,8 +400,7 @@ str_writer_push_json(int argc, VALUE *argv, VALUE self) {
435
400
  * Pops up a level in the JSON document closing the array or object that is
436
401
  * currently open.
437
402
  */
438
- static VALUE
439
- str_writer_pop(VALUE self) {
403
+ static VALUE str_writer_pop(VALUE self) {
440
404
  oj_str_writer_pop((StrWriter)DATA_PTR(self));
441
405
  return Qnil;
442
406
  }
@@ -447,8 +411,7 @@ str_writer_pop(VALUE self) {
447
411
  * Pops all level in the JSON document closing all the array or object that is
448
412
  * currently open.
449
413
  */
450
- static VALUE
451
- str_writer_pop_all(VALUE self) {
414
+ static VALUE str_writer_pop_all(VALUE self) {
452
415
  oj_str_writer_pop_all((StrWriter)DATA_PTR(self));
453
416
 
454
417
  return Qnil;
@@ -459,15 +422,14 @@ str_writer_pop_all(VALUE self) {
459
422
  *
460
423
  * Reset the writer back to the empty state.
461
424
  */
462
- static VALUE
463
- str_writer_reset(VALUE self) {
464
- StrWriter sw = (StrWriter)DATA_PTR(self);
425
+ static VALUE str_writer_reset(VALUE self) {
426
+ StrWriter sw = (StrWriter)DATA_PTR(self);
465
427
 
466
- sw->depth = 0;
467
- *sw->types = '\0';
428
+ sw->depth = 0;
429
+ *sw->types = '\0';
468
430
  sw->keyWritten = 0;
469
- sw->out.cur = sw->out.buf;
470
- *sw->out.cur = '\0';
431
+ sw->out.cur = sw->out.buf;
432
+ *sw->out.cur = '\0';
471
433
 
472
434
  return Qnil;
473
435
  }
@@ -479,26 +441,43 @@ str_writer_reset(VALUE self) {
479
441
  *
480
442
  * *return* [_String_]
481
443
  */
482
- static VALUE
483
- str_writer_to_s(VALUE self) {
484
- StrWriter sw = (StrWriter)DATA_PTR(self);
485
- VALUE rstr = rb_str_new(sw->out.buf, sw->out.cur - sw->out.buf);
444
+ static VALUE str_writer_to_s(VALUE self) {
445
+ StrWriter sw = (StrWriter)DATA_PTR(self);
446
+ VALUE rstr = rb_str_new(sw->out.buf, sw->out.cur - sw->out.buf);
486
447
 
487
448
  return oj_encode(rstr);
488
449
  }
489
450
 
451
+ /* Document-method: as_json
452
+ * call-seq: as_json()
453
+ *
454
+ * Returns the contents of the writer as a JSON element. If called from inside
455
+ * an array or hash by Oj the raw buffer will be used othersize a more
456
+ * inefficient parse of the contents and a return of the result is
457
+ * completed. The parse uses the strict mode.
458
+ *
459
+ * *return* [_Hash_|_Array_|_String_|_Integer_|_Float_|_True_|_False_|_nil|)
460
+ */
461
+ static VALUE str_writer_as_json(VALUE self) {
462
+ if (string_writer_optimized) {
463
+ return self;
464
+ }
465
+ return rb_hash_new();
466
+ }
467
+
490
468
  /* Document-class: Oj::StringWriter
491
- *
469
+ *
492
470
  * Supports building a JSON document one element at a time. Build the document
493
471
  * by pushing values into the document. Pushing an array or an object will
494
472
  * create that element in the JSON document and subsequent pushes will add the
495
473
  * elements to that array or object until a pop() is called. When complete
496
- * calling to_s() will return the JSON document. Note tha calling to_s() before
474
+ * calling to_s() will return the JSON document. Note that calling to_s() before
497
475
  * construction is complete will return the document in it's current state.
498
476
  */
499
- void
500
- oj_string_writer_init() {
477
+ void oj_string_writer_init(void) {
501
478
  oj_string_writer_class = rb_define_class_under(Oj, "StringWriter", rb_cObject);
479
+ rb_gc_register_address(&oj_string_writer_class);
480
+ rb_undef_alloc_func(oj_string_writer_class);
502
481
  rb_define_module_function(oj_string_writer_class, "new", str_writer_new, -1);
503
482
  rb_define_method(oj_string_writer_class, "push_key", str_writer_push_key, 1);
504
483
  rb_define_method(oj_string_writer_class, "push_object", str_writer_push_object, -1);
@@ -509,4 +488,6 @@ oj_string_writer_init() {
509
488
  rb_define_method(oj_string_writer_class, "pop_all", str_writer_pop_all, 0);
510
489
  rb_define_method(oj_string_writer_class, "reset", str_writer_reset, 0);
511
490
  rb_define_method(oj_string_writer_class, "to_s", str_writer_to_s, 0);
491
+ rb_define_method(oj_string_writer_class, "raw_json", str_writer_to_s, 0);
492
+ rb_define_method(oj_string_writer_class, "as_json", str_writer_as_json, 0);
512
493
  }