yaji 0.3.5-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/HISTORY.markdown +92 -0
- data/LICENSE +201 -0
- data/README.markdown +148 -0
- data/Rakefile +4 -0
- data/ext/yaji/api/yajl_common.h +89 -0
- data/ext/yaji/api/yajl_gen.h +159 -0
- data/ext/yaji/api/yajl_parse.h +193 -0
- data/ext/yaji/api/yajl_version.h +23 -0
- data/ext/yaji/extconf.rb +23 -0
- data/ext/yaji/parser_ext.c +509 -0
- data/ext/yaji/parser_ext.h +101 -0
- data/ext/yaji/yajl.c +159 -0
- data/ext/yaji/yajl_alloc.c +65 -0
- data/ext/yaji/yajl_alloc.h +51 -0
- data/ext/yaji/yajl_buf.c +119 -0
- data/ext/yaji/yajl_buf.h +80 -0
- data/ext/yaji/yajl_bytestack.h +85 -0
- data/ext/yaji/yajl_encode.c +195 -0
- data/ext/yaji/yajl_encode.h +53 -0
- data/ext/yaji/yajl_gen.c +347 -0
- data/ext/yaji/yajl_lex.c +737 -0
- data/ext/yaji/yajl_lex.h +142 -0
- data/ext/yaji/yajl_parser.c +448 -0
- data/ext/yaji/yajl_parser.h +84 -0
- data/ext/yaji/yajl_version.c +7 -0
- data/lib/yaji.rb +24 -0
- data/lib/yaji/version.rb +22 -0
- data/tasks/compile.rake +80 -0
- data/tasks/test.rake +7 -0
- data/tasks/util.rake +4 -0
- data/test/fixture.json +47 -0
- data/test/test_parser.rb +370 -0
- data/yaji.gemspec +27 -0
- metadata +142 -0
data/ext/yaji/extconf.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
ENV['RC_ARCHS'] = '' if RUBY_PLATFORM =~ /darwin/
|
3
|
+
|
4
|
+
require 'mkmf'
|
5
|
+
require 'rbconfig'
|
6
|
+
|
7
|
+
def define(macro, value = nil)
|
8
|
+
$defs.push("-D #{[macro.upcase, value].compact.join('=')}")
|
9
|
+
end
|
10
|
+
|
11
|
+
$CFLAGS << " #{ENV["CFLAGS"]}"
|
12
|
+
$LDFLAGS << " #{ENV["LDFLAGS"]}"
|
13
|
+
$LIBS << " #{ENV["LIBS"]}"
|
14
|
+
|
15
|
+
$CFLAGS << ' -std=c99 -Wall -funroll-loops -Wextra '
|
16
|
+
$CFLAGS << ' -O0 -ggdb3 -pedantic ' if ENV['DEBUG']
|
17
|
+
|
18
|
+
# have_library('yajl', 'yajl_parse', 'yajl/yajl_parse.h')
|
19
|
+
|
20
|
+
define("READ_BUFSIZE", "8192")
|
21
|
+
|
22
|
+
create_header("yaji_config.h")
|
23
|
+
create_makefile("parser_ext")
|
@@ -0,0 +1,509 @@
|
|
1
|
+
/*
|
2
|
+
* Author:: Couchbase <info@couchbase.com>
|
3
|
+
* Copyright:: 2011 Couchbase, Inc.
|
4
|
+
* License:: Apache License, Version 2.0
|
5
|
+
*
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
* you may not use this file except in compliance with the License.
|
8
|
+
* You may obtain a copy of the License at
|
9
|
+
*
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
*
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
* See the License for the specific language governing permissions and
|
16
|
+
* limitations under the License.
|
17
|
+
*/
|
18
|
+
|
19
|
+
#include "parser_ext.h"
|
20
|
+
|
21
|
+
#define STATUS_CONTINUE 1
|
22
|
+
|
23
|
+
#define RB_P(OBJ) \
|
24
|
+
rb_funcall(rb_stderr, rb_intern("print"), 1, rb_funcall(OBJ, rb_intern("object_id"), 0)); \
|
25
|
+
rb_funcall(rb_stderr, rb_intern("print"), 1, rb_str_new2(" ")); \
|
26
|
+
rb_funcall(rb_stderr, rb_intern("print"), 1, rb_funcall(OBJ, rb_intern("class"), 0)); \
|
27
|
+
rb_funcall(rb_stderr, rb_intern("print"), 1, rb_str_new2(" ")); \
|
28
|
+
rb_funcall(rb_stderr, rb_intern("puts"), 1, rb_funcall(OBJ, rb_intern("inspect"), 0));
|
29
|
+
|
30
|
+
#define RERAISE_PARSER_ERROR(parser) \
|
31
|
+
{ \
|
32
|
+
unsigned char* emsg = yajl_get_error(parser->handle, 1, \
|
33
|
+
(const unsigned char*)RSTRING_PTR(p->chunk), \
|
34
|
+
RSTRING_LEN(p->chunk)); \
|
35
|
+
VALUE errobj = rb_exc_new2(c_parse_error, (const char*) emsg); \
|
36
|
+
yajl_free_error(parser->handle, emsg); \
|
37
|
+
rb_exc_raise(errobj); \
|
38
|
+
}
|
39
|
+
|
40
|
+
static int yaji_null(void *ctx)
|
41
|
+
{
|
42
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
|
43
|
+
VALUE rv = rb_ary_new3(3, p->path_str, sym_null, Qnil);
|
44
|
+
rb_ary_push(p->events, rv);
|
45
|
+
return STATUS_CONTINUE;
|
46
|
+
}
|
47
|
+
|
48
|
+
static int yaji_boolean(void *ctx, int val)
|
49
|
+
{
|
50
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
|
51
|
+
VALUE rv = rb_ary_new3(3, p->path_str, sym_boolean, val ? Qtrue : Qfalse);
|
52
|
+
rb_ary_push(p->events, rv);
|
53
|
+
return STATUS_CONTINUE;
|
54
|
+
}
|
55
|
+
|
56
|
+
static int yaji_number(void *ctx, const char *val, unsigned int len)
|
57
|
+
{
|
58
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
|
59
|
+
char buf[len+1];
|
60
|
+
buf[len] = 0;
|
61
|
+
memcpy(buf, val, len);
|
62
|
+
VALUE rv;
|
63
|
+
|
64
|
+
if (memchr(buf, '.', len) || memchr(buf, 'e', len) || memchr(buf, 'E', len)) {
|
65
|
+
rv = rb_ary_new3(3, p->path_str, sym_number, rb_float_new(strtod(buf, NULL)));
|
66
|
+
} else {
|
67
|
+
rv = rb_ary_new3(3, p->path_str, sym_number, rb_cstr2inum(buf, 10));
|
68
|
+
}
|
69
|
+
rb_ary_push(p->events, rv);
|
70
|
+
return STATUS_CONTINUE;
|
71
|
+
}
|
72
|
+
|
73
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
74
|
+
#define YAJI_TO_STR(val, len, str) \
|
75
|
+
str = rb_str_new((const char *)val, len); \
|
76
|
+
rb_encoding *default_internal_enc = rb_default_internal_encoding(); \
|
77
|
+
rb_enc_associate(str, utf8_encoding); \
|
78
|
+
if (default_internal_enc) { \
|
79
|
+
str = rb_str_export_to_enc(str, default_internal_enc); \
|
80
|
+
}
|
81
|
+
#else
|
82
|
+
#define YAJI_TO_STR(val, len, str) \
|
83
|
+
str = rb_str_new((const char *)val, len);
|
84
|
+
#endif
|
85
|
+
|
86
|
+
static int yaji_string(void *ctx, const unsigned char *val, unsigned int len)
|
87
|
+
{
|
88
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
|
89
|
+
VALUE str, rv;
|
90
|
+
YAJI_TO_STR((const char *)val, len, str);
|
91
|
+
rv = rb_ary_new3(3, p->path_str, sym_string, str);
|
92
|
+
rb_ary_push(p->events, rv);
|
93
|
+
return STATUS_CONTINUE;
|
94
|
+
}
|
95
|
+
|
96
|
+
static int yaji_hash_key(void *ctx, const unsigned char *val, unsigned int len)
|
97
|
+
{
|
98
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
|
99
|
+
VALUE key, rv;
|
100
|
+
YAJI_TO_STR((const char *)val, len, key);
|
101
|
+
key = p->symbolize_keys ? ID2SYM(rb_to_id(key)) : key;
|
102
|
+
if (p->key_in_use) {
|
103
|
+
rb_ary_pop(p->path);
|
104
|
+
} else {
|
105
|
+
p->key_in_use = 1;
|
106
|
+
}
|
107
|
+
p->path_str = rb_ary_join(p->path, rb_str_new2("/"));
|
108
|
+
rb_str_freeze(p->path_str);
|
109
|
+
rv = rb_ary_new3(3, p->path_str, sym_hash_key, key);
|
110
|
+
rb_ary_push(p->events, rv);
|
111
|
+
rb_ary_push(p->path, key);
|
112
|
+
p->path_str = rb_ary_join(p->path, rb_str_new2("/"));
|
113
|
+
rb_str_freeze(p->path_str);
|
114
|
+
return STATUS_CONTINUE;
|
115
|
+
}
|
116
|
+
|
117
|
+
static int yaji_start_hash(void *ctx)
|
118
|
+
{
|
119
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
|
120
|
+
p->key_in_use = 0;
|
121
|
+
VALUE rv = rb_ary_new3(3, p->path_str, sym_start_hash, Qnil);
|
122
|
+
rb_ary_push(p->events, rv);
|
123
|
+
return STATUS_CONTINUE;
|
124
|
+
}
|
125
|
+
|
126
|
+
static int yaji_end_hash(void *ctx)
|
127
|
+
{
|
128
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
|
129
|
+
rb_ary_pop(p->path);
|
130
|
+
p->path_str = rb_ary_join(p->path, rb_str_new2("/"));
|
131
|
+
VALUE rv = rb_ary_new3(3, p->path_str, sym_end_hash, Qnil);
|
132
|
+
rb_ary_push(p->events, rv);
|
133
|
+
return STATUS_CONTINUE;
|
134
|
+
}
|
135
|
+
|
136
|
+
static int yaji_start_array(void *ctx)
|
137
|
+
{
|
138
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
|
139
|
+
VALUE rv = rb_ary_new3(3, p->path_str, sym_start_array, Qnil);
|
140
|
+
rb_ary_push(p->path, rb_str_new2(""));
|
141
|
+
p->path_str = rb_ary_join(p->path, rb_str_new2("/"));
|
142
|
+
rb_str_freeze(p->path_str);
|
143
|
+
rb_ary_push(p->events, rv);
|
144
|
+
return STATUS_CONTINUE;
|
145
|
+
}
|
146
|
+
|
147
|
+
static int yaji_end_array(void *ctx)
|
148
|
+
{
|
149
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(ctx);
|
150
|
+
|
151
|
+
rb_ary_pop(p->path);
|
152
|
+
p->path_str = rb_ary_join(p->path, rb_str_new2("/"));
|
153
|
+
|
154
|
+
VALUE rv = rb_ary_new3(3, p->path_str, sym_end_array, Qnil);
|
155
|
+
rb_ary_push(p->events, rv);
|
156
|
+
return STATUS_CONTINUE;
|
157
|
+
}
|
158
|
+
|
159
|
+
static VALUE rb_yaji_each_iter(VALUE chunk, VALUE parser);
|
160
|
+
|
161
|
+
static VALUE rb_yaji_parser_parse_chunk(VALUE chunk, VALUE self)
|
162
|
+
{
|
163
|
+
yajl_status rc;
|
164
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(self);
|
165
|
+
const char* buf;
|
166
|
+
unsigned int len;
|
167
|
+
int i;
|
168
|
+
|
169
|
+
if (NIL_P(chunk) || (len = RSTRING_LEN(chunk)) == 0) {
|
170
|
+
return INT2FIX(0);
|
171
|
+
}
|
172
|
+
buf = RSTRING_PTR(chunk);
|
173
|
+
p->events = rb_ary_new();
|
174
|
+
p->chunk = chunk;
|
175
|
+
rc = yajl_parse(p->handle, (const unsigned char*)buf, len);
|
176
|
+
if (rc == yajl_status_error) {
|
177
|
+
RERAISE_PARSER_ERROR(p);
|
178
|
+
}
|
179
|
+
for (i=0; i<RARRAY_LEN(p->events); i++) {
|
180
|
+
if (NIL_P(p->input)) {
|
181
|
+
p->effective_proc = p->on_object_cb;
|
182
|
+
p->effective_filter = p->filter;
|
183
|
+
p->effective_with_path = p->with_path ? Qtrue : Qfalse;
|
184
|
+
rb_yaji_each_iter(RARRAY_PTR(p->events)[i], self);
|
185
|
+
} else {
|
186
|
+
rb_funcall(p->parser_cb, id_call, 1, RARRAY_PTR(p->events)[i]);
|
187
|
+
}
|
188
|
+
}
|
189
|
+
return rb_funcall(chunk, id_bytesize, 0, NULL);
|
190
|
+
}
|
191
|
+
|
192
|
+
static VALUE rb_yaji_parser_new(int argc, VALUE *argv, VALUE klass)
|
193
|
+
{
|
194
|
+
yaji_parser* p;
|
195
|
+
VALUE opts, obj;
|
196
|
+
|
197
|
+
obj = Data_Make_Struct(klass, yaji_parser, rb_yaji_parser_mark, rb_yaji_parser_free, p);
|
198
|
+
p->handle = NULL;
|
199
|
+
p->config.allowComments = 1;
|
200
|
+
p->config.checkUTF8 = 1;
|
201
|
+
p->symbolize_keys = 0;
|
202
|
+
p->with_path = 0;
|
203
|
+
p->filter = Qnil;
|
204
|
+
p->rbufsize = Qnil;
|
205
|
+
p->input = Qnil;
|
206
|
+
p->parser_cb = Qnil;
|
207
|
+
p->on_object_cb = Qnil;
|
208
|
+
|
209
|
+
rb_scan_args(argc, argv, "02", &p->input, &opts);
|
210
|
+
if (NIL_P(opts) && TYPE(p->input) == T_HASH) {
|
211
|
+
opts = p->input;
|
212
|
+
p->input = Qnil;
|
213
|
+
}
|
214
|
+
if (!NIL_P(p->input)) {
|
215
|
+
if (TYPE(p->input) == T_STRING) {
|
216
|
+
p->input = rb_class_new_instance(1, &p->input, c_stringio);
|
217
|
+
} else if (rb_respond_to(p->input, id_perform) && rb_respond_to(p->input, id_on_body)) {
|
218
|
+
rb_block_call(p->input, id_on_body, 0, NULL, rb_yaji_parser_parse_chunk, obj);
|
219
|
+
} else if (!rb_respond_to(p->input, id_read)) {
|
220
|
+
rb_raise(c_parse_error, "input must be a String or IO or "
|
221
|
+
"something responding to #perform and #on_body e.g. Curl::Easy");
|
222
|
+
}
|
223
|
+
}
|
224
|
+
if (!NIL_P(opts)) {
|
225
|
+
Check_Type(opts, T_HASH);
|
226
|
+
if (rb_hash_aref(opts, sym_allow_comments) == Qfalse) {
|
227
|
+
p->config.allowComments = 0;
|
228
|
+
}
|
229
|
+
if (rb_hash_aref(opts, sym_check_utf8) == Qfalse) {
|
230
|
+
p->config.checkUTF8 = 0;
|
231
|
+
}
|
232
|
+
if (rb_hash_aref(opts, sym_symbolize_keys) == Qtrue) {
|
233
|
+
p->symbolize_keys = 1;
|
234
|
+
}
|
235
|
+
p->rbufsize = rb_hash_aref(opts, sym_read_buffer_size);
|
236
|
+
if (rb_hash_aref(opts, sym_with_path) == Qtrue) {
|
237
|
+
p->with_path = 1;
|
238
|
+
}
|
239
|
+
p->filter = rb_hash_aref(opts, sym_filter);
|
240
|
+
}
|
241
|
+
if (NIL_P(p->rbufsize)) {
|
242
|
+
p->rbufsize = INT2FIX(READ_BUFSIZE);
|
243
|
+
} else {
|
244
|
+
Check_Type(p->rbufsize, T_FIXNUM);
|
245
|
+
}
|
246
|
+
p->object_stack = rb_ary_new();
|
247
|
+
p->path = rb_ary_new();
|
248
|
+
rb_ary_push(p->path, rb_str_new("", 0));
|
249
|
+
p->path_str = rb_str_new("", 0);
|
250
|
+
p->handle = yajl_alloc(&yaji_callbacks, &p->config, NULL, (void *)obj);
|
251
|
+
rb_obj_call_init(obj, 0, 0);
|
252
|
+
return obj;
|
253
|
+
}
|
254
|
+
|
255
|
+
static VALUE rb_yaji_parser_init(int argc, VALUE *argv, VALUE self)
|
256
|
+
{
|
257
|
+
return self;
|
258
|
+
(void)argc;
|
259
|
+
(void)argv;
|
260
|
+
}
|
261
|
+
|
262
|
+
static VALUE rb_yaji_parser_write(VALUE self, VALUE val)
|
263
|
+
{
|
264
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(self);
|
265
|
+
|
266
|
+
if (NIL_P(p->on_object_cb)) {
|
267
|
+
rb_raise(rb_eArgError, "#on_object callback required");
|
268
|
+
}
|
269
|
+
if (!NIL_P(val)) {
|
270
|
+
Check_Type(val, T_STRING);
|
271
|
+
}
|
272
|
+
return rb_yaji_parser_parse_chunk(val, self);
|
273
|
+
}
|
274
|
+
|
275
|
+
static VALUE rb_yaji_parser_parse(int argc, VALUE* argv, VALUE self)
|
276
|
+
{
|
277
|
+
yajl_status rc;
|
278
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(self);
|
279
|
+
int i;
|
280
|
+
|
281
|
+
if (NIL_P(p->input)) {
|
282
|
+
rb_raise(rb_eArgError, "input object required to use #parse method");
|
283
|
+
}
|
284
|
+
rb_scan_args(argc, argv, "00&", &p->parser_cb);
|
285
|
+
RETURN_ENUMERATOR(self, argc, argv);
|
286
|
+
|
287
|
+
p->chunk = Qnil;
|
288
|
+
|
289
|
+
if (rb_respond_to(p->input, id_perform)) {
|
290
|
+
rb_funcall(p->input, id_perform, 0);
|
291
|
+
} else {
|
292
|
+
p->chunk = rb_str_new(NULL, 0);
|
293
|
+
while (rb_funcall(p->input, id_read, 2, p->rbufsize, p->chunk) != Qnil) {
|
294
|
+
rb_yaji_parser_parse_chunk(p->chunk, self);
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
p->events = rb_ary_new();
|
299
|
+
rc = yajl_parse_complete(p->handle);
|
300
|
+
|
301
|
+
if (rc == yajl_status_error ||
|
302
|
+
(rc == yajl_status_insufficient_data && p->chunk != Qnil &&
|
303
|
+
RSTRING_LEN(rb_funcall(p->chunk, id_strip, 0)) != 0)) {
|
304
|
+
RERAISE_PARSER_ERROR(p);
|
305
|
+
}
|
306
|
+
for (i=0; i<RARRAY_LEN(p->events); i++) {
|
307
|
+
rb_funcall(p->parser_cb, id_call, 1, RARRAY_PTR(p->events)[i]);
|
308
|
+
}
|
309
|
+
|
310
|
+
return Qnil;
|
311
|
+
}
|
312
|
+
|
313
|
+
static int rb_yaji_str_start_with(VALUE str, VALUE filter)
|
314
|
+
{
|
315
|
+
int i;
|
316
|
+
const char *ptr = RSTRING_PTR(str);
|
317
|
+
long len = RSTRING_LEN(str);
|
318
|
+
VALUE entry;
|
319
|
+
|
320
|
+
switch(TYPE(filter)) {
|
321
|
+
case T_STRING:
|
322
|
+
return RSTRING_LEN(filter) <= len && memcmp(RSTRING_PTR(filter), ptr, RSTRING_LEN(filter)) == 0;
|
323
|
+
break;
|
324
|
+
case T_ARRAY:
|
325
|
+
for (i=0; i<RARRAY_LEN(filter); i++) {
|
326
|
+
entry = RARRAY_PTR(filter)[i];
|
327
|
+
if (RSTRING_LEN(entry) <= len && memcmp(RSTRING_PTR(entry), ptr, RSTRING_LEN(entry)) == 0) {
|
328
|
+
return 1;
|
329
|
+
}
|
330
|
+
}
|
331
|
+
break;
|
332
|
+
}
|
333
|
+
return 0;
|
334
|
+
}
|
335
|
+
|
336
|
+
static VALUE rb_yaji_each_iter(VALUE chunk, VALUE parser)
|
337
|
+
{
|
338
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(parser);
|
339
|
+
VALUE path = rb_ary_shift(chunk);
|
340
|
+
VALUE event = rb_ary_shift(chunk);
|
341
|
+
VALUE value = rb_ary_shift(chunk);
|
342
|
+
VALUE last_entry, object, container, key, hash;
|
343
|
+
|
344
|
+
if (NIL_P(p->effective_filter) || rb_yaji_str_start_with(path, p->effective_filter)) {
|
345
|
+
if (event == sym_hash_key) {
|
346
|
+
rb_ary_push(p->object_stack, value);
|
347
|
+
} else if (event == sym_start_hash || event == sym_start_array) {
|
348
|
+
container = (event == sym_start_hash) ? rb_hash_new() : rb_ary_new();
|
349
|
+
last_entry = rb_ary_entry(p->object_stack, -1);
|
350
|
+
switch(TYPE(last_entry)) {
|
351
|
+
case T_STRING:
|
352
|
+
key = rb_ary_pop(p->object_stack);
|
353
|
+
hash = rb_ary_entry(p->object_stack, -1);
|
354
|
+
rb_hash_aset(hash, key, container);
|
355
|
+
break;
|
356
|
+
case T_ARRAY:
|
357
|
+
rb_ary_push(last_entry, container);
|
358
|
+
}
|
359
|
+
rb_ary_push(p->object_stack, container);
|
360
|
+
} else if (event == sym_end_hash || event == sym_end_array) {
|
361
|
+
object = rb_ary_pop(p->object_stack);
|
362
|
+
if (RARRAY_LEN(p->object_stack) == 0) {
|
363
|
+
if (RTEST(p->effective_with_path)) {
|
364
|
+
rb_funcall(p->effective_proc, id_call, 1, rb_ary_new3(2, path, object));
|
365
|
+
} else {
|
366
|
+
rb_funcall(p->effective_proc, id_call, 1, object);
|
367
|
+
}
|
368
|
+
}
|
369
|
+
} else {
|
370
|
+
last_entry = rb_ary_entry(p->object_stack, -1);
|
371
|
+
switch(TYPE(last_entry)) {
|
372
|
+
case T_STRING:
|
373
|
+
key = rb_ary_pop(p->object_stack);
|
374
|
+
hash = rb_ary_entry(p->object_stack, -1);
|
375
|
+
rb_hash_aset(hash, key, value);
|
376
|
+
break;
|
377
|
+
case T_ARRAY:
|
378
|
+
rb_ary_push(last_entry, value);
|
379
|
+
break;
|
380
|
+
case T_NIL:
|
381
|
+
if (RTEST(p->effective_with_path)) {
|
382
|
+
rb_funcall(p->effective_proc, id_call, 1, rb_ary_new3(2, path, value));
|
383
|
+
} else {
|
384
|
+
rb_funcall(p->effective_proc, id_call, 1, value);
|
385
|
+
}
|
386
|
+
break;
|
387
|
+
}
|
388
|
+
}
|
389
|
+
}
|
390
|
+
return Qnil;
|
391
|
+
}
|
392
|
+
|
393
|
+
static VALUE rb_yaji_parser_each(int argc, VALUE* argv, VALUE self)
|
394
|
+
{
|
395
|
+
VALUE filter, proc, options;
|
396
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(self);
|
397
|
+
|
398
|
+
if (NIL_P(p->input)) {
|
399
|
+
rb_raise(rb_eArgError, "input object required to use #each method");
|
400
|
+
}
|
401
|
+
RETURN_ENUMERATOR(self, argc, argv);
|
402
|
+
rb_scan_args(argc, argv, "02&", &filter, &options, &proc);
|
403
|
+
p->effective_proc = proc;
|
404
|
+
p->object_stack = rb_ary_new();
|
405
|
+
if (NIL_P(filter)) {
|
406
|
+
p->effective_filter = p->filter;
|
407
|
+
} else {
|
408
|
+
p->effective_filter = filter;
|
409
|
+
}
|
410
|
+
p->effective_with_path = p->with_path ? Qtrue : Qfalse;
|
411
|
+
if (options != Qnil) {
|
412
|
+
VALUE arg;
|
413
|
+
Check_Type(options, T_HASH);
|
414
|
+
arg = rb_hash_aref(options, sym_with_path);
|
415
|
+
if (!NIL_P(arg)) {
|
416
|
+
p->effective_with_path = arg;
|
417
|
+
}
|
418
|
+
}
|
419
|
+
rb_block_call(self, id_parse, 0, NULL, rb_yaji_each_iter, self);
|
420
|
+
return Qnil;
|
421
|
+
}
|
422
|
+
|
423
|
+
static void rb_yaji_parser_free(void *parser)
|
424
|
+
{
|
425
|
+
yaji_parser* p = parser;
|
426
|
+
if (p) {
|
427
|
+
if (p->handle) {
|
428
|
+
yajl_free(p->handle);
|
429
|
+
}
|
430
|
+
free(p);
|
431
|
+
}
|
432
|
+
}
|
433
|
+
|
434
|
+
static VALUE rb_yaji_parser_on_object(VALUE self)
|
435
|
+
{
|
436
|
+
yaji_parser *p = DATA_PTR(self);
|
437
|
+
|
438
|
+
if (rb_block_given_p()) {
|
439
|
+
p->on_object_cb = rb_block_proc();
|
440
|
+
}
|
441
|
+
return p->on_object_cb;
|
442
|
+
}
|
443
|
+
|
444
|
+
static void rb_yaji_parser_mark(void *parser)
|
445
|
+
{
|
446
|
+
yaji_parser* p = parser;
|
447
|
+
if (p) {
|
448
|
+
rb_gc_mark(p->input);
|
449
|
+
rb_gc_mark(p->rbufsize);
|
450
|
+
rb_gc_mark(p->events);
|
451
|
+
rb_gc_mark(p->path);
|
452
|
+
rb_gc_mark(p->path_str);
|
453
|
+
rb_gc_mark(p->parser_cb);
|
454
|
+
rb_gc_mark(p->on_object_cb);
|
455
|
+
rb_gc_mark(p->chunk);
|
456
|
+
rb_gc_mark(p->object_stack);
|
457
|
+
rb_gc_mark(p->effective_filter);
|
458
|
+
rb_gc_mark(p->effective_with_path);
|
459
|
+
rb_gc_mark(p->effective_proc);
|
460
|
+
}
|
461
|
+
}
|
462
|
+
|
463
|
+
/* Ruby Extension initializer */
|
464
|
+
void Init_parser_ext() {
|
465
|
+
m_yaji = rb_define_module("YAJI");
|
466
|
+
|
467
|
+
c_parse_error = rb_define_class_under(m_yaji, "ParseError", rb_eStandardError);
|
468
|
+
|
469
|
+
c_yaji_parser = rb_define_class_under(m_yaji, "Parser", rb_cObject);
|
470
|
+
rb_define_const(c_yaji_parser, "READ_BUFFER_SIZE", INT2FIX(READ_BUFSIZE));
|
471
|
+
rb_define_singleton_method(c_yaji_parser, "new", rb_yaji_parser_new, -1);
|
472
|
+
rb_define_method(c_yaji_parser, "initialize", rb_yaji_parser_init, -1);
|
473
|
+
rb_define_method(c_yaji_parser, "parse", rb_yaji_parser_parse, -1);
|
474
|
+
rb_define_method(c_yaji_parser, "each", rb_yaji_parser_each, -1);
|
475
|
+
rb_define_method(c_yaji_parser, "on_object", rb_yaji_parser_on_object, 0);
|
476
|
+
rb_define_method(c_yaji_parser, "write", rb_yaji_parser_write, 1);
|
477
|
+
rb_define_alias(c_yaji_parser, "<<", "write");
|
478
|
+
|
479
|
+
id_call = rb_intern("call");
|
480
|
+
id_read = rb_intern("read");
|
481
|
+
id_parse = rb_intern("parse");
|
482
|
+
id_strip = rb_intern("strip");
|
483
|
+
id_perform = rb_intern("perform");
|
484
|
+
id_on_body = rb_intern("on_body");
|
485
|
+
id_bytesize = rb_intern("bytesize");
|
486
|
+
|
487
|
+
sym_allow_comments = ID2SYM(rb_intern("allow_comments"));
|
488
|
+
sym_check_utf8 = ID2SYM(rb_intern("check_utf8"));
|
489
|
+
sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
|
490
|
+
sym_read_buffer_size = ID2SYM(rb_intern("read_buffer_size"));
|
491
|
+
sym_with_path = ID2SYM(rb_intern("with_path"));
|
492
|
+
sym_filter = ID2SYM(rb_intern("filter"));
|
493
|
+
sym_null = ID2SYM(rb_intern("null"));
|
494
|
+
sym_boolean = ID2SYM(rb_intern("boolean"));
|
495
|
+
sym_number = ID2SYM(rb_intern("number"));
|
496
|
+
sym_string = ID2SYM(rb_intern("string"));
|
497
|
+
sym_hash_key = ID2SYM(rb_intern("hash_key"));
|
498
|
+
sym_start_hash = ID2SYM(rb_intern("start_hash"));
|
499
|
+
sym_end_hash = ID2SYM(rb_intern("end_hash"));
|
500
|
+
sym_start_array = ID2SYM(rb_intern("start_array"));
|
501
|
+
sym_end_array = ID2SYM(rb_intern("end_array"));
|
502
|
+
|
503
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
504
|
+
utf8_encoding = rb_utf8_encoding();
|
505
|
+
#endif
|
506
|
+
|
507
|
+
rb_require("stringio");
|
508
|
+
c_stringio = rb_const_get(rb_cObject, rb_intern("StringIO"));
|
509
|
+
}
|