yaji 0.2.3-x86-mingw32 → 0.3.0-x86-mingw32
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.
- data/HISTORY.markdown +5 -0
- data/ext/yaji/parser_ext.c +94 -26
- data/ext/yaji/parser_ext.h +5 -1
- data/lib/yaji/version.rb +1 -1
- data/test/test_parser.rb +98 -3
- metadata +5 -5
data/HISTORY.markdown
CHANGED
data/ext/yaji/parser_ext.c
CHANGED
@@ -156,6 +156,8 @@ static int yaji_end_array(void *ctx)
|
|
156
156
|
return STATUS_CONTINUE;
|
157
157
|
}
|
158
158
|
|
159
|
+
static VALUE rb_yaji_each_iter(VALUE chunk, VALUE* params_p);
|
160
|
+
|
159
161
|
static VALUE rb_yaji_parser_parse_chunk(VALUE chunk, VALUE self)
|
160
162
|
{
|
161
163
|
yajl_status rc;
|
@@ -175,7 +177,16 @@ static VALUE rb_yaji_parser_parse_chunk(VALUE chunk, VALUE self)
|
|
175
177
|
RERAISE_PARSER_ERROR(p);
|
176
178
|
}
|
177
179
|
for (i=0; i<RARRAY_LEN(p->events); i++) {
|
178
|
-
|
180
|
+
if (NIL_P(p->input)) {
|
181
|
+
VALUE params[4];
|
182
|
+
params[0] = p->on_object_cb;
|
183
|
+
params[1] = p->object_stack;
|
184
|
+
params[2] = p->filter;
|
185
|
+
params[3] = p->with_path ? Qtrue : Qfalse;
|
186
|
+
rb_yaji_each_iter(RARRAY_PTR(p->events)[i], params);
|
187
|
+
} else {
|
188
|
+
rb_funcall(p->parser_cb, id_call, 1, RARRAY_PTR(p->events)[i]);
|
189
|
+
}
|
179
190
|
}
|
180
191
|
return rb_funcall(chunk, id_bytesize, 0, NULL);
|
181
192
|
}
|
@@ -190,18 +201,27 @@ static VALUE rb_yaji_parser_new(int argc, VALUE *argv, VALUE klass)
|
|
190
201
|
p->config.allowComments = 1;
|
191
202
|
p->config.checkUTF8 = 1;
|
192
203
|
p->symbolize_keys = 0;
|
204
|
+
p->with_path = 0;
|
205
|
+
p->filter = Qnil;
|
193
206
|
p->rbufsize = Qnil;
|
194
207
|
p->input = Qnil;
|
195
208
|
p->parser_cb = Qnil;
|
209
|
+
p->on_object_cb = Qnil;
|
196
210
|
|
197
|
-
rb_scan_args(argc, argv, "
|
198
|
-
if (TYPE(p->input) ==
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
211
|
+
rb_scan_args(argc, argv, "02", &p->input, &opts);
|
212
|
+
if (NIL_P(opts) && TYPE(p->input) == T_HASH) {
|
213
|
+
opts = p->input;
|
214
|
+
p->input = Qnil;
|
215
|
+
}
|
216
|
+
if (!NIL_P(p->input)) {
|
217
|
+
if (TYPE(p->input) == T_STRING) {
|
218
|
+
p->input = rb_class_new_instance(1, &p->input, c_stringio);
|
219
|
+
} else if (rb_respond_to(p->input, id_perform) && rb_respond_to(p->input, id_on_body)) {
|
220
|
+
rb_block_call(p->input, id_on_body, 0, NULL, rb_yaji_parser_parse_chunk, obj);
|
221
|
+
} else if (!rb_respond_to(p->input, id_read)) {
|
222
|
+
rb_raise(c_parse_error, "input must be a String or IO or "
|
223
|
+
"something responding to #perform and #on_body e.g. Curl::Easy");
|
224
|
+
}
|
205
225
|
}
|
206
226
|
if (!NIL_P(opts)) {
|
207
227
|
Check_Type(opts, T_HASH);
|
@@ -215,12 +235,20 @@ static VALUE rb_yaji_parser_new(int argc, VALUE *argv, VALUE klass)
|
|
215
235
|
p->symbolize_keys = 1;
|
216
236
|
}
|
217
237
|
p->rbufsize = rb_hash_aref(opts, sym_read_buffer_size);
|
238
|
+
if (rb_hash_aref(opts, sym_with_path) == Qtrue) {
|
239
|
+
p->with_path = 1;
|
240
|
+
}
|
241
|
+
p->filter = rb_hash_aref(opts, sym_filter);
|
218
242
|
}
|
219
243
|
if (NIL_P(p->rbufsize)) {
|
220
244
|
p->rbufsize = INT2FIX(READ_BUFSIZE);
|
221
245
|
} else {
|
222
246
|
Check_Type(p->rbufsize, T_FIXNUM);
|
223
247
|
}
|
248
|
+
p->object_stack = rb_ary_new();
|
249
|
+
p->path = rb_ary_new();
|
250
|
+
rb_ary_push(p->path, rb_str_new("", 0));
|
251
|
+
p->path_str = rb_str_new("", 0);
|
224
252
|
p->handle = yajl_alloc(&yaji_callbacks, &p->config, NULL, (void *)obj);
|
225
253
|
rb_obj_call_init(obj, 0, 0);
|
226
254
|
return obj;
|
@@ -229,8 +257,22 @@ static VALUE rb_yaji_parser_new(int argc, VALUE *argv, VALUE klass)
|
|
229
257
|
static VALUE rb_yaji_parser_init(int argc, VALUE *argv, VALUE self)
|
230
258
|
{
|
231
259
|
return self;
|
260
|
+
(void)argc;
|
261
|
+
(void)argv;
|
232
262
|
}
|
233
263
|
|
264
|
+
static VALUE rb_yaji_parser_write(VALUE self, VALUE val)
|
265
|
+
{
|
266
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(self);
|
267
|
+
|
268
|
+
if (NIL_P(p->on_object_cb)) {
|
269
|
+
rb_raise(rb_eArgError, "#on_object callback required");
|
270
|
+
}
|
271
|
+
if (!NIL_P(val)) {
|
272
|
+
Check_Type(val, T_STRING);
|
273
|
+
}
|
274
|
+
return rb_yaji_parser_parse_chunk(val, self);
|
275
|
+
}
|
234
276
|
|
235
277
|
static VALUE rb_yaji_parser_parse(int argc, VALUE* argv, VALUE self)
|
236
278
|
{
|
@@ -238,12 +280,12 @@ static VALUE rb_yaji_parser_parse(int argc, VALUE* argv, VALUE self)
|
|
238
280
|
yaji_parser* p = (yaji_parser*) DATA_PTR(self);
|
239
281
|
int i;
|
240
282
|
|
283
|
+
if (NIL_P(p->input)) {
|
284
|
+
rb_raise(rb_eArgError, "input object required to use #parse method");
|
285
|
+
}
|
241
286
|
rb_scan_args(argc, argv, "00&", &p->parser_cb);
|
242
287
|
RETURN_ENUMERATOR(self, argc, argv);
|
243
288
|
|
244
|
-
p->path = rb_ary_new();
|
245
|
-
rb_ary_push(p->path, rb_str_new("", 0));
|
246
|
-
p->path_str = rb_str_new("", 0);
|
247
289
|
p->chunk = Qnil;
|
248
290
|
|
249
291
|
if (rb_respond_to(p->input, id_perform)) {
|
@@ -270,20 +312,20 @@ static VALUE rb_yaji_parser_parse(int argc, VALUE* argv, VALUE self)
|
|
270
312
|
return Qnil;
|
271
313
|
}
|
272
314
|
|
273
|
-
static int rb_yaji_str_start_with(VALUE str, VALUE
|
315
|
+
static int rb_yaji_str_start_with(VALUE str, VALUE filter)
|
274
316
|
{
|
275
317
|
int i;
|
276
318
|
const char *ptr = RSTRING_PTR(str);
|
277
|
-
|
319
|
+
long len = RSTRING_LEN(str);
|
278
320
|
VALUE entry;
|
279
321
|
|
280
|
-
switch(TYPE(
|
322
|
+
switch(TYPE(filter)) {
|
281
323
|
case T_STRING:
|
282
|
-
return RSTRING_LEN(
|
324
|
+
return RSTRING_LEN(filter) <= len && memcmp(RSTRING_PTR(filter), ptr, RSTRING_LEN(filter)) == 0;
|
283
325
|
break;
|
284
326
|
case T_ARRAY:
|
285
|
-
for (i=0; i<RARRAY_LEN(
|
286
|
-
entry = RARRAY_PTR(
|
327
|
+
for (i=0; i<RARRAY_LEN(filter); i++) {
|
328
|
+
entry = RARRAY_PTR(filter)[i];
|
287
329
|
if (RSTRING_LEN(entry) <= len && memcmp(RSTRING_PTR(entry), ptr, RSTRING_LEN(entry)) == 0) {
|
288
330
|
return 1;
|
289
331
|
}
|
@@ -301,11 +343,11 @@ static VALUE rb_yaji_each_iter(VALUE chunk, VALUE* params_p)
|
|
301
343
|
VALUE value = rb_ary_shift(chunk);
|
302
344
|
VALUE proc = params[0];
|
303
345
|
VALUE stack = params[1];
|
304
|
-
VALUE
|
346
|
+
VALUE filter = params[2];
|
305
347
|
VALUE with_path = params[3];
|
306
348
|
VALUE last_entry, object, container, key, hash;
|
307
349
|
|
308
|
-
if (NIL_P(
|
350
|
+
if (NIL_P(filter) || rb_yaji_str_start_with(path, filter)) {
|
309
351
|
if (event == sym_hash_key) {
|
310
352
|
rb_ary_push(stack, value);
|
311
353
|
} else if (event == sym_start_hash || event == sym_start_array) {
|
@@ -356,17 +398,29 @@ static VALUE rb_yaji_each_iter(VALUE chunk, VALUE* params_p)
|
|
356
398
|
|
357
399
|
static VALUE rb_yaji_parser_each(int argc, VALUE* argv, VALUE self)
|
358
400
|
{
|
359
|
-
VALUE
|
401
|
+
VALUE filter, proc, options, params[4];
|
402
|
+
yaji_parser* p = (yaji_parser*) DATA_PTR(self);
|
403
|
+
|
404
|
+
if (NIL_P(p->input)) {
|
405
|
+
rb_raise(rb_eArgError, "input object required to use #each method");
|
406
|
+
}
|
360
407
|
RETURN_ENUMERATOR(self, argc, argv);
|
361
|
-
rb_scan_args(argc, argv, "02&", &
|
408
|
+
rb_scan_args(argc, argv, "02&", &filter, &options, &proc);
|
362
409
|
params[0] = proc; // callback
|
363
410
|
params[1] = rb_ary_new(); // stack
|
364
|
-
|
411
|
+
if (NIL_P(filter)) {
|
412
|
+
params[2] = p->filter;
|
413
|
+
} else {
|
414
|
+
params[2] = filter;
|
415
|
+
}
|
416
|
+
params[3] = p->with_path ? Qtrue : Qfalse;
|
365
417
|
if (options != Qnil) {
|
418
|
+
VALUE arg;
|
366
419
|
Check_Type(options, T_HASH);
|
367
|
-
|
368
|
-
|
369
|
-
|
420
|
+
arg = rb_hash_aref(options, sym_with_path);
|
421
|
+
if (!NIL_P(arg)) {
|
422
|
+
params[3] = arg;
|
423
|
+
}
|
370
424
|
}
|
371
425
|
rb_block_call(self, id_parse, 0, NULL, rb_yaji_each_iter, (VALUE)params);
|
372
426
|
return Qnil;
|
@@ -383,6 +437,16 @@ static void rb_yaji_parser_free(void *parser)
|
|
383
437
|
}
|
384
438
|
}
|
385
439
|
|
440
|
+
static VALUE rb_yaji_parser_on_object(VALUE self)
|
441
|
+
{
|
442
|
+
yaji_parser *p = DATA_PTR(self);
|
443
|
+
|
444
|
+
if (rb_block_given_p()) {
|
445
|
+
p->on_object_cb = rb_block_proc();
|
446
|
+
}
|
447
|
+
return p->on_object_cb;
|
448
|
+
}
|
449
|
+
|
386
450
|
static void rb_yaji_parser_mark(void *parser)
|
387
451
|
{
|
388
452
|
yaji_parser* p = parser;
|
@@ -409,6 +473,9 @@ void Init_parser_ext() {
|
|
409
473
|
rb_define_method(c_yaji_parser, "initialize", rb_yaji_parser_init, -1);
|
410
474
|
rb_define_method(c_yaji_parser, "parse", rb_yaji_parser_parse, -1);
|
411
475
|
rb_define_method(c_yaji_parser, "each", rb_yaji_parser_each, -1);
|
476
|
+
rb_define_method(c_yaji_parser, "on_object", rb_yaji_parser_on_object, 0);
|
477
|
+
rb_define_method(c_yaji_parser, "write", rb_yaji_parser_write, 1);
|
478
|
+
rb_define_alias(c_yaji_parser, "<<", "write");
|
412
479
|
|
413
480
|
id_call = rb_intern("call");
|
414
481
|
id_read = rb_intern("read");
|
@@ -423,6 +490,7 @@ void Init_parser_ext() {
|
|
423
490
|
sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
|
424
491
|
sym_read_buffer_size = ID2SYM(rb_intern("read_buffer_size"));
|
425
492
|
sym_with_path = ID2SYM(rb_intern("with_path"));
|
493
|
+
sym_filter = ID2SYM(rb_intern("filter"));
|
426
494
|
sym_null = ID2SYM(rb_intern("null"));
|
427
495
|
sym_boolean = ID2SYM(rb_intern("boolean"));
|
428
496
|
sym_number = ID2SYM(rb_intern("number"));
|
data/ext/yaji/parser_ext.h
CHANGED
@@ -45,7 +45,7 @@ static ID id_call, id_read, id_parse, id_perform, id_on_body, id_bytesize, id_st
|
|
45
45
|
static ID sym_allow_comments, sym_check_utf8, sym_symbolize_keys, sym_with_path,
|
46
46
|
sym_read_buffer_size, sym_null, sym_boolean, sym_number, sym_string,
|
47
47
|
sym_hash_key, sym_start_hash, sym_end_hash, sym_start_array,
|
48
|
-
sym_end_array;
|
48
|
+
sym_end_array, sym_filter;
|
49
49
|
|
50
50
|
static int yaji_null(void *ctx);
|
51
51
|
static int yaji_boolean(void *ctx, int val);
|
@@ -74,6 +74,7 @@ static yajl_callbacks yaji_callbacks = {
|
|
74
74
|
typedef struct {
|
75
75
|
int symbolize_keys;
|
76
76
|
int key_in_use;
|
77
|
+
int with_path;
|
77
78
|
VALUE input;
|
78
79
|
VALUE rbufsize;
|
79
80
|
VALUE events;
|
@@ -81,6 +82,9 @@ typedef struct {
|
|
81
82
|
VALUE path_str;
|
82
83
|
VALUE parser_cb;
|
83
84
|
VALUE chunk;
|
85
|
+
VALUE filter;
|
86
|
+
VALUE on_object_cb;
|
87
|
+
VALUE object_stack;
|
84
88
|
yajl_handle handle;
|
85
89
|
yajl_parser_config config;
|
86
90
|
} yaji_parser;
|
data/lib/yaji/version.rb
CHANGED
data/test/test_parser.rb
CHANGED
@@ -196,7 +196,7 @@ class TestParser < MiniTest::Unit::TestCase
|
|
196
196
|
assert_equal expected, objects
|
197
197
|
end
|
198
198
|
|
199
|
-
def
|
199
|
+
def test_it_optionally_yields_object_path
|
200
200
|
parser = YAJI::Parser.new(toys_json_str)
|
201
201
|
objects = []
|
202
202
|
parser.each(["/total_rows", "/rows/"], :with_path => true) do |o|
|
@@ -216,6 +216,28 @@ class TestParser < MiniTest::Unit::TestCase
|
|
216
216
|
assert_equal expected, objects
|
217
217
|
end
|
218
218
|
|
219
|
+
def test_it_allows_to_specify_filter_and_options_at_initialization
|
220
|
+
parser = YAJI::Parser.new(toys_json_str,
|
221
|
+
:filter => ["/total_rows", "/rows/"],
|
222
|
+
:with_path => true)
|
223
|
+
objects = []
|
224
|
+
parser.each do |o|
|
225
|
+
objects << o
|
226
|
+
end
|
227
|
+
expected = [["/total_rows", 2],
|
228
|
+
["/rows/", {
|
229
|
+
"id" => "buzz",
|
230
|
+
"props" => { "humanoid"=> true, "armed"=> true },
|
231
|
+
"movies" => [1,2,3]
|
232
|
+
}],
|
233
|
+
["/rows/", {
|
234
|
+
"id" => "barbie",
|
235
|
+
"props" => { "humanoid"=> true, "armed"=> false },
|
236
|
+
"movies" => [2,3]
|
237
|
+
}]]
|
238
|
+
assert_equal expected, objects
|
239
|
+
end
|
240
|
+
|
219
241
|
def test_it_doesnt_raise_exception_on_empty_input
|
220
242
|
YAJI::Parser.new("").parse
|
221
243
|
YAJI::Parser.new(" ").parse
|
@@ -223,9 +245,82 @@ class TestParser < MiniTest::Unit::TestCase
|
|
223
245
|
YAJI::Parser.new(" \n\n ").parse
|
224
246
|
end
|
225
247
|
|
248
|
+
def test_it_allows_to_create_parser_without_input
|
249
|
+
YAJI::Parser.new
|
250
|
+
YAJI::Parser.new(:filter => 'test')
|
251
|
+
YAJI::Parser.new(:with_path => true)
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_it_raises_argument_error_for_parser_without_input
|
255
|
+
parser = YAJI::Parser.new
|
256
|
+
assert_raises(ArgumentError) do
|
257
|
+
parser.parse
|
258
|
+
end
|
259
|
+
assert_raises(ArgumentError) do
|
260
|
+
parser.each{|x| }
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_it_raises_argument_error_on_write_without_callback_set_up
|
265
|
+
parser = YAJI::Parser.new
|
266
|
+
assert_raises(ArgumentError) do
|
267
|
+
parser.write('{"hello":"world"}')
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
def test_it_allows_to_feed_the_data_on_the_fly
|
272
|
+
parser = YAJI::Parser.new(:filter => '/rows/')
|
273
|
+
|
274
|
+
objects = []
|
275
|
+
parser.on_object do |obj|
|
276
|
+
objects << obj
|
277
|
+
end
|
278
|
+
|
279
|
+
parser.write(<<-JSON)
|
280
|
+
{
|
281
|
+
"total_rows": 2,
|
282
|
+
"rows": [
|
283
|
+
{
|
284
|
+
JSON
|
285
|
+
parser.write(<<-JSON)
|
286
|
+
"id": "buzz",
|
287
|
+
"props": {
|
288
|
+
"humanoid": true,
|
289
|
+
"armed": true
|
290
|
+
},
|
291
|
+
"movies": [1,2,3]
|
292
|
+
},
|
293
|
+
JSON
|
294
|
+
data = <<-JSON
|
295
|
+
{
|
296
|
+
"id": "barbie",
|
297
|
+
"props": {
|
298
|
+
"humanoid": true,
|
299
|
+
"armed": false
|
300
|
+
},
|
301
|
+
"movies": [2,3]
|
302
|
+
}
|
303
|
+
]
|
304
|
+
}
|
305
|
+
JSON
|
306
|
+
parser << data
|
307
|
+
|
308
|
+
expected = [{
|
309
|
+
"id" => "buzz",
|
310
|
+
"props" => { "humanoid"=> true, "armed"=> true },
|
311
|
+
"movies" => [1,2,3]
|
312
|
+
},
|
313
|
+
{
|
314
|
+
"id" => "barbie",
|
315
|
+
"props" => { "humanoid"=> true, "armed"=> false },
|
316
|
+
"movies" => [2,3]
|
317
|
+
}]
|
318
|
+
assert_equal expected, objects
|
319
|
+
end
|
320
|
+
|
226
321
|
def test_it_parses_chunked_data
|
227
322
|
generator = Generator.new(['{"total_rows":', '0,"offset":0,"rows":[]', '}'])
|
228
|
-
iter = YAJI::Parser.new(generator).each(["total_rows", "rows/", "errors/"], :with_path => true)
|
323
|
+
iter = YAJI::Parser.new(generator).each(["total_rows", "/rows/", "/errors/"], :with_path => true)
|
229
324
|
begin
|
230
325
|
loop do
|
231
326
|
iter.next
|
@@ -236,7 +331,7 @@ class TestParser < MiniTest::Unit::TestCase
|
|
236
331
|
|
237
332
|
def test_it_skips_empty_chunks
|
238
333
|
generator = Generator.new(['{"total_rows":', '0,"offset":0,"rows":[]', '}', '', nil])
|
239
|
-
iter = YAJI::Parser.new(generator).each(["total_rows", "rows/", "errors/"], :with_path => true)
|
334
|
+
iter = YAJI::Parser.new(generator).each(["total_rows", "/rows/", "/errors/"], :with_path => true)
|
240
335
|
begin
|
241
336
|
loop do
|
242
337
|
iter.next
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yaji
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: x86-mingw32
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -152,7 +152,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
152
152
|
version: '0'
|
153
153
|
segments:
|
154
154
|
- 0
|
155
|
-
hash: -
|
155
|
+
hash: -2453557434810599764
|
156
156
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
157
|
none: false
|
158
158
|
requirements:
|
@@ -161,10 +161,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
161
|
version: '0'
|
162
162
|
segments:
|
163
163
|
- 0
|
164
|
-
hash: -
|
164
|
+
hash: -2453557434810599764
|
165
165
|
requirements: []
|
166
166
|
rubyforge_project: yaji
|
167
|
-
rubygems_version: 1.8.
|
167
|
+
rubygems_version: 1.8.21
|
168
168
|
signing_key:
|
169
169
|
specification_version: 3
|
170
170
|
summary: Yet another JSON iterator
|