oj 3.7.4 → 3.11.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +12 -4
- data/ext/oj/buf.h +6 -34
- data/ext/oj/cache8.c +3 -3
- data/ext/oj/cache8.h +5 -33
- data/ext/oj/circarray.c +5 -9
- data/ext/oj/circarray.h +5 -8
- data/ext/oj/code.c +3 -6
- data/ext/oj/code.h +7 -10
- data/ext/oj/compat.c +11 -14
- data/ext/oj/custom.c +108 -75
- data/ext/oj/dump.c +132 -92
- data/ext/oj/dump.h +6 -7
- data/ext/oj/dump_compat.c +37 -34
- data/ext/oj/dump_leaf.c +3 -6
- data/ext/oj/dump_object.c +23 -17
- data/ext/oj/dump_strict.c +7 -9
- data/ext/oj/encode.h +6 -32
- data/ext/oj/err.c +2 -5
- data/ext/oj/err.h +6 -34
- data/ext/oj/extconf.rb +6 -0
- data/ext/oj/fast.c +39 -56
- data/ext/oj/hash.c +11 -39
- data/ext/oj/hash.h +5 -33
- data/ext/oj/hash_test.c +3 -31
- data/ext/oj/mimic_json.c +65 -44
- data/ext/oj/object.c +38 -69
- data/ext/oj/odd.c +18 -17
- data/ext/oj/odd.h +6 -9
- data/ext/oj/oj.c +139 -93
- data/ext/oj/oj.h +43 -35
- data/ext/oj/parse.c +164 -60
- data/ext/oj/parse.h +30 -31
- data/ext/oj/rails.c +119 -83
- data/ext/oj/rails.h +4 -7
- data/ext/oj/reader.c +5 -8
- data/ext/oj/reader.h +7 -10
- data/ext/oj/resolve.c +4 -7
- data/ext/oj/resolve.h +4 -7
- data/ext/oj/rxclass.c +8 -11
- data/ext/oj/rxclass.h +8 -11
- data/ext/oj/saj.c +9 -12
- data/ext/oj/scp.c +4 -7
- data/ext/oj/sparse.c +67 -33
- data/ext/oj/stream_writer.c +16 -15
- data/ext/oj/strict.c +9 -12
- data/ext/oj/string_writer.c +27 -8
- data/ext/oj/trace.c +5 -8
- data/ext/oj/trace.h +9 -12
- data/ext/oj/util.c +136 -0
- data/ext/oj/util.h +19 -0
- data/ext/oj/val_stack.c +28 -36
- data/ext/oj/val_stack.h +19 -50
- data/ext/oj/wab.c +29 -29
- data/lib/oj.rb +0 -8
- data/lib/oj/json.rb +1 -1
- data/lib/oj/mimic.rb +46 -2
- data/lib/oj/version.rb +2 -2
- data/pages/Modes.md +47 -45
- data/pages/Options.md +43 -10
- data/pages/Rails.md +60 -21
- data/pages/Security.md +1 -1
- data/test/activesupport5/abstract_unit.rb +45 -0
- data/test/activesupport5/decoding_test.rb +68 -60
- data/test/activesupport5/encoding_test.rb +111 -96
- data/test/activesupport5/encoding_test_cases.rb +33 -25
- data/test/activesupport5/test_helper.rb +43 -21
- data/test/activesupport5/time_zone_test_helpers.rb +18 -3
- data/test/activesupport6/abstract_unit.rb +44 -0
- data/test/activesupport6/decoding_test.rb +133 -0
- data/test/activesupport6/encoding_test.rb +507 -0
- data/test/activesupport6/encoding_test_cases.rb +98 -0
- data/test/activesupport6/test_common.rb +17 -0
- data/test/activesupport6/test_helper.rb +163 -0
- data/test/activesupport6/time_zone_test_helpers.rb +39 -0
- data/test/bar.rb +24 -6
- data/test/baz.rb +16 -0
- data/test/foo.rb +26 -57
- data/test/helper.rb +10 -0
- data/test/json_gem/json_common_interface_test.rb +8 -3
- data/test/json_gem/json_generator_test.rb +15 -3
- data/test/json_gem/test_helper.rb +8 -0
- data/test/prec.rb +23 -0
- data/test/sample_json.rb +1 -1
- data/test/test_compat.rb +21 -10
- data/test/test_custom.rb +135 -8
- data/test/test_integer_range.rb +1 -2
- data/test/test_object.rb +35 -2
- data/test/test_rails.rb +35 -0
- data/test/test_strict.rb +24 -1
- data/test/test_various.rb +52 -63
- data/test/test_writer.rb +19 -2
- data/test/tests.rb +1 -0
- data/test/zoo.rb +13 -0
- metadata +100 -75
data/ext/oj/parse.h
CHANGED
@@ -1,10 +1,7 @@
|
|
1
|
-
|
2
|
-
* Copyright (c) 2011, Peter Ohler
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2011 Peter Ohler. All rights reserved.
|
5
2
|
|
6
|
-
#ifndef
|
7
|
-
#define
|
3
|
+
#ifndef OJ_PARSE_H
|
4
|
+
#define OJ_PARSE_H
|
8
5
|
|
9
6
|
#include <stdarg.h>
|
10
7
|
#include <stdio.h>
|
@@ -17,9 +14,9 @@
|
|
17
14
|
#include "reader.h"
|
18
15
|
#include "rxclass.h"
|
19
16
|
|
20
|
-
struct
|
17
|
+
struct _rxClass;
|
21
18
|
|
22
|
-
typedef struct
|
19
|
+
typedef struct _numInfo {
|
23
20
|
int64_t i;
|
24
21
|
int64_t num;
|
25
22
|
int64_t div;
|
@@ -31,43 +28,44 @@ typedef struct _NumInfo {
|
|
31
28
|
int infinity;
|
32
29
|
int nan;
|
33
30
|
int neg;
|
34
|
-
int
|
31
|
+
int has_exp;
|
35
32
|
int no_big;
|
33
|
+
int bigdec_load;
|
36
34
|
} *NumInfo;
|
37
35
|
|
38
|
-
typedef struct
|
36
|
+
typedef struct _parseInfo {
|
39
37
|
// used for the string parser
|
40
38
|
const char *json;
|
41
39
|
const char *cur;
|
42
40
|
const char *end;
|
43
41
|
// used for the stream parser
|
44
|
-
struct
|
42
|
+
struct _reader rd;
|
45
43
|
|
46
|
-
struct
|
47
|
-
struct
|
44
|
+
struct _err err;
|
45
|
+
struct _options options;
|
48
46
|
VALUE handler;
|
49
|
-
struct
|
47
|
+
struct _valStack stack;
|
50
48
|
CircArray circ_array;
|
51
|
-
struct
|
49
|
+
struct _rxClass str_rx;
|
52
50
|
int expect_value;
|
53
51
|
int max_depth; // just for the json gem
|
54
52
|
VALUE proc;
|
55
|
-
VALUE (*start_hash)(struct
|
56
|
-
void (*end_hash)(struct
|
57
|
-
VALUE (*hash_key)(struct
|
58
|
-
void (*hash_set_cstr)(struct
|
59
|
-
void (*hash_set_num)(struct
|
60
|
-
void (*hash_set_value)(struct
|
53
|
+
VALUE (*start_hash)(struct _parseInfo *pi);
|
54
|
+
void (*end_hash)(struct _parseInfo *pi);
|
55
|
+
VALUE (*hash_key)(struct _parseInfo *pi, const char *key, size_t klen);
|
56
|
+
void (*hash_set_cstr)(struct _parseInfo *pi, Val kval, const char *str, size_t len, const char *orig);
|
57
|
+
void (*hash_set_num)(struct _parseInfo *pi, Val kval, NumInfo ni);
|
58
|
+
void (*hash_set_value)(struct _parseInfo *pi, Val kval, VALUE value);
|
61
59
|
|
62
|
-
VALUE (*start_array)(struct
|
63
|
-
void (*end_array)(struct
|
64
|
-
void (*array_append_cstr)(struct
|
65
|
-
void (*array_append_num)(struct
|
66
|
-
void (*array_append_value)(struct
|
60
|
+
VALUE (*start_array)(struct _parseInfo *pi);
|
61
|
+
void (*end_array)(struct _parseInfo *pi);
|
62
|
+
void (*array_append_cstr)(struct _parseInfo *pi, const char *str, size_t len, const char *orig);
|
63
|
+
void (*array_append_num)(struct _parseInfo *pi, NumInfo ni);
|
64
|
+
void (*array_append_value)(struct _parseInfo *pi, VALUE value);
|
67
65
|
|
68
|
-
void (*add_cstr)(struct
|
69
|
-
void (*add_num)(struct
|
70
|
-
void (*add_value)(struct
|
66
|
+
void (*add_cstr)(struct _parseInfo *pi, const char *str, size_t len, const char *orig);
|
67
|
+
void (*add_num)(struct _parseInfo *pi, NumInfo ni);
|
68
|
+
void (*add_value)(struct _parseInfo *pi, VALUE val);
|
71
69
|
VALUE err_class;
|
72
70
|
bool has_callbacks;
|
73
71
|
} *ParseInfo;
|
@@ -80,6 +78,7 @@ extern VALUE oj_num_as_value(NumInfo ni);
|
|
80
78
|
extern void oj_set_strict_callbacks(ParseInfo pi);
|
81
79
|
extern void oj_set_object_callbacks(ParseInfo pi);
|
82
80
|
extern void oj_set_compat_callbacks(ParseInfo pi);
|
81
|
+
extern void oj_set_custom_callbacks(ParseInfo pi);
|
83
82
|
extern void oj_set_wab_callbacks(ParseInfo pi);
|
84
83
|
|
85
84
|
extern void oj_sparse2(ParseInfo pi);
|
@@ -87,7 +86,7 @@ extern VALUE oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd);
|
|
87
86
|
|
88
87
|
static inline void
|
89
88
|
parse_info_init(ParseInfo pi) {
|
90
|
-
memset(pi, 0, sizeof(struct
|
89
|
+
memset(pi, 0, sizeof(struct _parseInfo));
|
91
90
|
}
|
92
91
|
|
93
92
|
static inline bool
|
@@ -108,4 +107,4 @@ empty_ok(Options options) {
|
|
108
107
|
return Yes == options->empty_string;
|
109
108
|
}
|
110
109
|
|
111
|
-
#endif /*
|
110
|
+
#endif /* OJ_PARSE_H */
|
data/ext/oj/rails.c
CHANGED
@@ -1,20 +1,18 @@
|
|
1
|
-
|
2
|
-
* Copyright (c) 2017, Peter Ohler
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2017 Peter Ohler. All rights reserved.
|
5
2
|
|
6
3
|
#include "rails.h"
|
7
4
|
#include "encode.h"
|
8
5
|
#include "code.h"
|
9
6
|
#include "encode.h"
|
10
7
|
#include "trace.h"
|
8
|
+
#include "util.h"
|
11
9
|
|
12
10
|
#define OJ_INFINITY (1.0/0.0)
|
13
11
|
|
14
12
|
// TBD keep static array of strings and functions to help with rails optimization
|
15
|
-
typedef struct
|
16
|
-
struct
|
17
|
-
struct
|
13
|
+
typedef struct _encoder {
|
14
|
+
struct _rOptTable ropts;
|
15
|
+
struct _options opts;
|
18
16
|
VALUE arg;
|
19
17
|
} *Encoder;
|
20
18
|
|
@@ -28,7 +26,7 @@ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok);
|
|
28
26
|
|
29
27
|
extern VALUE Oj;
|
30
28
|
|
31
|
-
static struct
|
29
|
+
static struct _rOptTable ropts = { 0, 0, NULL };
|
32
30
|
|
33
31
|
static VALUE encoder_class = Qnil;
|
34
32
|
static bool escape_html = true;
|
@@ -79,14 +77,15 @@ copy_opts(ROptTable src, ROptTable dest) {
|
|
79
77
|
if (NULL == src->table) {
|
80
78
|
dest->table = NULL;
|
81
79
|
} else {
|
82
|
-
dest->table = ALLOC_N(struct
|
83
|
-
memcpy(dest->table, src->table, sizeof(struct
|
80
|
+
dest->table = ALLOC_N(struct _rOpt, dest->alen);
|
81
|
+
memcpy(dest->table, src->table, sizeof(struct _rOpt) * dest->alen);
|
84
82
|
}
|
85
83
|
return NULL;
|
86
84
|
}
|
87
85
|
|
88
86
|
static int
|
89
|
-
dump_attr_cb(ID key, VALUE value,
|
87
|
+
dump_attr_cb(ID key, VALUE value, VALUE ov) {
|
88
|
+
Out out = (Out)ov;
|
90
89
|
int depth = out->depth;
|
91
90
|
size_t size = depth * out->indent + 1;
|
92
91
|
const char *attr = rb_id2name(key);
|
@@ -116,7 +115,7 @@ dump_attr_cb(ID key, VALUE value, Out out) {
|
|
116
115
|
dump_rails_val(value, depth, out, true);
|
117
116
|
out->depth = depth;
|
118
117
|
*out->cur++ = ',';
|
119
|
-
|
118
|
+
|
120
119
|
return ST_CONTINUE;
|
121
120
|
}
|
122
121
|
|
@@ -213,6 +212,8 @@ dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
|
|
213
212
|
|
214
213
|
if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) {
|
215
214
|
oj_dump_nil(Qnil, depth, out, false);
|
215
|
+
} else if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) {
|
216
|
+
oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out);
|
216
217
|
} else if (Yes == out->opts->bigdec_as_num) {
|
217
218
|
oj_dump_raw(str, (int)RSTRING_LEN(rstr), out);
|
218
219
|
} else {
|
@@ -221,15 +222,15 @@ dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
|
|
221
222
|
}
|
222
223
|
|
223
224
|
static void
|
224
|
-
dump_sec_nano(VALUE obj,
|
225
|
+
dump_sec_nano(VALUE obj, int64_t sec, long nsec, Out out) {
|
225
226
|
char buf[64];
|
226
|
-
struct
|
227
|
+
struct _timeInfo ti;
|
227
228
|
long one = 1000000000;
|
228
229
|
long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
|
229
230
|
int tzhour, tzmin;
|
230
231
|
char tzsign = '+';
|
231
232
|
int len;
|
232
|
-
|
233
|
+
|
233
234
|
if (out->end - out->cur <= 36) {
|
234
235
|
assure_size(out, 36);
|
235
236
|
}
|
@@ -248,7 +249,7 @@ dump_sec_nano(VALUE obj, time_t sec, long nsec, Out out) {
|
|
248
249
|
}
|
249
250
|
// 2012-01-05T23:58:07.123456000+09:00 or 2012/01/05 23:58:07 +0900
|
250
251
|
sec += tzsecs;
|
251
|
-
|
252
|
+
sec_as_time(sec, &ti);
|
252
253
|
if (0 > tzsecs) {
|
253
254
|
tzsign = '-';
|
254
255
|
tzhour = (int)(tzsecs / -3600);
|
@@ -258,19 +259,12 @@ dump_sec_nano(VALUE obj, time_t sec, long nsec, Out out) {
|
|
258
259
|
tzmin = (int)(tzsecs / 60) - (tzhour * 60);
|
259
260
|
}
|
260
261
|
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);
|
262
|
+
len = sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d %c%02d%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin);
|
264
263
|
} else if (0 == out->opts->sec_prec) {
|
265
264
|
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);
|
265
|
+
len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec);
|
269
266
|
} 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);
|
267
|
+
len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin);
|
274
268
|
}
|
275
269
|
} else if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
|
276
270
|
char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
|
@@ -280,9 +274,7 @@ dump_sec_nano(VALUE obj, time_t sec, long nsec, Out out) {
|
|
280
274
|
format[32] = '0' + out->opts->sec_prec;
|
281
275
|
len -= 9 - out->opts->sec_prec;
|
282
276
|
}
|
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);
|
277
|
+
len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec);
|
286
278
|
} else {
|
287
279
|
char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
|
288
280
|
|
@@ -291,24 +283,25 @@ dump_sec_nano(VALUE obj, time_t sec, long nsec, Out out) {
|
|
291
283
|
format[32] = '0' + out->opts->sec_prec;
|
292
284
|
len -= 9 - out->opts->sec_prec;
|
293
285
|
}
|
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);
|
286
|
+
len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec, tzsign, tzhour, tzmin);
|
298
287
|
}
|
299
288
|
oj_dump_cstr(buf, len, 0, 0, out);
|
300
289
|
}
|
301
290
|
|
302
291
|
static void
|
303
292
|
dump_time(VALUE obj, int depth, Out out, bool as_ok) {
|
304
|
-
|
293
|
+
long long sec;
|
305
294
|
long long nsec;
|
306
295
|
|
307
296
|
#ifdef HAVE_RB_TIME_TIMESPEC
|
308
|
-
{
|
297
|
+
if (16 <= sizeof(struct timespec)) {
|
309
298
|
struct timespec ts = rb_time_timespec(obj);
|
310
|
-
|
299
|
+
|
300
|
+
sec = (long long)ts.tv_sec;
|
311
301
|
nsec = ts.tv_nsec;
|
302
|
+
} else {
|
303
|
+
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
304
|
+
nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
|
312
305
|
}
|
313
306
|
#else
|
314
307
|
sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
@@ -319,7 +312,7 @@ dump_time(VALUE obj, int depth, Out out, bool as_ok) {
|
|
319
312
|
|
320
313
|
static void
|
321
314
|
dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
|
322
|
-
|
315
|
+
int64_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
|
323
316
|
long long nsec = 0;
|
324
317
|
|
325
318
|
if (rb_respond_to(obj, oj_tv_nsec_id)) {
|
@@ -339,7 +332,7 @@ dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
|
|
339
332
|
|
340
333
|
static ID parameters_id = 0;
|
341
334
|
|
342
|
-
typedef struct
|
335
|
+
typedef struct _strLen {
|
343
336
|
const char *str;
|
344
337
|
int len;
|
345
338
|
} *StrLen;
|
@@ -360,9 +353,9 @@ columns_array(VALUE rcols, int *ccnt) {
|
|
360
353
|
StrLen cols;
|
361
354
|
int i;
|
362
355
|
int cnt = (int)RARRAY_LEN(rcols);
|
363
|
-
|
356
|
+
|
364
357
|
*ccnt = cnt;
|
365
|
-
cols = ALLOC_N(struct
|
358
|
+
cols = ALLOC_N(struct _strLen, cnt);
|
366
359
|
for (i = 0, cp = cols; i < cnt; i++, cp++) {
|
367
360
|
v = rb_ary_entry(rcols, i);
|
368
361
|
if (T_STRING != rb_type(v)) {
|
@@ -379,7 +372,7 @@ dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
|
|
379
372
|
size_t size;
|
380
373
|
int d2 = depth + 1;
|
381
374
|
int i;
|
382
|
-
|
375
|
+
|
383
376
|
assure_size(out, 2);
|
384
377
|
*out->cur++ = '{';
|
385
378
|
size = depth * out->indent + 3;
|
@@ -439,7 +432,7 @@ dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok) {
|
|
439
432
|
int i, rcnt;
|
440
433
|
size_t size;
|
441
434
|
int d2 = depth + 1;
|
442
|
-
|
435
|
+
|
443
436
|
if (0 == rows_id) {
|
444
437
|
rows_id = rb_intern("@rows");
|
445
438
|
columns_id = rb_intern("@columns");
|
@@ -500,7 +493,7 @@ dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok) {
|
|
500
493
|
*out->cur++ = ']';
|
501
494
|
}
|
502
495
|
|
503
|
-
typedef struct
|
496
|
+
typedef struct _namedFunc {
|
504
497
|
const char *name;
|
505
498
|
DumpFunc func;
|
506
499
|
} *NamedFunc;
|
@@ -557,7 +550,7 @@ dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
|
|
557
550
|
dump_as_string(obj, depth, out, as_ok);
|
558
551
|
}
|
559
552
|
|
560
|
-
static struct
|
553
|
+
static struct _namedFunc dump_map[] = {
|
561
554
|
{ "ActionController::Parameters", dump_actioncontroller_parameters },
|
562
555
|
{ "ActiveRecord::Result", dump_activerecord_result },
|
563
556
|
{ "ActiveSupport::TimeWithZone", dump_timewithzone },
|
@@ -591,12 +584,12 @@ create_opt(ROptTable rot, VALUE clas) {
|
|
591
584
|
rot->len++;
|
592
585
|
if (NULL == rot->table) {
|
593
586
|
rot->alen = 256;
|
594
|
-
rot->table = ALLOC_N(struct
|
595
|
-
memset(rot->table, 0, sizeof(struct
|
587
|
+
rot->table = ALLOC_N(struct _rOpt, rot->alen);
|
588
|
+
memset(rot->table, 0, sizeof(struct _rOpt) * rot->alen);
|
596
589
|
} else if (rot->alen <= rot->len) {
|
597
590
|
rot->alen *= 2;
|
598
|
-
REALLOC_N(rot->table, struct
|
599
|
-
memset(rot->table + olen, 0, sizeof(struct
|
591
|
+
REALLOC_N(rot->table, struct _rOpt, rot->alen);
|
592
|
+
memset(rot->table + olen, 0, sizeof(struct _rOpt) * olen);
|
600
593
|
}
|
601
594
|
if (0 == olen) {
|
602
595
|
ro = rot->table;
|
@@ -604,10 +597,10 @@ create_opt(ROptTable rot, VALUE clas) {
|
|
604
597
|
ro = &rot->table[olen];
|
605
598
|
} else {
|
606
599
|
int i;
|
607
|
-
|
600
|
+
|
608
601
|
for (i = 0, ro = rot->table; i < olen; i++, ro++) {
|
609
602
|
if (clas < ro->clas) {
|
610
|
-
memmove(ro + 1, ro, sizeof(struct
|
603
|
+
memmove(ro + 1, ro, sizeof(struct _rOpt) * (olen - i));
|
611
604
|
break;
|
612
605
|
}
|
613
606
|
}
|
@@ -640,7 +633,7 @@ create_opt(ROptTable rot, VALUE clas) {
|
|
640
633
|
ro->dump = dump_to_s;
|
641
634
|
}
|
642
635
|
}
|
643
|
-
return
|
636
|
+
return ro;
|
644
637
|
}
|
645
638
|
|
646
639
|
static void
|
@@ -674,12 +667,12 @@ encoder_mark(void *ptr) {
|
|
674
667
|
*/
|
675
668
|
static VALUE
|
676
669
|
encoder_new(int argc, VALUE *argv, VALUE self) {
|
677
|
-
Encoder e = ALLOC(struct
|
670
|
+
Encoder e = ALLOC(struct _encoder);
|
678
671
|
|
679
672
|
e->opts = oj_default_options;
|
680
673
|
e->arg = Qnil;
|
681
674
|
copy_opts(&ropts, &e->ropts);
|
682
|
-
|
675
|
+
|
683
676
|
if (1 <= argc && Qnil != *argv) {
|
684
677
|
oj_parse_options(*argv, &e->opts);
|
685
678
|
e->arg = *argv;
|
@@ -734,7 +727,7 @@ optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
|
|
734
727
|
int i;
|
735
728
|
NamedFunc nf;
|
736
729
|
VALUE clas;
|
737
|
-
|
730
|
+
|
738
731
|
oj_rails_hash_opt = on;
|
739
732
|
oj_rails_array_opt = on;
|
740
733
|
oj_rails_float_opt = on;
|
@@ -757,6 +750,8 @@ optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
|
|
757
750
|
oj_rails_array_opt = on;
|
758
751
|
} else if (rb_cFloat == *argv) {
|
759
752
|
oj_rails_float_opt = on;
|
753
|
+
} else if (oj_string_writer_class == *argv) {
|
754
|
+
string_writer_optimized = on;
|
760
755
|
} else if (NULL != (ro = oj_rails_get_opt(rot, *argv)) ||
|
761
756
|
NULL != (ro = create_opt(rot, *argv))) {
|
762
757
|
ro->on = on;
|
@@ -766,14 +761,14 @@ optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
|
|
766
761
|
|
767
762
|
/* Document-method optimize
|
768
763
|
* call-seq: optimize(*classes)
|
769
|
-
*
|
764
|
+
*
|
770
765
|
* Use Oj rails optimized routines to encode the specified classes. This
|
771
766
|
* ignores the as_json() method on the class and uses an internal encoding
|
772
767
|
* instead. Passing in no classes indicates all should use the optimized
|
773
768
|
* version of encoding for all previously optimized classes. Passing in the
|
774
769
|
* Object class set a global switch that will then use the optimized behavior
|
775
770
|
* for all classes.
|
776
|
-
*
|
771
|
+
*
|
777
772
|
* - *classes* [_Class_] a list of classes to optimize
|
778
773
|
*/
|
779
774
|
static VALUE
|
@@ -787,19 +782,20 @@ encoder_optimize(int argc, VALUE *argv, VALUE self) {
|
|
787
782
|
|
788
783
|
/* Document-method: optimize
|
789
784
|
* call-seq: optimize(*classes)
|
790
|
-
*
|
785
|
+
*
|
791
786
|
* Use Oj rails optimized routines to encode the specified classes. This
|
792
787
|
* ignores the as_json() method on the class and uses an internal encoding
|
793
788
|
* instead. Passing in no classes indicates all should use the optimized
|
794
789
|
* version of encoding for all previously optimized classes. Passing in the
|
795
790
|
* Object class set a global switch that will then use the optimized behavior
|
796
791
|
* for all classes.
|
797
|
-
*
|
792
|
+
*
|
798
793
|
* - *classes* [_Class_] a list of classes to optimize
|
799
794
|
*/
|
800
795
|
static VALUE
|
801
796
|
rails_optimize(int argc, VALUE *argv, VALUE self) {
|
802
797
|
optimize(argc, argv, &ropts, true);
|
798
|
+
string_writer_optimized = true;
|
803
799
|
|
804
800
|
return Qnil;
|
805
801
|
}
|
@@ -813,7 +809,7 @@ rails_optimize(int argc, VALUE *argv, VALUE self) {
|
|
813
809
|
VALUE
|
814
810
|
rails_mimic_json(VALUE self) {
|
815
811
|
VALUE json;
|
816
|
-
|
812
|
+
|
817
813
|
if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
|
818
814
|
json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
|
819
815
|
} else {
|
@@ -827,7 +823,7 @@ rails_mimic_json(VALUE self) {
|
|
827
823
|
|
828
824
|
/* Document-method: deoptimize
|
829
825
|
* call-seq: deoptimize(*classes)
|
830
|
-
*
|
826
|
+
*
|
831
827
|
* Turn off Oj rails optimization on the specified classes.
|
832
828
|
*
|
833
829
|
* - *classes* [_Class_] a list of classes to deoptimize
|
@@ -843,7 +839,7 @@ encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
|
|
843
839
|
|
844
840
|
/* Document-method: deoptimize
|
845
841
|
* call-seq: deoptimize(*classes)
|
846
|
-
*
|
842
|
+
*
|
847
843
|
* Turn off Oj rails optimization on the specified classes.
|
848
844
|
*
|
849
845
|
* - *classes* [_Class_] a list of classes to deoptimize
|
@@ -851,13 +847,14 @@ encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
|
|
851
847
|
static VALUE
|
852
848
|
rails_deoptimize(int argc, VALUE *argv, VALUE self) {
|
853
849
|
optimize(argc, argv, &ropts, false);
|
850
|
+
string_writer_optimized = false;
|
854
851
|
|
855
852
|
return Qnil;
|
856
853
|
}
|
857
854
|
|
858
855
|
/* Document-method:optimized?
|
859
856
|
* call-seq: optimized?(clas)
|
860
|
-
*
|
857
|
+
*
|
861
858
|
* - *clas* [_Class_] Class to check
|
862
859
|
*
|
863
860
|
* @return true if the class is being optimized for rails and false otherwise
|
@@ -875,7 +872,7 @@ encoder_optimized(VALUE self, VALUE clas) {
|
|
875
872
|
|
876
873
|
/* Document-method: optimized?
|
877
874
|
* call-seq: optimized?(clas)
|
878
|
-
*
|
875
|
+
*
|
879
876
|
* Returns true if the specified Class is being optimized.
|
880
877
|
*/
|
881
878
|
static VALUE
|
@@ -888,7 +885,7 @@ rails_optimized(VALUE self, VALUE clas) {
|
|
888
885
|
return (ro->on) ? Qtrue : Qfalse;
|
889
886
|
}
|
890
887
|
|
891
|
-
typedef struct
|
888
|
+
typedef struct _oo {
|
892
889
|
Out out;
|
893
890
|
VALUE obj;
|
894
891
|
} *OO;
|
@@ -905,10 +902,10 @@ protect_dump(VALUE ov) {
|
|
905
902
|
static VALUE
|
906
903
|
encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) {
|
907
904
|
char buf[4096];
|
908
|
-
struct
|
909
|
-
struct
|
905
|
+
struct _out out;
|
906
|
+
struct _options copts = *opts;
|
910
907
|
volatile VALUE rstr = Qnil;
|
911
|
-
struct
|
908
|
+
struct _oo oo;
|
912
909
|
int line = 0;
|
913
910
|
|
914
911
|
oo.out = &out;
|
@@ -917,7 +914,7 @@ encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) {
|
|
917
914
|
copts.str_rx.tail = NULL;
|
918
915
|
copts.mode = RailsMode;
|
919
916
|
if (escape_html) {
|
920
|
-
copts.escape_mode =
|
917
|
+
copts.escape_mode = RailsXEsc;
|
921
918
|
} else {
|
922
919
|
copts.escape_mode = RailsEsc;
|
923
920
|
}
|
@@ -973,7 +970,7 @@ encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) {
|
|
973
970
|
|
974
971
|
/* Document-method: encode
|
975
972
|
* call-seq: encode(obj)
|
976
|
-
*
|
973
|
+
*
|
977
974
|
* - *obj* [_Object_] object to encode
|
978
975
|
*
|
979
976
|
* Returns encoded object as a JSON string.
|
@@ -984,7 +981,7 @@ encoder_encode(VALUE self, VALUE obj) {
|
|
984
981
|
|
985
982
|
if (Qnil != e->arg) {
|
986
983
|
VALUE argv[1] = { e->arg };
|
987
|
-
|
984
|
+
|
988
985
|
return encode(obj, &e->ropts, &e->opts, 1, argv);
|
989
986
|
}
|
990
987
|
return encode(obj, &e->ropts, &e->opts, 0, NULL);
|
@@ -992,9 +989,9 @@ encoder_encode(VALUE self, VALUE obj) {
|
|
992
989
|
|
993
990
|
/* Document-method: encode
|
994
991
|
* call-seq: encode(obj, opts=nil)
|
995
|
-
*
|
992
|
+
*
|
996
993
|
* Encode obj as a JSON String.
|
997
|
-
*
|
994
|
+
*
|
998
995
|
* - *obj* [_Object_|Hash|Array] object to convert to a JSON String
|
999
996
|
* - *opts* [_Hash_] options
|
1000
997
|
*
|
@@ -1015,6 +1012,7 @@ rails_encode(int argc, VALUE *argv, VALUE self) {
|
|
1015
1012
|
static VALUE
|
1016
1013
|
rails_use_standard_json_time_format(VALUE self, VALUE state) {
|
1017
1014
|
if (Qtrue == state || Qfalse == state) {
|
1015
|
+
// no change needed
|
1018
1016
|
} else if (Qnil == state) {
|
1019
1017
|
state = Qfalse;
|
1020
1018
|
} else {
|
@@ -1026,6 +1024,11 @@ rails_use_standard_json_time_format(VALUE self, VALUE state) {
|
|
1026
1024
|
return state;
|
1027
1025
|
}
|
1028
1026
|
|
1027
|
+
static VALUE
|
1028
|
+
rails_use_standard_json_time_format_get(VALUE self) {
|
1029
|
+
return xml_time ? Qtrue : Qfalse;
|
1030
|
+
}
|
1031
|
+
|
1029
1032
|
static VALUE
|
1030
1033
|
rails_escape_html_entities_in_json(VALUE self, VALUE state) {
|
1031
1034
|
rb_iv_set(self, "@escape_html_entities_in_json", state);
|
@@ -1034,17 +1037,23 @@ rails_escape_html_entities_in_json(VALUE self, VALUE state) {
|
|
1034
1037
|
return state;
|
1035
1038
|
}
|
1036
1039
|
|
1040
|
+
static VALUE
|
1041
|
+
rails_escape_html_entities_in_json_get(VALUE self) {
|
1042
|
+
return escape_html ? Qtrue : Qfalse;
|
1043
|
+
}
|
1044
|
+
|
1037
1045
|
static VALUE
|
1038
1046
|
rails_time_precision(VALUE self, VALUE prec) {
|
1039
1047
|
rb_iv_set(self, "@time_precision", prec);
|
1040
1048
|
oj_default_options.sec_prec = NUM2INT(prec);
|
1049
|
+
oj_default_options.sec_prec_set = true;
|
1041
1050
|
|
1042
1051
|
return prec;
|
1043
1052
|
}
|
1044
1053
|
|
1045
1054
|
/* Document-method: set_encoder
|
1046
1055
|
* call-seq: set_encoder()
|
1047
|
-
*
|
1056
|
+
*
|
1048
1057
|
* Sets the ActiveSupport.encoder to Oj::Rails::Encoder and wraps some of the
|
1049
1058
|
* formatting globals used by ActiveSupport to allow the use of those globals
|
1050
1059
|
* in the Oj::Rails optimizations.
|
@@ -1056,7 +1065,12 @@ rails_set_encoder(VALUE self) {
|
|
1056
1065
|
VALUE encoding;
|
1057
1066
|
VALUE pv;
|
1058
1067
|
VALUE verbose;
|
1059
|
-
|
1068
|
+
VALUE enc = resolve_classpath("ActiveSupport::JSON::Encoding");
|
1069
|
+
|
1070
|
+
if (Qnil != enc) {
|
1071
|
+
escape_html = Qtrue == rb_iv_get(self, "@escape_html_entities_in_json");
|
1072
|
+
xml_time = Qtrue == rb_iv_get(enc, "@use_standard_json_time_format");
|
1073
|
+
}
|
1060
1074
|
if (rb_const_defined_at(rb_cObject, rb_intern("ActiveSupport"))) {
|
1061
1075
|
active = rb_const_get_at(rb_cObject, rb_intern("ActiveSupport"));
|
1062
1076
|
} else {
|
@@ -1073,12 +1087,19 @@ rails_set_encoder(VALUE self) {
|
|
1073
1087
|
rb_gv_set("$VERBOSE", Qfalse);
|
1074
1088
|
rb_undef_method(encoding, "use_standard_json_time_format=");
|
1075
1089
|
rb_define_module_function(encoding, "use_standard_json_time_format=", rails_use_standard_json_time_format, 1);
|
1090
|
+
rb_undef_method(encoding, "use_standard_json_time_format");
|
1091
|
+
rb_define_module_function(encoding, "use_standard_json_time_format", rails_use_standard_json_time_format_get, 0);
|
1076
1092
|
|
1093
|
+
pv = rb_iv_get(encoding, "@escape_html_entities_in_json");
|
1094
|
+
escape_html = Qtrue == pv;
|
1077
1095
|
rb_undef_method(encoding, "escape_html_entities_in_json=");
|
1078
1096
|
rb_define_module_function(encoding, "escape_html_entities_in_json=", rails_escape_html_entities_in_json, 1);
|
1097
|
+
rb_undef_method(encoding, "escape_html_entities_in_json");
|
1098
|
+
rb_define_module_function(encoding, "escape_html_entities_in_json", rails_escape_html_entities_in_json_get, 0);
|
1079
1099
|
|
1080
1100
|
pv = rb_iv_get(encoding, "@time_precision");
|
1081
1101
|
oj_default_options.sec_prec = NUM2INT(pv);
|
1102
|
+
oj_default_options.sec_prec_set = true;
|
1082
1103
|
rb_undef_method(encoding, "time_precision=");
|
1083
1104
|
rb_define_module_function(encoding, "time_precision=", rails_time_precision, 1);
|
1084
1105
|
rb_gv_set("$VERBOSE", verbose);
|
@@ -1097,7 +1118,7 @@ rails_set_decoder(VALUE self) {
|
|
1097
1118
|
VALUE json;
|
1098
1119
|
VALUE json_error;
|
1099
1120
|
VALUE verbose;
|
1100
|
-
|
1121
|
+
|
1101
1122
|
if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
|
1102
1123
|
json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
|
1103
1124
|
} else {
|
@@ -1120,7 +1141,7 @@ rails_set_decoder(VALUE self) {
|
|
1120
1141
|
rb_undef_method(json, "parse");
|
1121
1142
|
rb_define_module_function(json, "parse", oj_mimic_parse, -1);
|
1122
1143
|
rb_gv_set("$VERBOSE", verbose);
|
1123
|
-
|
1144
|
+
|
1124
1145
|
return Qnil;
|
1125
1146
|
}
|
1126
1147
|
|
@@ -1140,7 +1161,7 @@ oj_optimize_rails(VALUE self) {
|
|
1140
1161
|
}
|
1141
1162
|
|
1142
1163
|
/* Document-module: Oj::Rails
|
1143
|
-
*
|
1164
|
+
*
|
1144
1165
|
* Module that provides rails and active support compatibility.
|
1145
1166
|
*/
|
1146
1167
|
/* Document-class: Oj::Rails::Encoder
|
@@ -1150,7 +1171,7 @@ oj_optimize_rails(VALUE self) {
|
|
1150
1171
|
void
|
1151
1172
|
oj_mimic_rails_init() {
|
1152
1173
|
VALUE rails = rb_define_module_under(Oj, "Rails");
|
1153
|
-
|
1174
|
+
|
1154
1175
|
rb_define_module_function(rails, "encode", rails_encode, -1);
|
1155
1176
|
|
1156
1177
|
encoder_class = rb_define_class_under(rails, "Encoder", rb_cObject);
|
@@ -1286,11 +1307,15 @@ dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
1286
1307
|
}
|
1287
1308
|
|
1288
1309
|
static int
|
1289
|
-
hash_cb(VALUE key, VALUE value,
|
1310
|
+
hash_cb(VALUE key, VALUE value, VALUE ov) {
|
1311
|
+
Out out = (Out)ov;
|
1290
1312
|
int depth = out->depth;
|
1291
1313
|
long size;
|
1292
1314
|
int rtype = rb_type(key);
|
1293
|
-
|
1315
|
+
|
1316
|
+
if (out->omit_nil && Qnil == value) {
|
1317
|
+
return ST_CONTINUE;
|
1318
|
+
}
|
1294
1319
|
if (rtype != T_STRING && rtype != T_SYMBOL) {
|
1295
1320
|
key = rb_funcall(key, oj_to_s_id, 0);
|
1296
1321
|
rtype = rb_type(key);
|
@@ -1396,25 +1421,36 @@ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1396
1421
|
|
1397
1422
|
static void
|
1398
1423
|
dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
1424
|
+
VALUE clas;
|
1425
|
+
|
1399
1426
|
if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
|
1400
1427
|
out->argc = 0;
|
1401
1428
|
return;
|
1402
1429
|
}
|
1430
|
+
clas = rb_obj_class(obj);
|
1403
1431
|
if (as_ok) {
|
1404
1432
|
ROpt ro;
|
1405
1433
|
|
1406
|
-
if (NULL != (ro = oj_rails_get_opt(out->ropts,
|
1434
|
+
if (NULL != (ro = oj_rails_get_opt(out->ropts, clas)) && ro->on) {
|
1407
1435
|
ro->dump(obj, depth, out, as_ok);
|
1436
|
+
} else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
|
1437
|
+
oj_dump_raw_json(obj, depth, out);
|
1408
1438
|
} else if (rb_respond_to(obj, oj_as_json_id)) {
|
1409
1439
|
dump_as_json(obj, depth, out, true);
|
1410
1440
|
} else if (rb_respond_to(obj, oj_to_hash_id)) {
|
1411
1441
|
dump_to_hash(obj, depth, out);
|
1442
|
+
} else if (oj_bigdecimal_class == clas) {
|
1443
|
+
dump_bigdecimal(obj, depth, out, false);
|
1412
1444
|
} else {
|
1413
1445
|
oj_dump_obj_to_s(obj, out);
|
1414
1446
|
}
|
1447
|
+
} else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
|
1448
|
+
oj_dump_raw_json(obj, depth, out);
|
1415
1449
|
} else if (rb_respond_to(obj, oj_to_hash_id)) {
|
1416
1450
|
// Always attempt to_hash.
|
1417
1451
|
dump_to_hash(obj, depth, out);
|
1452
|
+
} else if (oj_bigdecimal_class == clas) {
|
1453
|
+
dump_bigdecimal(obj, depth, out, false);
|
1418
1454
|
} else {
|
1419
1455
|
oj_dump_obj_to_s(obj, out);
|
1420
1456
|
}
|
@@ -1433,7 +1469,7 @@ static DumpFunc rails_funcs[] = {
|
|
1433
1469
|
dump_hash, // RUBY_T_HASH = 0x08,
|
1434
1470
|
dump_obj, // RUBY_T_STRUCT = 0x09,
|
1435
1471
|
oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
|
1436
|
-
|
1472
|
+
dump_as_string, // RUBY_T_FILE = 0x0b,
|
1437
1473
|
dump_obj, // RUBY_T_DATA = 0x0c,
|
1438
1474
|
NULL, // RUBY_T_MATCH = 0x0d,
|
1439
1475
|
// Rails raises a stack error on Complex and Rational. It also corrupts
|
@@ -1481,7 +1517,7 @@ oj_dump_rails_val(VALUE obj, int depth, Out out) {
|
|
1481
1517
|
out->opts->str_rx.head = NULL;
|
1482
1518
|
out->opts->str_rx.tail = NULL;
|
1483
1519
|
if (escape_html) {
|
1484
|
-
out->opts->escape_mode =
|
1520
|
+
out->opts->escape_mode = RailsXEsc;
|
1485
1521
|
} else {
|
1486
1522
|
out->opts->escape_mode = RailsEsc;
|
1487
1523
|
}
|