Exemple #1
0
/*
 * call-seq: to_json(state = nil, depth = 0)
 *
 * Returns a JSON string containing a JSON object, that is unparsed from
 * this Hash instance.
 * _state_ is a JSON::State object, that can also be used to configure the
 * produced JSON string output further.
 * _depth_ is used to find out nesting depth, to indent accordingly.
 */
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
{
    VALUE Vstate, Vdepth, result;
    long depth;

    rb_scan_args(argc, argv, "02", &Vstate, &Vdepth);
    depth = NIL_P(Vdepth) ? 0 : FIX2LONG(Vdepth);
    if (NIL_P(Vstate)) {
        long len = RHASH_SIZE(self);
        result = rb_str_buf_new(len);
        rb_str_buf_cat2(result, "{");
        rb_hash_foreach(self, hash_to_json_i, result);
        rb_str_buf_cat2(result, "}");
    } else {
        GET_STATE(Vstate);
        check_max_nesting(state, depth);
        if (state->check_circular) {
            VALUE self_id = rb_obj_id(self);
            if (RTEST(rb_hash_aref(state->seen, self_id))) {
                rb_raise(eCircularDatastructure,
                        "circular data structures not supported!");
            }
            rb_hash_aset(state->seen, self_id, Qtrue);
            result = mHash_json_transfrom(self, Vstate, LONG2FIX(depth));
            rb_hash_delete(state->seen, self_id);
        } else {
            result = mHash_json_transfrom(self, Vstate, LONG2FIX(depth));
        }
    }
    OBJ_INFECT(result, self);
    FORCE_UTF8(result);
    return result;
}
Exemple #2
0
/*
 * call-seq: to_json(state = nil, depth = 0)
 *
 * Returns a JSON string containing a JSON array, that is unparsed from
 * this Array instance.
 * _state_ is a JSON::State object, that can also be used to configure the
 * produced JSON string output further.
 * _depth_ is used to find out nesting depth, to indent accordingly.
 */
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
    VALUE Vstate, Vdepth, result;

    rb_scan_args(argc, argv, "02", &Vstate, &Vdepth);
    if (NIL_P(Vstate)) {
        long i, len = RARRAY_LEN(self);
        result = rb_str_buf_new(2 + 2 * len);
        rb_str_buf_cat2(result, "[");
        OBJ_INFECT(result, self);
        for (i = 0;  i < len; i++) {
            VALUE element = RARRAY_PTR(self)[i];
            OBJ_INFECT(result, element);
            if (i > 0) rb_str_buf_cat2(result, ",");
            element = rb_funcall(element, i_to_json, 0);
            Check_Type(element, T_STRING);
            rb_str_buf_append(result, element);
        }
        rb_str_buf_cat2(result, "]");
    } else {
        result = mArray_json_transfrom(self, Vstate, Vdepth);
    }
    OBJ_INFECT(result, self);
    FORCE_UTF8(result);
    return result;
}
Exemple #3
0
static VALUE
rb_rdiscount_toc_content(int argc, VALUE *argv, VALUE self)
{
    char *res;
    int szres;

    int flags = rb_rdiscount__get_flags(self);

    /* grab char pointer to markdown input text */
    VALUE text = rb_funcall(self, rb_intern("text"), 0);
    Check_Type(text, T_STRING);

    /* allocate a ruby string buffer and wrap it in a stream */
    VALUE buf = rb_str_buf_new(4096);

    MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);

    if ( mkd_compile(doc, flags) ) {
        szres = mkd_toc(doc, &res);

        if ( szres != EOF ) {
            rb_str_cat(buf, res, szres);
            rb_str_cat(buf, "\n", 1);
        }
    }
    mkd_cleanup(doc);

    return buf;
}
size_t _msgpack_buffer_read_from_io_to_string(msgpack_buffer_t* b, VALUE string, size_t length)
{
    if(RSTRING_LEN(string) == 0) {
        /* direct read */
        VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), string);
        if(ret == Qnil) {
            return 0;
        }
        return RSTRING_LEN(string);
    }

    /* copy via io_buffer */
    if(b->io_buffer == Qnil) {
        b->io_buffer = rb_str_buf_new(0);
    }

    VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), b->io_buffer);
    if(ret == Qnil) {
        return 0;
    }
    size_t rl = RSTRING_LEN(b->io_buffer);

    rb_str_buf_cat(string, (const void*)RSTRING_PTR(b->io_buffer), rl);
    return rl;
}
Exemple #5
0
/**
 * Document-method: MessagePack::Unpacker#initialize
 *
 * call-seq:
 *   MessagePack::Unpacker.new(stream = nil)
 *
 * Creates instance of MessagePack::Unpacker.
 *
 * You can specify a _stream_ for input stream.
 * It is required to implement *sysread* or *readpartial* method.
 *
 * With the input stream, buffers will be feeded into the deserializer automatically.
 *
 * Without the input stream, use *feed* method manually. Or you can manage the buffer manually
 * with *execute*, *finished?*, *data* and *reset* methods.
 */
