Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block parameters for Parser.new and Encoder.new #139

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 29 additions & 24 deletions ext/yajl/yajl_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,22 +389,25 @@ static int yajl_found_end_array(void * ctx) {
/*
* Document-method: new
*
* call-seq: new([:symbolize_keys => true, [:allow_comments => false[, :check_utf8 => false]]])
* call-seq: new([:symbolize_keys => true, [:allow_comments => false[, :check_utf8 => false]]][, &callback])
*
* :symbolize_keys will turn hash keys into Ruby symbols, defaults to false.
*
* :allow_comments will turn on/off the check for comments inside the JSON stream, defaults to true.
*
* :check_utf8 will validate UTF8 characters found in the JSON stream, defaults to true.
*
* If a block was passed, it's called when an object has been parsed off the stream. This is especially
* useful when parsing a stream of multiple JSON objects.
*/
static VALUE rb_yajl_parser_new(int argc, VALUE * argv, VALUE klass) {
yajl_parser_wrapper * wrapper;
yajl_parser_config cfg;
VALUE opts, obj;
VALUE opts, blk, obj;
int allowComments = 1, checkUTF8 = 1, symbolizeKeys = 0;

/* Scan off config vars */
if (rb_scan_args(argc, argv, "01", &opts) == 1) {
if (rb_scan_args(argc, argv, "01&", &opts, &blk) == 1) {
Check_Type(opts, T_HASH);

if (rb_hash_aref(opts, sym_allow_comments) == Qfalse) {
Expand All @@ -426,15 +429,15 @@ static VALUE rb_yajl_parser_new(int argc, VALUE * argv, VALUE klass) {
wrapper->objectsFound = 0;
wrapper->symbolizeKeys = symbolizeKeys;
wrapper->builderStack = rb_ary_new();
wrapper->parse_complete_callback = Qnil;
wrapper->parse_complete_callback = blk;
rb_obj_call_init(obj, 0, 0);
return obj;
}

/*
* Document-method: initialize
*
* call-seq: new([:symbolize_keys => true, [:allow_comments => false[, :check_utf8 => false]]])
* call-seq: new([:symbolize_keys => true, [:allow_comments => false[, :check_utf8 => false]]][, &callback])
*
* :symbolize_keys will turn hash keys into Ruby symbols, defaults to false.
*
Expand Down Expand Up @@ -462,7 +465,7 @@ static VALUE rb_yajl_parser_init(int argc, VALUE * argv, VALUE self) {
* reading off of a socket directly.
*
* If a block was passed, it's called when an object has been parsed off the stream. This is especially
* usefull when parsing a stream of multiple JSON objects.
* useful when parsing a stream of multiple JSON objects.
*
* NOTE: you can optionally assign the +on_parse_complete+ callback, and it will be called the same way the optional
* block is for this method.
Expand Down Expand Up @@ -572,27 +575,29 @@ static unsigned char * defaultIndentString = (unsigned char *)" ";
/*
* Document-method: new
*
* call-seq: initialize([:pretty => false[, :indent => ' '][, :terminator => "\n"]])
*
* :pretty will enable/disable beautifying or "pretty priting" the output string.
*
* :indent is the character(s) used to indent the output string.
*
* :terminator allows you to specify a character to be used as the termination character after a full JSON string has been generated by
* the encoder. This would be especially useful when encoding in chunks (via a block or callback during the encode process), to be able to
* determine when the last chunk of the current encode is sent.
* If you specify this option to be nil, it will be ignored if encoding directly to an IO or simply returning a string. But if a block is used,
* the encoder will still pass it - I hope that makes sense ;).
* call-seq: new([:pretty => false[, :indent => ' '][, :terminator => "\n"]][, &callback])
*
* :pretty will enable/disable beautifying or "pretty priting" the output string.
*
* :indent is the character(s) used to indent the output string.
*
* :terminator allows you to specify a character to be used as the termination character after a full JSON string has been generated by
* the encoder. This would be especially useful when encoding in chunks (via a block or callback during the encode process), to be able to
* determine when the last chunk of the current encode is sent.
* If you specify this option to be nil, it will be ignored if encoding directly to an IO or simply returning a string. But if a block is used,
* the encoder will still pass it - I hope that makes sense ;).
*
* If an optional block is passed, it's called when encoding is complete and passed the resulting JSON string
*/
static VALUE rb_yajl_encoder_new(int argc, VALUE * argv, VALUE klass) {
yajl_encoder_wrapper * wrapper;
yajl_gen_config cfg;
VALUE opts, obj, indent;
VALUE opts, blk, obj, indent;
unsigned char *indentString = NULL, *actualIndent = NULL;
int beautify = 0, htmlSafe = 0;

/* Scan off config vars */
if (rb_scan_args(argc, argv, "01", &opts) == 1) {
if (rb_scan_args(argc, argv, "01&", &opts, &blk) == 1) {
Check_Type(opts, T_HASH);

if (rb_hash_aref(opts, sym_pretty) == Qtrue) {
Expand Down Expand Up @@ -621,7 +626,7 @@ static VALUE rb_yajl_encoder_new(int argc, VALUE * argv, VALUE klass) {
obj = Data_Make_Struct(klass, yajl_encoder_wrapper, yajl_encoder_wrapper_mark, yajl_encoder_wrapper_free, wrapper);
wrapper->indentString = actualIndent;
wrapper->encoder = yajl_gen_alloc(&cfg, NULL);
wrapper->on_progress_callback = Qnil;
wrapper->on_progress_callback = blk;
if (opts != Qnil && rb_funcall(opts, intern_has_key, 1, sym_terminator) == Qtrue) {
wrapper->terminator = rb_hash_aref(opts, sym_terminator);
#ifdef HAVE_RUBY_ENCODING_H
Expand All @@ -639,7 +644,7 @@ static VALUE rb_yajl_encoder_new(int argc, VALUE * argv, VALUE klass) {
/*
* Document-method: initialize
*
* call-seq: initialize([:pretty => false[, :indent => ' '][, :terminator => "\n"]])
* call-seq: initialize([:pretty => false[, :indent => ' '][, :terminator => "\n"]][, &callback])
*
* :pretty will enable/disable beautifying or "pretty priting" the output string.
*
Expand Down Expand Up @@ -702,10 +707,10 @@ static VALUE rb_yajl_encoder_encode(int argc, VALUE * argv, VALUE self) {
rb_io_write(io, wrapper->terminator);
}
return Qnil;
} else if (blk != Qnil) {
rb_funcall(blk, intern_call, 1, outBuff);
} else if (wrapper->on_progress_callback != Qnil) {
rb_funcall(wrapper->on_progress_callback, intern_call, 1, outBuff);
if (wrapper->terminator != 0) {
rb_funcall(blk, intern_call, 1, wrapper->terminator);
rb_funcall(wrapper->on_progress_callback, intern_call, 1, wrapper->terminator);
}
return Qnil;
} else {
Expand Down
19 changes: 19 additions & 0 deletions spec/encoding/encoding_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,25 @@ def to_s
output.should == output
end

it "should encode with a callback passed via on_progress" do
callback = lambda { |str|
# no-op
}
encoder = Yajl::Encoder.new
encoder.on_progress = callback
callback.should_receive(:call).with('{}')
encoder.encode({})
end

it "should encode with a callback passed as block" do
callback = lambda { |str|
# no-op
}
encoder = Yajl::Encoder.new(&callback)
callback.should_receive(:call).with('{}')
encoder.encode({})
end

it "should encode with it's class method with :pretty and a tab character indent options set, to an IO" do
output = "{\n\t\"foo\": 1234\n}"
obj = {:foo => 1234}
Expand Down
9 changes: 9 additions & 0 deletions spec/parsing/chunked_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
@parser.on_parse_complete = @callback
end

it "should take the callback as block parameter" do
@callback = lambda { |hash|
# no-op
}
@parser = Yajl::Parser.new(&@callback)
@callback.should_receive(:call).with(@final)
@parser << '[{"abc": 123},{"def": 456}]'
end

it "should parse a single chunk" do
@callback.should_receive(:call).with(@final)
@parser << '[{"abc": 123},{"def": 456}]'
Expand Down