couchbase 1.2.0.z.beta3 → 1.2.0.z.beta4

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,7 +9,7 @@ before_install:
9
9
  - wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -
10
10
  - echo deb http://packages.couchbase.com/snapshot/ubuntu oneiric oneiric/main | sudo tee /etc/apt/sources.list.d/couchbase.list
11
11
  - sudo apt-get update
12
- - sudo apt-get -y install libevent-dev libvbucket-dev libcouchbase-dev
12
+ - sudo apt-get -y install libcouchbase2-dev
13
13
 
14
14
  rvm:
15
15
  - 1.8.7
@@ -1,3 +1,24 @@
1
+ ## 1.2.0.z.beta4 / 2012-11-21
2
+
3
+ * Do not hide ValueFormat reason
4
+ * Adjust version check for MultiJson monkeypatch
5
+ * Update error codes
6
+ * Remove mentions of LCB_LIBEVENT_ERROR in utils.c
7
+ * Add Makefile for easier build with repo layout
8
+ * Check HTTP error code when building exception object
9
+ * Remove debug output in tests
10
+ * Make rack session store adapter quiet
11
+ * RCBC-90 Update documentation about session store
12
+ * Protect against non string values in :plain mode
13
+ * RCBC-89 Fetch documents using binary protocol by default
14
+ * Deserialize Base64 value from view
15
+ * Remove all_docs mentions
16
+ * RCBC-92 Use more portable version of rb_sprintf()
17
+ * Do not expose docs embedded in HTTP response
18
+ * RCBC-94 Reset global exception after usage
19
+ * Fix number of arguments to Kernel#sprintf
20
+ * Increase default connection timeout
21
+
1
22
  ## 1.2.0.z.beta3 / 2012-10-12
2
23
 
3
24
  * Update view API
@@ -0,0 +1,3 @@
1
+ all:
2
+ $(MAKE) -C../.. ruby-client
3
+
@@ -443,7 +443,6 @@ store a couple of posts using memcached API:
443
443
  c['hello-world'] = {:title => 'Hello World',
444
444
  :body => 'Well hello and welcome to my new blog...',
445
445
  :date => '2009/01/15 15:52:20'}
446
- c.all_docs.count #=> 3
447
446
 
448
447
  Now let's create design doc with sample view and save it in file
449
448
  'blog.json':
@@ -493,7 +492,7 @@ You can also use Enumerator to iterate view results
493
492
 
494
493
  require 'date'
495
494
  posts_by_date = Hash.new{|h,k| h[k] = []}
496
- enum = c.all_docs(:include_docs => true).each # request hasn't issued yet
495
+ enum = c.recent_posts(:include_docs => true).each # request hasn't issued yet
497
496
  enum.inject(posts_by_date) do |acc, doc|
498
497
  acc[date] = Date.strptime(doc['date'], '%Y/%m/%d')
499
498
  acc
