oj 3.7.4 → 3.13.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1360 -0
  3. data/README.md +31 -8
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +53 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -43
  11. data/ext/oj/circarray.h +16 -17
  12. data/ext/oj/code.c +165 -179
  13. data/ext/oj/code.h +27 -29
  14. data/ext/oj/compat.c +174 -194
  15. data/ext/oj/custom.c +790 -866
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +848 -863
  18. data/ext/oj/dump.h +81 -67
  19. data/ext/oj/dump_compat.c +85 -123
  20. data/ext/oj/dump_leaf.c +100 -188
  21. data/ext/oj/dump_object.c +527 -656
  22. data/ext/oj/dump_strict.c +315 -338
  23. data/ext/oj/encode.h +7 -34
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -29
  26. data/ext/oj/err.h +48 -48
  27. data/ext/oj/extconf.rb +17 -4
  28. data/ext/oj/fast.c +1073 -1088
  29. data/ext/oj/intern.c +298 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +469 -436
  32. data/ext/oj/object.c +532 -599
  33. data/ext/oj/odd.c +154 -138
  34. data/ext/oj/odd.h +37 -38
  35. data/ext/oj/oj.c +1333 -986
  36. data/ext/oj/oj.h +336 -316
  37. data/ext/oj/parse.c +1002 -846
  38. data/ext/oj/parse.h +92 -87
  39. data/ext/oj/parser.c +1587 -0
  40. data/ext/oj/parser.h +102 -0
  41. data/ext/oj/rails.c +888 -878
  42. data/ext/oj/rails.h +11 -14
  43. data/ext/oj/reader.c +141 -147
  44. data/ext/oj/reader.h +73 -89
  45. data/ext/oj/resolve.c +41 -62
  46. data/ext/oj/resolve.h +7 -9
  47. data/ext/oj/rxclass.c +71 -75
  48. data/ext/oj/rxclass.h +18 -19
  49. data/ext/oj/saj.c +443 -486
  50. data/ext/oj/saj2.c +596 -0
  51. data/ext/oj/saj2.h +23 -0
  52. data/ext/oj/scp.c +88 -113
  53. data/ext/oj/sparse.c +787 -709
  54. data/ext/oj/stream_writer.c +133 -159
  55. data/ext/oj/strict.c +127 -118
  56. data/ext/oj/string_writer.c +230 -249
  57. data/ext/oj/trace.c +34 -41
  58. data/ext/oj/trace.h +19 -19
  59. data/ext/oj/usual.c +1207 -0
  60. data/ext/oj/usual.h +68 -0
  61. data/ext/oj/util.c +136 -0
  62. data/ext/oj/util.h +20 -0
  63. data/ext/oj/val_stack.c +60 -68
  64. data/ext/oj/val_stack.h +91 -129
  65. data/ext/oj/validate.c +46 -0
  66. data/ext/oj/wab.c +342 -353
  67. data/lib/oj/bag.rb +1 -0
  68. data/lib/oj/easy_hash.rb +5 -4
  69. data/lib/oj/error.rb +1 -1
  70. data/lib/oj/json.rb +1 -1
  71. data/lib/oj/mimic.rb +48 -14
  72. data/lib/oj/saj.rb +20 -6
  73. data/lib/oj/state.rb +9 -8
  74. data/lib/oj/version.rb +2 -2
  75. data/lib/oj.rb +0 -8
  76. data/pages/Compatibility.md +1 -1
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +53 -46
  79. data/pages/Options.md +78 -11
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +73 -22
  82. data/pages/Security.md +1 -1
  83. data/test/activerecord/result_test.rb +7 -2
  84. data/test/activesupport5/abstract_unit.rb +45 -0
  85. data/test/activesupport5/decoding_test.rb +68 -60
  86. data/test/activesupport5/encoding_test.rb +111 -96
  87. data/test/activesupport5/encoding_test_cases.rb +33 -25
  88. data/test/activesupport5/test_helper.rb +43 -21
  89. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  90. data/test/activesupport6/abstract_unit.rb +44 -0
  91. data/test/activesupport6/decoding_test.rb +133 -0
  92. data/test/activesupport6/encoding_test.rb +507 -0
  93. data/test/activesupport6/encoding_test_cases.rb +98 -0
  94. data/test/activesupport6/test_common.rb +17 -0
  95. data/test/activesupport6/test_helper.rb +163 -0
  96. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  97. data/test/activesupport7/abstract_unit.rb +49 -0
  98. data/test/activesupport7/decoding_test.rb +125 -0
  99. data/test/activesupport7/encoding_test.rb +486 -0
  100. data/test/activesupport7/encoding_test_cases.rb +104 -0
  101. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  102. data/test/bar.rb +6 -12
  103. data/test/baz.rb +16 -0
  104. data/test/bug.rb +16 -0
  105. data/test/foo.rb +69 -75
  106. data/test/helper.rb +16 -0
  107. data/test/json_gem/json_common_interface_test.rb +8 -3
  108. data/test/json_gem/json_generator_test.rb +21 -8
  109. data/test/json_gem/json_parser_test.rb +8 -1
  110. data/test/json_gem/test_helper.rb +12 -0
  111. data/test/mem.rb +33 -0
  112. data/test/perf.rb +1 -1
  113. data/test/perf_dump.rb +50 -0
  114. data/test/perf_once.rb +58 -0
  115. data/test/perf_parser.rb +189 -0
  116. data/test/perf_scp.rb +11 -10
  117. data/test/perf_strict.rb +17 -23
  118. data/test/prec.rb +23 -0
  119. data/test/sample_json.rb +1 -1
  120. data/test/test_compat.rb +46 -10
  121. data/test/test_custom.rb +145 -7
  122. data/test/test_fast.rb +62 -2
  123. data/test/test_file.rb +23 -7
  124. data/test/test_gc.rb +11 -0
  125. data/test/test_generate.rb +21 -0
  126. data/test/test_hash.rb +11 -1
  127. data/test/test_integer_range.rb +1 -2
  128. data/test/test_object.rb +43 -12
  129. data/test/test_parser.rb +11 -0
  130. data/test/test_parser_debug.rb +27 -0
  131. data/test/test_parser_saj.rb +335 -0
  132. data/test/test_parser_usual.rb +217 -0
  133. data/test/test_rails.rb +35 -0
  134. data/test/test_saj.rb +1 -1
  135. data/test/test_scp.rb +3 -5
  136. data/test/test_strict.rb +26 -1
  137. data/test/test_various.rb +86 -65
  138. data/test/test_wab.rb +2 -0
  139. data/test/test_writer.rb +19 -2
  140. data/test/tests.rb +10 -1
  141. data/test/tests_mimic.rb +9 -0
  142. data/test/tests_mimic_addition.rb +9 -0
  143. data/test/zoo.rb +13 -0
  144. metadata +63 -110
  145. data/ext/oj/hash.c +0 -163
  146. data/ext/oj/hash.h +0 -46
  147. data/ext/oj/hash_test.c +0 -512
data/ext/oj/rails.c CHANGED
@@ -1,158 +1,153 @@
1
- /* rails.c
2
- * Copyright (c) 2017, Peter Ohler
3
- * All rights reserved.
4
- */
1
+ // Copyright (c) 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 "rails.h"
7
- #include "encode.h"
5
+
8
6
  #include "code.h"
9
7
  #include "encode.h"
10
8
  #include "trace.h"
9
+ #include "util.h"
11
10
 
12
- #define OJ_INFINITY (1.0/0.0)
11
+ #define OJ_INFINITY (1.0 / 0.0)
13
12
 
14
13
  // TBD keep static array of strings and functions to help with rails optimization
15
- typedef struct _Encoder {
16
- struct _ROptTable ropts;
17
- struct _Options opts;
18
- VALUE arg;
19
- } *Encoder;
14
+ typedef struct _encoder {
15
+ struct _rOptTable ropts;
16
+ struct _options opts;
17
+ VALUE arg;
18
+ } * Encoder;
20
19
 
21
- bool oj_rails_hash_opt = false;
22
- bool oj_rails_array_opt = false;
23
- bool oj_rails_float_opt = false;
20
+ bool oj_rails_hash_opt = false;
21
+ bool oj_rails_array_opt = false;
22
+ bool oj_rails_float_opt = false;
24
23
 
25
- extern void oj_mimic_json_methods(VALUE json);
24
+ extern void oj_mimic_json_methods(VALUE json);
26
25
 
27
- static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok);
26
+ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok);
28
27
 
29
- extern VALUE Oj;
28
+ extern VALUE Oj;
30
29
 
31
- static struct _ROptTable ropts = { 0, 0, NULL };
30
+ static struct _rOptTable ropts = {0, 0, NULL};
32
31
 
33
- static VALUE encoder_class = Qnil;
34
- static bool escape_html = true;
35
- static bool xml_time = true;
32
+ static VALUE encoder_class = Qnil;
33
+ static bool escape_html = true;
34
+ static bool xml_time = true;
36
35
 
37
- static ROpt create_opt(ROptTable rot, VALUE clas);
36
+ static ROpt create_opt(ROptTable rot, VALUE clas);
38
37
 