static VALUE MessagePack_Unpacker_initialize(int argc, VALUE *argv, VALUE self)
{
	VALUE stream;
	switch(argc) {
	case 0:
		stream = Qnil;
		break;
	case 1:
		stream = argv[0];
		break;
	default:
		rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc);
	}

	UNPACKER(self, mp);
	template_init(mp);
	mp->user.finished = 0;
	mp->user.offset = 0;
	mp->user.buffer.size = 0;
	mp->user.buffer.free = 0;
	mp->user.buffer.ptr = NULL;
	mp->user.stream = stream;
	mp->user.streambuf = rb_str_buf_new(MSGPACK_UNPACKER_BUFFER_RESERVE_SIZE);
	mp->user.stream_append_method = append_method_of(stream);
	return self;
}
Exemple #6
0
// Read one record completely and return it as a Ruby String object.
static VALUE sedna_read(SC *conn, int strip_n)
{
	int bytes_read = 0;
	char buffer[RESULT_BUF_LEN];
	VALUE str = rb_str_buf_new(0);
	OBJ_TAINT(str);

	do {
		bytes_read = SEgetData(conn, buffer, RESULT_BUF_LEN - 1);
		if(bytes_read == SEDNA_ERROR) {
			sedna_err(conn, SEDNA_ERROR);
		} else {
			if(bytes_read > 0) {
				if(strip_n) {
					// Strange bug adds newlines to beginning of every result
					// except the first. Strip them! This a known issue in the
					// network protocol and serialization mechanism.
					// See: http://sourceforge.net/mailarchive/forum.php?thread_name=3034886f0812030132v3bbd8e2erd86480d3dc640664%40mail.gmail.com&forum_name=sedna-discussion
					STR_CAT(str, buffer + 1, bytes_read - 1);
					// Do not strip newlines from subsequent buffer reads.
					strip_n = 0;
				} else {
					STR_CAT(str, buffer, bytes_read);
				}
			}
		}
	} while(bytes_read > 0);

	return str;
}
Exemple #7
0
static VALUE
rb_rdiscount_to_html(int argc, VALUE *argv, VALUE self)
{
    /* grab char pointer to markdown input text */
    char *res;
    int szres;
    VALUE encoding;
    VALUE text = rb_funcall(self, rb_intern("text"), 0);
    VALUE buf = rb_str_buf_new(1024);
    Check_Type(text, T_STRING);

    int flags = rb_rdiscount__get_flags(self);

    MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);

    if ( mkd_compile(doc, flags) ) {
        szres = mkd_document(doc, &res);

        if ( szres != EOF ) {
            rb_str_cat(buf, res, szres);
            rb_str_cat(buf, "\n", 1);
        }
    }
    mkd_cleanup(doc);


    /* force the input encoding */
    if ( rb_respond_to(text, rb_intern("encoding")) ) {
      encoding = rb_funcall(text, rb_intern("encoding"), 0);
      rb_funcall(buf, rb_intern("force_encoding"), 1, encoding);
    }

    return buf;
}
Exemple #8
0
VALUE
rb_enc_vsprintf(rb_encoding *enc, const char *fmt, va_list ap)
{
    rb_printf_buffer_extra buffer;
#define f buffer.base
    VALUE result;

    f._flags = __SWR | __SSTR;
    f._bf._size = 0;
    f._w = 120;
    result = rb_str_buf_new(f._w);
    if (enc) {
	if (rb_enc_mbminlen(enc) > 1) {
	    /* the implementation deeply depends on plain char */
	    rb_raise(rb_eArgError, "cannot construct wchar_t based encoding string: %s",
		     rb_enc_name(enc));
	}
	rb_enc_associate(result, enc);
    }
    f._bf._base = (unsigned char *)result;
    f._p = (unsigned char *)RSTRING_PTR(result);
    RBASIC(result)->klass = 0;
    f.vwrite = ruby__sfvwrite;
    f.vextra = ruby__sfvextra;
    buffer.value = 0;
    BSD_vfprintf(&f, fmt, ap);
    RBASIC(result)->klass = rb_cString;
    rb_str_resize(result, (char *)f._p - RSTRING_PTR(result));
#undef f

    return result;
}
Exemple #9
0
static VALUE
dnssd_tr_encode(VALUE self)
{
	long i;
	VALUE buf;
	/* Declare ary volatile to prevent it from being reclaimed when:
	 * buf is allocated later, key/values are converted to strings */
	volatile VALUE ary = rb_funcall2(self, rb_intern("to_a"), 0, 0);
	/* array of key, value pairs */
	VALUE *ptr = RARRAY(ary)->ptr;
	
	buf = rb_str_buf_new(dnssd_tr_convert_pairs(ary));
	for(i=0; i<RARRAY(ary)->len; i++) {
		uint8_t len;
		VALUE key = RARRAY(ptr[i])->ptr[0];
		VALUE value = RARRAY(ptr[i])->ptr[1];
		if (!NIL_P(value)) {
			len = (uint8_t)(RSTRING(key)->len + RSTRING(value)->len + 1);
			rb_str_buf_cat(buf, &len, 1);
			rb_str_buf_append(buf, key);
			rb_str_buf_cat(buf, "=", 1);
			rb_str_buf_append(buf, value);	
		} else {
			len = (uint8_t)RSTRING(key)->len;
			rb_str_buf_cat(buf, &len, 1);
			rb_str_buf_append(buf, key);
		}
	}
	return buf;
}
Exemple #10
0
mustache_ruby_context_t* create_mustache_ruby_context()
{
    mustache_ruby_context_t* r_ctx = mustache_malloc(sizeof(mustache_ruby_context_t));
    r_ctx->buffer = rb_str_buf_new(INITIAL_BUFFER_SIZE);
    r_ctx->buffer_length = 0;
    return r_ctx;
}
Exemple #11
0
/*
 * call-seq: to_json(*)
 *
 * This string should be encoded with UTF-8 A call to this method
 * returns a JSON string encoded with UTF16 big endian characters as
 * \u????.
 */
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
{
    VALUE result = rb_str_buf_new(RSTRING_LEN(self));
    rb_str_buf_cat2(result, "\"");
    JSON_convert_UTF8_to_JSON(result, self, strictConversion);
    rb_str_buf_cat2(result, "\"");
    return result;
}
Exemple #12
0
static VALUE
rb_fairy_string_buffer_initialize(VALUE self)
{
  fairy_string_buffer_t *sb;
  
  GetFairyStringBufferPtr(self, sb);
  sb->string_sizes = rb_fairy_fixnum_buffer_new();
  sb->buffer = rb_str_buf_new(STRING_BUFFER_CAPA);
  return self;
}
Exemple #13
0
VALUE string_spec_rb_str_buf_new(VALUE self, VALUE len, VALUE str) {
  VALUE buf;

  buf = rb_str_buf_new(NUM2LONG(len));

  if(RTEST(str)) {
    snprintf(RSTRING_PTR(buf), NUM2LONG(len), "%s", RSTRING_PTR(str));
  }

  return buf;
}
Exemple #14
0
/**
 * Document-method: MessagePack.pack
 *
 * call-seq:
 *   MessagePack.pack(object, out = '') -> String
 *
 * Serializes the object into raw bytes. The encoding of the string is ASCII-8BIT on Ruby 1.9.
 * This method is same as object.to_msgpack(out = '').
 *
 * _out_ is an object that implements *<<* method like String or IO.
 */
