oj 3.4.0 → 3.5.0
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 +5 -5
- data/README.md +1 -1
- data/ext/oj/compat.c +39 -5
- data/ext/oj/custom.c +37 -6
- data/ext/oj/dump_compat.c +11 -1
- data/ext/oj/dump_object.c +10 -0
- data/ext/oj/dump_strict.c +16 -0
- data/ext/oj/mimic_json.c +4 -3
- data/ext/oj/object.c +73 -28
- data/ext/oj/oj.c +10 -2
- data/ext/oj/oj.h +2 -0
- data/ext/oj/rails.c +11 -2
- data/ext/oj/saj.c +1 -1
- data/ext/oj/sparse.c +1 -26
- data/ext/oj/strict.c +55 -5
- data/ext/oj/trace.c +77 -0
- data/ext/oj/trace.h +26 -0
- data/ext/oj/wab.c +67 -7
- data/lib/oj/version.rb +1 -1
- data/pages/Encoding.md +3 -3
- data/pages/Modes.md +1 -0
- data/pages/Options.md +6 -1
- data/pages/Rails.md +27 -4
- data/test/activesupport5/encoding_test.rb +1 -0
- data/test/foo.rb +32 -0
- data/test/test_various.rb +1 -0
- metadata +15 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 30b24a6a60285c820a9e10671a976043a9163c2e98a3c07ba16af43ad88b8e6f
|
4
|
+
data.tar.gz: 90fc1a46d76296f2e226434a26b6acc0cbe16fa378173ea98700b2250ecf45ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71d7f8f0c32e3183a9f228764ffacdbd94cac6497e4af07e3ede247a676b2abd3815b3c51228992429a400a0ef879b8f54a8767cfa8b3a573a9931b46ec785e0
|
7
|
+
data.tar.gz: ce7fb5fa634fd8122173712faed5435bee5ec3477445d969f3a16f62ac6703dae9fee0f0476cbbfdc8852ba4a7243753d543e44f61eb286489b7a700e0e0dde5
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# [](http://www.ohler.com/oj) gem
|
2
2
|
|
3
|
-
[](http://travis-ci.org/ohler55/oj?branch=master) [](https://ci.appveyor.com/project/ohler55/oj)  
|
3
|
+
[](http://travis-ci.org/ohler55/oj?branch=master) [](https://ci.appveyor.com/project/ohler55/oj)  
|
4
4
|
|
5
5
|
A *fast* JSON parser and Object marshaller as a Ruby gem.
|
6
6
|
|
data/ext/oj/compat.c
CHANGED
@@ -11,6 +11,7 @@
|
|
11
11
|
#include "resolve.h"
|
12
12
|
#include "hash.h"
|
13
13
|
#include "encode.h"
|
14
|
+
#include "trace.h"
|
14
15
|
|
15
16
|
static void
|
16
17
|
hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
@@ -55,6 +56,9 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
|
|
55
56
|
} else {
|
56
57
|
rb_hash_aset(parent->val, rkey, rstr);
|
57
58
|
}
|
59
|
+
if (Yes == pi->options.trace) {
|
60
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
|
61
|
+
}
|
58
62
|
}
|
59
63
|
}
|
60
64
|
|
@@ -67,6 +71,9 @@ start_hash(ParseInfo pi) {
|
|
67
71
|
} else {
|
68
72
|
h = rb_hash_new();
|
69
73
|
}
|
74
|
+
if (Yes == pi->options.trace) {
|
75
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
76
|
+
}
|
70
77
|
return h;
|
71
78
|
}
|
72
79
|
|
@@ -90,6 +97,9 @@ end_hash(struct _ParseInfo *pi) {
|
|
90
97
|
parent->classname = 0;
|
91
98
|
}
|
92
99
|
}
|
100
|
+
if (Yes == pi->options.trace) {
|
101
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
102
|
+
}
|
93
103
|
}
|
94
104
|
|
95
105
|
static VALUE
|
@@ -120,23 +130,34 @@ add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
120
130
|
}
|
121
131
|
}
|
122
132
|
pi->stack.head->val = rstr;
|
133
|
+
if (Yes == pi->options.trace) {
|
134
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
|
135
|
+
}
|
123
136
|
}
|
124
137
|
|
125
138
|
static void
|
126
139
|
add_num(ParseInfo pi, NumInfo ni) {
|
127
140
|
pi->stack.head->val = oj_num_as_value(ni);
|
141
|
+
if (Yes == pi->options.trace) {
|
142
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
|
143
|
+
}
|
128
144
|
}
|
129
145
|
|
130
146
|
static void
|
131
147
|
hash_set_num(struct _ParseInfo *pi, Val parent, NumInfo ni) {
|
148
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
149
|
+
|
132
150
|
if (!oj_use_hash_alt && rb_cHash != rb_obj_class(parent->val)) {
|
133
151
|
// The rb_hash_set would still work but the unit tests for the
|
134
152
|
// json gem require the less efficient []= method be called to set
|
135
153
|
// values. Even using the store method to set the values will fail
|
136
154
|
// the unit tests.
|
137
|
-
rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent),
|
155
|
+
rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, calc_hash_key(pi, parent), rval);
|
138
156
|
} else {
|
139
|
-
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent),
|
157
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rval);
|
158
|
+
}
|
159
|
+
if (Yes == pi->options.trace) {
|
160
|
+
oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
|
140
161
|
}
|
141
162
|
}
|
142
163
|
|
@@ -151,6 +172,9 @@ hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
|
151
172
|
} else {
|
152
173
|
rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
|
153
174
|
}
|
175
|
+
if (Yes == pi->options.trace) {
|
176
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
177
|
+
}
|
154
178
|
}
|
155
179
|
|
156
180
|
static VALUE
|
@@ -158,20 +182,27 @@ start_array(ParseInfo pi) {
|
|
158
182
|
if (Qnil != pi->options.array_class) {
|
159
183
|
return rb_class_new_instance(0, NULL, pi->options.array_class);
|
160
184
|
}
|
185
|
+
if (Yes == pi->options.trace) {
|
186
|
+
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
187
|
+
}
|
161
188
|
return rb_ary_new();
|
162
189
|
}
|
163
190
|
|
164
191
|
static void
|
165
192
|
array_append_num(ParseInfo pi, NumInfo ni) {
|
166
|
-
Val
|
193
|
+
Val parent = stack_peek(&pi->stack);
|
194
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
167
195
|
|
168
196
|
if (!oj_use_array_alt && rb_cArray != rb_obj_class(parent->val)) {
|
169
197
|
// The rb_ary_push would still work but the unit tests for the json
|
170
198
|
// gem require the less efficient << method be called to push the
|
171
199
|
// values.
|
172
|
-
rb_funcall(parent->val, rb_intern("<<"), 1,
|
200
|
+
rb_funcall(parent->val, rb_intern("<<"), 1, rval);
|
173
201
|
} else {
|
174
|
-
rb_ary_push(parent->val,
|
202
|
+
rb_ary_push(parent->val, rval);
|
203
|
+
}
|
204
|
+
if (Yes == pi->options.trace) {
|
205
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
175
206
|
}
|
176
207
|
}
|
177
208
|
|
@@ -189,6 +220,9 @@ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
189
220
|
}
|
190
221
|
}
|
191
222
|
rb_ary_push(stack_peek(&pi->stack)->val, rstr);
|
223
|
+
if (Yes == pi->options.trace) {
|
224
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
|
225
|
+
}
|
192
226
|
}
|
193
227
|
|
194
228
|
void
|
data/ext/oj/custom.c
CHANGED
@@ -14,6 +14,7 @@
|
|
14
14
|
#include "oj.h"
|
15
15
|
#include "parse.h"
|
16
16
|
#include "resolve.h"
|
17
|
+
#include "trace.h"
|
17
18
|
|
18
19
|
extern void oj_set_obj_ivar(Val parent, Val kval, VALUE value);
|
19
20
|
extern VALUE oj_parse_xml_time(const char *str, int len); // from object.c
|
@@ -874,6 +875,9 @@ void
|
|
874
875
|
oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
875
876
|
int type = rb_type(obj);
|
876
877
|
|
878
|
+
if (Yes == out->opts->trace) {
|
879
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
880
|
+
}
|
877
881
|
if (MAX_DEPTH < depth) {
|
878
882
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
879
883
|
}
|
@@ -882,10 +886,16 @@ oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
882
886
|
|
883
887
|
if (NULL != f) {
|
884
888
|
f(obj, depth, out, true);
|
889
|
+
if (Yes == out->opts->trace) {
|
890
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
891
|
+
}
|
885
892
|
return;
|
886
893
|
}
|
887
894
|
}
|
888
895
|
oj_dump_nil(Qnil, depth, out, false);
|
896
|
+
if (Yes == out->opts->trace) {
|
897
|
+
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
898
|
+
}
|
889
899
|
}
|
890
900
|
|
891
901
|
///// load functions /////
|
@@ -946,6 +956,9 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
|
|
946
956
|
default:
|
947
957
|
break;
|
948
958
|
}
|
959
|
+
if (Yes == pi->options.trace) {
|
960
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
|
961
|
+
}
|
949
962
|
}
|
950
963
|
}
|
951
964
|
|
@@ -963,6 +976,9 @@ end_hash(struct _ParseInfo *pi) {
|
|
963
976
|
}
|
964
977
|
parent->clas = Qundef;
|
965
978
|
}
|
979
|
+
if (Yes == pi->options.trace) {
|
980
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
981
|
+
}
|
966
982
|
}
|
967
983
|
|
968
984
|
static VALUE
|
@@ -981,11 +997,12 @@ calc_hash_key(ParseInfo pi, Val parent) {
|
|
981
997
|
|
982
998
|
static void
|
983
999
|
hash_set_num(struct _ParseInfo *pi, Val kval, NumInfo ni) {
|
984
|
-
Val
|
1000
|
+
Val parent = stack_peek(&pi->stack);
|
1001
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
985
1002
|
|
986
1003
|
switch (rb_type(parent->val)) {
|
987
1004
|
case T_OBJECT:
|
988
|
-
oj_set_obj_ivar(parent, kval,
|
1005
|
+
oj_set_obj_ivar(parent, kval, rval);
|
989
1006
|
break;
|
990
1007
|
case T_HASH:
|
991
1008
|
if (4 == parent->klen && NULL != parent->key && rb_cTime == parent->clas && 0 == strncmp("time", parent->key, 4)) {
|
@@ -1001,7 +1018,7 @@ hash_set_num(struct _ParseInfo *pi, Val kval, NumInfo ni) {
|
|
1001
1018
|
if (86400 == ni->exp) { // UTC time
|
1002
1019
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
1003
1020
|
// Since the ruby C routines alway create local time, the
|
1004
|
-
// offset and then a
|
1021
|
+
// offset and then a conversion to UTC keeps makes the time
|
1005
1022
|
// match the expected value.
|
1006
1023
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
1007
1024
|
} else if (ni->hasExp) {
|
@@ -1020,13 +1037,17 @@ hash_set_num(struct _ParseInfo *pi, Val kval, NumInfo ni) {
|
|
1020
1037
|
} else {
|
1021
1038
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
1022
1039
|
}
|
1040
|
+
rval = parent->val;
|
1023
1041
|
} else {
|
1024
|
-
rb_hash_aset(parent->val, calc_hash_key(pi, kval),
|
1042
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval), rval);
|
1025
1043
|
}
|
1026
1044
|
break;
|
1027
1045
|
default:
|
1028
1046
|
break;
|
1029
1047
|
}
|
1048
|
+
if (Yes == pi->options.trace) {
|
1049
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
1050
|
+
}
|
1030
1051
|
}
|
1031
1052
|
|
1032
1053
|
static void
|
@@ -1043,13 +1064,20 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
|
1043
1064
|
default:
|
1044
1065
|
break;
|
1045
1066
|
}
|
1067
|
+
if (Yes == pi->options.trace) {
|
1068
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
1069
|
+
}
|
1046
1070
|
}
|
1047
1071
|
|
1048
1072
|
static void
|
1049
1073
|
array_append_num(ParseInfo pi, NumInfo ni) {
|
1050
|
-
Val
|
1074
|
+
Val parent = stack_peek(&pi->stack);
|
1075
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
1051
1076
|
|
1052
|
-
rb_ary_push(parent->val,
|
1077
|
+
rb_ary_push(parent->val, rval);
|
1078
|
+
if (Yes == pi->options.trace) {
|
1079
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
1080
|
+
}
|
1053
1081
|
}
|
1054
1082
|
|
1055
1083
|
static void
|
@@ -1066,6 +1094,9 @@ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
1066
1094
|
}
|
1067
1095
|
}
|
1068
1096
|
rb_ary_push(stack_peek(&pi->stack)->val, rstr);
|
1097
|
+
if (Yes == pi->options.trace) {
|
1098
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
|
1099
|
+
}
|
1069
1100
|
}
|
1070
1101
|
|
1071
1102
|
void
|
data/ext/oj/dump_compat.c
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
#include "code.h"
|
7
7
|
#include "dump.h"
|
8
8
|
#include "rails.h"
|
9
|
+
#include "trace.h"
|
9
10
|
|
10
11
|
// Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
|
11
12
|
#define OJ_INFINITY (1.0/0.0)
|
@@ -901,7 +902,10 @@ set_state_depth(VALUE state, int depth) {
|
|
901
902
|
void
|
902
903
|
oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
|
903
904
|
int type = rb_type(obj);
|
904
|
-
|
905
|
+
|
906
|
+
if (Yes == out->opts->trace) {
|
907
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
908
|
+
}
|
905
909
|
if (out->opts->dump_opts.max_depth <= depth) {
|
906
910
|
// When JSON.dump is called then an ArgumentError is expected and the
|
907
911
|
// limit is the depth inclusive. If JSON.generate is called then a
|
@@ -924,8 +928,14 @@ oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
924
928
|
|
925
929
|
if (NULL != f) {
|
926
930
|
f(obj, depth, out, as_ok);
|
931
|
+
if (Yes == out->opts->trace) {
|
932
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
933
|
+
}
|
927
934
|
return;
|
928
935
|
}
|
929
936
|
}
|
930
937
|
oj_dump_nil(Qnil, depth, out, false);
|
938
|
+
if (Yes == out->opts->trace) {
|
939
|
+
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
940
|
+
}
|
931
941
|
}
|
data/ext/oj/dump_object.c
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
|
6
6
|
#include "dump.h"
|
7
7
|
#include "odd.h"
|
8
|
+
#include "trace.h"
|
8
9
|
|
9
10
|
static const char hex_chars[17] = "0123456789abcdef";
|
10
11
|
|
@@ -816,6 +817,9 @@ void
|
|
816
817
|
oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
817
818
|
int type = rb_type(obj);
|
818
819
|
|
820
|
+
if (Yes == out->opts->trace) {
|
821
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
822
|
+
}
|
819
823
|
if (MAX_DEPTH < depth) {
|
820
824
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
821
825
|
}
|
@@ -824,8 +828,14 @@ oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
|
824
828
|
|
825
829
|
if (NULL != f) {
|
826
830
|
f(obj, depth, out, false);
|
831
|
+
if (Yes == out->opts->trace) {
|
832
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
833
|
+
}
|
827
834
|
return;
|
828
835
|
}
|
829
836
|
}
|
830
837
|
oj_dump_nil(Qnil, depth, out, false);
|
838
|
+
if (Yes == out->opts->trace) {
|
839
|
+
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
840
|
+
}
|
831
841
|
}
|
data/ext/oj/dump_strict.c
CHANGED
@@ -12,6 +12,7 @@
|
|
12
12
|
#include <errno.h>
|
13
13
|
|
14
14
|
#include "dump.h"
|
15
|
+
#include "trace.h"
|
15
16
|
|
16
17
|
#if !HAS_ENCODING_SUPPORT || defined(RUBINIUS_RUBY)
|
17
18
|
#define rb_eEncodingError rb_eException
|
@@ -366,6 +367,9 @@ void
|
|
366
367
|
oj_dump_strict_val(VALUE obj, int depth, Out out) {
|
367
368
|
int type = rb_type(obj);
|
368
369
|
|
370
|
+
if (Yes == out->opts->trace) {
|
371
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
372
|
+
}
|
369
373
|
if (MAX_DEPTH < depth) {
|
370
374
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
371
375
|
}
|
@@ -374,6 +378,9 @@ oj_dump_strict_val(VALUE obj, int depth, Out out) {
|
|
374
378
|
|
375
379
|
if (NULL != f) {
|
376
380
|
f(obj, depth, out, false);
|
381
|
+
if (Yes == out->opts->trace) {
|
382
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
383
|
+
}
|
377
384
|
return;
|
378
385
|
}
|
379
386
|
}
|
@@ -409,6 +416,9 @@ void
|
|
409
416
|
oj_dump_null_val(VALUE obj, int depth, Out out) {
|
410
417
|
int type = rb_type(obj);
|
411
418
|
|
419
|
+
if (Yes == out->opts->trace) {
|
420
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
421
|
+
}
|
412
422
|
if (MAX_DEPTH < depth) {
|
413
423
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
414
424
|
}
|
@@ -417,8 +427,14 @@ oj_dump_null_val(VALUE obj, int depth, Out out) {
|
|
417
427
|
|
418
428
|
if (NULL != f) {
|
419
429
|
f(obj, depth, out, false);
|
430
|
+
if (Yes == out->opts->trace) {
|
431
|
+
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
432
|
+
}
|
420
433
|
return;
|
421
434
|
}
|
422
435
|
}
|
423
436
|
oj_dump_nil(Qnil, depth, out, false);
|
437
|
+
if (Yes == out->opts->trace) {
|
438
|
+
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
439
|
+
}
|
424
440
|
}
|
data/ext/oj/mimic_json.c
CHANGED
@@ -44,13 +44,13 @@ static VALUE state_class;
|
|
44
44
|
/* Document-method: parser=
|
45
45
|
* call-seq: parser=(parser)
|
46
46
|
*
|
47
|
-
* Does nothing other than provide
|
47
|
+
* Does nothing other than provide compatibility.
|
48
48
|
* - *parser* [_Object_] ignored
|
49
49
|
*/
|
50
50
|
/* Document-method: generator=
|
51
51
|
* call-seq: generator=(generator)
|
52
52
|
*
|
53
|
-
* Does nothing other than provide
|
53
|
+
* Does nothing other than provide compatibility.
|
54
54
|
* - *generator* [_Object_] ignored
|
55
55
|
*/
|
56
56
|
|
@@ -606,7 +606,7 @@ mimic_parse_bang(int argc, VALUE *argv, VALUE self) {
|
|
606
606
|
/* Document-method: recurse_proc
|
607
607
|
* call-seq: recurse_proc(obj, &proc)
|
608
608
|
*
|
609
|
-
* Yields to the proc for every element in the obj
|
609
|
+
* Yields to the proc for every element in the obj recursively.
|
610
610
|
*
|
611
611
|
* - *obj* [_Hash_|Array] object to walk
|
612
612
|
* - *proc* [_Proc_] to yield to on each element
|
@@ -684,6 +684,7 @@ static struct _Options mimic_object_to_json_options = {
|
|
684
684
|
No, // allow_invalid
|
685
685
|
No, // create_ok
|
686
686
|
No, // allow_nan
|
687
|
+
No, // trace
|
687
688
|
oj_json_class,// create_id
|
688
689
|
10, // create_id_len
|
689
690
|
3, // sec_prec
|
data/ext/oj/object.c
CHANGED
@@ -13,6 +13,7 @@
|
|
13
13
|
#include "hash.h"
|
14
14
|
#include "odd.h"
|
15
15
|
#include "encode.h"
|
16
|
+
#include "trace.h"
|
16
17
|
|
17
18
|
inline static long
|
18
19
|
read_long(const char *str, size_t len) {
|
@@ -286,7 +287,7 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
286
287
|
if (86400 == ni->exp) { // UTC time
|
287
288
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
288
289
|
// Since the ruby C routines alway create local time, the
|
289
|
-
// offset and then a
|
290
|
+
// offset and then a conversion to UTC keeps makes the time
|
290
291
|
// match the expected value.
|
291
292
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
292
293
|
} else if (ni->hasExp) {
|
@@ -482,9 +483,10 @@ oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
|
482
483
|
|
483
484
|
static void
|
484
485
|
hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
485
|
-
const char
|
486
|
-
int
|
487
|
-
Val
|
486
|
+
const char *key = kval->key;
|
487
|
+
int klen = kval->klen;
|
488
|
+
Val parent = stack_peek(&pi->stack);
|
489
|
+
volatile VALUE rval = Qnil;
|
488
490
|
|
489
491
|
WHICH_TYPE:
|
490
492
|
switch (rb_type(parent->val)) {
|
@@ -499,41 +501,50 @@ hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *o
|
|
499
501
|
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), str_to_value(pi, str, len, orig));
|
500
502
|
break;
|
501
503
|
case T_STRING:
|
504
|
+
rval = str_to_value(pi, str, len, orig);
|
502
505
|
if (4 == klen && 's' == *key && 'e' == key[1] && 'l' == key[2] && 'f' == key[3]) {
|
503
|
-
rb_funcall(parent->val, oj_replace_id, 1,
|
506
|
+
rb_funcall(parent->val, oj_replace_id, 1, rval);
|
504
507
|
} else {
|
505
|
-
oj_set_obj_ivar(parent, kval,
|
508
|
+
oj_set_obj_ivar(parent, kval, rval);
|
506
509
|
}
|
507
510
|
break;
|
508
511
|
case T_OBJECT:
|
509
|
-
|
512
|
+
rval = str_to_value(pi, str, len, orig);
|
513
|
+
oj_set_obj_ivar(parent, kval, rval);
|
510
514
|
break;
|
511
515
|
case T_CLASS:
|
512
516
|
if (0 == parent->odd_args) {
|
513
517
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
|
514
518
|
return;
|
515
|
-
} else
|
516
|
-
|
519
|
+
} else {
|
520
|
+
rval = str_to_value(pi, str, len, orig);
|
521
|
+
if (0 != oj_odd_set_arg(parent->odd_args, kval->key, kval->klen, rval)) {
|
522
|
+
char buf[256];
|
517
523
|
|
518
|
-
|
519
|
-
|
524
|
+
if ((int)sizeof(buf) - 1 <= klen) {
|
525
|
+
klen = sizeof(buf) - 2;
|
526
|
+
}
|
527
|
+
memcpy(buf, key, klen);
|
528
|
+
buf[klen] = '\0';
|
529
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
|
520
530
|
}
|
521
|
-
memcpy(buf, key, klen);
|
522
|
-
buf[klen] = '\0';
|
523
|
-
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
|
524
531
|
}
|
525
532
|
break;
|
526
533
|
default:
|
527
534
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
|
528
535
|
return;
|
529
536
|
}
|
537
|
+
if (Yes == pi->options.trace) {
|
538
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
539
|
+
}
|
530
540
|
}
|
531
541
|
|
532
542
|
static void
|
533
543
|
hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
534
|
-
const char
|
535
|
-
int
|
536
|
-
Val
|
544
|
+
const char *key = kval->key;
|
545
|
+
int klen = kval->klen;
|
546
|
+
Val parent = stack_peek(&pi->stack);
|
547
|
+
volatile VALUE rval = Qnil;
|
537
548
|
|
538
549
|
WHICH_TYPE:
|
539
550
|
switch (rb_type(parent->val)) {
|
@@ -545,35 +556,43 @@ hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
|
545
556
|
}
|
546
557
|
break;
|
547
558
|
case T_HASH:
|
548
|
-
|
559
|
+
rval = oj_num_as_value(ni);
|
560
|
+
rb_hash_aset(parent->val, calc_hash_key(pi, kval, parent->k1), rval);
|
549
561
|
break;
|
550
562
|
case T_OBJECT:
|
551
563
|
if (2 == klen && '^' == *key && 'i' == key[1] &&
|
552
564
|
!ni->infinity && !ni->neg && 1 == ni->div && 0 == ni->exp && 0 != pi->circ_array) { // fixnum
|
553
565
|
oj_circ_array_set(pi->circ_array, parent->val, ni->i);
|
554
566
|
} else {
|
555
|
-
|
567
|
+
rval = oj_num_as_value(ni);
|
568
|
+
oj_set_obj_ivar(parent, kval, rval);
|
556
569
|
}
|
557
570
|
break;
|
558
571
|
case T_CLASS:
|
559
572
|
if (0 == parent->odd_args) {
|
560
573
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an odd class", rb_class2name(rb_obj_class(parent->val)));
|
561
574
|
return;
|
562
|
-
} else
|
563
|
-
|
575
|
+
} else {
|
576
|
+
rval = oj_num_as_value(ni);
|
577
|
+
if (0 != oj_odd_set_arg(parent->odd_args, key, klen, rval)) {
|
578
|
+
char buf[256];
|
564
579
|
|
565
|
-
|
566
|
-
|
580
|
+
if ((int)sizeof(buf) - 1 <= klen) {
|
581
|
+
klen = sizeof(buf) - 2;
|
582
|
+
}
|
583
|
+
memcpy(buf, key, klen);
|
584
|
+
buf[klen] = '\0';
|
585
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
|
567
586
|
}
|
568
|
-
memcpy(buf, key, klen);
|
569
|
-
buf[klen] = '\0';
|
570
|
-
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "%s is not an attribute of %s", buf, rb_class2name(rb_obj_class(parent->val)));
|
571
587
|
}
|
572
588
|
break;
|
573
589
|
default:
|
574
590
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
|
575
591
|
return;
|
576
592
|
}
|
593
|
+
if (Yes == pi->options.trace) {
|
594
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
|
595
|
+
}
|
577
596
|
}
|
578
597
|
|
579
598
|
static void
|
@@ -644,10 +663,16 @@ hash_set_value(ParseInfo pi, Val kval, VALUE value) {
|
|
644
663
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "can not add attributes to a %s", rb_class2name(rb_obj_class(parent->val)));
|
645
664
|
return;
|
646
665
|
}
|
666
|
+
if (Yes == pi->options.trace) {
|
667
|
+
oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
|
668
|
+
}
|
647
669
|
}
|
648
670
|
|
649
671
|
static VALUE
|
650
672
|
start_hash(ParseInfo pi) {
|
673
|
+
if (Yes == pi->options.trace) {
|
674
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
675
|
+
}
|
651
676
|
return Qnil;
|
652
677
|
}
|
653
678
|
|
@@ -664,10 +689,15 @@ end_hash(struct _ParseInfo *pi) {
|
|
664
689
|
oj_odd_free(oa);
|
665
690
|
parent->odd_args = 0;
|
666
691
|
}
|
692
|
+
if (Yes == pi->options.trace) {
|
693
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
694
|
+
}
|
667
695
|
}
|
668
696
|
|
669
697
|
static void
|
670
698
|
array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
699
|
+
volatile VALUE rval = Qnil;
|
700
|
+
|
671
701
|
if (3 <= len && 0 != pi->circ_array) {
|
672
702
|
if ('i' == str[1]) {
|
673
703
|
long i = read_long(str + 2, len - 2);
|
@@ -686,22 +716,37 @@ array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
|
686
716
|
|
687
717
|
}
|
688
718
|
}
|
689
|
-
|
719
|
+
rval = str_to_value(pi, str, len, orig);
|
720
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
721
|
+
if (Yes == pi->options.trace) {
|
722
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
|
723
|
+
}
|
690
724
|
}
|
691
725
|
|
692
726
|
static void
|
693
727
|
array_append_num(ParseInfo pi, NumInfo ni) {
|
694
|
-
|
728
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
729
|
+
|
730
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
731
|
+
if (Yes == pi->options.trace) {
|
732
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
733
|
+
}
|
695
734
|
}
|
696
735
|
|
697
736
|
static void
|
698
737
|
add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
699
738
|
pi->stack.head->val = str_to_value(pi, str, len, orig);
|
739
|
+
if (Yes == pi->options.trace) {
|
740
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
|
741
|
+
}
|
700
742
|
}
|
701
743
|
|
702
744
|
static void
|
703
745
|
add_num(ParseInfo pi, NumInfo ni) {
|
704
746
|
pi->stack.head->val = oj_num_as_value(ni);
|
747
|
+
if (Yes == pi->options.trace) {
|
748
|
+
oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
|
749
|
+
}
|
705
750
|
}
|
706
751
|
|
707
752
|
void
|