39
- ROpt
40
- oj_rails_get_opt(ROptTable rot, VALUE clas) {
38
+ ROpt oj_rails_get_opt(ROptTable rot, VALUE clas) {
41
39
  if (NULL == rot) {
42
- rot = &ropts;
40
+ rot = &ropts;
43
41
  }
44
42
  if (0 < rot->len) {
45
- int lo = 0;
46
- int hi = rot->len - 1;
47
- int mid;
48
- VALUE v;
49
-
50
- if (clas < rot->table->clas || rot->table[hi].clas < clas) {
51
- return NULL;
52
- }
53
- if (rot->table[lo].clas == clas) {
54
- return rot->table;
55
- }
56
- if (rot->table[hi].clas == clas) {
57
- return &rot->table[hi];
58
- }
59
- while (2 <= hi - lo) {
60
- mid = (hi + lo) / 2;
61
- v = rot->table[mid].clas;
62
- if (v == clas) {
63
- return &rot->table[mid];
64
- }
65
- if (v < clas) {
66
- lo = mid;
67
- } else {
68
- hi = mid;
69
- }
70
- }
43
+ int lo = 0;
44
+ int hi = rot->len - 1;
45
+ int mid;
46
+ VALUE v;
47
+
48
+ if (clas < rot->table->clas || rot->table[hi].clas < clas) {
49
+ return NULL;
50
+ }
51
+ if (rot->table[lo].clas == clas) {
52
+ return rot->table;
53
+ }
54
+ if (rot->table[hi].clas == clas) {
55
+ return &rot->table[hi];
56
+ }
57
+ while (2 <= hi - lo) {
58
+ mid = (hi + lo) / 2;
59
+ v = rot->table[mid].clas;
60
+ if (v == clas) {
61
+ return &rot->table[mid];
62
+ }
63
+ if (v < clas) {
64
+ lo = mid;
65
+ } else {
66
+ hi = mid;
67
+ }
68
+ }
71
69
  }
72
70
  return NULL;
73
71
  }
74
72
 
75
- static ROptTable
76
- copy_opts(ROptTable src, ROptTable dest) {
77
- dest->len = src->len;
73
+ static ROptTable copy_opts(ROptTable src, ROptTable dest) {
74
+ dest->len = src->len;
78
75
  dest->alen = src->alen;
79
76
  if (NULL == src->table) {
80
- dest->table = NULL;
77
+ dest->table = NULL;
81
78
  } else {
82
- dest->table = ALLOC_N(struct _ROpt, dest->alen);
83
- memcpy(dest->table, src->table, sizeof(struct _ROpt) * dest->alen);
79
+ dest->table = ALLOC_N(struct _rOpt, dest->alen);
80
+ memcpy(dest->table, src->table, sizeof(struct _rOpt) * dest->alen);
84
81
  }
85
82
  return NULL;
86
83
  }
87
84
 
88
- static int
89
- dump_attr_cb(ID key, VALUE value, Out out) {
90
- int depth = out->depth;
91
- size_t size = depth * out->indent + 1;
92
- const char *attr = rb_id2name(key);
85
+ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
86
+ Out out = (Out)ov;
87
+ int depth = out->depth;
88
+ size_t size = depth * out->indent + 1;
89
+ const char *attr = rb_id2name(key);
93
90
 
94
91
  // Some exceptions such as NoMethodError have an invisible attribute where
95
92
  // the key name is NULL. Not an empty string but NULL.
96
93
  if (NULL == attr) {
97
- attr = "";
94
+ attr = "";
98
95
  }
99
96
  if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
100
- return ST_CONTINUE;
97
+ return ST_CONTINUE;
101
98
  }
102
99
  assure_size(out, size);
103
100
  fill_indent(out, depth);
104
101
  if ('@' == *attr) {
105
- attr++;
106
- oj_dump_cstr(attr, strlen(attr), 0, 0, out);
102
+ attr++;
103
+ oj_dump_cstr(attr, strlen(attr), 0, 0, out);
107
104
  } else {
108
- char buf[32];
105
+ char buf[32];
109
106
 
110
- *buf = '~';
111
- strncpy(buf + 1, attr, sizeof(buf) - 2);
112
- buf[sizeof(buf) - 1] = '\0';
113
- oj_dump_cstr(buf, strlen(buf), 0, 0, out);
107
+ *buf = '~';
108
+ strncpy(buf + 1, attr, sizeof(buf) - 2);
109
+ buf[sizeof(buf) - 1] = '\0';
110
+ oj_dump_cstr(buf, strlen(buf), 0, 0, out);
114
111
  }
115
112
  *out->cur++ = ':';
116
113
  dump_rails_val(value, depth, out, true);
117
- out->depth = depth;
114
+ out->depth = depth;
118
115
  *out->cur++ = ',';
119
-
116
+
120
117
  return ST_CONTINUE;
121
118
  }
122
119
 
123
- static void
124
- dump_obj_attrs(VALUE obj, int depth, Out out, bool as_ok) {
120
+ static void dump_obj_attrs(VALUE obj, int depth, Out out, bool as_ok) {
125
121
  assure_size(out, 2);
126
122
  *out->cur++ = '{';
127
- out->depth = depth + 1;
123
+ out->depth = depth + 1;
128
124
  rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
129
125
  if (',' == *(out->cur - 1)) {
130
- out->cur--; // backup to overwrite last comma
126
+ out->cur--; // backup to overwrite last comma
131
127
  }
132
128
  out->depth = depth;
133
129
  fill_indent(out, depth);
134
130
  *out->cur++ = '}';
135
- *out->cur = '\0';
131
+ *out->cur = '\0';
136
132
  }
137
133
 
138
- static void
139
- dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
140
- int d3 = depth + 2;
141
- size_t size = d3 * out->indent + 2;
142
- size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
143
- volatile VALUE ma;
144
- volatile VALUE v;
145
- int cnt;
146
- int i;
147
- int len;
148
- const char *name;
134
+ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
135
+ int d3 = depth + 2;
136
+ size_t size = d3 * out->indent + 2;
137
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
138
+ volatile VALUE ma;
139
+ volatile VALUE v;
140
+ int cnt;
141
+ int i;
142
+ int len;
143
+ const char * name;
149
144
 
150
145
  #ifdef RSTRUCT_LEN
151
146
  #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
152
147
  cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
153
- #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
148
+ #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
154
149
  cnt = (int)RSTRUCT_LEN(obj);
155
- #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
150
+ #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
156
151
  #else
157
152
  // This is a bit risky as a struct in C ruby is not the same as a Struct
158
153
  // class in interpreted Ruby so length() may not be defined.
@@ -162,507 +157,506 @@ dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
162
157
  assure_size(out, 2);
163
158
  *out->cur++ = '{';
164
159
  for (i = 0; i < cnt; i++) {
165
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
166
-
167
- name = rb_string_value_ptr((VALUE*)&s);
168
- len = (int)RSTRING_LEN(s);
169
- assure_size(out, size + sep_len + 6);
170
- if (0 < i) {
171
- *out->cur++ = ',';
172
- }
173
- fill_indent(out, d3);
174
- *out->cur++ = '"';
175
- memcpy(out->cur, name, len);
176
- out->cur += len;
177
- *out->cur++ = '"';
178
- if (0 < out->opts->dump_opts.before_size) {
179
- strcpy(out->cur, out->opts->dump_opts.before_sep);
180
- out->cur += out->opts->dump_opts.before_size;
181
- }
182
- *out->cur++ = ':';
183
- if (0 < out->opts->dump_opts.after_size) {
184
- strcpy(out->cur, out->opts->dump_opts.after_sep);
185
- out->cur += out->opts->dump_opts.after_size;
186
- }
160
+ volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
161
+
162
+ name = RSTRING_PTR(s);
163
+ len = (int)RSTRING_LEN(s);
164
+ assure_size(out, size + sep_len + 6);
165
+ if (0 < i) {
166
+ *out->cur++ = ',';
167
+ }
168
+ fill_indent(out, d3);
169
+ *out->cur++ = '"';
170
+ APPEND_CHARS(out->cur, name, len);
171
+ *out->cur++ = '"';
172
+ if (0 < out->opts->dump_opts.before_size) {
173
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
174
+ }
175
+ *out->cur++ = ':';
176
+ if (0 < out->opts->dump_opts.after_size) {
177
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
178
+ }
187
179
  #ifdef RSTRUCT_LEN
188
- v = RSTRUCT_GET(obj, i);
180
+ v = RSTRUCT_GET(obj, i);
189
181
  #else
190
- v = rb_struct_aref(obj, INT2FIX(i));
182
+ v = rb_struct_aref(obj, INT2FIX(i));
191
183
  #endif
192
- dump_rails_val(v, d3, out, true);
184
+ dump_rails_val(v, d3, out, true);
193
185
  }
194
186
  fill_indent(out, depth);
195
187
  *out->cur++ = '}';
196
- *out->cur = '\0';
188
+ *out->cur = '\0';
197
189
  }
198
190
 
199
- static ID to_a_id = 0;
191
+ static ID to_a_id = 0;
200
192
 
201
- static void
202
- dump_enumerable(VALUE obj, int depth, Out out, bool as_ok) {
193
+ static void dump_enumerable(VALUE obj, int depth, Out out, bool as_ok) {
203
194
  if (0 == to_a_id) {
204
- to_a_id = rb_intern("to_a");
195
+ to_a_id = rb_intern("to_a");
205
196
  }
206
197
  dump_rails_val(rb_funcall(obj, to_a_id, 0), depth, out, false);
207
198
  }
208
199
 
209
- static void
210
- dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
211
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
212
- const char *str = rb_string_value_ptr((VALUE*)&rstr);
200
+ static void dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
201
+ volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
202
+ const char * str = RSTRING_PTR(rstr);
213
203
 
214
204
  if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) {
215
- oj_dump_nil(Qnil, depth, out, false);
205
+ oj_dump_nil(Qnil, depth, out, false);
206
+ } else if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) {
207
+ oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out);
216
208
  } else if (Yes == out->opts->bigdec_as_num) {
217
- oj_dump_raw(str, (int)RSTRING_LEN(rstr), out);
209
+ oj_dump_raw(str, (int)RSTRING_LEN(rstr), out);
218
210
  } else {
219
- oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out);
211
+ oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out);
220
212
  }
221
213
  }
222
214
 
223
- static void
224
- dump_sec_nano(VALUE obj, time_t sec, long nsec, Out out) {
225
- char buf[64];
226
- struct tm *tm;
227
- long one = 1000000000;
228
- long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
229
- int tzhour, tzmin;
230
- char tzsign = '+';
231
- int len;
232
-
215
+ static void dump_sec_nano(VALUE obj, int64_t sec, long nsec, Out out) {
216
+ char buf[64];
217
+ struct _timeInfo ti;
218
+ long one = 1000000000;
219
+ long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
220
+ int tzhour, tzmin;
221
+ char tzsign = '+';
222
+ int len;
223
+
233
224
  if (out->end - out->cur <= 36) {
234
- assure_size(out, 36);
225
+ assure_size(out, 36);
235
226
  }
236
227
  if (9 > out->opts->sec_prec) {
237
- int i;
238
-
239
- // Rails does not round when reducing precision but instead floors,
240
- for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
241
- nsec = nsec / 10;
242
- one /= 10;
243
- }
244
- if (one <= nsec) {
245
- nsec -= one;
246
- sec++;
247
- }
228
+ int i;
229
+
230
+ // Rails does not round when reducing precision but instead floors,
231
+ for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
232
+ nsec = nsec / 10;
233
+ one /= 10;
234
+ }
235
+ if (one <= nsec) {
236
+ nsec -= one;
237
+ sec++;
238
+ }
248
239
  }
249
240
  // 2012-01-05T23:58:07.123456000+09:00 or 2012/01/05 23:58:07 +0900
250
241
  sec += tzsecs;
251
- tm = gmtime(&sec);
242
+ sec_as_time(sec, &ti);
252
243
  if (0 > tzsecs) {
253
244
  tzsign = '-';
254
245
  tzhour = (int)(tzsecs / -3600);
255
- tzmin = (int)(tzsecs / -60) - (tzhour * 60);
246
+ tzmin = (int)(tzsecs / -60) - (tzhour * 60);
256
247
  } else {
257
248
  tzhour = (int)(tzsecs / 3600);
258
- tzmin = (int)(tzsecs / 60) - (tzhour * 60);
249
+ tzmin = (int)(tzsecs / 60) - (tzhour * 60);
259
250
  }
260
251
  if (!xml_time) {
261
- len = sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d %c%02d%02d",
262
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
263
- tm->tm_hour, tm->tm_min, tm->tm_sec, tzsign, tzhour, tzmin);
252
+ len = sprintf(buf,
253
+ "%04d/%02d/%02d %02d:%02d:%02d %c%02d%02d",
254
+ ti.year,
255
+ ti.mon,
256
+ ti.day,
257
+ ti.hour,
258
+ ti.min,
259
+ ti.sec,
260
+ tzsign,
261
+ tzhour,
262
+ tzmin);
264
263
  } else if (0 == out->opts->sec_prec) {
265
- if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
266
- len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ",
267
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
268
- tm->tm_hour, tm->tm_min, tm->tm_sec);
269
- } else {
270
- len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
271
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
272
- tm->tm_hour, tm->tm_min, tm->tm_sec,
273
- tzsign, tzhour, tzmin);
274
- }
264
+ if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
265
+ len = sprintf(buf,
266
+ "%04d-%02d-%02dT%02d:%02d:%02dZ",
267
+ ti.year,
268
+ ti.mon,
269
+ ti.day,
270
+ ti.hour,
271
+ ti.min,
272
+ ti.sec);
273
+ } else {
274
+ len = sprintf(buf,
275
+ "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
276
+ ti.year,
277
+ ti.mon,
278
+ ti.day,
279
+ ti.hour,
280
+ ti.min,
281
+ ti.sec,
282
+ tzsign,
283
+ tzhour,
284
+ tzmin);
285
+ }
275
286
  } else if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
276
- char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
277
-
278
- len = 30;
279
- if (9 > out->opts->sec_prec) {
280
- format[32] = '0' + out->opts->sec_prec;
281
- len -= 9 - out->opts->sec_prec;
282
- }
283
- len = sprintf(buf, format,
284
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
285
- tm->tm_hour, tm->tm_min, tm->tm_sec, nsec);
287
+ char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
288
+
289
+ len = 30;
290
+ if (9 > out->opts->sec_prec) {
291
+ format[32] = '0' + out->opts->sec_prec;
292
+ len -= 9 - out->opts->sec_prec;
293
+ }
294
+ len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec);
286
295
  } else {
287
- char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
288
-
289
- len = 35;
290
- if (9 > out->opts->sec_prec) {
291
- format[32] = '0' + out->opts->sec_prec;
292
- len -= 9 - out->opts->sec_prec;
293
- }
294
- len = sprintf(buf, format,
295
- tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
296
- tm->tm_hour, tm->tm_min, tm->tm_sec, nsec,
297
- tzsign, tzhour, tzmin);
296
+ char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
297
+
298
+ len = 35;
299
+ if (9 > out->opts->sec_prec) {
300
+ format[32] = '0' + out->opts->sec_prec;
301
+ len -= 9 - out->opts->sec_prec;
302
+ }
303
+ len = sprintf(buf,
304
+ format,
305
+ ti.year,
306
+ ti.mon,
307
+ ti.day,
308
+ ti.hour,
309
+ ti.min,
310
+ ti.sec,
311
+ nsec,
312
+ tzsign,
313
+ tzhour,
314
+ tzmin);
298
315
  }
