oj 3.4.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
# [![{}j](http://www.ohler.com/dev/images/oj_comet_64.svg)](http://www.ohler.com/oj) gem
|
2
2
|
|
3
|
-
[![Build Status](https://img.shields.io/travis/ohler55/oj/master.svg)](http://travis-ci.org/ohler55/oj?branch=master) [![AppVeyor](https://img.shields.io/appveyor/ci/ohler55/oj/master.svg)](https://ci.appveyor.com/project/ohler55/oj) ![Gem](https://img.shields.io/gem/v/oj.svg) ![Gem](https://img.shields.io/gem/dt/oj.svg)
|
3
|
+
[![Build Status](https://img.shields.io/travis/ohler55/oj/master.svg)](http://travis-ci.org/ohler55/oj?branch=master) [![AppVeyor](https://img.shields.io/appveyor/ci/ohler55/oj/master.svg)](https://ci.appveyor.com/project/ohler55/oj) ![Gem](https://img.shields.io/gem/v/oj.svg) ![Gem](https://img.shields.io/gem/dt/oj.svg)
|
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
|