static VALUE MessagePack_pack(int argc, VALUE* argv, VALUE self)
{
    VALUE out;
    if(argc == 1) {
        out = rb_str_buf_new(0);
    } else if(argc == 2) {
        out = argv[1];
    } else {
        rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc);
    }
    return rb_funcall(argv[0], s_to_msgpack, 1, out);
}
Exemple #15
0
// escape for uri path ('/', '+' are not changed)
// or component ('/', '+' are changed)
static VALUE ext_escape(VALUE _, VALUE s, VALUE v_ispath) {
  Check_Type(s, T_STRING);
  long len = RSTRING_LEN(s);
  const char* ptr = RSTRING_PTR(s);
  volatile VALUE res = rb_str_buf_new(len);
  bool ispath = RTEST(v_ispath);
  for (long i = 0; i < len; i++) {
    _concat_char(res, ptr[i], ispath);
  }
  rb_enc_associate(res, u8_encoding);
  return res;
}
Exemple #16
0
size_t _msgpack_buffer_skip_from_io(msgpack_buffer_t* b, size_t length)
{
    if(b->io_buffer == Qnil) {
        b->io_buffer = rb_str_buf_new(0);
    }

    VALUE ret = rb_funcall(b->io, b->io_partial_read_method, 2, LONG2NUM(length), b->io_buffer);
    if(ret == Qnil) {
        return 0;
    }
    return RSTRING_LEN(b->io_buffer);
}
Exemple #17
0
static inline VALUE _msgpack_buffer_chunk_as_string(msgpack_buffer_chunk_t* c)
{
    size_t chunk_size = c->last - c->first;
    if(chunk_size == 0) {
        return rb_str_buf_new(0);
    }

    if(c->mapped_string != NO_MAPPED_STRING) {
        return rb_str_dup(c->mapped_string);
    }

    return rb_str_new(c->first, chunk_size);
}
Exemple #18
0
static inline VALUE _msgpack_buffer_head_chunk_as_string(msgpack_buffer_t* b)
{
    size_t length = b->head->last - b->read_buffer;
    if(length == 0) {
        return rb_str_buf_new(0);
    }

    if(b->head->mapped_string != NO_MAPPED_STRING) {
        return _msgpack_buffer_refer_head_mapped_string(b, length);
    }

    return rb_str_new(b->read_buffer, length);
}
Exemple #19
0
/**
 * Reads from buffer given number of bytes and shifts the pointer.
 *
 * buffer - pointer to the buffer pointer
 * buffer_size - pointer to the buffer size
 * count - number of bytes to read
 *
 * Returns ruby string with bytes.
 *
 */