299
316
  oj_dump_cstr(buf, len, 0, 0, out);
300
317
  }
301
318
 
302
- static void
303
- dump_time(VALUE obj, int depth, Out out, bool as_ok) {
304
- time_t sec;
305
- long long nsec;
319
+ static void dump_time(VALUE obj, int depth, Out out, bool as_ok) {
320
+ long long sec;
321
+ long long nsec;
306
322
 
307
- #ifdef HAVE_RB_TIME_TIMESPEC
308
- {
309
- struct timespec ts = rb_time_timespec(obj);
310
- sec = ts.tv_sec;
311
- nsec = ts.tv_nsec;
323
+ if (16 <= sizeof(struct timespec)) {
324
+ struct timespec ts = rb_time_timespec(obj);
325
+
326
+ sec = (long long)ts.tv_sec;
327
+ nsec = ts.tv_nsec;
328
+ } else {
329
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
330
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
312
331
  }
313
- #else
314
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
315
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
316
- #endif
317
332
  dump_sec_nano(obj, sec, nsec, out);
318
333
  }
319
334
 
320
- static void
321
- dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
322
- time_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
323
- long long nsec = 0;
335
+ static void dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
336
+ int64_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
337
+ long long nsec = 0;
324
338
 
325
339
  if (rb_respond_to(obj, oj_tv_nsec_id)) {
326
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
340
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
327
341
  } else if (rb_respond_to(obj, oj_tv_usec_id)) {
328
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
342
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
329
343
  }
330
344
  dump_sec_nano(obj, sec, nsec, out);
331
345
  }
332
346
 
333
- static void
334
- dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
335
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
347
+ static void dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
348
+ volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
336
349
 
337
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
350
+ oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
338
351
  }
339
352
 
340
- static ID parameters_id = 0;
353
+ static ID parameters_id = 0;
341
354
 
342
- typedef struct _StrLen {
343
- const char *str;
344
- int len;
345
- } *StrLen;
355
+ typedef struct _strLen {
356
+ const char *str;
357
+ int len;
358
+ } * StrLen;
346
359
 
347
- static void
348
- dump_actioncontroller_parameters(VALUE obj, int depth, Out out, bool as_ok) {
360
+ static void dump_actioncontroller_parameters(VALUE obj, int depth, Out out, bool as_ok) {
349
361
  if (0 == parameters_id) {
350
- parameters_id = rb_intern("@parameters");
362
+ parameters_id = rb_intern("@parameters");
351
363
  }
352
364
  out->argc = 0;
353
365
  dump_rails_val(rb_ivar_get(obj, parameters_id), depth, out, true);
354
366
  }
355
367
 
356
- static StrLen
357
- columns_array(VALUE rcols, int *ccnt) {
358
- volatile VALUE v;
359
- StrLen cp;
360
- StrLen cols;
361
- int i;
362
- int cnt = (int)RARRAY_LEN(rcols);
363
-
368
+ static StrLen columns_array(VALUE rcols, int *ccnt) {
369
+ volatile VALUE v;
370
+ StrLen cp;
371
+ StrLen cols;
372
+ int i;
373
+ int cnt = (int)RARRAY_LEN(rcols);
374
+
364
375
  *ccnt = cnt;
365
- cols = ALLOC_N(struct _StrLen, cnt);
376
+ cols = ALLOC_N(struct _strLen, cnt);
366
377
  for (i = 0, cp = cols; i < cnt; i++, cp++) {
367
- v = rb_ary_entry(rcols, i);
368
- if (T_STRING != rb_type(v)) {
369
- v = rb_funcall(v, oj_to_s_id, 0);
370
- }
371
- cp->str = StringValuePtr(v);
372
- cp->len = (int)RSTRING_LEN(v);
378
+ v = RARRAY_AREF(rcols, i);
379
+ if (T_STRING != rb_type(v)) {
380
+ v = rb_funcall(v, oj_to_s_id, 0);
381
+ }
382
+ cp->str = StringValuePtr(v);
383
+ cp->len = (int)RSTRING_LEN(v);
373
384
  }
374
385
  return cols;
375
386
  }
376
387
 
377
- static void
378
- dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
379
- size_t size;
380
- int d2 = depth + 1;
381
- int i;
382
-
388
+ static void dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
389
+ size_t size;
390
+ int d2 = depth + 1;
391
+ int i;
392
+
383
393
  assure_size(out, 2);
384
394
  *out->cur++ = '{';
385
- size = depth * out->indent + 3;
395
+ size = depth * out->indent + 3;
386
396
  for (i = 0; i < ccnt; i++, cols++) {
387
- assure_size(out, size);
388
- if (out->opts->dump_opts.use) {
389
- if (0 < out->opts->dump_opts.array_size) {
390
- strcpy(out->cur, out->opts->dump_opts.array_nl);
391
- out->cur += out->opts->dump_opts.array_size;
392
- }
393
- if (0 < out->opts->dump_opts.indent_size) {
394
- int i;
395
- for (i = d2; 0 < i; i--) {
396
- strcpy(out->cur, out->opts->dump_opts.indent_str);
397
- out->cur += out->opts->dump_opts.indent_size;
398
- }
399
- }
400
- } else {
401
- fill_indent(out, d2);
402
- }
403
- oj_dump_cstr(cols->str, cols->len, 0, 0, out);
404
- *out->cur++ = ':';
405
- dump_rails_val(rb_ary_entry(row, i), depth, out, true);
406
- if (i < ccnt - 1) {
407
- *out->cur++ = ',';
408
- }
397
+ assure_size(out, size);
398
+ if (out->opts->dump_opts.use) {
399
+ if (0 < out->opts->dump_opts.array_size) {
400
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
401
+ }
402
+ if (0 < out->opts->dump_opts.indent_size) {
403
+ int i;
404
+ for (i = d2; 0 < i; i--) {
405
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
406
+ }
407
+ }
408
+ } else {
409
+ fill_indent(out, d2);
410
+ }
411
+ oj_dump_cstr(cols->str, cols->len, 0, 0, out);
412
+ *out->cur++ = ':';
413
+ dump_rails_val(RARRAY_AREF(row, i), depth, out, true);
414
+ if (i < ccnt - 1) {
415
+ *out->cur++ = ',';
416
+ }
409
417
  }
410
418
  size = depth * out->indent + 1;
411
419
  assure_size(out, size);
412
420
  if (out->opts->dump_opts.use) {
413
- if (0 < out->opts->dump_opts.array_size) {
414
- strcpy(out->cur, out->opts->dump_opts.array_nl);
415
- out->cur += out->opts->dump_opts.array_size;
416
- }
417
- if (0 < out->opts->dump_opts.indent_size) {
418
- int i;
419
-
420
- for (i = depth; 0 < i; i--) {
421
- strcpy(out->cur, out->opts->dump_opts.indent_str);
422
- out->cur += out->opts->dump_opts.indent_size;
423
- }
424
- }
421
+ if (0 < out->opts->dump_opts.array_size) {
422
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
423
+ }
424
+ if (0 < out->opts->dump_opts.indent_size) {
425
+ int i;
426
+
427
+ for (i = depth; 0 < i; i--) {
428
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
429
+ }
430
+ }
425
431
  } else {
426
- fill_indent(out, depth);
432
+ fill_indent(out, depth);
427
433
  }
428
434
  *out->cur++ = '}';
429
435
  }
430
436
 
431
- static ID rows_id = 0;
432
- static ID columns_id = 0;
433
-
434
- static void
435
- dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok) {
436
- volatile VALUE rows;
437
- StrLen cols;
438
- int ccnt = 0;
439
- int i, rcnt;
440
- size_t size;
441
- int d2 = depth + 1;
442
-
437
+ static ID rows_id = 0;
438
+ static ID columns_id = 0;
439
+
440
+ static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok) {
441
+ volatile VALUE rows;
442
+ StrLen cols;
443
+ int ccnt = 0;
444
+ int i, rcnt;
445
+ size_t size;
446
+ int d2 = depth + 1;
447
+
443
448
  if (0 == rows_id) {
444
- rows_id = rb_intern("@rows");
445
- columns_id = rb_intern("@columns");
449
+ rows_id = rb_intern("@rows");
450
+ columns_id = rb_intern("@columns");
446
451
  }
447
452
  out->argc = 0;
448
- cols = columns_array(rb_ivar_get(obj, columns_id), &ccnt);
449
- rows = rb_ivar_get(obj, rows_id);
450
- rcnt = (int)RARRAY_LEN(rows);
453
+ cols = columns_array(rb_ivar_get(obj, columns_id), &ccnt);
454
+ rows = rb_ivar_get(obj, rows_id);
455
+ rcnt = (int)RARRAY_LEN(rows);
451
456
  assure_size(out, 2);
452
457
  *out->cur++ = '[';
453
458
  if (out->opts->dump_opts.use) {
454
- size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
459
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
455
460
  } else {
456
- size = d2 * out->indent + 2;
461
+ size = d2 * out->indent + 2;
457
462
  }
458
463
  assure_size(out, 2);
459
464
  for (i = 0; i < rcnt; i++) {
460
- assure_size(out, size);
461
- if (out->opts->dump_opts.use) {
462
- if (0 < out->opts->dump_opts.array_size) {
463
- strcpy(out->cur, out->opts->dump_opts.array_nl);
464
- out->cur += out->opts->dump_opts.array_size;
465
- }
466
- if (0 < out->opts->dump_opts.indent_size) {
467
- int i;
468
- for (i = d2; 0 < i; i--) {
469
- strcpy(out->cur, out->opts->dump_opts.indent_str);
470
- out->cur += out->opts->dump_opts.indent_size;
471
- }
472
- }
473
- } else {
474
- fill_indent(out, d2);
475
- }
476
- dump_row(rb_ary_entry(rows, i), cols, ccnt, d2, out);
477
- if (i < rcnt - 1) {
478
- *out->cur++ = ',';
479
- }
465
+ assure_size(out, size);
466
+ if (out->opts->dump_opts.use) {
467
+ if (0 < out->opts->dump_opts.array_size) {
468
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
469
+ }
470
+ if (0 < out->opts->dump_opts.indent_size) {
471
+ int i;
472
+ for (i = d2; 0 < i; i--) {
473
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
474
+ }
475
+ }
476
+ } else {
477
+ fill_indent(out, d2);
478
+ }
479
+ dump_row(RARRAY_AREF(rows, i), cols, ccnt, d2, out);
480
+ if (i < rcnt - 1) {
481
+ *out->cur++ = ',';
482
+ }
480
483
  }
481
484
  xfree(cols);
482
485
  size = depth * out->indent + 1;
483
486
  assure_size(out, size);
484
487
  if (out->opts->dump_opts.use) {
485
- if (0 < out->opts->dump_opts.array_size) {
486
- strcpy(out->cur, out->opts->dump_opts.array_nl);
487
- out->cur += out->opts->dump_opts.array_size;
488
- }
489
- if (0 < out->opts->dump_opts.indent_size) {
490
- int i;
491
-
492
- for (i = depth; 0 < i; i--) {
493
- strcpy(out->cur, out->opts->dump_opts.indent_str);
494
- out->cur += out->opts->dump_opts.indent_size;
495
- }
496
- }
488
+ if (0 < out->opts->dump_opts.array_size) {
489
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
490
+ }
491
+ if (0 < out->opts->dump_opts.indent_size) {
492
+ int i;
493
+
494
+ for (i = depth; 0 < i; i--) {
495
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
496
+ }
497
+ }
497
498
  } else {
498
- fill_indent(out, depth);
499
+ fill_indent(out, depth);
499
500
  }
500
501
  *out->cur++ = ']';
501
502
  }
502
503
 
