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.
@@ -1,3 +1,8 @@
1
+ === 0.3.0 / 2012-04-18
2
+
3
+ * Allow to specify filter at parser initialization
4
+ * Implement feeding of the input on the fly
5
+
1
6
  === 0.2.3 / 2012-04-10
2
7
 
3
8
  * Add build for Windows
@@ -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
- rb_funcall(p->parser_cb, id_call, 1, RARRAY_PTR(p->events)[i]);
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, "11", &p->input, &opts);
198
- if (TYPE(p->input) == T_STRING) {
199
- p->input = rb_class_new_instance(1, &p->input, c_stringio);
200
- } else if (rb_respond_to(p->input, id_perform) && rb_respond_to(p->input, id_on_body)) {
201
- rb_block_call(p->input, id_on_body, 0, NULL, rb_yaji_parser_parse_chunk, obj);
202
- } else if (!rb_respond_to(p->input, id_read)) {
203
- rb_raise(c_parse_error, "input must be a String or IO or "
204
- "something responding to #perform and #on_body e.g. Curl::Easy");
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 query)
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
- int len = RSTRING_LEN(str);
319
+ long len = RSTRING_LEN(str);
278
320
  VALUE entry;
279
321
 
280
- switch(TYPE(query)) {
322
+ switch(TYPE(filter)) {
281
323
  case T_STRING:
282
- return RSTRING_LEN(query) <= len && memcmp(RSTRING_PTR(query), ptr, RSTRING_LEN(query)) == 0;
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(query); i++) {
286
- entry = RARRAY_PTR(query)[i];
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 query = params[2];
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(query) || rb_yaji_str_start_with(path, query)) {
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 query, proc, options, params[4];
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&", &query, &options, &proc);
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
- params[2] = query;
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
- params[3] = rb_hash_aref(options, sym_with_path);
368
- } else {
369
- params[3] = Qnil;
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"));
@@ -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;
@@ -18,5 +18,5 @@
18
18
  #
19
19
 
20
20
  module YAJI
21
- VERSION = "0.2.3"
21
+ VERSION = "0.3.0"
22
22
  end
@@ -196,7 +196,7 @@ class TestParser < MiniTest::Unit::TestCase
196
196
  assert_equal expected, objects
197
197
  end
198
198
 
199
- def test_it_optionally_yeilds_object_path
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.2.3
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-10 00:00:00.000000000Z
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: -1814389335541304246
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: -1814389335541304246
164
+ hash: -2453557434810599764
165
165
  requirements: []
166
166
  rubyforge_project: yaji
167
- rubygems_version: 1.8.18
167
+ rubygems_version: 1.8.21
168
168
  signing_key:
169
169
  specification_version: 3
170
170
  summary: Yet another JSON iterator