couchbase 1.3.4-x64-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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +22 -0
  4. data/.yardopts +5 -0
  5. data/CONTRIBUTING.markdown +75 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +201 -0
  8. data/Makefile +3 -0
  9. data/README.markdown +649 -0
  10. data/RELEASE_NOTES.markdown +796 -0
  11. data/Rakefile +20 -0
  12. data/couchbase.gemspec +49 -0
  13. data/examples/chat-em/Gemfile +7 -0
  14. data/examples/chat-em/README.markdown +45 -0
  15. data/examples/chat-em/server.rb +82 -0
  16. data/examples/chat-goliath-grape/Gemfile +5 -0
  17. data/examples/chat-goliath-grape/README.markdown +50 -0
  18. data/examples/chat-goliath-grape/app.rb +67 -0
  19. data/examples/chat-goliath-grape/config/app.rb +20 -0
  20. data/examples/transcoders/Gemfile +3 -0
  21. data/examples/transcoders/README.markdown +59 -0
  22. data/examples/transcoders/cb-zcat +40 -0
  23. data/examples/transcoders/cb-zcp +45 -0
  24. data/examples/transcoders/gzip_transcoder.rb +49 -0
  25. data/examples/transcoders/options.rb +54 -0
  26. data/ext/couchbase_ext/.gitignore +4 -0
  27. data/ext/couchbase_ext/arguments.c +956 -0
  28. data/ext/couchbase_ext/arithmetic.c +307 -0
  29. data/ext/couchbase_ext/bucket.c +1370 -0
  30. data/ext/couchbase_ext/context.c +65 -0
  31. data/ext/couchbase_ext/couchbase_ext.c +1364 -0
  32. data/ext/couchbase_ext/couchbase_ext.h +644 -0
  33. data/ext/couchbase_ext/delete.c +163 -0
  34. data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
  35. data/ext/couchbase_ext/extconf.rb +168 -0
  36. data/ext/couchbase_ext/get.c +316 -0
  37. data/ext/couchbase_ext/gethrtime.c +129 -0
  38. data/ext/couchbase_ext/http.c +432 -0
  39. data/ext/couchbase_ext/multithread_plugin.c +1090 -0
  40. data/ext/couchbase_ext/observe.c +171 -0
  41. data/ext/couchbase_ext/plugin_common.c +171 -0
  42. data/ext/couchbase_ext/result.c +129 -0
  43. data/ext/couchbase_ext/stats.c +163 -0
  44. data/ext/couchbase_ext/store.c +542 -0
  45. data/ext/couchbase_ext/timer.c +192 -0
  46. data/ext/couchbase_ext/touch.c +186 -0
  47. data/ext/couchbase_ext/unlock.c +176 -0
  48. data/ext/couchbase_ext/utils.c +551 -0
  49. data/ext/couchbase_ext/version.c +142 -0
  50. data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
  51. data/lib/active_support/cache/couchbase_store.rb +430 -0
  52. data/lib/couchbase.rb +155 -0
  53. data/lib/couchbase/bucket.rb +457 -0
  54. data/lib/couchbase/cluster.rb +119 -0
  55. data/lib/couchbase/connection_pool.rb +58 -0
  56. data/lib/couchbase/constants.rb +12 -0
  57. data/lib/couchbase/result.rb +26 -0
  58. data/lib/couchbase/transcoder.rb +120 -0
  59. data/lib/couchbase/utils.rb +62 -0
  60. data/lib/couchbase/version.rb +21 -0
  61. data/lib/couchbase/view.rb +506 -0
  62. data/lib/couchbase/view_row.rb +272 -0
  63. data/lib/ext/multi_json_fix.rb +56 -0
  64. data/lib/rack/session/couchbase.rb +108 -0
  65. data/tasks/benchmark.rake +6 -0
  66. data/tasks/compile.rake +158 -0
  67. data/tasks/test.rake +100 -0
  68. data/tasks/util.rake +21 -0
  69. data/test/profile/.gitignore +1 -0
  70. data/test/profile/Gemfile +6 -0
  71. data/test/profile/benchmark.rb +195 -0
  72. data/test/setup.rb +178 -0
  73. data/test/test_arithmetic.rb +185 -0
  74. data/test/test_async.rb +316 -0
  75. data/test/test_bucket.rb +250 -0
  76. data/test/test_cas.rb +235 -0
  77. data/test/test_couchbase.rb +77 -0
  78. data/test/test_couchbase_connection_pool.rb +77 -0
  79. data/test/test_couchbase_rails_cache_store.rb +361 -0
  80. data/test/test_delete.rb +120 -0
  81. data/test/test_errors.rb +82 -0
  82. data/test/test_eventmachine.rb +70 -0
  83. data/test/test_format.rb +164 -0
  84. data/test/test_get.rb +407 -0
  85. data/test/test_stats.rb +57 -0
  86. data/test/test_store.rb +216 -0
  87. data/test/test_timer.rb +42 -0
  88. data/test/test_touch.rb +97 -0
  89. data/test/test_unlock.rb +119 -0
  90. data/test/test_utils.rb +58 -0
  91. data/test/test_version.rb +52 -0
  92. metadata +336 -0