@@ -237,8 +237,18 @@ cb_params_store_init_item(struct params_st *params, lcb_size_t idx,
237
237
  {
238
238
  key_obj = unify_key(params->bucket, key_obj, 1);
239
239
  value_obj = encode_value(value_obj, params->cmd.store.flags);
240
- if (value_obj == Qundef) {
241
- rb_raise(eValueFormatError, "unable to convert value for key '%s'", RSTRING_PTR(key_obj));
240
+ if (rb_obj_is_kind_of(value_obj, rb_eStandardError)) {
241
+ VALUE exc_str = rb_funcall(value_obj, id_to_s, 0);
242
+ VALUE msg = rb_funcall(rb_mKernel, id_sprintf, 3,
243
+ rb_str_new2("unable to convert value for key '%s': %s"), key_obj, exc_str);
244
+ VALUE exc = rb_exc_new3(eValueFormatError, msg);
245
+ rb_ivar_set(exc, id_iv_inner_exception, value_obj);
246
+ rb_exc_raise(exc);
247
+ }
248
+ /* the value must be string after conversion */
249
+ if (TYPE(value_obj) != T_STRING) {
250
+ VALUE val = rb_any_to_s(value_obj);
251
+ rb_raise(eValueFormatError, "unable to convert value for key '%s' to string: %s", RSTRING_PTR(key_obj), RSTRING_PTR(val));
242
252
  }
243
253
  params->cmd.store.items[idx].v.v0.datatype = params->cmd.store.datatype;
244
254
  params->cmd.store.items[idx].v.v0.operation = params->cmd.store.operation;
@@ -108,6 +108,7 @@ ID id_iv_error;
108
108
  ID id_iv_flags;
109
109
  ID id_iv_from_master;
110
110
  ID id_iv_headers;
111
+ ID id_iv_inner_exception;
111
112
  ID id_iv_key;
112
113
  ID id_iv_node;
113
114
  ID id_iv_operation;
@@ -123,6 +124,7 @@ ID id_password;
123
124
  ID id_path;
124
125
  ID id_port;
125
126
  ID id_scheme;
127
+ ID id_sprintf;
126
128
  ID id_to_s;
127
129
  ID id_user;
128
130
  ID id_verify_observe_options;
@@ -130,6 +132,8 @@ ID id_verify_observe_options;
130
132
  /* Errors */
131
133
  VALUE eBaseError;
132
134
  VALUE eValueFormatError;
135
+ VALUE eHTTPError;
136
+
133
137
  /* LCB_SUCCESS = 0x00 */
134
138
  /* LCB_AUTH_CONTINUE = 0x01 */
135
139
  VALUE eAuthError; /* LCB_AUTH_ERROR = 0x02 */
@@ -144,20 +148,21 @@ VALUE eLibcouchbaseError; /* LCB_ERROR = 0x0a */
144
148
  VALUE eTmpFailError; /* LCB_ETMPFAIL = 0x0b */
145
149
  VALUE eKeyExistsError; /* LCB_KEY_EEXISTS = 0x0c */
146
150
  VALUE eNotFoundError; /* LCB_KEY_ENOENT = 0x0d */
147
- VALUE eLibeventError; /* LCB_LIBEVENT_ERROR = 0x0e */
148
- VALUE eNetworkError; /* LCB_NETWORK_ERROR = 0x0f */
149
- VALUE eNotMyVbucketError; /* LCB_NOT_MY_VBUCKET = 0x10 */
150
- VALUE eNotStoredError; /* LCB_NOT_STORED = 0x11 */
151
- VALUE eNotSupportedError; /* LCB_NOT_SUPPORTED = 0x12 */
152
- VALUE eUnknownCommandError; /* LCB_UNKNOWN_COMMAND = 0x13 */
153
- VALUE eUnknownHostError; /* LCB_UNKNOWN_HOST = 0x14 */
154
- VALUE eProtocolError; /* LCB_PROTOCOL_ERROR = 0x15 */
155
- VALUE eTimeoutError; /* LCB_ETIMEDOUT = 0x16 */
156
- VALUE eConnectError; /* LCB_CONNECT_ERROR = 0x17 */
157
- VALUE eBucketNotFoundError; /* LCB_BUCKET_ENOENT = 0x18 */
158
- VALUE eClientNoMemoryError; /* LCB_CLIENT_ENOMEM = 0x19 */
159
- VALUE eClientTmpFailError; /* LCB_CLIENT_ETMPFAIL = 0x20 */
160
- VALUE eBadHandleError; /* LCB_EBADHANDLE = 0x21 */
151
+ VALUE eDlopenFailedError; /* LCB_DLOPEN_FAILED = 0x0e */
152
+ VALUE eDlsymFailedError; /* LCB_DLSYM_FAILED = 0x0f */
153
+ VALUE eNetworkError; /* LCB_NETWORK_ERROR = 0x10 */
154
+ VALUE eNotMyVbucketError; /* LCB_NOT_MY_VBUCKET = 0x11 */
155
+ VALUE eNotStoredError; /* LCB_NOT_STORED = 0x12 */
156
+ VALUE eNotSupportedError; /* LCB_NOT_SUPPORTED = 0x13 */
157
+ VALUE eUnknownCommandError; /* LCB_UNKNOWN_COMMAND = 0x14 */
158
+ VALUE eUnknownHostError; /* LCB_UNKNOWN_HOST = 0x15 */
159
+ VALUE eProtocolError; /* LCB_PROTOCOL_ERROR = 0x16 */
160
+ VALUE eTimeoutError; /* LCB_ETIMEDOUT = 0x17 */
161
+ VALUE eConnectError; /* LCB_CONNECT_ERROR = 0x18 */
162
+ VALUE eBucketNotFoundError; /* LCB_BUCKET_ENOENT = 0x19 */
163
+ VALUE eClientNoMemoryError; /* LCB_CLIENT_ENOMEM = 0x1a */
164
+ VALUE eClientTmpFailError; /* LCB_CLIENT_ETMPFAIL = 0x1b */
165
+ VALUE eBadHandleError; /* LCB_EBADHANDLE = 0x1c */
161
166
 
162
167
 
163
168
  /* Ruby Extension initializer */
@@ -179,17 +184,24 @@ Init_couchbase_ext(void)
179
184
  /* Document-class: Couchbase::Error::Auth
180
185
  * Authentication error
181
186
  *
187
+ * You provided an invalid username/password combination.
188
+ *
182
189
  * @since 1.0.0
183
190
  */
184
191
  eAuthError = rb_define_class_under(mError, "Auth", eBaseError);
185
192
  /* Document-class: Couchbase::Error::BucketNotFound
186
- * The given bucket not found in the cluster
193
+ * Bucket not found
194
+ *
195
+ * The requested bucket not found in the cluster
187
196
  *
188
197
  * @since 1.0.0
189
198
  */
190
199
  eBucketNotFoundError = rb_define_class_under(mError, "BucketNotFound", eBaseError);
191
200
  /* Document-class: Couchbase::Error::Busy
192
- * The cluster is too busy now. Try again later
201
+ * The cluster is too busy
202
+ *
203
+ * The server is too busy to handle your request right now.
204
+ * please back off and try again at a later time.
193
205
  *
194
206
  * @since 1.0.0
195
207
  */
@@ -203,6 +215,9 @@ Init_couchbase_ext(void)
203
215
  /* Document-class: Couchbase::Error::Internal
204
216
  * Internal error
205
217
  *
218
+ * Internal error inside the library. You would have
219
+ * to destroy the instance and create a new one to recover.
220
+ *
206
221
  * @since 1.0.0
207
222
  */
208
223
  eInternalError = rb_define_class_under(mError, "Internal", eBaseError);
@@ -215,6 +230,8 @@ Init_couchbase_ext(void)
215
230
  /* Document-class: Couchbase::Error::KeyExists
216
231
  * Key already exists
217
232
  *
233
+ * The key already exists (with another CAS value)
234
+ *
218
235
  * @since 1.0.0
219
236
  */
220
237
  eKeyExistsError = rb_define_class_under(mError, "KeyExists", eBaseError);
@@ -224,21 +241,20 @@ Init_couchbase_ext(void)
224
241
  * @since 1.0.0
225
242
  */
226
243
  eLibcouchbaseError = rb_define_class_under(mError, "Libcouchbase", eBaseError);
227
- /* Document-class: Couchbase::Error::Libevent
228
- * Problem using libevent
229
- *
230
- * @since 1.0.0
231
- */
232
- eLibeventError = rb_define_class_under(mError, "Libevent", eBaseError);
233
244
  /* Document-class: Couchbase::Error::Network
234
245
  * Network error
235
246
  *
247
+ * A network related problem occured (name lookup, read/write/connect
248
+ * etc)
249
+ *
236
250
  * @since 1.0.0
237
251
  */
238
252
  eNetworkError = rb_define_class_under(mError, "Network", eBaseError);
239
253
  /* Document-class: Couchbase::Error::NoMemory
240
254
  * Out of memory error (on Server)
241
255
  *
256
+ * The client ran out of memory
257
+ *
242
258
  * @since 1.0.0
243
259
  */
244
260
  eNoMemoryError = rb_define_class_under(mError, "NoMemory", eBaseError);
@@ -257,29 +273,44 @@ Init_couchbase_ext(void)
257
273
  /* Document-class: Couchbase::Error::NotMyVbucket
258
274
  * The vbucket is not located on this server
259
275
  *
276
+ * The server who received the request is not responsible for the
277
+ * object anymore. (This happens during changes in the cluster
278
+ * topology)
279
+ *
260
280
  * @since 1.0.0
261
281
  */
262
282
  eNotMyVbucketError = rb_define_class_under(mError, "NotMyVbucket", eBaseError);
263
283
  /* Document-class: Couchbase::Error::NotStored
264
284
  * Not stored
265
285
  *
286
+ * The object was not stored on the server
287
+ *
266
288
  * @since 1.0.0
267
289
  */
268
290
  eNotStoredError = rb_define_class_under(mError, "NotStored", eBaseError);
269
291
  /* Document-class: Couchbase::Error::NotSupported
270
292
  * Not supported
271
293
  *
294
+ * The server doesn't support the requested command. This error differs
295
+ * from {Couchbase::Error::UnknownCommand} by that the server knows
296
+ * about the command, but for some reason decided to not support it.
297
+ *
272
298
  * @since 1.0.0
273
299
  */
274
300
  eNotSupportedError = rb_define_class_under(mError, "NotSupported", eBaseError);
275
301
  /* Document-class: Couchbase::Error::Range
276
302
  * Invalid range
277
303
  *
304
+ * An invalid range specified
305
+ *
278
306
  * @since 1.0.0
279
307
  */
280
308
  eRangeError = rb_define_class_under(mError, "Range", eBaseError);
281
309
  /* Document-class: Couchbase::Error::TemporaryFail
282
- * Temporary failure. Try again later
310
+ * Temporary failure
311
+ *
312
+ * The server tried to perform the requested operation, but failed
313
+ * due to a temporary constraint. Retrying the operation may work.
283
314
  *
284
315
  * @since 1.0.0
285
316
  */
@@ -287,24 +318,33 @@ Init_couchbase_ext(void)
287
318
  /* Document-class: Couchbase::Error::ClientTemporaryFail
288
319
  * Temporary failure (on Client)
289
320
  *
321
+ * The client encountered a temporary error (retry might resolve
322
+ * the problem)
323
+ *
290
324
  * @since 1.2.0
291
325
  */
292
326
  eClientTmpFailError = rb_define_class_under(mError, "ClientTemporaryFail", eBaseError);
293
327
  /* Document-class: Couchbase::Error::TooBig
294
328
  * Object too big
295
329
  *
330
+ * The sever reported that this object is too big
331
+ *
296
332
  * @since 1.0.0
297
333
  */
298
334
  eTooBigError = rb_define_class_under(mError, "TooBig", eBaseError);
299
335
  /* Document-class: Couchbase::Error::UnknownCommand
300
336
  * Unknown command
301
337
  *
338
+ * The server doesn't know what that command is.
339
+ *
302
340
  * @since 1.0.0
303
341
  */
304
342
  eUnknownCommandError = rb_define_class_under(mError, "UnknownCommand", eBaseError);
305
343
  /* Document-class: Couchbase::Error::UnknownHost
306
344
  * Unknown host
307
345
  *
346
+ * The server failed to resolve the requested hostname
347
+ *
308
348
  * @since 1.0.0
309
349
  */
310
350
  eUnknownHostError = rb_define_class_under(mError, "UnknownHost", eBaseError);
@@ -317,12 +357,17 @@ Init_couchbase_ext(void)
317
357
  /* Document-class: Couchbase::Error::Protocol
318
358
  * Protocol error
319
359
  *
360
+ * There is something wrong with the datastream received from
361
+ * the server
362
+ *
320
363
  * @since 1.0.0
321
364
  */
322
365
  eProtocolError = rb_define_class_under(mError, "Protocol", eBaseError);
323
366
  /* Document-class: Couchbase::Error::Timeout
324
367
  * Timeout error
325
368
  *
369
+ * The operation timed out
370
+ *
326
371
  * @since 1.1.0
327
372
  */
328
373
  eTimeoutError = rb_define_class_under(mError, "Timeout", eBaseError);
@@ -341,6 +386,30 @@ Init_couchbase_ext(void)
341
386
  */
342
387
  eBadHandleError = rb_define_class_under(mError, "BadHandle", eBaseError);
343
388
 
389
+ /* Document-class: Couchbase::Error::DlopenFailed
390
+ * dlopen() failed
391
+ *
392
+ * Failed to open shared object
393
+ *
394
+ * @since 1.2.0
395
+ */
396
+ eDlopenFailedError = rb_define_class_under(mError, "DlopenFailed", eBaseError);
397
+
398
+ /* Document-class: Couchbase::Error::DlsymFailed
399
+ * dlsym() failed
400
+ *
401
+ * Failed to locate the requested symbol in the shared object
402
+ *
403
+ * @since 1.2.0
404
+ */
405
+ eDlsymFailedError = rb_define_class_under(mError, "DlsymFailed", eBaseError);
406
+
407
+ /* Document-class: Couchbase::Error::HTTP
408
+ * HTTP error with status code
409
+ *
410
+ * @since 1.2.0
411
+ */
412
+ eHTTPError = rb_define_class_under(mError, "HTTP", eBaseError);
344
413
  /* Document-method: error
345
414
  *
346
415
  * The underlying libcouchbase library could return one of the following
@@ -352,29 +421,31 @@ Init_couchbase_ext(void)
352
421
  * 0x02 :: LCB_AUTH_ERROR (Authentication error)
353
422
  * 0x03 :: LCB_DELTA_BADVAL (Not a number)
354
423
  * 0x04 :: LCB_E2BIG (Object too big)
355
- * 0x05 :: LCB_EBUSY (Too busy. Try again later)
424
+ * 0x05 :: LCB_EBUSY (Too busy)
356
425
  * 0x06 :: LCB_EINTERNAL (Internal error)
357
426
  * 0x07 :: LCB_EINVAL (Invalid arguments)
358
427
  * 0x08 :: LCB_ENOMEM (Out of memory)
359
428
  * 0x09 :: LCB_ERANGE (Invalid range)
360
429
  * 0x0a :: LCB_ERROR (Generic error)
361
- * 0x0b :: LCB_ETMPFAIL (Temporary failure. Try again later)
430
+ * 0x0b :: LCB_ETMPFAIL (Temporary failure)
362
431
  * 0x0c :: LCB_KEY_EEXISTS (Key exists (with a different CAS value))
363
432
  * 0x0d :: LCB_KEY_ENOENT (No such key)
364
- * 0x0e :: LCB_LIBEVENT_ERROR (Problem using libevent)
365
- * 0x0f :: LCB_NETWORK_ERROR (Network error)
366
- * 0x10 :: LCB_NOT_MY_VBUCKET (The vbucket is not located on this server)
367
- * 0x11 :: LCB_NOT_STORED (Not stored)
368
- * 0x12 :: LCB_NOT_SUPPORTED (Not supported)
369
- * 0x13 :: LCB_UNKNOWN_COMMAND (Unknown command)
370
- * 0x14 :: LCB_UNKNOWN_HOST (Unknown host)
371
- * 0x15 :: LCB_PROTOCOL_ERROR (Protocol error)
372
- * 0x16 :: LCB_ETIMEDOUT (Operation timed out)
373
- * 0x17 :: LCB_CONNECT_ERROR (Connection failure)
374
- * 0x18 :: LCB_BUCKET_ENOENT (No such bucket)
375
- * 0x19 :: LCB_CLIENT_ENOMEM (Out of memory on the client)
376
- * 0x20 :: LCB_CLIENT_ETMPFAIL (Temporary failure on the client)
377
- * 0x21 :: LCB_EBADHANDLE (Invalid handle type)
433
+ * 0x0e :: LCB_DLOPEN_FAILED (Failed to open shared object)
434
+ * 0x0f :: LCB_DLSYM_FAILED (Failed to locate the requested symbol in shared object)
435
+ * 0x10 :: LCB_NETWORK_ERROR (Network error)
436
+ * 0x11 :: LCB_NOT_MY_VBUCKET (The vbucket is not located on this server)
437
+ * 0x12 :: LCB_NOT_STORED (Not stored)
438
+ * 0x13 :: LCB_NOT_SUPPORTED (Not supported)
439
+ * 0x14 :: LCB_UNKNOWN_COMMAND (Unknown command)
440
+ * 0x15 :: LCB_UNKNOWN_HOST (Unknown host)
441
+ * 0x16 :: LCB_PROTOCOL_ERROR (Protocol error)
442
+ * 0x17 :: LCB_ETIMEDOUT (Operation timed out)
443
+ * 0x18 :: LCB_CONNECT_ERROR (Connection failure)
444
+ * 0x19 :: LCB_BUCKET_ENOENT (No such bucket)
445
+ * 0x1a :: LCB_CLIENT_ENOMEM (Out of memory on the client)
446
+ * 0x1b :: LCB_CLIENT_ETMPFAIL (Temporary failure on the client)
447
+ * 0x1c :: LCB_EBADHANDLE (Invalid handle type)
448
+ *
378
449
  *
379
450
  * @since 1.0.0
380
451
  *
@@ -410,6 +481,14 @@ Init_couchbase_ext(void)
410
481
  * @return [Symbol] the operation (+nil+ unless accessible) */
411
482
  rb_define_attr(eBaseError, "operation", 1, 0);
412
483
  id_iv_operation = rb_intern("@operation");
484
+ /* Document-method: inner_exception
485
+ *
486
+ * @since 1.2.0.beta4
487
+ *
488
+ * @return [Exception] the inner exception or +nil+. Some exceptions like
489
+ * {Error::ValueFormat} wrap the original exception */
490
+ rb_define_attr(eBaseError, "inner_exception", 1, 0);
491
+ id_iv_inner_exception = rb_intern("@inner_exception");
413
492
 
414
493
  /* Document-class: Couchbase::Result
415
494
  *
@@ -910,6 +989,7 @@ Init_couchbase_ext(void)
910
989
  id_path = rb_intern("path");
911
990
  id_port = rb_intern("port");
912
991
  id_scheme = rb_intern("scheme");
992
+ id_sprintf = rb_intern("sprintf");
913
993
  id_to_s = rb_intern("to_s");
914
994
  id_user = rb_intern("user");
915
995
  id_verify_observe_options = rb_intern("verify_observe_options");
@@ -228,6 +228,7 @@ extern ID id_iv_error;
228
228
  extern ID id_iv_flags;
229
229
  extern ID id_iv_from_master;
230
230
  extern ID id_iv_headers;
231
+ extern ID id_iv_inner_exception;
231
232
  extern ID id_iv_key;
232
233
  extern ID id_iv_node;
233
234
  extern ID id_iv_operation;
@@ -243,6 +244,7 @@ extern ID id_password;
243
244
  extern ID id_path;
244
245
  extern ID id_port;
245
246
  extern ID id_scheme;
247
+ extern ID id_sprintf;
246
248
  extern ID id_to_s;
247
249
  extern ID id_user;
248
250
  extern ID id_verify_observe_options;
@@ -250,6 +252,7 @@ extern ID id_verify_observe_options;
250
252
  /* Errors */
251
253
  extern VALUE eBaseError;
252
254
  extern VALUE eValueFormatError;
255
+ extern VALUE eHTTPError;
253
256
  /* LCB_SUCCESS = 0x00 */
254
257
  /* LCB_AUTH_CONTINUE = 0x01 */
255
258
  extern VALUE eAuthError; /* LCB_AUTH_ERROR = 0x02 */
@@ -264,20 +267,21 @@ extern VALUE eLibcouchbaseError; /* LCB_ERROR = 0x0a */
264
267
  extern VALUE eTmpFailError; /* LCB_ETMPFAIL = 0x0b */
265
268
  extern VALUE eKeyExistsError; /* LCB_KEY_EEXISTS = 0x0c */
266
269
  extern VALUE eNotFoundError; /* LCB_KEY_ENOENT = 0x0d */
267
- extern VALUE eLibeventError; /* LCB_LIBEVENT_ERROR = 0x0e */
268
- extern VALUE eNetworkError; /* LCB_NETWORK_ERROR = 0x0f */
269
- extern VALUE eNotMyVbucketError; /* LCB_NOT_MY_VBUCKET = 0x10 */
270
- extern VALUE eNotStoredError; /* LCB_NOT_STORED = 0x11 */
271
- extern VALUE eNotSupportedError; /* LCB_NOT_SUPPORTED = 0x12 */
272
- extern VALUE eUnknownCommandError; /* LCB_UNKNOWN_COMMAND = 0x13 */
273
- extern VALUE eUnknownHostError; /* LCB_UNKNOWN_HOST = 0x14 */
274
- extern VALUE eProtocolError; /* LCB_PROTOCOL_ERROR = 0x15 */
275
- extern VALUE eTimeoutError; /* LCB_ETIMEDOUT = 0x16 */
276
- extern VALUE eConnectError; /* LCB_CONNECT_ERROR = 0x17 */
277
- extern VALUE eBucketNotFoundError; /* LCB_BUCKET_ENOENT = 0x18 */
278
- extern VALUE eClientNoMemoryError; /* LCB_CLIENT_ENOMEM = 0x19 */
279
- extern VALUE eClientTmpFailError; /* LCB_CLIENT_ETMPFAIL = 0x20 */
280
- extern VALUE eBadHandleError; /* LCB_EBADHANDLE = 0x21 */
270
+ extern VALUE eDlopenFailedError; /* LCB_DLOPEN_FAILED = 0x0e */
271
+ extern VALUE eDlsymFailedError; /* LCB_DLSYM_FAILED = 0x0f */
272
+ extern VALUE eNetworkError; /* LCB_NETWORK_ERROR = 0x10 */
273
+ extern VALUE eNotMyVbucketError; /* LCB_NOT_MY_VBUCKET = 0x11 */
274
+ extern VALUE eNotStoredError; /* LCB_NOT_STORED = 0x12 */
275
+ extern VALUE eNotSupportedError; /* LCB_NOT_SUPPORTED = 0x13 */
276
+ extern VALUE eUnknownCommandError; /* LCB_UNKNOWN_COMMAND = 0x14 */
277
+ extern VALUE eUnknownHostError; /* LCB_UNKNOWN_HOST = 0x15 */
278
+ extern VALUE eProtocolError; /* LCB_PROTOCOL_ERROR = 0x16 */
279
+ extern VALUE eTimeoutError; /* LCB_ETIMEDOUT = 0x17 */
280
+ extern VALUE eConnectError; /* LCB_CONNECT_ERROR = 0x18 */
281
+ extern VALUE eBucketNotFoundError; /* LCB_BUCKET_ENOENT = 0x19 */
282
+ extern VALUE eClientNoMemoryError; /* LCB_CLIENT_ENOMEM = 0x1a */
283
+ extern VALUE eClientTmpFailError; /* LCB_CLIENT_ETMPFAIL = 0x1b */
284
+ extern VALUE eBadHandleError; /* LCB_EBADHANDLE = 0x1c */
281
285
 
282
286
  void strip_key_prefix(struct bucket_st *bucket, VALUE key);
283
287
  VALUE cb_check_error(lcb_error_t rc, const char *msg, VALUE key);
@@ -152,8 +152,10 @@ cb_bucket_delete(int argc, VALUE *argv, VALUE self)
152
152
  if (exc != Qnil) {
153
153
  rb_exc_raise(cb_gc_unprotect(bucket, exc));
154
154
  }
155
- if (bucket->exception != Qnil) {
156
- rb_exc_raise(bucket->exception);
155
+ exc = bucket->exception;
156
+ if (exc != Qnil) {
157
+ bucket->exception = Qnil;
158
+ rb_exc_raise(exc);
157
159
  }
158
160
  if (params.cmd.remove.num > 1) {
159
161
  return rv; /* return as a hash {key => true, ...} */
@@ -119,7 +119,7 @@ if try_compile(<<-SRC)
119
119
  define("HAVE_STDARG_PROTOTYPES")
120
120
  end
121
121
 
122
- have_library("couchbase", "lcb_set_http_data_callback", "libcouchbase/couchbase.h") or abort "You should install libcouchbase >= 2.0.0beta2. See http://www.couchbase.com/develop/ for more details"
122
+ have_library("couchbase", "lcb_verify_compiler_setup", "libcouchbase/couchbase.h") or abort "You should install libcouchbase >= 2.0.0beta3. See http://www.couchbase.com/develop/ for more details"
123
123
  have_header("mach/mach_time.h")
124
124
  have_header("stdint.h") or abort "Failed to locate stdint.h"
125
125
  have_header("sys/time.h")
@@ -42,16 +42,21 @@ get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_get_
42
42
  cas = ULL2NUM(resp->v.v0.cas);
43
43
  val = Qnil;
44
44
  if (resp->v.v0.nbytes != 0) {
45
- val = decode_value(STR_NEW((const char*)resp->v.v0.bytes, resp->v.v0.nbytes),
46
- resp->v.v0.flags, ctx->force_format);
47
- if (val == Qundef) {
45
+ VALUE raw = STR_NEW((const char*)resp->v.v0.bytes, resp->v.v0.nbytes);
46
+ val = decode_value(raw, resp->v.v0.flags, ctx->force_format);
47
+ if (rb_obj_is_kind_of(val, rb_eStandardError)) {
48
+ VALUE exc_str = rb_funcall(val, id_to_s, 0);
49
+ VALUE msg = rb_funcall(rb_mKernel, id_sprintf, 3,
50
+ rb_str_new2("unable to convert value for key '%s': %s"), key, exc_str);
48
51
  if (ctx->exception != Qnil) {
49
52
  cb_gc_unprotect(bucket, ctx->exception);
50
53
  }
51
- ctx->exception = rb_exc_new2(eValueFormatError, "unable to convert value");
54
+ ctx->exception = rb_exc_new3(eValueFormatError, msg);
52
55
  rb_ivar_set(ctx->exception, id_iv_operation, sym_get);
53
56
  rb_ivar_set(ctx->exception, id_iv_key, key);
57
+ rb_ivar_set(ctx->exception, id_iv_inner_exception, val);
54
58
  cb_gc_protect(bucket, ctx->exception);
59
+ val = raw;
55
60
  }
56
61
  } else if (flags_get_format(resp->v.v0.flags) == sym_plain) {
57
62
  val = STR_NEW_CSTR("");
@@ -275,8 +280,10 @@ cb_bucket_get(int argc, VALUE *argv, VALUE self)
275
280
  cb_gc_unprotect(bucket, exc);
276
281
  rb_exc_raise(exc);
277
282
  }
278
- if (bucket->exception != Qnil) {
279
- rb_exc_raise(bucket->exception);
283
+ exc = bucket->exception;
284
+ if (exc != Qnil) {
285
+ bucket->exception = Qnil;
286
+ rb_exc_raise(exc);
280
287
  }
281
288
  if (params.cmd.get.gat || params.cmd.get.assemble_hash ||
282
289
  (params.cmd.get.extended && (params.cmd.get.num > 1 || params.cmd.get.array))) {
@@ -160,8 +160,10 @@ cb_bucket_observe(int argc, VALUE *argv, VALUE self)
160
160
  cb_gc_unprotect(bucket, exc);
161
161
  rb_exc_raise(exc);
162
162
  }
163
- if (bucket->exception != Qnil) {
164
- rb_exc_raise(bucket->exception);
163
+ exc = bucket->exception;
164
+ if (exc != Qnil) {
165
+ bucket->exception = Qnil;
166
+ rb_exc_raise(exc);
165
167
  }
166
168
  if (params.cmd.observe.num > 1 || params.cmd.observe.array) {
167
169
  return rv; /* return as a hash {key => {}, ...} */
@@ -157,8 +157,10 @@ cb_bucket_stats(int argc, VALUE *argv, VALUE self)
157
157
  cb_gc_unprotect(bucket, exc);
158
158
  rb_exc_raise(exc);
159
159
  }
160
- if (bucket->exception != Qnil) {
161
- rb_exc_raise(bucket->exception);
160
+ exc = bucket->exception;
161
+ if (exc != Qnil) {
162
+ bucket->exception = Qnil;
163
+ rb_exc_raise(exc);
162
164
  }
163
165
  return rv;
164
166
  }
@@ -161,8 +161,10 @@ cb_bucket_store(lcb_storage_t cmd, int argc, VALUE *argv, VALUE self)
161
161
  cb_gc_unprotect(bucket, exc);
162
162
  rb_exc_raise(exc);
163
163
  }
164
- if (bucket->exception != Qnil) {
165
- rb_exc_raise(bucket->exception);
164
+ exc = bucket->exception;
165
+ if (exc != Qnil) {
166
+ bucket->exception = Qnil;
167
+ rb_exc_raise(exc);
166
168
  }
167
169
  if (RTEST(obs)) {
168
170
  cb_gc_unprotect(bucket, obs);
@@ -174,8 +174,10 @@ cb_bucket_touch(int argc, VALUE *argv, VALUE self)
174
174
  if (exc != Qnil) {
175
175
  rb_exc_raise(cb_gc_unprotect(bucket, exc));
176
176
  }
177
- if (bucket->exception != Qnil) {
178
- rb_exc_raise(bucket->exception);
177
+ exc = bucket->exception;
178
+ if (exc != Qnil) {
179
+ bucket->exception = Qnil;
180
+ rb_exc_raise(exc);
179
181
  }
180
182
  if (params.cmd.touch.num > 1) {
181
183
  return rv; /* return as a hash {key => true, ...} */
@@ -164,8 +164,10 @@ cb_bucket_unlock(int argc, VALUE *argv, VALUE self)
164
164
  if (exc != Qnil) {
165
165
  rb_exc_raise(cb_gc_unprotect(bucket, exc));
166
166
  }
167
- if (bucket->exception != Qnil) {
168
- rb_exc_raise(bucket->exception);
167
+ exc = bucket->exception;
168
+ if (exc != Qnil) {
169
+ bucket->exception = Qnil;
170
+ rb_exc_raise(exc);
169
171
  }
170
172
  if (params.cmd.unlock.num > 1) {
171
173
  return rv; /* return as a hash {key => true, ...} */
@@ -77,7 +77,8 @@ cb_check_error_with_status(lcb_error_t rc, const char *msg, VALUE key,
77
77
  VALUE klass, exc, str;
78
78
  char buf[300];
79
79
 
80
- if (rc == LCB_SUCCESS || rc == LCB_AUTH_CONTINUE) {
80
+ if ((rc == LCB_SUCCESS && (status == 0 || status / 100 == 2)) ||
81
+ rc == LCB_AUTH_CONTINUE) {
81
82
  return Qnil;
82
83
  }
83
84
  switch (rc) {
@@ -114,8 +115,11 @@ cb_check_error_with_status(lcb_error_t rc, const char *msg, VALUE key,
114
115
  case LCB_KEY_ENOENT:
115
116
  klass = eNotFoundError;
116
117
  break;
117
- case LCB_LIBEVENT_ERROR:
118
- klass = eLibeventError;
118
+ case LCB_DLOPEN_FAILED:
119
+ klass = eDlopenFailedError;
120
+ break;
121
+ case LCB_DLSYM_FAILED:
122
+ klass = eDlsymFailedError;
119
123
  break;
120
124
  case LCB_NETWORK_ERROR:
121
125
  klass = eNetworkError;
@@ -170,6 +174,7 @@ cb_check_error_with_status(lcb_error_t rc, const char *msg, VALUE key,
170
174
  }
171
175
  if (status > 0) {
172
176
  const char *reason = NULL;
177
+ klass = eHTTPError;
173
178
  snprintf(buf, 300, "status=\"%d\"", status);
174
179
  rb_str_buf_cat2(str, buf);
175
180
  switch (status) {
@@ -367,9 +372,10 @@ do_decode(VALUE *args)
367
372
  }
368
373
 
369
374
  static VALUE
370
- coding_failed(void)
375
+ coding_failed(VALUE unused, VALUE exc)
371
376
  {
372
- return Qundef;
377
+ (void)unused;
378
+ return exc;
373
379
  }
374
380
 
375
381
  VALUE
@@ -379,13 +385,8 @@ encode_value(VALUE val, uint32_t flags)
379
385
 
380
386
  args[0] = val;
381
387
  args[1] = (VALUE)flags;
382
- /* FIXME re-raise proper exception */
383
388
  blob = rb_rescue(do_encode, (VALUE)args, coding_failed, 0);
384
- /* it must be bytestring after all */
385
- if (TYPE(blob) != T_STRING) {
386
- return Qundef;
387
- }
388
- return blob;
389
+ return blob; /* bytestring or exception object */
389
390
  }
390
391
 
391
392
  VALUE
@@ -401,7 +402,7 @@ decode_value(VALUE blob, uint32_t flags, VALUE force_format)
401
402
  args[1] = (VALUE)flags;
402
403
  args[2] = (VALUE)force_format;
403
404
  val = rb_rescue(do_decode, (VALUE)args, coding_failed, 0);
404
- return val;
405
+ return val; /* the value or exception object */
405
406
  }
406
407
 
407
408
  void
@@ -137,8 +137,10 @@ cb_bucket_version(int argc, VALUE *argv, VALUE self)
137
137
  cb_gc_unprotect(bucket, exc);
138
138
  rb_exc_raise(exc);
139
139
  }
140
- if (bucket->exception != Qnil) {
141
- rb_exc_raise(bucket->exception);
140
+ exc = bucket->exception;
141
+ if (exc != Qnil) {
142
+ bucket->exception = Qnil;
143
+ rb_exc_raise(exc);
142
144
  }
143
145
  return rv;
144
146
  }
@@ -16,7 +16,7 @@ module ActionDispatch
16
16
  # Or remove this file and add following line to your `config/application.rb`:
17
17
  #
18
18
  # require 'action_dispatch/middleware/session/couchbase_store'
19
- # config.session_storage = :couchbase_store
19
+ # config.session_store :couchbase_store
20
20
  #
21
21
  # You can also pass additional options:
22
22
  #
@@ -25,7 +25,7 @@ module ActionDispatch
25
25
  # :expire_after => 5.minutes,
26
26
  # :couchbase => {:bucket => "sessions", :default_format => :marshal}
27
27
  # }
28
- # config.session_storage = :couchbase_store, session_options
28
+ # config.session_store :couchbase_store, session_options
29
29
  #
30
30
  # By default sessions will be serialized to JSON, to allow analyse them
31
31
  # using Map/Reduce.
@@ -106,6 +106,9 @@ module Couchbase
106
106
  req.on_body do |body|
107
107
  res = MultiJson.load(body.value)
108
108
  res["rows"].each do |obj|
109
+ if obj['doc']
110
+ obj['doc']['value'] = obj['doc'].delete('json')
111
+ end
109
112
  doc = ViewRow.wrap(self, obj)
110
113
  key = doc.id.sub(/^_design\//, '')
111
114
  next if self.environment == :production && key =~ /dev_/
@@ -117,17 +120,6 @@ module Couchbase
117
120
  async? ? nil : docmap
118
121
  end
119
122
 
120
- # Fetch all documents from the bucket.
121
- #
122
- # @since 1.2.0
123
- #
124
- # @param [Hash] params Params for Couchbase +/_all_docs+ query
125
- #
126
- # @return [Couchbase::View] View object
127
- def all_docs(params = {})
128
- View.new(self, "_all_docs", params)
129
- end
130
-
131
123
  # Update or create design doc with supplied views
132
124
  #
133
125
  # @since 1.2.0
@@ -17,5 +17,5 @@
17
17
 
18
18
  # Couchbase ruby client
19
19
  module Couchbase
20
- VERSION = "1.2.0.z.beta3"
20
+ VERSION = "1.2.0.z.beta4"
21
21
  end
@@ -15,6 +15,8 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
+ require 'base64'
19
+
18
20
  module Couchbase
19
21
 
20
22
  module Error
@@ -50,7 +52,7 @@ module Couchbase
50
52
  def initialize(bucket, endpoint, params = {})
51
53
  @bucket = bucket
52
54
  @endpoint = endpoint
53
- @params = params
55
+ @params = {:connection_timeout => 75_000}.merge(params)
54
56
  @wrapper_class = params.delete(:wrapper_class) || ViewRow
55
57
  unless @wrapper_class.respond_to?(:wrap)
56
58
  raise ArgumentError, "wrapper class should reposond to :wrap, check the options"
@@ -142,8 +144,14 @@ module Couchbase
142
144
  # the document and store them in {ViewRow#meta} hash.
143
145
  #
144
146
  # @param [Hash] params parameters for Couchbase query.
145
- # @option params [true, false] :include_docs (false) Include the full
146
- # content of the documents in the return.
147
+ # @option params [true, false] :include_docs (false) Include the
148
+ # full content of the documents in the return. Note that the document
149
+ # is fetched from the in memory cache where it may have been changed
150
+ # or even deleted. See also +:quiet+ parameter below to control error
151
+ # reporting during fetch.
152
+ # @option params [true, false] :quiet (true) Do not raise error if
153
+ # associated document not found in the memory. If the parameter +true+
154
+ # will use +nil+ value instead.
147
155
  # @option params [true, false] :descending (false) Return the documents
148
156
  # in descending by key order
149
157
  # @option params [String, Fixnum, Hash, Array] :key Return only
@@ -175,7 +183,7 @@ module Couchbase
175
183
  # response stream.
176
184
  # :stop:: Stop immediately when an error condition occurs. No
177
185
  # further view information will be returned.
178
- # @option params [Fixnum] :connection_timeout (60000) Timeout before the
186
+ # @option params [Fixnum] :connection_timeout (75000) Timeout before the
179
187
  # view request is dropped (milliseconds)
180
188
  # @option params [true, false] :reduce (true) Use the reduction function
181
189
  # @option params [true, false] :group (false) Group the results using
@@ -236,6 +244,11 @@ module Couchbase
236
244
  body = MultiJson.dump(body) unless body.is_a?(String)
237
245
  options.update(:body => body, :method => params.delete(:method) || :post)
238
246
  end
247
+ include_docs = params.delete(:include_docs)
248
+ quiet = true
249
+ if params.has_key?(:quiet)
250
+ quiet = params.delete(:quiet)
251
+ end
239
252
  path = Utils.build_query(@endpoint, params)
240
253
  request = @bucket.make_http_request(path, options)
241
254
  res = []
@@ -260,6 +273,17 @@ module Couchbase
260
273
  raise Error::View.new(from, reason)
261
274
  end
262
275
  else
276
+ if include_docs
277
+ val, flags, cas = @bucket.get(obj['id'], :extended => true, :quiet => quiet)
278
+ obj['doc'] = {
279
+ 'value' => val,
280
+ 'meta' => {
281
+ 'id' => obj['id'],
282
+ 'flags' => flags,
283
+ 'cas' => cas
284
+ }
285
+ }
286
+ end
263
287
  if block_given?
264
288
  yield @wrapper_class.wrap(@bucket, obj)
265
289
  else
@@ -115,7 +115,7 @@ module Couchbase
115
115
  @value = data['value']
116
116
  if data['doc']
117
117
  @meta = data['doc']['meta']
118
- @doc = data['doc']['json']
118
+ @doc = data['doc']['value']
119
119
  end
120
120
  @id = data['id'] || @meta && @meta['id']
121
121
  @views = []
@@ -24,6 +24,16 @@ if MultiJson.respond_to?(:engine)
24
24
  else
25
25
  multi_json_engine = MultiJson.send(:adapter)
26
26
  end
27
+
28
+ # Patch for MultiJson versions < 1.3.3
29
+ require 'multi_json/version'
30
+ if Gem::Version.new(MultiJson::VERSION) < Gem::Version.new('1.3.3')
31
+ class << MultiJson
32
+ alias :dump :encode
33
+ alias :load :decode
34
+ end
35
+ end
36
+
27
37
  if multi_json_engine.name =~ /JsonGem$/
28
38
  class << multi_json_engine
29
39
  alias _load_object load
@@ -36,12 +46,3 @@ if multi_json_engine.name =~ /JsonGem$/
36
46
  end
37
47
  end
38
48
  end
39
-
40
- # Patch for MultiJson versions < 1.3.3
41
- if MultiJson.respond_to?(:decode) && MultiJson.respond_to?(:encode) &&
42
- !MultiJson.respond_to?(:load) && !MultiJson.respond_to?(:dump)
43
- class << MultiJson
44
- alias :dump :encode
45
- alias :load :decode
46
- end
47
- end
@@ -42,7 +42,8 @@ module Rack
42
42
  attr_reader :mutex, :pool
43
43
 
44
44
  DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge(
45
- :couchbase => {:default_format => :document, :key_prefix => 'rack:session:'})
45
+ :couchbase => {:quiet => true, :default_format => :document,
46
+ :key_prefix => 'rack:session:'})
46
47
 
47
48
  def initialize(app, options = {})
48
49
  # Support old :expires option
@@ -75,7 +76,7 @@ module Rack
75
76
 
76
77
  def set_session(env, session_id, new_session, options)
77
78
  with_lock(env, false) do
78
- @pool.set session_id, new_session, options
79
+ @pool.set(session_id, new_session, options)
79
80
  session_id
80
81
  end
81
82
  end
@@ -84,7 +84,7 @@ namespace :ports do
84
84
  directory "ports"
85
85
 
86
86
  task :libcouchbase => ["ports"] do
87
- recipe = MiniPortile.new "libcouchbase", "2.0.0beta2_1_gf60b9fe"
87
+ recipe = MiniPortile.new "libcouchbase", "2.0.0beta3"
88
88
  recipe.files << "http://packages.couchbase.com/clients/c/libcouchbase-#{recipe.version}.tar.gz"
89
89
  recipe.configure_options.push("--disable-debug",
90
90
  "--disable-dependency-tracking",
@@ -71,7 +71,6 @@ class TestTouch < MiniTest::Unit::TestCase
71
71
  end
72
72
  ret = connection.unlock(uniq_id(1) => info[uniq_id(1)][2],
73
73
  uniq_id(2) => info[uniq_id(2)][2])
74
- puts ret.inspect
75
74
  assert ret[uniq_id(1)]
76
75
  assert ret[uniq_id(2)]
77
76
  connection.set(uniq_id(1), "bar")
@@ -19,8 +19,40 @@ require File.join(File.dirname(__FILE__), 'setup')
19
19
 
20
20
  class TestUtils < MiniTest::Unit::TestCase
21
21
 
22
+ def setup
23
+ @mock = start_mock
24
+ end
25
+
26
+ def teardown
27
+ stop_mock(@mock)
28
+ end
29
+
22
30
  def test_complex_startkey
23
31
  assert_equal "all_docs?startkey=%5B%22Deadmau5%22%2C%22%22%5D", Couchbase::Utils.build_query("all_docs", :startkey => ["Deadmau5", ""])
24
32
  end
25
33
 
34
+ def test_it_provides_enough_info_with_value_error
35
+ class << MultiJson
36
+ alias dump_good dump
37
+ def dump(obj)
38
+ raise ArgumentError, "cannot accept your object"
39
+ end
40
+ end
41
+ connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port)
42
+ assert_raises(Couchbase::Error::ValueFormat) do
43
+ connection.set(uniq_id, "foo")
44
+ end
45
+ begin
46
+ connection.set(uniq_id, "foo")
47
+ rescue Couchbase::Error::ValueFormat => ex
48
+ assert_match /cannot accept your object/, ex.to_s
49
+ assert_instance_of ArgumentError, ex.inner_exception
50
+ end
51
+ ensure
52
+ class << MultiJson
53
+ undef dump
54
+ alias dump dump_good
55
+ end
56
+ end
57
+
26
58
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchbase
3
3
  version: !ruby/object:Gem::Version
4
- hash: 8279698299
4
+ hash: 4727249961
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 1
@@ -9,8 +9,8 @@ version: !ruby/object:Gem::Version
9
9
  - 0
10
10
  - z
11
11
  - beta
12
- - 3
13
- version: 1.2.0.z.beta3
12
+ - 4
13
+ version: 1.2.0.z.beta4
14
14
  platform: ruby
15
15
  authors:
16
16
  - Couchbase
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2012-10-16 00:00:00 +03:00
21
+ date: 2012-11-21 00:00:00 +03:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -213,6 +213,7 @@ files:
213
213
  - Gemfile
214
214
  - HISTORY.markdown
215
215
  - LICENSE
216
+ - Makefile
216
217
  - README.markdown
217
218
  - Rakefile
218
219
  - couchbase.gemspec
@@ -310,5 +311,25 @@ rubygems_version: 1.6.2
310
311
  signing_key:
311
312
  specification_version: 3
312
313
  summary: Couchbase ruby driver
313
- test_files: []
314
-
314
+ test_files:
315
+ - test/profile/.gitignore
316
+ - test/profile/Gemfile
317
+ - test/profile/benchmark.rb
318
+ - test/setup.rb
319
+ - test/test_arithmetic.rb
320
+ - test/test_async.rb
321
+ - test/test_bucket.rb
322
+ - test/test_cas.rb
323
+ - test/test_couchbase.rb
324
+ - test/test_couchbase_rails_cache_store.rb
325
+ - test/test_delete.rb
326
+ - test/test_errors.rb
327
+ - test/test_format.rb
328
+ - test/test_get.rb
329
+ - test/test_stats.rb
330
+ - test/test_store.rb
331
+ - test/test_timer.rb
332
+ - test/test_touch.rb
333
+ - test/test_unlock.rb
334
+ - test/test_utils.rb
335
+ - test/test_version.rb