503
- typedef struct _NamedFunc {
504
- const char *name;
505
- DumpFunc func;
506
- } *NamedFunc;
504
+ typedef struct _namedFunc {
505
+ const char *name;
506
+ DumpFunc func;
507
+ } * NamedFunc;
507
508
 
508
- static void
509
- dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
509
+ static void dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
510
510
  if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
511
- out->argc = 0;
512
- return;
511
+ out->argc = 0;
512
+ return;
513
513
  }
514
514
  oj_dump_obj_to_s(obj, out);
515
515
  }
516
516
 
517
- static void
518
- dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
519
- volatile VALUE ja;
517
+ static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
518
+ volatile VALUE ja;
520
519
 
521
- if (Yes == out->opts->trace) {
522
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
520
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
521
+ oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
523
522
  }
524
523
  // Some classes elect to not take an options argument so check the arity
525
524
  // of as_json.
526
525
  if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
527
- ja = rb_funcall(obj, oj_as_json_id, 0);
526
+ ja = rb_funcall(obj, oj_as_json_id, 0);
528
527
  } else {
529
- ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
528
+ ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
530
529
  }
531
- if (Yes == out->opts->trace) {
532
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
530
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
531
+ oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
533
532
  }
534
533
 
535
534
  out->argc = 0;
536
535
  if (ja == obj || !as_ok) {
537
- // Once as_json is called it should never be called again on the same
538
- // object with as_ok.
539
- dump_rails_val(ja, depth, out, false);
536
+ // Once as_json is called it should never be called again on the same
537
+ // object with as_ok.
538
+ dump_rails_val(ja, depth, out, false);
540
539
  } else {
541
- int type = rb_type(ja);
540
+ int type = rb_type(ja);
542
541
 
543
- if (T_HASH == type || T_ARRAY == type) {
544
- dump_rails_val(ja, depth, out, true);
545
- } else {
546
- dump_rails_val(ja, depth, out, true);
547
- }
542
+ if (T_HASH == type || T_ARRAY == type) {
543
+ dump_rails_val(ja, depth, out, true);
544
+ } else {
545
+ dump_rails_val(ja, depth, out, true);
546
+ }
548
547
  }
549
548
  }
550
549
 
551
- static void
552
- dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
550
+ static void dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
553
551
  if (as_ok && rb_respond_to(obj, oj_as_json_id)) {
554
- dump_as_json(obj, depth, out, false);
555
- return;
552
+ dump_as_json(obj, depth, out, false);
553
+ return;
556
554
  }
557
555
  dump_as_string(obj, depth, out, as_ok);
558
556
  }
559
557
 
