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
@@ -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
  }