@@ -0,0 +1,171 @@
1
+ /* vim: ft=c et ts=8 sts=4 sw=4 cino=
2
+ *
3
+ * Copyright 2011, 2012 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "couchbase_ext.h"
19
+
20
+ void
21
+ cb_observe_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_observe_resp_t *resp)
22
+ {
23
+ struct cb_context_st *ctx = (struct cb_context_st *)cookie;
24
+ struct cb_bucket_st *bucket = ctx->bucket;
25
+ VALUE key, res, exc;
26
+
27
+ if (resp->v.v0.key) {
28
+ key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
29
+ exc = cb_check_error(error, "failed to execute observe request", key);
30
+ if (exc != Qnil) {
31
+ ctx->exception = exc;
32
+ }
33
+ res = rb_class_new_instance(0, NULL, cb_cResult);
34
+ rb_ivar_set(res, cb_id_iv_completed, Qfalse);
35
+ rb_ivar_set(res, cb_id_iv_error, ctx->exception);
36
+ rb_ivar_set(res, cb_id_iv_operation, cb_sym_observe);
37
+ rb_ivar_set(res, cb_id_iv_key, key);
38
+ rb_ivar_set(res, cb_id_iv_cas, ULL2NUM(resp->v.v0.cas));
39
+ rb_ivar_set(res, cb_id_iv_from_master, resp->v.v0.from_master ? Qtrue : Qfalse);
40
+ rb_ivar_set(res, cb_id_iv_time_to_persist, ULONG2NUM(resp->v.v0.ttp));
41
+ rb_ivar_set(res, cb_id_iv_time_to_replicate, ULONG2NUM(resp->v.v0.ttr));
42
+ switch (resp->v.v0.status) {
43
+ case LCB_OBSERVE_FOUND:
44
+ rb_ivar_set(res, cb_id_iv_status, cb_sym_found);
45
+ break;
46
+ case LCB_OBSERVE_PERSISTED:
47
+ rb_ivar_set(res, cb_id_iv_status, cb_sym_persisted);
48
+ break;
49
+ case LCB_OBSERVE_NOT_FOUND:
50
+ rb_ivar_set(res, cb_id_iv_status, cb_sym_not_found);
51
+ break;
52
+ default:
53
+ rb_ivar_set(res, cb_id_iv_status, Qnil);
54
+ }
55
+ if (bucket->async) { /* asynchronous */
56
+ if (ctx->proc != Qnil) {
57
+ cb_proc_call(bucket, ctx->proc, 1, res);
58
+ }
59
+ } else { /* synchronous */
60
+ if (NIL_P(ctx->exception)) {
61
+ VALUE stats = rb_hash_aref(ctx->rv, key);
62
+ if (NIL_P(stats)) {
63
+ stats = rb_ary_new();
64
+ rb_hash_aset(ctx->rv, key, stats);
65
+ }
66
+ rb_ary_push(stats, res);
67
+ }
68
+ }
69
+ } else {
70
+ if (bucket->async && ctx->proc != Qnil) {
71
+ res = rb_class_new_instance(0, NULL, cb_cResult);
72
+ rb_ivar_set(res, cb_id_iv_completed, Qtrue);
73
+ cb_proc_call(bucket, ctx->proc, 1, res);
74
+ }
75
+ ctx->nqueries--;
76
+ ctx->proc = Qnil;
77
+ if (bucket->async) {
78
+ cb_context_free(ctx);
79
+ }
80
+ }
81
+ (void)handle;
82
+ }
83
+
84
+ /*
85
+ * Observe key state
86
+ *
87
+ * @since 1.2.0.dp6
88
+ *
89
+ * @overload observe(*keys, options = {})
90
+ * @param keys [String, Symbol, Array] One or several keys to fetch
91
+ * @param options [Hash] Options for operation.
92
+ *
93
+ * @yieldparam ret [Result] the result of operation in asynchronous mode
94
+ * (valid attributes: +error+, +status+, +operation+, +key+, +cas+,
95
+ * +from_master+, +time_to_persist+, +time_to_replicate+).
96
+ *
97
+ * @return [Hash<String, Array<Result>>, Array<Result>] the state of the
98
+ * keys on all nodes. If the +keys+ argument was String or Symbol, this
99
+ * method will return just array of results (result per each node),
100
+ * otherwise it will return hash map.
101
+ *
102
+ * @example Observe single key
103
+ * c.observe("foo")
104
+ * #=> [#<Couchbase::Result:0x00000001650df0 ...>, ...]
105
+ *
106
+ * @example Observe multiple keys
107
+ * keys = ["foo", "bar"]
108
+ * stats = c.observe(keys)
109
+ * stats.size #=> 2
110
+ * stats["foo"] #=> [#<Couchbase::Result:0x00000001650df0 ...>, ...]
111
+ */
112
+
113
+ VALUE
114
+ cb_bucket_observe(int argc, VALUE *argv, VALUE self)
115
+ {
116
+ struct cb_bucket_st *bucket = DATA_PTR(self);
117
+ struct cb_context_st *ctx;
118
+ VALUE rv, proc, exc;
119
+ lcb_error_t err;
120
+ struct cb_params_st params;
121
+
122
+ if (!cb_bucket_connected_bang(bucket, cb_sym_observe)) {
123
+ return Qnil;
124
+ }
125
+
126
+ memset(&params, 0, sizeof(struct cb_params_st));
127
+ rb_scan_args(argc, argv, "0*&", &params.args, &proc);
128
+ if (!bucket->async && proc != Qnil) {
129
+ rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
130
+ }
131
+ params.type = cb_cmd_observe;
132
+ params.bucket = bucket;
133
+ cb_params_build(&params);
134
+ ctx = cb_context_alloc_common(bucket, proc, params.cmd.observe.num);
135
+ err = lcb_observe(bucket->handle, (const void *)ctx,
136
+ params.cmd.observe.num, params.cmd.observe.ptr);
137
+ cb_params_destroy(&params);
138
+ exc = cb_check_error(err, "failed to schedule observe request", Qnil);
139
+ if (exc != Qnil) {
140
+ cb_context_free(ctx);
141
+ rb_exc_raise(exc);
142
+ }
143
+ bucket->nbytes += params.npayload;
144
+ if (bucket->async) {
145
+ cb_maybe_do_loop(bucket);
146
+ return Qnil;
147
+ } else {
148
+ if (ctx->nqueries > 0) {
149
+ /* we have some operations pending */
150
+ lcb_wait(bucket->handle);
151
+ }
152
+ exc = ctx->exception;
153
+ rv = ctx->rv;
154
+ cb_context_free(ctx);
155
+ if (exc != Qnil) {
156
+ rb_exc_raise(exc);
157
+ }
158
+ exc = bucket->exception;
159
+ if (exc != Qnil) {
160
+ bucket->exception = Qnil;
161
+ rb_exc_raise(exc);
162
+ }
163
+ if (params.cmd.observe.num > 1 || params.cmd.observe.array) {
164
+ return rv; /* return as a hash {key => {}, ...} */
165
+ } else {
166
+ VALUE vv = Qnil;
167
+ rb_hash_foreach(rv, cb_first_value_i, (VALUE)&vv);
168
+ return vv; /* return first value */
169
+ }
170
+ }
171
+ }
@@ -0,0 +1,171 @@
1
+ /* vim: ft=c et ts=8 sts=4 sw=4 cino=
2
+ *
3
+ * Copyright 2012 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "couchbase_ext.h"
19
+
20
+ #ifndef _WIN32
21
+
22
+ #include <errno.h>
23
+ #include <sys/types.h>
24
+ #include <sys/socket.h>
25
+
26
+ #ifndef RUBY_WIN32_H
27
+ # include <unistd.h>
28
+ #ifdef HAVE_FCNTL_H
29
+ # include <fcntl.h>
30
+ #endif
31
+ #define INVALID_SOCKET (-1)
32
+ #else /* RUBY_WIN32_h */
33
+ static st_table *socket_2_fd = NULL;
34
+ #endif
35
+
36
+ /* Copied from libev plugin */
37
+ lcb_ssize_t
38
+ cb_io_recv(struct lcb_io_opt_st *iops, lcb_socket_t sock,
39
+ void *buffer, lcb_size_t len, int flags)
40
+ {
41
+ lcb_ssize_t ret = recv(sock, buffer, len, flags);
42
+ if (ret < 0) {
43
+ iops->v.v0.error = errno;
44
+ }
45
+ return ret;
46
+ }
47
+
48
+ lcb_ssize_t
49
+ cb_io_recvv(struct lcb_io_opt_st *iops, lcb_socket_t sock,
50
+ struct lcb_iovec_st *iov, lcb_size_t niov)
51
+ {
52
+ struct msghdr msg;
53
+ struct iovec vec[2];
54
+ lcb_ssize_t ret;
55
+
56
+ if (niov != 2) {
57
+ return -1;
58
+ }
59
+ memset(&msg, 0, sizeof(msg));
60
+ msg.msg_iov = vec;
61
+ msg.msg_iovlen = iov[1].iov_len ? (lcb_size_t)2 : (lcb_size_t)1;
62
+ msg.msg_iov[0].iov_base = iov[0].iov_base;
63
+ msg.msg_iov[0].iov_len = iov[0].iov_len;
64
+ msg.msg_iov[1].iov_base = iov[1].iov_base;
65
+ msg.msg_iov[1].iov_len = iov[1].iov_len;
66
+ ret = recvmsg(sock, &msg, 0);
67
+
68
+ if (ret < 0) {
69
+ iops->v.v0.error = errno;
70
+ }
71
+
72
+ return ret;
73
+ }
74
+
75
+ lcb_ssize_t
76
+ cb_io_send(struct lcb_io_opt_st *iops, lcb_socket_t sock,
77
+ const void *msg, lcb_size_t len, int flags)
78
+ {
79
+ lcb_ssize_t ret = send(sock, msg, len, flags);
80
+ if (ret < 0) {
81
+ iops->v.v0.error = errno;
82
+ }
83
+ return ret;
84
+ }
85
+
86
+ lcb_ssize_t
87
+ cb_io_sendv(struct lcb_io_opt_st *iops, lcb_socket_t sock,
88
+ struct lcb_iovec_st *iov, lcb_size_t niov)
89
+ {
90
+ struct msghdr msg;
91
+ struct iovec vec[2];
92
+ lcb_ssize_t ret;
93
+
94
+ if (niov != 2) {
95
+ return -1;
96
+ }
97
+ memset(&msg, 0, sizeof(msg));
98
+ msg.msg_iov = vec;
99
+ msg.msg_iovlen = iov[1].iov_len ? (lcb_size_t)2 : (lcb_size_t)1;
100
+ msg.msg_iov[0].iov_base = iov[0].iov_base;
101
+ msg.msg_iov[0].iov_len = iov[0].iov_len;
102
+ msg.msg_iov[1].iov_base = iov[1].iov_base;
103
+ msg.msg_iov[1].iov_len = iov[1].iov_len;
104
+ ret = sendmsg(sock, &msg, 0);
105
+
106
+ if (ret < 0) {
107
+ iops->v.v0.error = errno;
108
+ }
109
+ return ret;
110
+ }
111
+
112
+ static int
113
+ make_socket_nonblocking(lcb_socket_t sock)
114
+ {
115
+ int flags = 0;
116
+ #ifdef F_GETFL
117
+ if ((flags = fcntl(sock, F_GETFL, NULL)) < 0) {
118
+ return -1;
119
+ }
120
+ #endif
121
+ if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
122
+ return -1;
123
+ }
124
+
125
+ return 0;
126
+ }
127
+
128
+ static int
129
+ close_socket(lcb_socket_t sock)
130
+ {
131
+ return close(sock);
132
+ }
133
+
134
+ lcb_socket_t
135
+ cb_io_socket(struct lcb_io_opt_st *iops, int domain, int type,
136
+ int protocol)
137
+ {
138
+ lcb_socket_t sock = socket(domain, type, protocol);
139
+ if (sock == INVALID_SOCKET) {
140
+ iops->v.v0.error = errno;
141
+ } else {
142
+ if (make_socket_nonblocking(sock) != 0) {
143
+ int error = errno;
144
+ iops->v.v0.close(iops, sock);
145
+ iops->v.v0.error = error;
146
+ sock = INVALID_SOCKET;
147
+ }
148
+ }
149
+
150
+ return sock;
151
+ }
152
+
153
+ void
154
+ cb_io_close(struct lcb_io_opt_st *iops, lcb_socket_t sock)
155
+ {
156
+ close_socket(sock);
157
+ (void)iops;
158
+ }
159
+
160
+ int
161
+ cb_io_connect(struct lcb_io_opt_st *iops, lcb_socket_t sock,
162
+ const struct sockaddr *name, unsigned int namelen)
163
+ {
164
+ int ret = connect(sock, name, (socklen_t)namelen);
165
+ if (ret < 0) {
166
+ iops->v.v0.error = errno;
167
+ }
168
+ return ret;
169
+ }
170
+
171
+ #endif
@@ -0,0 +1,129 @@
1
+ /* vim: ft=c et ts=8 sts=4 sw=4 cino=
2
+ *
3
+ * Copyright 2011, 2012 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "couchbase_ext.h"
19
+
20
+ /*
21
+ * Check if result of operation was successful.
22
+ *
23
+ * @since 1.0.0
24
+ *
25
+ * @return [true, false] +false+ if there is an +error+ object attached,
26
+ * +false+ otherwise.
27
+ */
28
+ VALUE
29
+ cb_result_success_p(VALUE self)
30
+ {
31
+ return RTEST(rb_attr_get(self, cb_id_iv_error)) ? Qfalse : Qtrue;
32
+ }
33
+
34
+ /*
35
+ * Returns a string containing a human-readable representation of the Result.
36
+ *
37
+ * @since 1.0.0
38
+ *
39
+ * @return [String]
40
+ */
41
+ VALUE
42
+ cb_result_inspect(VALUE self)
43
+ {
44
+ VALUE str, attr;
45
+ char buf[100];
46
+
47
+ str = rb_str_buf_new2("#<");
48
+ rb_str_buf_cat2(str, rb_obj_classname(self));
49
+ snprintf(buf, 100, ":%p", (void *)self);
50
+ rb_str_buf_cat2(str, buf);
51
+
52
+ attr = rb_attr_get(self, cb_id_iv_operation);
53
+ if (RTEST(attr)) {
54
+ rb_str_buf_cat2(str, " operation=");
55
+ rb_str_append(str, rb_inspect(attr));
56
+ }
57
+
58
+ attr = rb_attr_get(self, cb_id_iv_error);
59
+ if (RTEST(attr)) {
60
+ rb_str_buf_cat2(str, " error=");
61
+ rb_str_append(str, rb_inspect(attr));
62
+ }
63
+
64
+ attr = rb_attr_get(self, cb_id_iv_value);
65
+ if (RTEST(attr) && rb_obj_is_kind_of(attr, cb_cBucket)) {
66
+ rb_str_buf_cat2(str, " bucket="); /* value also accessible using alias #bucket */
67
+ rb_str_append(str, rb_inspect(attr));
68
+ }
69
+
70
+ attr = rb_attr_get(self, cb_id_iv_key);
71
+ if (RTEST(attr)) {
72
+ rb_str_buf_cat2(str, " key=");
73
+ rb_str_append(str, rb_inspect(attr));
74
+ }
75
+
76
+ attr = rb_attr_get(self, cb_id_iv_status);
77
+ if (RTEST(attr)) {
78
+ rb_str_buf_cat2(str, " status=");
79
+ rb_str_append(str, rb_inspect(attr));
80
+ }
81
+
82
+ attr = rb_attr_get(self, cb_id_iv_cas);
83
+ if (RTEST(attr)) {
84
+ rb_str_buf_cat2(str, " cas=");
85
+ rb_str_append(str, rb_inspect(attr));
86
+ }
87
+
88
+ attr = rb_attr_get(self, cb_id_iv_flags);
89
+ if (RTEST(attr)) {
90
+ rb_str_buf_cat2(str, " flags=0x");
91
+ rb_str_append(str, rb_funcall(attr, cb_id_to_s, 1, INT2FIX(16)));
92
+ }
93
+
94
+ attr = rb_attr_get(self, cb_id_iv_node);
95
+ if (RTEST(attr)) {
96
+ rb_str_buf_cat2(str, " node=");
97
+ rb_str_append(str, rb_inspect(attr));
98
+ }
99
+
100
+ attr = rb_attr_get(self, cb_id_iv_from_master);
101
+ if (attr != Qnil) {
102
+ rb_str_buf_cat2(str, " from_master=");
103
+ rb_str_append(str, rb_inspect(attr));
104
+ }
105
+
106
+ attr = rb_attr_get(self, cb_id_iv_time_to_persist);
107
+ if (RTEST(attr)) {
108
+ rb_str_buf_cat2(str, " time_to_persist=");
109
+ rb_str_append(str, rb_inspect(attr));
110
+ }
111
+
112
+ attr = rb_attr_get(self, cb_id_iv_time_to_replicate);
113
+ if (RTEST(attr)) {
114
+ rb_str_buf_cat2(str, " time_to_replicate=");
115
+ rb_str_append(str, rb_inspect(attr));
116
+ }
117
+
118
+ attr = rb_attr_get(self, cb_id_iv_headers);
119
+ if (RTEST(attr)) {
120
+ rb_str_buf_cat2(str, " headers=");
121
+ rb_str_append(str, rb_inspect(attr));
122
+ }
123
+
124
+ rb_str_buf_cat2(str, ">");
125
+
126
+ return str;
127
+ }
128
+
129
+