560
- static struct _NamedFunc dump_map[] = {
561
- { "ActionController::Parameters", dump_actioncontroller_parameters },
562
- { "ActiveRecord::Result", dump_activerecord_result },
563
- { "ActiveSupport::TimeWithZone", dump_timewithzone },
564
- { "BigDecimal", dump_bigdecimal },
565
- { "Range", dump_to_s },
566
- { "Regexp", dump_regexp },
558
+ static struct _namedFunc dump_map[] = {
559
+ {"ActionController::Parameters", dump_actioncontroller_parameters},
560
+ {"ActiveRecord::Result", dump_activerecord_result},
561
+ {"ActiveSupport::TimeWithZone", dump_timewithzone},
562
+ {"BigDecimal", dump_bigdecimal},
563
+ {"Range", dump_to_s},
564
+ {"Regexp", dump_regexp},
567
565
  //{ "Regexp", dump_to_s },
568
- { "Time", dump_time },
569
- { NULL, NULL },
566
+ {"Time", dump_time},
567
+ {NULL, NULL},
570
568
  };
571
569
 
572
- static VALUE activerecord_base = Qundef;
573
- static ID attributes_id = 0;
570
+ static VALUE activerecord_base = Qundef;
571
+ static ID attributes_id = 0;
574
572
 
575
- static void
576
- dump_activerecord(VALUE obj, int depth, Out out, bool as_ok) {
573
+ static void dump_activerecord(VALUE obj, int depth, Out out, bool as_ok) {
577
574
  if (0 == attributes_id) {
578
- attributes_id = rb_intern("@attributes");
575
+ attributes_id = rb_intern("@attributes");
579
576
  }
580
577
  out->argc = 0;
581
578
  dump_rails_val(rb_ivar_get(obj, attributes_id), depth, out, true);
582
579
  }
583
580
 
584
- static ROpt
585
- create_opt(ROptTable rot, VALUE clas) {
586
- ROpt ro;
587
- NamedFunc nf;
588
- const char *classname = rb_class2name(clas);
589
- int olen = rot->len;
581
+ static ROpt create_opt(ROptTable rot, VALUE clas) {
582
+ ROpt ro;
583
+ NamedFunc nf;
584
+ const char *classname = rb_class2name(clas);
585
+ int olen = rot->len;
590
586
 
591
587
  rot->len++;
592
588
  if (NULL == rot->table) {
593
- rot->alen = 256;
594
- rot->table = ALLOC_N(struct _ROpt, rot->alen);
595
- memset(rot->table, 0, sizeof(struct _ROpt) * rot->alen);
589
+ rot->alen = 256;
590
+ rot->table = ALLOC_N(struct _rOpt, rot->alen);
591
+ memset(rot->table, 0, sizeof(struct _rOpt) * rot->alen);
596
592
  } else if (rot->alen <= rot->len) {
597
- rot->alen *= 2;
598
- REALLOC_N(rot->table, struct _ROpt, rot->alen);
599
- memset(rot->table + olen, 0, sizeof(struct _ROpt) * olen);
593
+ rot->alen *= 2;
594
+ REALLOC_N(rot->table, struct _rOpt, rot->alen);
595
+ memset(rot->table + olen, 0, sizeof(struct _rOpt) * olen);
600
596
  }
601
597
  if (0 == olen) {
602
- ro = rot->table;
598
+ ro = rot->table;
603
599
  } else if (rot->table[olen - 1].clas < clas) {
604
- ro = &rot->table[olen];
600
+ ro = &rot->table[olen];
605
601
  } else {
606
- int i;
607
-
608
- for (i = 0, ro = rot->table; i < olen; i++, ro++) {
609
- if (clas < ro->clas) {
610
- memmove(ro + 1, ro, sizeof(struct _ROpt) * (olen - i));
611
- break;
612
- }
613
- }
602
+ int i;
603
+
604
+ for (i = 0, ro = rot->table; i < olen; i++, ro++) {
605
+ if (clas < ro->clas) {
606
+ memmove(ro + 1, ro, sizeof(struct _rOpt) * (olen - i));
607
+ break;
608
+ }
609
+ }
614
610
  }
615
611
  ro->clas = clas;
616
- ro->on = true;
612
+ ro->on = true;
617
613
  ro->dump = dump_obj_attrs;
618
614
  for (nf = dump_map; NULL != nf->name; nf++) {
619
- if (0 == strcmp(nf->name, classname)) {
620
- ro->dump = nf->func;
621
- break;
622
- }
615
+ if (0 == strcmp(nf->name, classname)) {
616
+ ro->dump = nf->func;
617
+ break;
618
+ }
623
619
  }
624
620
  if (ro->dump == dump_obj_attrs) {
625
- if (Qundef == activerecord_base) {
626
- // If not defined let an exception be raised.
627
- VALUE ar = rb_const_get_at(rb_cObject, rb_intern("ActiveRecord"));
628
-
629
- if (Qundef != ar) {
630
- activerecord_base = rb_const_get_at(ar, rb_intern("Base"));
631
- }
632
- }
633
- if (Qundef != activerecord_base && Qtrue == rb_class_inherited_p(clas, activerecord_base)) {
634
- ro->dump = dump_activerecord;
635
- } else if (Qtrue == rb_class_inherited_p(clas, rb_cStruct)) { // check before enumerable
636
- ro->dump = dump_struct;
637
- } else if (Qtrue == rb_class_inherited_p(clas, rb_mEnumerable)) {
638
- ro->dump = dump_enumerable;
639
- } else if (Qtrue == rb_class_inherited_p(clas, rb_eException)) {
640
- ro->dump = dump_to_s;
641
- }
642
- }
643
- return NULL;
621
+ if (Qundef == activerecord_base) {
622
+ // If not defined let an exception be raised.
623
+ VALUE ar = rb_const_get_at(rb_cObject, rb_intern("ActiveRecord"));
624
+
625
+ if (Qundef != ar) {
626
+ activerecord_base = rb_const_get_at(ar, rb_intern("Base"));
627
+ }
628
+ }
629
+ if (Qundef != activerecord_base && Qtrue == rb_class_inherited_p(clas, activerecord_base)) {
630
+ ro->dump = dump_activerecord;
631
+ } else if (Qtrue == rb_class_inherited_p(clas, rb_cStruct)) { // check before enumerable
632
+ ro->dump = dump_struct;
633
+ } else if (Qtrue == rb_class_inherited_p(clas, rb_mEnumerable)) {
634
+ ro->dump = dump_enumerable;
635
+ } else if (Qtrue == rb_class_inherited_p(clas, rb_eException)) {
636
+ ro->dump = dump_to_s;
637
+ }
638
+ }
639
+ return ro;
644
640
  }
645
641
 
646
- static void
647
- encoder_free(void *ptr) {
642
+ static void encoder_free(void *ptr) {
648
643
  if (NULL != ptr) {
649
- Encoder e = (Encoder)ptr;
644
+ Encoder e = (Encoder)ptr;
650
645
 
651
- if (NULL != e->ropts.table) {
652
- xfree(e->ropts.table);
653
- }
654
- xfree(ptr);
646
+ if (NULL != e->ropts.table) {
647
+ xfree(e->ropts.table);
648
+ }
649
+ xfree(ptr);
655
650
  }
656
651
  }
657
652
 
658
- static void
659
- encoder_mark(void *ptr) {
653
+ static void encoder_mark(void *ptr) {
660
654
  if (NULL != ptr) {
661
- Encoder e = (Encoder)ptr;
655
+ Encoder e = (Encoder)ptr;
662
656
 
663
- if (Qnil != e->arg) {
664
- rb_gc_mark(e->arg);
665
- }
657
+ if (Qnil != e->arg) {
658
+ rb_gc_mark(e->arg);
659
+ }
666
660
  }
667
661
  }
668
662
 
@@ -672,113 +666,111 @@ encoder_mark(void *ptr) {
672
666
  * Creates a new Encoder.
673
667
  * - *options* [_Hash_] formatting options
674
668
  */
675
- static VALUE
676
- encoder_new(int argc, VALUE *argv, VALUE self) {
677
- Encoder e = ALLOC(struct _Encoder);
669
+ static VALUE encoder_new(int argc, VALUE *argv, VALUE self) {
670
+ Encoder e = ALLOC(struct _encoder);
678
671
 
679
672
  e->opts = oj_default_options;
680
- e->arg = Qnil;
673
+ e->arg = Qnil;
681
674
  copy_opts(&ropts, &e->ropts);
682
-
675
+
683
676
  if (1 <= argc && Qnil != *argv) {
684
- oj_parse_options(*argv, &e->opts);
685
- e->arg = *argv;
677
+ oj_parse_options(*argv, &e->opts);
678
+ e->arg = *argv;
686
679
  }
687
680
  return Data_Wrap_Struct(encoder_class, encoder_mark, encoder_free, e);
688
681
  }
689
682
 
690
- static VALUE
691
- resolve_classpath(const char *name) {
692
- char class_name[1024];
693
- VALUE clas;
694
- char *end = class_name + sizeof(class_name) - 1;
695
- char *s;
696
- const char *n = name;
697
- ID cid;
683
+ static VALUE resolve_classpath(const char *name) {
684
+ char class_name[1024];
685
+ VALUE clas;
686
+ char * end = class_name + sizeof(class_name) - 1;
687
+ char * s;
688
+ const char *n = name;
689
+ ID cid;
698
690
 
699
691
  clas = rb_cObject;
700
692
  for (s = class_name; '\0' != *n; n++) {
701
- if (':' == *n) {
702
- *s = '\0';
703
- n++;
704
- if (':' != *n) {
705
- return Qnil;
706
- }
707
- cid = rb_intern(class_name);
708
- if (!rb_const_defined_at(clas, cid)) {
709
- return Qnil;
710
- }
711
- clas = rb_const_get_at(clas, cid);
712
- s = class_name;
713
- } else if (end <= s) {
714
- return Qnil;
715
- } else {
716
- *s++ = *n;
717
- }
718
- }
719
- *s = '\0';
693
+ if (':' == *n) {
694
+ *s = '\0';
695
+ n++;
696
+ if (':' != *n) {
697
+ return Qnil;
698
+ }
699
+ cid = rb_intern(class_name);
700
+ if (!rb_const_defined_at(clas, cid)) {
701
+ return Qnil;
702
+ }
703
+ clas = rb_const_get_at(clas, cid);
704
+ s = class_name;
705
+ } else if (end <= s) {
706
+ return Qnil;
707
+ } else {
708
+ *s++ = *n;
709
+ }
710
+ }
711
+ *s = '\0';
720
712
  cid = rb_intern(class_name);
721
713
  if (!rb_const_defined_at(clas, cid)) {
722
- return Qnil;
714
+ return Qnil;
723
715
  }
724
716
  clas = rb_const_get_at(clas, cid);
725
717
 
726
718
  return clas;
727
719
  }
728
720
 
729
- static void
730
- optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
731
- ROpt ro;
721
+ static void optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
722
+ ROpt ro;
732
723
 
733
724
  if (0 == argc) {
734
- int i;
735
- NamedFunc nf;
736
- VALUE clas;
737
-
738
- oj_rails_hash_opt = on;
739
- oj_rails_array_opt = on;
740
- oj_rails_float_opt = on;
741
-
742
- for (nf = dump_map; NULL != nf->name; nf++) {
743
- if (Qnil != (clas = resolve_classpath(nf->name))) {
744
- if (NULL == oj_rails_get_opt(rot, clas)) {
745
- create_opt(rot, clas);
746
- }
747
- }
748
- }
749
- for (i = 0; i < rot->len; i++) {
750
- rot->table[i].on = on;
751
- }
725
+ int i;
726
+ NamedFunc nf;
727
+ VALUE clas;
728
+
729
+ oj_rails_hash_opt = on;
730
+ oj_rails_array_opt = on;
731
+ oj_rails_float_opt = on;
732
+
733
+ for (nf = dump_map; NULL != nf->name; nf++) {
734
+ if (Qnil != (clas = resolve_classpath(nf->name))) {
735
+ if (NULL == oj_rails_get_opt(rot, clas)) {
736
+ create_opt(rot, clas);
737
+ }
738
+ }
739
+ }
740
+ for (i = 0; i < rot->len; i++) {
741
+ rot->table[i].on = on;
742
+ }
752
743
  }
753
744
  for (; 0 < argc; argc--, argv++) {
754
- if (rb_cHash == *argv) {
755
- oj_rails_hash_opt = on;
756
- } else if (rb_cArray == *argv) {
757
- oj_rails_array_opt = on;
758
- } else if (rb_cFloat == *argv) {
759
- oj_rails_float_opt = on;
760
- } else if (NULL != (ro = oj_rails_get_opt(rot, *argv)) ||
761
- NULL != (ro = create_opt(rot, *argv))) {
762
- ro->on = on;
763
- }
745
+ if (rb_cHash == *argv) {
746
+ oj_rails_hash_opt = on;
747
+ } else if (rb_cArray == *argv) {
748
+ oj_rails_array_opt = on;
749
+ } else if (rb_cFloat == *argv) {
750
+ oj_rails_float_opt = on;
751
+ } else if (oj_string_writer_class == *argv) {
752
+ string_writer_optimized = on;
753
+ } else if (NULL != (ro = oj_rails_get_opt(rot, *argv)) ||
754
+ NULL != (ro = create_opt(rot, *argv))) {
755
+ ro->on = on;
756
+ }
764
757
  }
765
758
  }
766
759
 
767
760
  /* Document-method optimize
768
761
  * call-seq: optimize(*classes)
769
- *
762
+ *
770
763
  * Use Oj rails optimized routines to encode the specified classes. This
771
764
  * ignores the as_json() method on the class and uses an internal encoding
772
765
  * instead. Passing in no classes indicates all should use the optimized
773
766
  * version of encoding for all previously optimized classes. Passing in the
774
767
  * Object class set a global switch that will then use the optimized behavior
775
768
  * for all classes.
776
- *
769
+ *
777
770
  * - *classes* [_Class_] a list of classes to optimize
778
771
  */
779
- static VALUE
780
- encoder_optimize(int argc, VALUE *argv, VALUE self) {
781
- Encoder e = (Encoder)DATA_PTR(self);
772
+ static VALUE encoder_optimize(int argc, VALUE *argv, VALUE self) {
773
+ Encoder e = (Encoder)DATA_PTR(self);
782
774
 
783
775
  optimize(argc, argv, &e->ropts, true);
784
776
 
@@ -787,19 +779,19 @@ encoder_optimize(int argc, VALUE *argv, VALUE self) {
787
779
 
788
780
  /* Document-method: optimize
789
781
  * call-seq: optimize(*classes)
790
- *
782
+ *
791
783
  * Use Oj rails optimized routines to encode the specified classes. This
792
784
  * ignores the as_json() method on the class and uses an internal encoding
793
785
  * instead. Passing in no classes indicates all should use the optimized
794
786
  * version of encoding for all previously optimized classes. Passing in the
795
787
  * Object class set a global switch that will then use the optimized behavior
796
788
  * for all classes.
797
- *
789
+ *
798
790
  * - *classes* [_Class_] a list of classes to optimize
799
791
  */
800
- static VALUE
801
- rails_optimize(int argc, VALUE *argv, VALUE self) {
792
+ static VALUE rails_optimize(int argc, VALUE *argv, VALUE self) {
802
793
  optimize(argc, argv, &ropts, true);
794
+ string_writer_optimized = true;
803
795
 
804
796
  return Qnil;
805
797
  }
@@ -812,14 +804,15 @@ rails_optimize(int argc, VALUE *argv, VALUE self) {
812
804
  */
813
805
  VALUE
814
806
  rails_mimic_json(VALUE self) {
815
- VALUE json;
816
-
807
+ VALUE json;
808
+
817
809
  if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
818
- json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
810
+ json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
819
811
  } else {
820
- json = rb_define_module("JSON");
812
+ json = rb_define_module("JSON");
821
813
  }
822
814
  oj_mimic_json_methods(json);
815
+ // Setting the default mode breaks the prmoise in the docs not to.
823
816
  //oj_default_options.mode = RailsMode;
824
817
 
825
818
  return Qnil;
@@ -827,14 +820,13 @@ rails_mimic_json(VALUE self) {
827
820
 
828
821
  /* Document-method: deoptimize
829
822
  * call-seq: deoptimize(*classes)
830
- *
823
+ *
831
824
  * Turn off Oj rails optimization on the specified classes.
832
825
  *
833
826
  * - *classes* [_Class_] a list of classes to deoptimize
834
827
  */
835
- static VALUE
836
- encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
837
- Encoder e = (Encoder)DATA_PTR(self);
828
+ static VALUE encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
829
+ Encoder e = (Encoder)DATA_PTR(self);
838
830
 
839
831
  optimize(argc, argv, &e->ropts, false);
840
832
 
@@ -843,182 +835,172 @@ encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
843
835
 
844
836
  /* Document-method: deoptimize
845
837
  * call-seq: deoptimize(*classes)
846
- *
838
+ *
847
839
  * Turn off Oj rails optimization on the specified classes.
848
840
  *
849
841
  * - *classes* [_Class_] a list of classes to deoptimize
850
842
  */
851
- static VALUE
852
- rails_deoptimize(int argc, VALUE *argv, VALUE self) {
843
+ static VALUE rails_deoptimize(int argc, VALUE *argv, VALUE self) {
853
844
  optimize(argc, argv, &ropts, false);
845
+ string_writer_optimized = false;
854
846
 
855
847
  return Qnil;
856
848
  }
857
849
 
858
850
  /* Document-method:optimized?
859
851
  * call-seq: optimized?(clas)
860
- *
852
+ *
861
853
  * - *clas* [_Class_] Class to check
862
854
  *
863
855
  * @return true if the class is being optimized for rails and false otherwise
864
856
  */
865
- static VALUE
866
- encoder_optimized(VALUE self, VALUE clas) {
867
- Encoder e = (Encoder)DATA_PTR(self);
868
- ROpt ro = oj_rails_get_opt(&e->ropts, clas);
857
+ static VALUE encoder_optimized(VALUE self, VALUE clas) {
858
+ Encoder e = (Encoder)DATA_PTR(self);
859
+ ROpt ro = oj_rails_get_opt(&e->ropts, clas);
869
860
 
870
861
  if (NULL == ro) {
871
- return Qfalse;
862
+ return Qfalse;
872
863
  }
873
864
  return (ro->on) ? Qtrue : Qfalse;
874
865
  }
875
866
 
876
867
  /* Document-method: optimized?
877
868
  * call-seq: optimized?(clas)
878
- *
869
+ *
879
870
  * Returns true if the specified Class is being optimized.
880
871
  */
881
- static VALUE
882
- rails_optimized(VALUE self, VALUE clas) {
883
- ROpt ro = oj_rails_get_opt(&ropts, clas);
872
+ static VALUE rails_optimized(VALUE self, VALUE clas) {
873
+ ROpt ro = oj_rails_get_opt(&ropts, clas);
884
874
 
885
875
  if (NULL == ro) {
886
- return Qfalse;
876
+ return Qfalse;
887
877
  }
888
878
  return (ro->on) ? Qtrue : Qfalse;
889
879
  }
890
880
 
891
- typedef struct _OO {
892
- Out out;
893
- VALUE obj;
894
- } *OO;
881
+ typedef struct _oo {
882
+ Out out;
883
+ VALUE obj;
884
+ } * OO;
895
885
 
896
- static VALUE
897
- protect_dump(VALUE ov) {
898
- OO oo = (OO)ov;
886
+ static VALUE protect_dump(VALUE ov) {
887
+ OO oo = (OO)ov;
899
888
 
900
889
  dump_rails_val(oo->obj, 0, oo->out, true);
901
890
 
902
891
  return Qnil;
903
892
  }
904
893
 
905
- static VALUE
906
- encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) {
907
- char buf[4096];
908
- struct _Out out;
909
- struct _Options copts = *opts;
910
- volatile VALUE rstr = Qnil;
911
- struct _OO oo;
912
- int line = 0;
913
-
914
- oo.out = &out;
915
- oo.obj = obj;
894
+ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) {
895
+ struct _out out;
896
+ struct _options copts = *opts;
897
+ volatile VALUE rstr = Qnil;
898
+ struct _oo oo;
899
+ int line = 0;
900
+
901
+ oo.out = &out;
902
+ oo.obj = obj;
916
903
  copts.str_rx.head = NULL;
917
904
  copts.str_rx.tail = NULL;
918
- copts.mode = RailsMode;
905
+ copts.mode = RailsMode;
919
906
  if (escape_html) {
920
- copts.escape_mode = JXEsc;
907
+ copts.escape_mode = RailsXEsc;
921
908
  } else {
922
- copts.escape_mode = RailsEsc;
923
- }
924
- out.buf = buf;
925
- out.end = buf + sizeof(buf) - 10;
926
- out.allocated = false;
927
- out.omit_nil = copts.dump_opts.omit_nil;
928
- out.caller = 0;
929
- out.cur = out.buf;
930
- out.circ_cnt = 0;
931
- out.opts = &copts;
932
- out.hash_cnt = 0;
933
- out.indent = copts.indent;
934
- out.argc = argc;
935
- out.argv = argv;
936
- out.ropts = ropts;
909
+ copts.escape_mode = RailsEsc;
910
+ }
911
+
912
+ oj_out_init(&out);
913
+
914
+ out.omit_nil = copts.dump_opts.omit_nil;
915
+ out.caller = 0;
916
+ out.cur = out.buf;
917
+ out.circ_cnt = 0;
918
+ out.opts = &copts;
919
+ out.hash_cnt = 0;
920
+ out.indent = copts.indent;
921
+ out.argc = argc;
922
+ out.argv = argv;
923
+ out.ropts = ropts;
937
924
  if (Yes == copts.circular) {
938
- oj_cache8_new(&out.circ_cache);
925
+ oj_cache8_new(&out.circ_cache);
939
926
  }
940
- //dump_rails_val(*argv, 0, &out, true);
927
+ // dump_rails_val(*argv, 0, &out, true);
941
928
  rb_protect(protect_dump, (VALUE)&oo, &line);
942
929
 
943
930
  if (0 == line) {
944
- if (0 < out.indent) {
945
- switch (*(out.cur - 1)) {
946
- case ']':
947
- case '}':
948
- assure_size(&out, 2);
949
- *out.cur++ = '\n';
950
- default:
951
- break;
952
- }
953
- }
954
- *out.cur = '\0';
955
-
956
- if (0 == out.buf) {
957
- rb_raise(rb_eNoMemError, "Not enough memory.");
958
- }
959
- rstr = rb_str_new2(out.buf);
960
- rstr = oj_encode(rstr);
931
+ if (0 < out.indent) {
932
+ switch (*(out.cur - 1)) {
933
+ case ']':
934
+ case '}': assure_size(&out, 2); *out.cur++ = '\n';
935
+ default: break;
936
+ }
937
+ }
938
+ *out.cur = '\0';
939
+
940
+ if (0 == out.buf) {
941
+ rb_raise(rb_eNoMemError, "Not enough memory.");
942
+ }
943
+ rstr = rb_str_new2(out.buf);
944
+ rstr = oj_encode(rstr);
961
945
  }
962
946
  if (Yes == copts.circular) {
963
- oj_cache8_delete(out.circ_cache);
964
- }
965
- if (out.allocated) {
966
- xfree(out.buf);
947
+ oj_cache8_delete(out.circ_cache);
967
948
  }
949
+
950
+ oj_out_free(&out);
951
+
968
952
  if (0 != line) {
969
- rb_jump_tag(line);
953
+ rb_jump_tag(line);
970
954
  }
971
955
  return rstr;
972
956
  }
973
957
 
974
958
  /* Document-method: encode
975
959
  * call-seq: encode(obj)
976
- *
960
+ *
977
961
  * - *obj* [_Object_] object to encode
978
962
  *
979
963
  * Returns encoded object as a JSON string.
980
964
  */
981
- static VALUE
982
- encoder_encode(VALUE self, VALUE obj) {
983
- Encoder e = (Encoder)DATA_PTR(self);
965
+ static VALUE encoder_encode(VALUE self, VALUE obj) {
966
+ Encoder e = (Encoder)DATA_PTR(self);
984
967
 
985
968
  if (Qnil != e->arg) {
986
- VALUE argv[1] = { e->arg };
987
-
988
- return encode(obj, &e->ropts, &e->opts, 1, argv);
969
+ VALUE argv[1] = {e->arg};
970
+
971
+ return encode(obj, &e->ropts, &e->opts, 1, argv);
989
972
  }
990
973
  return encode(obj, &e->ropts, &e->opts, 0, NULL);
991
974
  }
992
975
 
993
976
  /* Document-method: encode
994
977
  * call-seq: encode(obj, opts=nil)
995
- *
978
+ *
996
979
  * Encode obj as a JSON String.
997
- *
980
+ *
998
981
  * - *obj* [_Object_|Hash|Array] object to convert to a JSON String
999
982
  * - *opts* [_Hash_] options
1000
983
  *
1001
984
  * Returns [_String_]
1002
985
  */
1003
- static VALUE
1004
- rails_encode(int argc, VALUE *argv, VALUE self) {
986
+ static VALUE rails_encode(int argc, VALUE *argv, VALUE self) {
1005
987
  if (1 > argc) {
1006
- rb_raise(rb_eArgError, "wrong number of arguments (0 for 1).");
988
+ rb_raise(rb_eArgError, "wrong number of arguments (0 for 1).");
1007
989
  }
1008
990
  if (1 == argc) {
1009
- return encode(*argv, NULL, &oj_default_options, 0, NULL);
991
+ return encode(*argv, NULL, &oj_default_options, 0, NULL);
1010
992
  } else {
1011
- return encode(*argv, NULL, &oj_default_options, argc - 1, argv + 1);
993
+ return encode(*argv, NULL, &oj_default_options, argc - 1, argv + 1);
1012
994
  }
1013
995
  }
1014
996
 
1015
- static VALUE
1016
- rails_use_standard_json_time_format(VALUE self, VALUE state) {
997
+ static VALUE rails_use_standard_json_time_format(VALUE self, VALUE state) {
1017
998
  if (Qtrue == state || Qfalse == state) {
999
+ // no change needed
1018
1000
  } else if (Qnil == state) {
1019
- state = Qfalse;
1001
+ state = Qfalse;
1020
1002
  } else {
1021
- state = Qtrue;
1003
+ state = Qtrue;
1022
1004
  }
1023
1005
  rb_iv_set(self, "@use_standard_json_time_format", state);
1024
1006
  xml_time = Qtrue == state;
@@ -1026,45 +1008,56 @@ rails_use_standard_json_time_format(VALUE self, VALUE state) {
1026
1008
  return state;
1027
1009
  }
1028
1010
 
1029
- static VALUE
1030
- rails_escape_html_entities_in_json(VALUE self, VALUE state) {
1011
+ static VALUE rails_use_standard_json_time_format_get(VALUE self) {
1012
+ return xml_time ? Qtrue : Qfalse;
1013
+ }
1014
+
1015
+ static VALUE rails_escape_html_entities_in_json(VALUE self, VALUE state) {
1031
1016
  rb_iv_set(self, "@escape_html_entities_in_json", state);
1032
1017
  escape_html = Qtrue == state;
1033
1018
 
1034
1019
  return state;
1035
1020
  }
1036
1021
 
1037
- static VALUE
1038
- rails_time_precision(VALUE self, VALUE prec) {
1022
+ static VALUE rails_escape_html_entities_in_json_get(VALUE self) {
1023
+ return escape_html ? Qtrue : Qfalse;
1024
+ }
1025
+
1026
+ static VALUE rails_time_precision(VALUE self, VALUE prec) {
1039
1027
  rb_iv_set(self, "@time_precision", prec);
1040
- oj_default_options.sec_prec = NUM2INT(prec);
1028
+ oj_default_options.sec_prec = NUM2INT(prec);
1029
+ oj_default_options.sec_prec_set = true;
1041
1030
 
1042
1031
  return prec;
1043
1032
  }
1044
1033
 
1045
1034
  /* Document-method: set_encoder
1046
1035
  * call-seq: set_encoder()
1047
- *
1036
+ *
1048
1037
  * Sets the ActiveSupport.encoder to Oj::Rails::Encoder and wraps some of the
1049
1038
  * formatting globals used by ActiveSupport to allow the use of those globals
1050
1039
  * in the Oj::Rails optimizations.
1051
1040
  */
1052
- static VALUE
1053
- rails_set_encoder(VALUE self) {
1054
- VALUE active;
1055
- VALUE json;
1056
- VALUE encoding;
1057
- VALUE pv;
1058
- VALUE verbose;
1059
-
1041
+ static VALUE rails_set_encoder(VALUE self) {
1042
+ VALUE active;
1043
+ VALUE json;
1044
+ VALUE encoding;
1045
+ VALUE pv;
1046
+ VALUE verbose;
1047
+ VALUE enc = resolve_classpath("ActiveSupport::JSON::Encoding");
1048
+
1049
+ if (Qnil != enc) {
1050
+ escape_html = Qtrue == rb_iv_get(self, "@escape_html_entities_in_json");
1051
+ xml_time = Qtrue == rb_iv_get(enc, "@use_standard_json_time_format");
1052
+ }
1060
1053
  if (rb_const_defined_at(rb_cObject, rb_intern("ActiveSupport"))) {
1061
- active = rb_const_get_at(rb_cObject, rb_intern("ActiveSupport"));
1054
+ active = rb_const_get_at(rb_cObject, rb_intern("ActiveSupport"));
1062
1055
  } else {
1063
- rb_raise(rb_eStandardError, "ActiveSupport not loaded.");
1056
+ rb_raise(rb_eStandardError, "ActiveSupport not loaded.");
1064
1057
  }
1065
1058
  rb_funcall(active, rb_intern("json_encoder="), 1, encoder_class);
1066
1059
 
1067
- json = rb_const_get_at(active, rb_intern("JSON"));
1060
+ json = rb_const_get_at(active, rb_intern("JSON"));
1068
1061
  encoding = rb_const_get_at(json, rb_intern("Encoding"));
1069
1062
 
1070
1063
  // rb_undef_method doesn't work for modules or maybe sometimes
@@ -1072,13 +1065,32 @@ rails_set_encoder(VALUE self) {
1072
1065
  verbose = rb_gv_get("$VERBOSE");
1073
1066
  rb_gv_set("$VERBOSE", Qfalse);
1074
1067
  rb_undef_method(encoding, "use_standard_json_time_format=");
1075
- rb_define_module_function(encoding, "use_standard_json_time_format=", rails_use_standard_json_time_format, 1);
1076
-
1068
+ rb_define_module_function(encoding,
1069
+ "use_standard_json_time_format=",
1070
+ rails_use_standard_json_time_format,
1071
+ 1);
1072
+ rb_undef_method(encoding, "use_standard_json_time_format");
1073
+ rb_define_module_function(encoding,
1074
+ "use_standard_json_time_format",
1075
+ rails_use_standard_json_time_format_get,
1076
+ 0);
1077
+
1078
+ pv = rb_iv_get(encoding, "@escape_html_entities_in_json");
1079
+ escape_html = Qtrue == pv;
1077
1080
  rb_undef_method(encoding, "escape_html_entities_in_json=");
1078
- rb_define_module_function(encoding, "escape_html_entities_in_json=", rails_escape_html_entities_in_json, 1);
1079
-
1080
- pv = rb_iv_get(encoding, "@time_precision");
1081
- oj_default_options.sec_prec = NUM2INT(pv);
1081
+ rb_define_module_function(encoding,
1082
+ "escape_html_entities_in_json=",
1083
+ rails_escape_html_entities_in_json,
1084
+ 1);
1085
+ rb_undef_method(encoding, "escape_html_entities_in_json");
1086
+ rb_define_module_function(encoding,
1087
+ "escape_html_entities_in_json",
1088
+ rails_escape_html_entities_in_json_get,
1089
+ 0);
1090
+
1091
+ pv = rb_iv_get(encoding, "@time_precision");
1092
+ oj_default_options.sec_prec = NUM2INT(pv);
1093
+ oj_default_options.sec_prec_set = true;
1082
1094
  rb_undef_method(encoding, "time_precision=");
1083
1095
  rb_define_module_function(encoding, "time_precision=", rails_time_precision, 1);
1084
1096
  rb_gv_set("$VERBOSE", verbose);
@@ -1092,16 +1104,15 @@ rails_set_encoder(VALUE self) {
1092
1104
  * Sets the JSON.parse function to be the Oj::parse function which is json gem
1093
1105
  * compatible.
1094
1106
  */
1095
- static VALUE
1096
- rails_set_decoder(VALUE self) {
1097
- VALUE json;
1098
- VALUE json_error;
1099
- VALUE verbose;
1100
-
1107
+ static VALUE rails_set_decoder(VALUE self) {
1108
+ VALUE json;
1109
+ VALUE json_error;
1110
+ VALUE verbose;
1111
+
1101
1112
  if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
1102
- json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
1113
+ json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
1103
1114
  } else {
1104
- json = rb_define_module("JSON");
1115
+ json = rb_define_module("JSON");
1105
1116
  }
1106
1117
  if (rb_const_defined_at(json, rb_intern("JSONError"))) {
1107
1118
  json_error = rb_const_get(json, rb_intern("JSONError"));
@@ -1111,7 +1122,7 @@ rails_set_decoder(VALUE self) {
1111
1122
  if (rb_const_defined_at(json, rb_intern("ParserError"))) {
1112
1123
  oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError"));
1113
1124
  } else {
1114
- oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error);
1125
+ oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error);
1115
1126
  }
1116
1127
  // rb_undef_method doesn't work for modules or maybe sometimes
1117
1128
  // doesn't. Anyway setting verbose should hide the warning.
@@ -1120,7 +1131,7 @@ rails_set_decoder(VALUE self) {
1120
1131
  rb_undef_method(json, "parse");
1121
1132
  rb_define_module_function(json, "parse", oj_mimic_parse, -1);
1122
1133
  rb_gv_set("$VERBOSE", verbose);
1123
-
1134
+
1124
1135
  return Qnil;
1125
1136
  }
1126
1137
 
@@ -1140,20 +1151,22 @@ oj_optimize_rails(VALUE self) {
1140
1151
  }
1141
1152
 
1142
1153
  /* Document-module: Oj::Rails
1143
- *
1154
+ *
1144
1155
  * Module that provides rails and active support compatibility.
1145
1156
  */
1146
1157
  /* Document-class: Oj::Rails::Encoder
1147
1158
  *
1148
1159
  * The Oj ActiveSupport compliant encoder.
1149
1160
  */
1150
- void
1151
- oj_mimic_rails_init() {
1152
- VALUE rails = rb_define_module_under(Oj, "Rails");
1153
-
1161
+ void oj_mimic_rails_init(void) {
1162
+ VALUE rails = rb_define_module_under(Oj, "Rails");
1163
+
1154
1164
  rb_define_module_function(rails, "encode", rails_encode, -1);
1155
1165
 
1156
1166
  encoder_class = rb_define_class_under(rails, "Encoder", rb_cObject);
1167
+ rb_gc_register_address(&encoder_class);
1168
+ rb_undef_alloc_func(encoder_class);
1169
+
1157
1170
  rb_define_module_function(encoder_class, "new", encoder_new, -1);
1158
1171
  rb_define_module_function(rails, "optimize", rails_optimize, -1);
1159
1172
  rb_define_module_function(rails, "deoptimize", rails_deoptimize, -1);
@@ -1169,321 +1182,318 @@ oj_mimic_rails_init() {
1169
1182
  rb_define_method(encoder_class, "optimized?", encoder_optimized, 1);
1170
1183
  }
1171
1184
 
1172
- static void
1173
- dump_to_hash(VALUE obj, int depth, Out out) {
1185
+ static void dump_to_hash(VALUE obj, int depth, Out out) {
1174
1186
  dump_rails_val(rb_funcall(obj, oj_to_hash_id, 0), depth, out, true);
1175
1187
  }
1176
1188
 
1177
- static void
1178
- dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1179
- char buf[64];
1180
- char *b;
1181
- double d = rb_num2dbl(obj);
1182
- int cnt = 0;
1189
+ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1190
+ char buf[64];
1191
+ char * b;
1192
+ double d = rb_num2dbl(obj);
1193
+ int cnt = 0;
1183
1194
 
1184
1195
  if (0.0 == d) {
1185
- b = buf;
1186
- *b++ = '0';
1187
- *b++ = '.';
1188
- *b++ = '0';
1189
- *b++ = '\0';
1190
- cnt = 3;
1196
+ b = buf;
1197
+ *b++ = '0';
1198
+ *b++ = '.';
1199
+ *b++ = '0';
1200
+ *b++ = '\0';
1201
+ cnt = 3;
1191
1202
  } else {
1192
- if (isnan(d) || OJ_INFINITY == d || -OJ_INFINITY == d) {
1193
- strcpy(buf, "null");
1194
- cnt = 4;
1195
- } else if (d == (double)(long long int)d) {
1196
- cnt = snprintf(buf, sizeof(buf), "%.1f", d);
1197
- } else if (oj_rails_float_opt) {
1198
- cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
1199
- } else {
1200
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1201
-
1202
- strcpy(buf, rb_string_value_ptr((VALUE*)&rstr));
1203
- cnt = (int)RSTRING_LEN(rstr);
1204
- }
1203
+ if (isnan(d) || OJ_INFINITY == d || -OJ_INFINITY == d) {
1204
+ strcpy(buf, "null");
1205
+ cnt = 4;
1206
+ } else if (d == (double)(long long int)d) {
1207
+ cnt = snprintf(buf, sizeof(buf), "%.1f", d);
1208
+ } else if (oj_rails_float_opt) {
1209
+ cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
1210
+ } else {
1211
+ volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1212
+
1213
+ strcpy(buf, RSTRING_PTR(rstr));
1214
+ cnt = (int)RSTRING_LEN(rstr);
1215
+ }
1205
1216
  }
1206
1217
  assure_size(out, cnt);
1207
1218
  for (b = buf; '\0' != *b; b++) {
1208
- *out->cur++ = *b;
1219
+ *out->cur++ = *b;
1209
1220
  }
1210
1221
  *out->cur = '\0';
1211
1222
  }
1212
1223
 
1213
- static void
1214
- dump_array(VALUE a, int depth, Out out, bool as_ok) {
1215
- size_t size;
1216
- int i, cnt;
1217
- int d2 = depth + 1;
1224
+ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
1225
+ size_t size;
1226
+ int i, cnt;
1227
+ int d2 = depth + 1;
1218
1228
 
1219
1229
  if (Yes == out->opts->circular) {
1220
- if (0 > oj_check_circular(a, out)) {
1221
- oj_dump_nil(Qnil, 0, out, false);
1222
- return;
1223
- }
1230
+ if (0 > oj_check_circular(a, out)) {
1231
+ oj_dump_nil(Qnil, 0, out, false);
1232
+ return;
1233
+ }
1224
1234
  }
1225
- //if (!oj_rails_array_opt && as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) {
1235
+ // if (!oj_rails_array_opt && as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) {
1226
1236
  if (as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) {
1227
- dump_as_json(a, depth, out, false);
1228
- return;
1237
+ dump_as_json(a, depth, out, false);
1238
+ return;
1229
1239
  }
1230
- cnt = (int)RARRAY_LEN(a);
1240
+ cnt = (int)RARRAY_LEN(a);
1231
1241
  *out->cur++ = '[';
1232
- size = 2;
1242
+ size = 2;
1233
1243
  assure_size(out, size);
1234
1244
  if (0 == cnt) {
1235
- *out->cur++ = ']';
1245
+ *out->cur++ = ']';
1236
1246
  } else {
1237
- if (out->opts->dump_opts.use) {
1238
- size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
1239
- } else {
1240
- size = d2 * out->indent + 2;
1241
- }
1242
- cnt--;
1243
- for (i = 0; i <= cnt; i++) {
1244
- assure_size(out, size);
1245
- if (out->opts->dump_opts.use) {
1246
- if (0 < out->opts->dump_opts.array_size) {
1247
- strcpy(out->cur, out->opts->dump_opts.array_nl);
1248
- out->cur += out->opts->dump_opts.array_size;
1249
- }
1250
- if (0 < out->opts->dump_opts.indent_size) {
1251
- int i;
1252
- for (i = d2; 0 < i; i--) {
1253
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1254
- out->cur += out->opts->dump_opts.indent_size;
1255
- }
1256
- }
1257
- } else {
1258
- fill_indent(out, d2);
1259
- }
1260
- dump_rails_val(rb_ary_entry(a, i), d2, out, true);
1261
- if (i < cnt) {
1262
- *out->cur++ = ',';
1263
- }
1264
- }
1265
- size = depth * out->indent + 1;
1266
- assure_size(out, size);
1267
- if (out->opts->dump_opts.use) {
1268
- if (0 < out->opts->dump_opts.array_size) {
1269
- strcpy(out->cur, out->opts->dump_opts.array_nl);
1270
- out->cur += out->opts->dump_opts.array_size;
1271
- }
1272
- if (0 < out->opts->dump_opts.indent_size) {
1273
- int i;
1274
-
1275
- for (i = depth; 0 < i; i--) {
1276
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1277
- out->cur += out->opts->dump_opts.indent_size;
1278
- }
1279
- }
1280
- } else {
1281
- fill_indent(out, depth);
1282
- }
1283
- *out->cur++ = ']';
1247
+ if (out->opts->dump_opts.use) {
1248
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
1249
+ } else {
1250
+ size = d2 * out->indent + 2;
1251
+ }
1252
+ assure_size(out, size * cnt);
1253
+ cnt--;
1254
+ for (i = 0; i <= cnt; i++) {
1255
+ if (out->opts->dump_opts.use) {
1256
+ if (0 < out->opts->dump_opts.array_size) {
1257
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
1258
+ }
1259
+ if (0 < out->opts->dump_opts.indent_size) {
1260
+ int i;
1261
+ for (i = d2; 0 < i; i--) {
1262
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1263
+ }
1264
+ }
1265
+ } else {
1266
+ fill_indent(out, d2);
1267
+ }
1268
+ dump_rails_val(RARRAY_AREF(a, i), d2, out, true);
1269
+ if (i < cnt) {
1270
+ *out->cur++ = ',';
1271
+ }
1272
+ }
1273
+ size = depth * out->indent + 1;
1274
+ assure_size(out, size);
1275
+ if (out->opts->dump_opts.use) {
1276
+ if (0 < out->opts->dump_opts.array_size) {
1277
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
1278
+ }
1279
+ if (0 < out->opts->dump_opts.indent_size) {
1280
+ int i;
1281
+
1282
+ for (i = depth; 0 < i; i--) {
1283
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1284
+ }
1285
+ }
1286
+ } else {
1287
+ fill_indent(out, depth);
1288
+ }
1289
+ *out->cur++ = ']';
1284
1290
  }
1285
1291
  *out->cur = '\0';
1286
1292
  }
1287
1293
 
1288
- static int
1289
- hash_cb(VALUE key, VALUE value, Out out) {
1290
- int depth = out->depth;
1291
- long size;
1292
- int rtype = rb_type(key);
1293
-
1294
+ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
1295
+ Out out = (Out)ov;
1296
+ int depth = out->depth;
1297
+ long size;
1298
+ int rtype = rb_type(key);
1299
+
1300
+ if (out->omit_nil && Qnil == value) {
1301
+ return ST_CONTINUE;
1302
+ }
1294
1303
  if (rtype != T_STRING && rtype != T_SYMBOL) {
1295
- key = rb_funcall(key, oj_to_s_id, 0);
1296
- rtype = rb_type(key);
1304
+ key = rb_funcall(key, oj_to_s_id, 0);
1305
+ rtype = rb_type(key);
1297
1306
  }
1298
1307
  if (!out->opts->dump_opts.use) {
1299
- size = depth * out->indent + 1;
1300
- assure_size(out, size);
1301
- fill_indent(out, depth);
1302
- if (rtype == T_STRING) {
1303
- oj_dump_str(key, 0, out, false);
1304
- } else {
1305
- oj_dump_sym(key, 0, out, false);
1306
- }
1307
- *out->cur++ = ':';
1308
+ size = depth * out->indent + 1;
1309
+ assure_size(out, size);
1310
+ fill_indent(out, depth);
1311
+ if (rtype == T_STRING) {
1312
+ oj_dump_str(key, 0, out, false);
1313
+ } else {
1314
+ oj_dump_sym(key, 0, out, false);
1315
+ }
1316
+ *out->cur++ = ':';
1308
1317
  } else {
1309
- size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1310
- assure_size(out, size);
1311
- if (0 < out->opts->dump_opts.hash_size) {
1312
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
1313
- out->cur += out->opts->dump_opts.hash_size;
1314
- }
1315
- if (0 < out->opts->dump_opts.indent_size) {
1316
- int i;
1317
- for (i = depth; 0 < i; i--) {
1318
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1319
- out->cur += out->opts->dump_opts.indent_size;
1320
- }
1321
- }
1322
- if (rtype == T_STRING) {
1323
- oj_dump_str(key, 0, out, false);
1324
- } else {
1325
- oj_dump_sym(key, 0, out, false);
1326
- }
1327
- size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
1328
- assure_size(out, size);
1329
- if (0 < out->opts->dump_opts.before_size) {
1330
- strcpy(out->cur, out->opts->dump_opts.before_sep);
1331
- out->cur += out->opts->dump_opts.before_size;
1332
- }
1333
- *out->cur++ = ':';
1334
- if (0 < out->opts->dump_opts.after_size) {
1335
- strcpy(out->cur, out->opts->dump_opts.after_sep);
1336
- out->cur += out->opts->dump_opts.after_size;
1337
- }
1318
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1319
+ assure_size(out, size);
1320
+ if (0 < out->opts->dump_opts.hash_size) {
1321
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
1322
+ }
1323
+ if (0 < out->opts->dump_opts.indent_size) {
1324
+ int i;
1325
+ for (i = depth; 0 < i; i--) {
1326
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1327
+ }
1328
+ }
1329
+ if (rtype == T_STRING) {
1330
+ oj_dump_str(key, 0, out, false);
1331
+ } else {
1332
+ oj_dump_sym(key, 0, out, false);
1333
+ }
1334
+ size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
1335
+ assure_size(out, size);
1336
+ if (0 < out->opts->dump_opts.before_size) {
1337
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
1338
+ }
1339
+ *out->cur++ = ':';
1340
+ if (0 < out->opts->dump_opts.after_size) {
1341
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
1342
+ }
1338
1343
  }
1339
1344
  dump_rails_val(value, depth, out, true);
1340
- out->depth = depth;
1345
+ out->depth = depth;
1341
1346
  *out->cur++ = ',';
1342
1347
 
1343
1348
  return ST_CONTINUE;
1344
1349
  }
1345
1350
 
1346
- static void
1347
- dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
1348
- int cnt;
1349
- size_t size;
1351
+ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
1352
+ int cnt;
1353
+ size_t size;
1350
1354
 
1351
1355
  if (Yes == out->opts->circular) {
1352
- if (0 > oj_check_circular(obj, out)) {
1353
- oj_dump_nil(Qnil, 0, out, false);
1354
- return;
1355
- }
1356
+ if (0 > oj_check_circular(obj, out)) {
1357
+ oj_dump_nil(Qnil, 0, out, false);
1358
+ return;
1359
+ }
1356
1360
  }
1357
1361
  if ((!oj_rails_hash_opt || 0 < out->argc) && as_ok && rb_respond_to(obj, oj_as_json_id)) {
1358
- dump_as_json(obj, depth, out, false);
1359
- return;
1362
+ dump_as_json(obj, depth, out, false);
1363
+ return;
1360
1364
  }
1361
- cnt = (int)RHASH_SIZE(obj);
1365
+ cnt = (int)RHASH_SIZE(obj);
1362
1366
  size = depth * out->indent + 2;
1363
1367
  assure_size(out, 2);
1364
1368
  *out->cur++ = '{';
1365
1369
  if (0 == cnt) {
1366
- *out->cur++ = '}';
1370
+ *out->cur++ = '}';
1367
1371
  } else {
1368
- out->depth = depth + 1;
1369
- rb_hash_foreach(obj, hash_cb, (VALUE)out);
1370
- if (',' == *(out->cur - 1)) {
1371
- out->cur--; // backup to overwrite last comma
1372
- }
1373
- if (!out->opts->dump_opts.use) {
1374
- assure_size(out, size);
1375
- fill_indent(out, depth);
1376
- } else {
1377
- size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1378
- assure_size(out, size);
1379
- if (0 < out->opts->dump_opts.hash_size) {
1380
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
1381
- out->cur += out->opts->dump_opts.hash_size;
1382
- }
1383
- if (0 < out->opts->dump_opts.indent_size) {
1384
- int i;
1385
-
1386
- for (i = depth; 0 < i; i--) {
1387
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1388
- out->cur += out->opts->dump_opts.indent_size;
1389
- }
1390
- }
1391
- }
1392
- *out->cur++ = '}';
1372
+ out->depth = depth + 1;
1373
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
1374
+ if (',' == *(out->cur - 1)) {
1375
+ out->cur--; // backup to overwrite last comma
1376
+ }
1377
+ if (!out->opts->dump_opts.use) {
1378
+ assure_size(out, size);
1379
+ fill_indent(out, depth);
1380
+ } else {
1381
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1382
+ assure_size(out, size);
1383
+ if (0 < out->opts->dump_opts.hash_size) {
1384
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
1385
+ }
1386
+ if (0 < out->opts->dump_opts.indent_size) {
1387
+ int i;
1388
+
1389
+ for (i = depth; 0 < i; i--) {
1390
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1391
+ }
1392
+ }
1393
+ }
1394
+ *out->cur++ = '}';
1393
1395
  }
1394
1396
  *out->cur = '\0';
1395
1397
  }
1396
1398
 
1397
- static void
1398
- dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
1399
+ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
1400
+ VALUE clas;
1401
+
1399
1402
  if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
1400
- out->argc = 0;
1401
- return;
1403
+ out->argc = 0;
1404
+ return;
1402
1405
  }
1406
+ clas = rb_obj_class(obj);
1403
1407
  if (as_ok) {
1404
- ROpt ro;
1405
-
1406
- if (NULL != (ro = oj_rails_get_opt(out->ropts, rb_obj_class(obj))) && ro->on) {
1407
- ro->dump(obj, depth, out, as_ok);
1408
- } else if (rb_respond_to(obj, oj_as_json_id)) {
1409
- dump_as_json(obj, depth, out, true);
1410
- } else if (rb_respond_to(obj, oj_to_hash_id)) {
1411
- dump_to_hash(obj, depth, out);
1412
- } else {
1413
- oj_dump_obj_to_s(obj, out);
1414
- }
1408
+ ROpt ro;
1409
+
1410
+ if (NULL != (ro = oj_rails_get_opt(out->ropts, clas)) && ro->on) {
1411
+ ro->dump(obj, depth, out, as_ok);
1412
+ } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
1413
+ oj_dump_raw_json(obj, depth, out);
1414
+ } else if (rb_respond_to(obj, oj_as_json_id)) {
1415
+ dump_as_json(obj, depth, out, true);
1416
+ } else if (rb_respond_to(obj, oj_to_hash_id)) {
1417
+ dump_to_hash(obj, depth, out);
1418
+ } else if (oj_bigdecimal_class == clas) {
1419
+ dump_bigdecimal(obj, depth, out, false);
1420
+ } else {
1421
+ oj_dump_obj_to_s(obj, out);
1422
+ }
1423
+ } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
1424
+ oj_dump_raw_json(obj, depth, out);
1415
1425
  } else if (rb_respond_to(obj, oj_to_hash_id)) {
1416
- // Always attempt to_hash.
1417
- dump_to_hash(obj, depth, out);
1426
+ // Always attempt to_hash.
1427
+ dump_to_hash(obj, depth, out);
1428
+ } else if (oj_bigdecimal_class == clas) {
1429
+ dump_bigdecimal(obj, depth, out, false);
1418
1430
  } else {
1419
- oj_dump_obj_to_s(obj, out);
1431
+ oj_dump_obj_to_s(obj, out);
1420
1432
  }
1421
1433
  }
1422
1434
 
1423
- static DumpFunc rails_funcs[] = {
1424
- NULL, // RUBY_T_NONE = 0x00,
1425
- dump_obj, // RUBY_T_OBJECT = 0x01,
1426
- oj_dump_class, // RUBY_T_CLASS = 0x02,
1427
- oj_dump_class, // RUBY_T_MODULE = 0x03,
1428
- dump_float, // RUBY_T_FLOAT = 0x04,
1429
- oj_dump_str, // RUBY_T_STRING = 0x05,
1430
- dump_regexp, // RUBY_T_REGEXP = 0x06,
1431
- //dump_as_string, // RUBY_T_REGEXP = 0x06,
1432
- dump_array, // RUBY_T_ARRAY = 0x07,
1433
- dump_hash, // RUBY_T_HASH = 0x08,
1434
- dump_obj, // RUBY_T_STRUCT = 0x09,
1435
- oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
1436
- NULL, // RUBY_T_FILE = 0x0b,
1437
- dump_obj, // RUBY_T_DATA = 0x0c,
1438
- NULL, // RUBY_T_MATCH = 0x0d,
1435
+ static DumpFunc rails_funcs[] = {
1436
+ NULL, // RUBY_T_NONE = 0x00,
1437
+ dump_obj, // RUBY_T_OBJECT = 0x01,
1438
+ oj_dump_class, // RUBY_T_CLASS = 0x02,
1439
+ oj_dump_class, // RUBY_T_MODULE = 0x03,
1440
+ dump_float, // RUBY_T_FLOAT = 0x04,
1441
+ oj_dump_str, // RUBY_T_STRING = 0x05,
1442
+ dump_regexp, // RUBY_T_REGEXP = 0x06,
1443
+ // dump_as_string, // RUBY_T_REGEXP = 0x06,
1444
+ dump_array, // RUBY_T_ARRAY = 0x07,
1445
+ dump_hash, // RUBY_T_HASH = 0x08,
1446
+ dump_obj, // RUBY_T_STRUCT = 0x09,
1447
+ oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
1448
+ dump_as_string, // RUBY_T_FILE = 0x0b,
1449
+ dump_obj, // RUBY_T_DATA = 0x0c,
1450
+ NULL, // RUBY_T_MATCH = 0x0d,
1439
1451
  // Rails raises a stack error on Complex and Rational. It also corrupts
1440
1452
  // something which causes a segfault on the next call. Oj will not mimic
1441
1453
  // that behavior.
1442
- dump_as_string, // RUBY_T_COMPLEX = 0x0e,
1443
- dump_as_string, // RUBY_T_RATIONAL = 0x0f,
1444
- NULL, // 0x10
1445
- oj_dump_nil, // RUBY_T_NIL = 0x11,
1446
- oj_dump_true, // RUBY_T_TRUE = 0x12,
1447
- oj_dump_false, // RUBY_T_FALSE = 0x13,
1448
- oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
1449
- oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
1454
+ dump_as_string, // RUBY_T_COMPLEX = 0x0e,
1455
+ dump_as_string, // RUBY_T_RATIONAL = 0x0f,
1456
+ NULL, // 0x10
1457
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
1458
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
1459
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
1460
+ oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
1461
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
1450
1462
  };
1451
1463
 
1452
- static void
1453
- dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1454
- int type = rb_type(obj);
1464
+ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1465
+ int type = rb_type(obj);
1455
1466
 
1456
- if (Yes == out->opts->trace) {
1457
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
1467
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
1468
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
1458
1469
  }
1459
1470
  if (MAX_DEPTH < depth) {
1460
- rb_raise(rb_eNoMemError, "Too deeply nested.\n");
1471
+ rb_raise(rb_eNoMemError, "Too deeply nested.\n");
1461
1472
  }
1462
1473
  if (0 < type && type <= RUBY_T_FIXNUM) {
1463
- DumpFunc f = rails_funcs[type];
1474
+ DumpFunc f = rails_funcs[type];
1464
1475
 
1465
- if (NULL != f) {
1466
- f(obj, depth, out, as_ok);
1467
- if (Yes == out->opts->trace) {
1468
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
1469
- }
1470
- return;
1471
- }
1476
+ if (NULL != f) {
1477
+ f(obj, depth, out, as_ok);
1478
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
1479
+ oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
1480
+ }
1481
+ return;
1482
+ }
1472
1483
  }
1473
1484
  oj_dump_nil(Qnil, depth, out, false);
1474
- if (Yes == out->opts->trace) {
1475
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
1485
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
1486
+ oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
1476
1487
  }
1477
1488
  }
1478
1489
 
1479
- void
1480
- oj_dump_rails_val(VALUE obj, int depth, Out out) {
1490
+ void oj_dump_rails_val(VALUE obj, int depth, Out out) {
1481
1491
  out->opts->str_rx.head = NULL;
1482
1492
  out->opts->str_rx.tail = NULL;
1483
1493
  if (escape_html) {
1484
- out->opts->escape_mode = JXEsc;
1494
+ out->opts->escape_mode = RailsXEsc;
1485
1495
  } else {
1486
- out->opts->escape_mode = RailsEsc;
1496
+ out->opts->escape_mode = RailsEsc;
1487
1497
  }
1488
1498
  dump_rails_val(obj, depth, out, true);
1489
1499
  }