static inline VALUE read_bytes( uint8_t **buffer, long *buffer_size, long count )
{
    if ( *buffer_size < count )
        rb_raise( rb_eProtobufCoderDecodingError, "can't read %ld bytes: buffer contains only %ld bytes", count, *buffer_size );

    // Copy slice to ruby string
    VALUE result = rb_str_buf_new( count );
    rb_str_resize( result, count );
    MEMCPY( RSTRING_PTR( result ), *buffer, uint8_t, count );

    *buffer = *buffer + count;
    *buffer_size = *buffer_size - count;

    return result;
}
Exemple #20
0
static VALUE fast_pack(VALUE self)
{
    VALUE res;
    long i;
    char c;

    res = rb_str_buf_new(0);

    for (i = 0; i < RARRAY_LEN(self); i++) {
        c = FIX2LONG(RARRAY_PTR(self)[i]);
        rb_str_buf_cat(res, &c, sizeof(char));
    }

    return res;
}
Exemple #21
0
/**
 * RubyWatchman.dump(serializable)
 *
 * Converts the Ruby object, `serializable`, into a binary string in the
 * Watchman binary protocol format.
 *
 * Examples of serializable objects include arrays, hashes, strings, numbers
 * (integers, floats), booleans, and nil.
 */
VALUE RubyWatchman_dump(VALUE self, VALUE serializable) {
    watchman_t *w = watchman_init();
    watchman_dump(w, serializable);

    // update header with final length information
    uint64_t *len =
        (uint64_t *)(w->data + sizeof(WATCHMAN_HEADER) - sizeof(uint64_t) - 1);
    *len = w->len - sizeof(WATCHMAN_HEADER) + 1;

    // prepare final return value
    VALUE serialized = rb_str_buf_new(w->len);
    rb_str_buf_cat(serialized, (const char*)w->data, w->len);
    watchman_free(w);
    return serialized;
}
Exemple #22
0
// Perform the actual HTTP request by calling libcurl.
static VALUE perform_request(VALUE self) {
  struct curl_state *state;
  Data_Get_Struct(self, struct curl_state, state);

  CURL* curl = state->handle;

  // headers
  VALUE header_buffer = rb_str_buf_new(32768);
  curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &session_write_handler);
  curl_easy_setopt(curl, CURLOPT_HEADERDATA, header_buffer);

  // body
  VALUE body_buffer = Qnil;
  if (!state->download_file) {
    body_buffer = rb_str_buf_new(32768);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &session_write_handler);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, body_buffer);
  }

  #if defined(HAVE_TBR) && defined(USE_TBR)
  CURLcode ret = rb_thread_blocking_region(curl_easy_perform, curl, RUBY_UBF_IO, 0);
  #else
  CURLcode ret = curl_easy_perform(curl);
  #endif

  if (CURLE_OK == ret) {
    VALUE response = create_response(curl);
    if (!NIL_P(body_buffer)) {
      rb_iv_set(response, "@body", body_buffer);
    }
    rb_funcall(response, rb_intern("parse_headers"), 1, header_buffer);
    return response;
  } else {
    rb_raise(select_error(ret), "%s", state->error_buf);
  }
}
Exemple #23
0
static int _serialize_func(VALUE k, VALUE v, VALUE arr) {
  long vlen = RSTRING_LEN(v);
  // deleted field
  if (vlen == 0) {
    return ST_CONTINUE;
  }

  long klen = RSTRING_LEN(k);
  long capa = klen + vlen + 4;
  volatile VALUE s = rb_str_buf_new(capa);
  sprintf(RSTRING_PTR(s), "%.*s: %.*s\r\n", (int)klen, RSTRING_PTR(k), (int)vlen, RSTRING_PTR(v));
  STR_SET_LEN(s, capa);
  rb_enc_associate(s, u8_encoding);
  rb_ary_push(arr, s);
  return ST_CONTINUE;
}
Exemple #24
0
static VALUE
rb_rdiscount_to_html(int argc, VALUE *argv, VALUE self)
{
    /* grab char pointer to markdown input text */
    char *res;
    int szres;
    VALUE encoding;
    VALUE text = rb_funcall(self, rb_intern("text"), 0);
    VALUE buf = rb_str_buf_new(1024);
    Check_Type(text, T_STRING);

    int flags = rb_rdiscount__get_flags(self);
    
    /* 
     * Force Discount to use ASCII character encoding for isalnum(), isalpha(),
     * and similar functions.
     * 
     * Ruby tends to use UTF-8 encoding, which is ill-defined for these
     * functions since they expect 8-bit codepoints (and UTF-8 has codepoints
     * of at least 21 bits).
     */
    char *old_locale = strdup(setlocale(LC_CTYPE, NULL));
    setlocale(LC_CTYPE, "C");   // ASCII (and passthru characters > 127)

    MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);

    if ( mkd_compile(doc, flags) ) {
        szres = mkd_document(doc, &res);

        if ( szres != EOF ) {
            rb_str_cat(buf, res, szres);
            rb_str_cat(buf, "\n", 1);
        }
    }
    mkd_cleanup(doc);

    setlocale(LC_CTYPE, old_locale);
    free(old_locale);

    /* force the input encoding */
    if ( rb_respond_to(text, rb_intern("encoding")) ) {
      encoding = rb_funcall(text, rb_intern("encoding"), 0);
      rb_funcall(buf, rb_intern("force_encoding"), 1, encoding);
    }

    return buf;
}
Exemple #25
0
VALUE mCDB_Reader_get(VALUE self, VALUE key) {
  struct cdb db;
  VALUE value;
  StringValue(key);
  int fd = open_cdb_fd(self);
  size_t vlen;
  cdb_init(&db,fd);
  if(cdb_find(&db,RSTRING_PTR(key),RSTRING_LEN(key)) > 0) {
    vlen = cdb_datalen(&db);
    value = rb_str_buf_new(vlen);
    cdb_read(&db,RSTRING_PTR(value),vlen,cdb_datapos(&db));
    rb_str_set_len(value,vlen);
    return value;
  }
  close(fd);
  return Qnil;
}
Exemple #26
0
static void printP(int argc, VALUE *argv,
                   const char *convMethod, const char *sep)
{
	VALUE dispString = rb_str_buf_new(128);
	ID conv = rb_intern(convMethod);

	for (int i = 0; i < argc; ++i)
	{
		VALUE str = rb_funcall2(argv[i], conv, 0, NULL);
		rb_str_buf_append(dispString, str);

		if (i < argc)
			rb_str_buf_cat2(dispString, sep);
	}

	showMsg(RSTRING_PTR(dispString));
}
Exemple #27
0
/*
 * call-seq:
 *     digest_obj.inspect -> string
 *
 * Creates a printable version of the digest object.
 */
