oj 3.7.4 → 3.11.2
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.
- 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
|
}
|