oj 3.7.4 → 3.13.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1360 -0
  3. data/README.md +31 -8
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +53 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -43
  11. data/ext/oj/circarray.h +16 -17
  12. data/ext/oj/code.c +165 -179
  13. data/ext/oj/code.h +27 -29
  14. data/ext/oj/compat.c +174 -194
  15. data/ext/oj/custom.c +790 -866
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +848 -863
  18. data/ext/oj/dump.h +81 -67
  19. data/ext/oj/dump_compat.c +85 -123
  20. data/ext/oj/dump_leaf.c +100 -188
  21. data/ext/oj/dump_object.c +527 -656
  22. data/ext/oj/dump_strict.c +315 -338
  23. data/ext/oj/encode.h +7 -34
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -29
  26. data/ext/oj/err.h +48 -48
  27. data/ext/oj/extconf.rb +17 -4
  28. data/ext/oj/fast.c +1073 -1088
  29. data/ext/oj/intern.c +298 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +469 -436
  32. data/ext/oj/object.c +532 -599
  33. data/ext/oj/odd.c +154 -138
  34. data/ext/oj/odd.h +37 -38
  35. data/ext/oj/oj.c +1333 -986
  36. data/ext/oj/oj.h +336 -316
  37. data/ext/oj/parse.c +1002 -846
  38. data/ext/oj/parse.h +92 -87
  39. data/ext/oj/parser.c +1587 -0
  40. data/ext/oj/parser.h +102 -0
  41. data/ext/oj/rails.c +888 -878
  42. data/ext/oj/rails.h +11 -14
  43. data/ext/oj/reader.c +141 -147
  44. data/ext/oj/reader.h +73 -89
  45. data/ext/oj/resolve.c +41 -62
  46. data/ext/oj/resolve.h +7 -9
  47. data/ext/oj/rxclass.c +71 -75
  48. data/ext/oj/rxclass.h +18 -19
  49. data/ext/oj/saj.c +443 -486
  50. data/ext/oj/saj2.c +596 -0
  51. data/ext/oj/saj2.h +23 -0
  52. data/ext/oj/scp.c +88 -113
  53. data/ext/oj/sparse.c +787 -709
  54. data/ext/oj/stream_writer.c +133 -159
  55. data/ext/oj/strict.c +127 -118
  56. data/ext/oj/string_writer.c +230 -249
  57. data/ext/oj/trace.c +34 -41
  58. data/ext/oj/trace.h +19 -19
  59. data/ext/oj/usual.c +1207 -0
  60. data/ext/oj/usual.h +68 -0
  61. data/ext/oj/util.c +136 -0
  62. data/ext/oj/util.h +20 -0
  63. data/ext/oj/val_stack.c +60 -68
  64. data/ext/oj/val_stack.h +91 -129
  65. data/ext/oj/validate.c +46 -0
  66. data/ext/oj/wab.c +342 -353
  67. data/lib/oj/bag.rb +1 -0
  68. data/lib/oj/easy_hash.rb +5 -4
  69. data/lib/oj/error.rb +1 -1
  70. data/lib/oj/json.rb +1 -1
  71. data/lib/oj/mimic.rb +48 -14
  72. data/lib/oj/saj.rb +20 -6
  73. data/lib/oj/state.rb +9 -8
  74. data/lib/oj/version.rb +2 -2
  75. data/lib/oj.rb +0 -8
  76. data/pages/Compatibility.md +1 -1
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +53 -46
  79. data/pages/Options.md +78 -11
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +73 -22
  82. data/pages/Security.md +1 -1
  83. data/test/activerecord/result_test.rb +7 -2
  84. data/test/activesupport5/abstract_unit.rb +45 -0
  85. data/test/activesupport5/decoding_test.rb +68 -60
  86. data/test/activesupport5/encoding_test.rb +111 -96
  87. data/test/activesupport5/encoding_test_cases.rb +33 -25
  88. data/test/activesupport5/test_helper.rb +43 -21
  89. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  90. data/test/activesupport6/abstract_unit.rb +44 -0
  91. data/test/activesupport6/decoding_test.rb +133 -0
  92. data/test/activesupport6/encoding_test.rb +507 -0
  93. data/test/activesupport6/encoding_test_cases.rb +98 -0
  94. data/test/activesupport6/test_common.rb +17 -0
  95. data/test/activesupport6/test_helper.rb +163 -0
  96. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  97. data/test/activesupport7/abstract_unit.rb +49 -0
  98. data/test/activesupport7/decoding_test.rb +125 -0
  99. data/test/activesupport7/encoding_test.rb +486 -0
  100. data/test/activesupport7/encoding_test_cases.rb +104 -0
  101. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  102. data/test/bar.rb +6 -12
  103. data/test/baz.rb +16 -0
  104. data/test/bug.rb +16 -0
  105. data/test/foo.rb +69 -75
  106. data/test/helper.rb +16 -0
  107. data/test/json_gem/json_common_interface_test.rb +8 -3
  108. data/test/json_gem/json_generator_test.rb +21 -8
  109. data/test/json_gem/json_parser_test.rb +8 -1
  110. data/test/json_gem/test_helper.rb +12 -0
  111. data/test/mem.rb +33 -0
  112. data/test/perf.rb +1 -1
  113. data/test/perf_dump.rb +50 -0
  114. data/test/perf_once.rb +58 -0
  115. data/test/perf_parser.rb +189 -0
  116. data/test/perf_scp.rb +11 -10
  117. data/test/perf_strict.rb +17 -23
  118. data/test/prec.rb +23 -0
  119. data/test/sample_json.rb +1 -1
  120. data/test/test_compat.rb +46 -10
  121. data/test/test_custom.rb +145 -7
  122. data/test/test_fast.rb +62 -2
  123. data/test/test_file.rb +23 -7
  124. data/test/test_gc.rb +11 -0
  125. data/test/test_generate.rb +21 -0
  126. data/test/test_hash.rb +11 -1
  127. data/test/test_integer_range.rb +1 -2
  128. data/test/test_object.rb +43 -12
  129. data/test/test_parser.rb +11 -0
  130. data/test/test_parser_debug.rb +27 -0
  131. data/test/test_parser_saj.rb +335 -0
  132. data/test/test_parser_usual.rb +217 -0
  133. data/test/test_rails.rb +35 -0
  134. data/test/test_saj.rb +1 -1
  135. data/test/test_scp.rb +3 -5
  136. data/test/test_strict.rb +26 -1
  137. data/test/test_various.rb +86 -65
  138. data/test/test_wab.rb +2 -0
  139. data/test/test_writer.rb +19 -2
  140. data/test/tests.rb +10 -1
  141. data/test/tests_mimic.rb +9 -0
  142. data/test/tests_mimic_addition.rb +9 -0
  143. data/test/zoo.rb +13 -0
  144. metadata +63 -110
  145. data/ext/oj/hash.c +0 -163
  146. data/ext/oj/hash.h +0 -46
  147. data/ext/oj/hash_test.c +0 -512
data/ext/oj/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
  }