Example #1
0
/*
 * Document-method: parse
 *
 * call-seq:
 *  parse(input, buffer_size=8092)
 *  parse(input, buffer_size=8092) { |obj| ... }
 *
 * +input+ can either be a string or an IO to parse JSON from
 *
 * +buffer_size+ is the size of chunk that will be parsed off the input (if it's an IO) for each loop of the parsing process.
 * 8092 is a good balance between the different types of streams (off disk, off a socket, etc...), but this option
 * is here so the caller can better tune their parsing depending on the type of stream being passed.
 * A larger read buffer will perform better for files off disk, where as a smaller size may be more efficient for
 * 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.
 *
 * 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.
*/
static VALUE rb_yajl_parser_parse(int argc, VALUE * argv, VALUE self) {
    yajl_status stat;
    yajl_parser_wrapper * wrapper;
    VALUE rbufsize, input, blk;
    unsigned int len;
    const char * cptr;

    GetParser(self, wrapper);

    /* setup our parameters */
    rb_scan_args(argc, argv, "11&", &input, &rbufsize, &blk);
    if (NIL_P(rbufsize)) {
        rbufsize = INT2FIX(READ_BUFSIZE);
    } else {
        Check_Type(rbufsize, T_FIXNUM);
    }
    if (!NIL_P(blk)) {
        rb_yajl_parser_set_complete_cb(self, blk);
    }

    if (TYPE(input) == T_STRING) {
        cptr = RSTRING_PTR(input);
        len = RSTRING_LEN(input);
        yajl_parse_chunk((const unsigned char*)cptr, len, wrapper->parser);
    } else if (rb_respond_to(input, intern_io_read)) {
        VALUE parsed = rb_str_new(0, FIX2LONG(rbufsize));
        while (rb_funcall(input, intern_io_read, 2, rbufsize, parsed) != Qnil) {
            cptr = RSTRING_PTR(parsed);
            len = RSTRING_LEN(parsed);
            yajl_parse_chunk((const unsigned char*)cptr, len, wrapper->parser);
        }
    } else {
        rb_raise(cParseError, "input must be a string or IO");
    }

    /* parse any remaining buffered data */
    stat = yajl_parse_complete(wrapper->parser);

    if (wrapper->parse_complete_callback != Qnil) {
        yajl_check_and_fire_callback((void *)self);
        return Qnil;
    }

    // Because we've overridden the yajl_parse_complete state of the parser to allow
    // us to parse multiple objects out of one stream; we can't use it to determine
    // whether we've parsed a single object. Instead we'll check whether we've successfully
    // parsed a single token.
    if (!RARRAY_LEN(wrapper->builderStack) ||
            wrapper->nestedHashLevel ||
            wrapper->nestedArrayLevel) {
        rb_raise(cParseError, "unexpected end of JSON string");
    }

    return rb_ary_pop(wrapper->builderStack);
}
Example #2
0
/*
 * Document-method: parse
 *
 * call-seq:
 *  parse(input, buffer_size=8092)
 *  parse(input, buffer_size=8092) { |obj| ... }
 *
 * +input+ can either be a string or an IO to parse JSON from
 *
 * +buffer_size+ is the size of chunk that will be parsed off the input (if it's an IO) for each loop of the parsing process.
 * 8092 is a good balance between the different types of streams (off disk, off a socket, etc...), but this option
 * is here so the caller can better tune their parsing depending on the type of stream being passed.
 * A larger read buffer will perform better for files off disk, where as a smaller size may be more efficient for
 * 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.
 *
 * 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.
*/
static VALUE rb_yajl_parser_parse(int argc, VALUE * argv, VALUE self) {
    yajl_status stat;
    yajl_parser_wrapper * wrapper;
    VALUE rbufsize, input, blk;
    unsigned int len;
    const char * cptr;

    GetParser(self, wrapper);

    /* setup our parameters */
    rb_scan_args(argc, argv, "11&", &input, &rbufsize, &blk);
    if (NIL_P(rbufsize)) {
        rbufsize = INT2FIX(READ_BUFSIZE);
    } else {
        Check_Type(rbufsize, T_FIXNUM);
    }
    if (!NIL_P(blk)) {
        rb_yajl_parser_set_complete_cb(self, blk);
    }

    if (TYPE(input) == T_STRING) {
        cptr = RSTRING_PTR(input);
        len = RSTRING_LEN(input);
        yajl_parse_chunk((const unsigned char*)cptr, len, wrapper->parser);
    } else if (rb_respond_to(input, intern_io_read)) {
        VALUE parsed = rb_str_new(0, FIX2LONG(rbufsize));
        while (rb_funcall(input, intern_io_read, 2, rbufsize, parsed) != Qnil) {
            cptr = RSTRING_PTR(parsed);
            len = RSTRING_LEN(parsed);
            yajl_parse_chunk((const unsigned char*)cptr, len, wrapper->parser);
        }
    } else {
        rb_raise(cParseError, "input must be a string or IO");
    }

    /* parse any remaining buffered data */
    stat = yajl_parse_complete(wrapper->parser);

    if (wrapper->parse_complete_callback != Qnil) {
        yajl_check_and_fire_callback((void *)self);
        return Qnil;
    }

    return rb_ary_pop(wrapper->builderStack);
}
Example #3
0
/*
 * Document-method: parse_chunk
 *
 * call-seq: parse_chunk(string_chunk)
 *
 * +string_chunk+ can be a partial or full JSON string to push on the parser.
 *
 * This method will throw an exception if the +on_parse_complete+ callback hasn't been assigned yet.
 * The +on_parse_complete+ callback assignment is required so the user can handle objects that have been
 * parsed off the stream as they're found.
 */
static VALUE rb_yajl_parser_parse_chunk(VALUE self, VALUE chunk) {
    yajl_parser_wrapper * wrapper;
    unsigned int len;

    GetParser(self, wrapper);
    if (NIL_P(chunk)) {
        rb_raise(cParseError, "Can't parse a nil string.");
    }

    if (wrapper->parse_complete_callback != Qnil) {
        const char * cptr = RSTRING_PTR(chunk);
        len = RSTRING_LEN(chunk);
        yajl_parse_chunk((const unsigned char*)cptr, len, wrapper->parser);
    } else {
        rb_raise(cParseError, "The on_parse_complete callback isn't setup, parsing useless.");
    }

    return Qnil;
}