static VALUE
rb_digest_instance_inspect(VALUE self)
{
    VALUE str;
    size_t digest_len = 32;	/* about this size at least */
    char *cname;

    cname = rb_obj_classname(self);

    /* #<Digest::ClassName: xxxxx...xxxx> */
    str = rb_str_buf_new(2 + strlen(cname) + 2 + digest_len * 2 + 1);
    rb_str_buf_cat2(str, "#<");
    rb_str_buf_cat2(str, cname);
    rb_str_buf_cat2(str, ": ");
    rb_str_buf_append(str, rb_digest_instance_hexdigest(0, 0, self));
    rb_str_buf_cat2(str, ">");
    return str;
}
Exemple #28
0
VALUE mCDB_Reader_each_for_key(VALUE self,VALUE key) {
  struct cdb db;
  VALUE value;
  struct cdb_find find;
  StringValue(key);
  int fd = open_cdb_fd(self);
  size_t vlen;
  cdb_init(&db,fd);
  cdb_findinit(&find,&db,RSTRING_PTR(key),RSTRING_LEN(key));
  while(cdb_findnext(&find) > 0) {
    vlen = cdb_datalen(&db);
    value = rb_str_buf_new(vlen);
    cdb_read(&db,RSTRING_PTR(value),vlen,cdb_datapos(&db));
    rb_str_set_len(value,vlen);
    rb_yield(value);
  }
  close(fd);
  return Qnil;
}
Exemple #29
0
static VALUE
rb_rdiscount_to_html(int argc, VALUE *argv, VALUE self)
{
    /* grab char pointer to markdown input text */
    VALUE text = rb_funcall(self, rb_intern("text"), 0);
    Check_Type(text, T_STRING);

    /* allocate a ruby string buffer and wrap it in a stream */
    VALUE buf = rb_str_buf_new(4096);
    FILE *stream = rb_str_io_new(buf);

    int flags = rb_rdiscount__get_flags(self);

    MMIOT *doc = mkd_string(RSTRING_PTR(text), RSTRING_LEN(text), flags);
    markdown(doc, stream, flags);

    fclose(stream);

    return buf;
}
Exemple #30
0
inline static VALUE mHash_json_transfrom(VALUE self, VALUE Vstate, VALUE Vdepth) {
    long depth, len = RHASH_SIZE(self);
    VALUE result;
    GET_STATE(Vstate);

    depth = 1 + FIX2LONG(Vdepth);
    result = rb_str_buf_new(len);
    state->memo = result;
    state->depth = LONG2FIX(depth);
    state->flag = 0;
    rb_str_buf_cat2(result, "{");
    if (RSTRING_LEN(state->object_nl)) rb_str_buf_append(result, state->object_nl);
    rb_hash_foreach(self, hash_to_json_state_i, Vstate);
    if (RSTRING_LEN(state->object_nl)) rb_str_buf_append(result, state->object_nl);
    if (RSTRING_LEN(state->object_nl)) {
        rb_str_buf_append(result, rb_str_times(state->indent, Vdepth));
    }
    rb_str_buf_cat2(result, "}");
    return result;
}