memcached 0.5 → 0.6

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.
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,2 +1,4 @@
1
1
 
2
+ v0.6. Better documentation; benchmark suite; improve buffered IO API; remove namespace accessor in favor of generic options hash; patch up extconf.rb to handle unusual library situations; increase test coverage.
3
+
2
4
  v0.5. First release.
data/Manifest CHANGED
@@ -1,6 +1,5 @@
1
1
  CHANGELOG
2
2
  ext/extconf.rb
3
- ext/libmemcached.h
4
3
  ext/libmemcached.i
5
4
  ext/libmemcached_wrap.c
6
5
  lib/memcached/behaviors.rb
@@ -11,9 +10,12 @@ lib/memcached.rb
11
10
  LICENSE
12
11
  Manifest
13
12
  README
14
- test/benchmark/benchmark_test.rb
13
+ test/benchmark/benchmark.rb
14
+ test/benchmark/benchmark_set_get.rb
15
+ test/benchmark/profile.rb
15
16
  test/setup.rb
16
17
  test/teardown.rb
17
18
  test/test_helper.rb
18
19
  test/unit/binding_test.rb
19
20
  test/unit/memcached_test.rb
21
+ TODO
data/README CHANGED
@@ -7,14 +7,10 @@ An interface to the libmemcached C client.
7
7
 
8
8
  Copyright 2008 Cloudburst, LLC. Licensed under the AFL 3. See the included LICENSE file. Portions copyright 2008 TangentOrg, Brian Aker, licensed under the BSD license, and used with permission.
9
9
 
10
- The public certificate for the gem is here[http://rubyforge.org/frs/download.php/25331/evan_weaver-original-public_cert.pem].
10
+ The public certificate for this gem is here[http://rubyforge.org/frs/download.php/25331/evan_weaver-original-public_cert.pem].
11
11
 
12
12
  If you like this software, please {make a donation}[http://blog.evanweaver.com/donate/], or {recommend Evan}[http://www.workingwithrails.com/person/7739-evan-weaver] at Working with Rails.
13
13
 
14
- == Status
15
-
16
- Very new. Risky in production.
17
-
18
14
  == Features
19
15
 
20
16
  * clean API
@@ -22,13 +18,13 @@ Very new. Risky in production.
22
18
  * multiple hashing modes, including consistent hashing
23
19
  * ludicrous speed, including optional non-blocking IO
24
20
 
25
- == Requirements
21
+ The <b>memcached</b> library wraps the pure-C libmemcached client via SWIG. Both libraries are very new; use caution.
26
22
 
27
- * {libmemcached 0.13}[http://tangent.org/552/libmemcached.html]
23
+ == Installation
28
24
 
29
- Other versions of libmemcached are not supported.
25
+ You need {libmemcached 0.13}[http://tangent.org/552/libmemcached.html]. Other versions of libmemcached are not supported. You also need {memcached itself}[http://www.danga.com/memcached/] if you want to test against a local server.
30
26
 
31
- Extract the tarball, then for Linux, run:
27
+ Download and extract the {libmemcached tarball}[http://download.tangent.org/libmemcached-0.13.tar.gz]. Then for Linux, run:
32
28
  ./configure
33
29
  make && sudo make install
34
30
 
@@ -36,9 +32,96 @@ For OS X/MacPorts, run:
36
32
  ./configure --prefix=/opt/local
37
33
  make && sudo make install
38
34
 
35
+ Now install the gem:
36
+ sudo gem install memcached --no-rdoc --no-ri
37
+
39
38
  == Usage
40
39
 
41
- Whatever!
40
+ Start a local memcached server:
41
+ $ memcached -p 11211 &
42
+
43
+ Now, in Ruby, require the library and instantiate a Memcached object at a global level:
44
+
45
+ require 'memcached'
46
+ $cache = Memcached.new("127.0.0.1:11211")
47
+
48
+ Now you can set things and get things:
49
+
50
+ value = 'hello'
51
+ $cache.set 'test', value
52
+ $cache.get 'test' #=> "hello"
53
+
54
+ You can set with an expiration timeout:
55
+
56
+ value = 'hello'
57
+ $cache.set 'test', value, 1
58
+ sleep(2)
59
+ $cache.get 'test' #=> raises Memcached::NotFound
60
+
61
+ You can get multiple values at once:
62
+
63
+ value = 'hello'
64
+ $cache.set 'test', value
65
+ $cache.get ['test', 'test2'] #=> ["hello", Memcached::NotFound]
66
+
67
+ You can set a counter and increment it:
68
+
69
+ start = 1
70
+ $cache.set 'counter', start, 0, false
71
+ $cache.increment 'counter' #=> 2
72
+ $cache.increment 'counter' #=> 3
73
+ $cache.get('counter', false).to_i #=> 3
74
+
75
+ You can get some server stats:
76
+
77
+ $cache.stats #=> {..., :bytes_written=>[62], :version=>["1.2.4"] ...}
78
+
79
+ Note that the API is not the same as that of <b>Ruby-MemCache</b> or <b>memcache-client</b>. In particular, <tt>nil</tt> is a valid record value. Memcached#get does not return <tt>nil</tt> on failure, rather it raises <b>Memcached::NotFound</b>. This is consistent with the behavior of memcached itself. For example:
80
+
81
+ $cache.set 'test', nil
82
+ $cache.get 'test' #=> nil
83
+ $cache.delete 'test'
84
+ $cache.get 'test' #=> raises Memcached::NotFound
85
+
86
+ A compatibility wrapper for legacy applications is in progress.
87
+
88
+ == Threading
89
+
90
+ <b>memcached</b> is threadsafe, but each thread requires its own Memcached instance. Create a global Memcached, and then call Memcached#clone each time you spawn a thread.
91
+
92
+ thread = Thread.new do
93
+ cache = $cache.clone
94
+ # Perform operations on cache, not $cache
95
+ cache.set 'example', 1
96
+ cache.get 'example'
97
+ # ...
98
+ end
99
+
100
+ # Join the thread so that exceptions don't get lost
101
+ thread.join
102
+
103
+ == Benchmarks
104
+
105
+ <b>memcached</b> is much, much faster than <b>memcache-client</b>:
106
+
107
+ user system total real
108
+ set:ruby:noblock:memcached 0.050000 0.000000 0.050000 ( 0.054205)
109
+ set:ruby:memcached 0.130000 0.160000 0.290000 ( 0.338529)
110
+ set:ruby:memcache-client 3.690000 0.130000 3.820000 ( 4.030806)
111
+ ...
112
+ get:ruby:memcached 0.110000 0.020000 0.130000 ( 0.316446)
113
+ get:ruby:memcache-client 3.730000 0.120000 3.850000 ( 4.040446)
114
+ ...
115
+ missing:ruby:memcached 0.160000 0.090000 0.250000 ( 0.401891)
116
+ missing:ruby:memcache-client 3.650000 0.090000 3.740000 ( 3.880192)
117
+ ...
118
+ mixed:ruby:noblock:memcached 0.190000 0.230000 0.420000 ( 0.667130)
119
+ mixed:ruby:memcached 0.250000 0.250000 0.500000 ( 0.663093)
120
+ mixed:ruby:memcache-client 7.410000 0.210000 7.620000 ( 7.942145)
121
+
122
+ These benchmarks were run on x86-64 Linux. You can easily run your own benchmarks, as long as you have memcached itself on your system:
123
+ $ ruby -e 'system("ruby #{File.dirname(`gem which memcached`.split("\n").
124
+ last)}/../test/benchmark/benchmark.rb")'
42
125
 
43
126
  == Reporting problems
44
127
 
@@ -48,4 +131,5 @@ Patches and contributions are very welcome. Please note that contributors are re
48
131
 
49
132
  == Further resources
50
133
 
51
- Whatever!
134
+ * {Memcached wiki}[http://www.socialtext.net/memcached/index.cgi]
135
+ * {Libmemcached homepage}[http://tangent.org/552/libmemcached.html]
data/TODO ADDED
@@ -0,0 +1,11 @@
1
+
2
+ Can happen any time:
3
+
4
+ * real multiget
5
+ * look for memory leaks
6
+
7
+ Waiting on libmemcached 0.14:
8
+
9
+ * verify version
10
+ * CAS support
11
+ * passing missing increment/decrement tests
data/ext/extconf.rb CHANGED
@@ -12,5 +12,13 @@ if ENV['DEBUG']
12
12
  end
13
13
 
14
14
  dir_config 'libmemcached'
15
- find_library 'memcached', 'memcached_server_add'
15
+
16
+ # XXX There's probably a better way to do this
17
+ unless find_library 'memcached', 'memcached_server_add', *ENV['LD_LIBRARY_PATH'].to_s.split(":")
18
+ raise "shared library 'libmemcached' not found"
19
+ end
20
+ unless find_header 'libmemcached/memcached.h', *ENV['INCLUDE_PATH'].to_s.split(":")
21
+ raise "header file 'libmemcached/memcached.h' not found"
22
+ end
23
+
16
24
  create_makefile 'libmemcached'
data/ext/libmemcached.i CHANGED
@@ -55,7 +55,7 @@
55
55
  free($1);
56
56
  };
57
57
 
58
- %include "libmemcached.h"
58
+ %include "/opt/local/include/libmemcached/memcached.h"
59
59
 
60
60
  // Manual wrappers
61
61
 
@@ -94,3 +94,14 @@ void memcached_repair_server_st(memcached_st *in_ptr, memcached_server_st *host)
94
94
  host->write_ptr= 0;
95
95
  };
96
96
  %}
97
+
98
+ // Stub some bogus methods left in the 0.13 memcached.h header
99
+ %{
100
+ memcached_return memcached_mdelete(memcached_st *ptr, char **key, size_t *key_length, unsigned int number_of_keys, time_t expiration) {
101
+ return;
102
+ };
103
+ memcached_return memcached_mdelete_by_key(memcached_st *ptr, char *master_key, size_t master_key_length,
104
+ char **key, size_t *key_length, unsigned int number_of_keys, time_t expiration) {
105
+ return;
106
+ };
107
+ %}
@@ -1940,6 +1940,15 @@ void memcached_repair_server_st(memcached_st *in_ptr, memcached_server_st *host)
1940
1940
  host->write_ptr= 0;
1941
1941
  };
1942
1942
 
1943
+
1944
+ memcached_return memcached_mdelete(memcached_st *ptr, char **key, size_t *key_length, unsigned int number_of_keys, time_t expiration) {
1945
+ return;
1946
+ };
1947
+ memcached_return memcached_mdelete_by_key(memcached_st *ptr, char *master_key, size_t master_key_length,
1948
+ char **key, size_t *key_length, unsigned int number_of_keys, time_t expiration) {
1949
+ return;
1950
+ };
1951
+
1943
1952
  swig_class cMemcachedServerSt;
1944
1953
 
1945
1954
  SWIGINTERN VALUE
@@ -8222,6 +8231,135 @@ fail:
8222
8231
  }
8223
8232
 
8224
8233
 
8234
+ SWIGINTERN VALUE
8235
+ _wrap_memcached_mdelete(int argc, VALUE *argv, VALUE self) {
8236
+ memcached_st *arg1 = (memcached_st *) 0 ;
8237
+ char **arg2 = (char **) 0 ;
8238
+ size_t *arg3 = (size_t *) 0 ;
8239
+ unsigned int arg4 ;
8240
+ time_t arg5 ;
8241
+ memcached_return result;
8242
+ void *argp1 = 0 ;
8243
+ int res1 = 0 ;
8244
+ void *argp2 = 0 ;
8245
+ int res2 = 0 ;
8246
+ void *argp3 = 0 ;
8247
+ int res3 = 0 ;
8248
+ unsigned int val4 ;
8249
+ int ecode4 = 0 ;
8250
+ VALUE vresult = Qnil;
8251
+
8252
+ if ((argc < 5) || (argc > 5)) {
8253
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 5)",argc); SWIG_fail;
8254
+ }
8255
+ res1 = SWIG_ConvertPtr(argv[0], &argp1,SWIGTYPE_p_memcached_st, 0 | 0 );
8256
+ if (!SWIG_IsOK(res1)) {
8257
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "memcached_mdelete" "', argument " "1"" of type '" "memcached_st *""'");
8258
+ }
8259
+ arg1 = (memcached_st *)(argp1);
8260
+ res2 = SWIG_ConvertPtr(argv[1], &argp2,SWIGTYPE_p_p_char, 0 | 0 );
8261
+ if (!SWIG_IsOK(res2)) {
8262
+ SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "memcached_mdelete" "', argument " "2"" of type '" "char **""'");
8263
+ }
8264
+ arg2 = (char **)(argp2);
8265
+ res3 = SWIG_ConvertPtr(argv[2], &argp3,SWIGTYPE_p_size_t, 0 | 0 );
8266
+ if (!SWIG_IsOK(res3)) {
8267
+ SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "memcached_mdelete" "', argument " "3"" of type '" "size_t *""'");
8268
+ }
8269
+ arg3 = (size_t *)(argp3);
8270
+ ecode4 = SWIG_AsVal_unsigned_SS_int(argv[3], &val4);
8271
+ if (!SWIG_IsOK(ecode4)) {
8272
+ SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "memcached_mdelete" "', argument " "4"" of type '" "unsigned int""'");
8273
+ }
8274
+ arg4 = (unsigned int)(val4);
8275
+ {
8276
+ if (NIL_P(argv[4]))
8277
+ arg5 = (time_t)-1;
8278
+ else
8279
+ arg5 = NUM2LONG(rb_funcall(argv[4], rb_intern("tv_sec"), 0));
8280
+ }
8281
+ result = (memcached_return)memcached_mdelete(arg1,arg2,arg3,arg4,arg5);
8282
+ vresult = SWIG_From_int((int)(result));
8283
+ return vresult;
8284
+ fail:
8285
+ return Qnil;
8286
+ }
8287
+
8288
+
8289
+ SWIGINTERN VALUE
8290
+ _wrap_memcached_mdelete_by_key(int argc, VALUE *argv, VALUE self) {
8291
+ memcached_st *arg1 = (memcached_st *) 0 ;
8292
+ char *arg2 = (char *) 0 ;
8293
+ size_t arg3 ;
8294
+ char **arg4 = (char **) 0 ;
8295
+ size_t *arg5 = (size_t *) 0 ;
8296
+ unsigned int arg6 ;
8297
+ time_t arg7 ;
8298
+ memcached_return result;
8299
+ void *argp1 = 0 ;
8300
+ int res1 = 0 ;
8301
+ int res2 ;
8302
+ char *buf2 = 0 ;
8303
+ int alloc2 = 0 ;
8304
+ size_t val3 ;
8305
+ int ecode3 = 0 ;
8306
+ void *argp4 = 0 ;
8307
+ int res4 = 0 ;
8308
+ void *argp5 = 0 ;
8309
+ int res5 = 0 ;
8310
+ unsigned int val6 ;
8311
+ int ecode6 = 0 ;
8312
+ VALUE vresult = Qnil;
8313
+
8314
+ if ((argc < 7) || (argc > 7)) {
8315
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 7)",argc); SWIG_fail;
8316
+ }
8317
+ res1 = SWIG_ConvertPtr(argv[0], &argp1,SWIGTYPE_p_memcached_st, 0 | 0 );
8318
+ if (!SWIG_IsOK(res1)) {
8319
+ SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "memcached_mdelete_by_key" "', argument " "1"" of type '" "memcached_st *""'");
8320
+ }
8321
+ arg1 = (memcached_st *)(argp1);
8322
+ res2 = SWIG_AsCharPtrAndSize(argv[1], &buf2, NULL, &alloc2);
8323
+ if (!SWIG_IsOK(res2)) {
8324
+ SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "memcached_mdelete_by_key" "', argument " "2"" of type '" "char *""'");
8325
+ }
8326
+ arg2 = buf2;
8327
+ ecode3 = SWIG_AsVal_size_t(argv[2], &val3);
8328
+ if (!SWIG_IsOK(ecode3)) {
8329
+ SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "memcached_mdelete_by_key" "', argument " "3"" of type '" "size_t""'");
8330
+ }
8331
+ arg3 = (size_t)(val3);
8332
+ res4 = SWIG_ConvertPtr(argv[3], &argp4,SWIGTYPE_p_p_char, 0 | 0 );
8333
+ if (!SWIG_IsOK(res4)) {
8334
+ SWIG_exception_fail(SWIG_ArgError(res4), "in method '" "memcached_mdelete_by_key" "', argument " "4"" of type '" "char **""'");
8335
+ }
8336
+ arg4 = (char **)(argp4);
8337
+ res5 = SWIG_ConvertPtr(argv[4], &argp5,SWIGTYPE_p_size_t, 0 | 0 );
8338
+ if (!SWIG_IsOK(res5)) {
8339
+ SWIG_exception_fail(SWIG_ArgError(res5), "in method '" "memcached_mdelete_by_key" "', argument " "5"" of type '" "size_t *""'");
8340
+ }
8341
+ arg5 = (size_t *)(argp5);
8342
+ ecode6 = SWIG_AsVal_unsigned_SS_int(argv[5], &val6);
8343
+ if (!SWIG_IsOK(ecode6)) {
8344
+ SWIG_exception_fail(SWIG_ArgError(ecode6), "in method '" "memcached_mdelete_by_key" "', argument " "6"" of type '" "unsigned int""'");
8345
+ }
8346
+ arg6 = (unsigned int)(val6);
8347
+ {
8348
+ if (NIL_P(argv[6]))
8349
+ arg7 = (time_t)-1;
8350
+ else
8351
+ arg7 = NUM2LONG(rb_funcall(argv[6], rb_intern("tv_sec"), 0));
8352
+ }
8353
+ result = (memcached_return)memcached_mdelete_by_key(arg1,arg2,arg3,arg4,arg5,arg6,arg7);
8354
+ vresult = SWIG_From_int((int)(result));
8355
+ if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
8356
+ return vresult;
8357
+ fail:
8358
+ if (alloc2 == SWIG_NEWOBJ) free((char*)buf2);
8359
+ return Qnil;
8360
+ }
8361
+
8362
+
8225
8363
  SWIGINTERN VALUE
8226
8364
  _wrap_memcached_fetch_execute(int argc, VALUE *argv, VALUE self) {
8227
8365
  memcached_st *arg1 = (memcached_st *) 0 ;
@@ -9146,6 +9284,8 @@ SWIGEXPORT void Init_libmemcached(void) {
9146
9284
  rb_define_module_function(mLibmemcached, "memcached_append_by_key", _wrap_memcached_append_by_key, -1);
9147
9285
  rb_define_module_function(mLibmemcached, "memcached_cas_by_key", _wrap_memcached_cas_by_key, -1);
9148
9286
  rb_define_module_function(mLibmemcached, "memcached_delete_by_key", _wrap_memcached_delete_by_key, -1);
9287
+ rb_define_module_function(mLibmemcached, "memcached_mdelete", _wrap_memcached_mdelete, -1);
9288
+ rb_define_module_function(mLibmemcached, "memcached_mdelete_by_key", _wrap_memcached_mdelete_by_key, -1);
9149
9289
  rb_define_module_function(mLibmemcached, "memcached_fetch_execute", _wrap_memcached_fetch_execute, -1);
9150
9290
  rb_define_module_function(mLibmemcached, "memcached_result_free", _wrap_memcached_result_free, -1);
9151
9291
  rb_define_module_function(mLibmemcached, "memcached_result_create", _wrap_memcached_result_create, -1);
data/lib/memcached.rb CHANGED
@@ -4,3 +4,20 @@ require 'memcached/integer'
4
4
  require 'memcached/exceptions'
5
5
  require 'memcached/behaviors'
6
6
  require 'memcached/memcached'
7
+
8
+ =begin rdoc
9
+ The generated SWIG module for accessing libmemcached's C API.
10
+
11
+ Includes the full set of libmemcached static methods (as defined in <tt>$INCLUDE_PATH/libmemcached/memcached.h</tt>), and classes for the available structs:
12
+
13
+ * Libmemcached::MemcachedResultSt
14
+ * Libmemcached::MemcachedServerSt
15
+ * Libmemcached::MemcachedSt
16
+ * Libmemcached::MemcachedStatSt
17
+ * Libmemcached::MemcachedStringSt
18
+
19
+ A number of SWIG typemaps and C helper methods are also defined in <tt>ext/libmemcached.i</tt>.
20
+
21
+ =end
22
+ module Libmemcached
23
+ end
@@ -1,6 +1,8 @@
1
1
 
2
2
  class Memcached
3
3
 
4
+ #:stopdoc:
5
+
4
6
  def self.load_constants(prefix, hash = {}, offset = 0)
5
7
  Libmemcached.constants.grep(/^#{prefix}/).each do |const_name|
6
8
  hash[const_name[prefix.length..-1].downcase.to_sym] = Libmemcached.const_get(const_name) + offset
@@ -21,9 +23,12 @@ class Memcached
21
23
  DISTRIBUTION_VALUES = {}
22
24
  BEHAVIOR_VALUES.merge!(load_constants("MEMCACHED_DISTRIBUTION_", DISTRIBUTION_VALUES, 2))
23
25
 
26
+ #:startdoc:
27
+
24
28
  private
25
29
 
26
- def set_behavior(behavior, value)
30
+ # Set a behavior option for this Memcached instance. Accepts a Symbol <tt>behavior</tt> and either <tt>true</tt>, <tt>false</tt>, or a Symbol for <tt>value</tt>. Arguments are validated and converted into integers for the struct setter method.
31
+ def set_behavior(behavior, value) #:doc:
27
32
  raise ArgumentError, "No setting #{behavior.inspect}" unless b_id = BEHAVIORS[behavior]
28
33
  raise ArgumentError, "No setting value #{value.inspect}" unless v_id = BEHAVIOR_VALUES[value]
29
34
 
@@ -1,12 +1,55 @@
1
1
 
2
2
  class Memcached
3
3
 
4
+ =begin rdoc
5
+
6
+ Superclass for all Memcached runtime exceptions.
7
+
8
+ Subclasses correspond one-to-one with server response strings or libmemcached errors. For example, raising <b>Memcached::NotFound</b> means that the server returned <tt>"NOT_FOUND\r\n"</tt>.
9
+
10
+ == Subclasses
11
+
12
+ * Memcached::AKeyLengthOfZeroWasProvided
13
+ * Memcached::ATimeoutOccurred
14
+ * Memcached::ActionNotSupported
15
+ * Memcached::ActionQueued
16
+ * Memcached::ClientError
17
+ * Memcached::ConnectionBindFailure
18
+ * Memcached::ConnectionDataDoesNotExist
19
+ * Memcached::ConnectionDataExists
20
+ * Memcached::ConnectionFailure
21
+ * Memcached::ConnectionSocketCreateFailure
22
+ * Memcached::CouldNotOpenUnixSocket
23
+ * Memcached::Failure
24
+ * Memcached::FetchWasNotCompleted
25
+ * Memcached::HostnameLookupFailure
26
+ * Memcached::MemoryAllocationFailure
27
+ * Memcached::NoServersDefined
28
+ * Memcached::NotFound
29
+ * Memcached::NotStored
30
+ * Memcached::PartialRead
31
+ * Memcached::ProtocolError
32
+ * Memcached::ReadFailure
33
+ * Memcached::ServerDelete
34
+ * Memcached::ServerEnd
35
+ * Memcached::ServerError
36
+ * Memcached::ServerValue
37
+ * Memcached::SomeErrorsWereReported
38
+ * Memcached::StatValue
39
+ * Memcached::SystemError
40
+ * Memcached::UnknownReadFailure
41
+ * Memcached::WriteFailure
42
+
43
+ =end
4
44
  class Error < RuntimeError
5
45
  end
6
46
 
7
- class NotImplemented < StandardError
47
+ # Raised if a method depends on functionality not yet completed in libmemcached.
48
+ class NotImplemented < NoMethodError
8
49
  end
9
50
 
51
+ #:stopdoc:
52
+
10
53
  class << self
11
54
  private
12
55
  def camelize(string)
@@ -14,17 +57,19 @@ class Memcached
14
57
  end
15
58
  end
16
59
 
17
- @@exceptions = []
18
- @@empty_struct = Libmemcached::MemcachedSt.new
19
- Libmemcached.memcached_create(@@empty_struct)
60
+ EXCEPTIONS = []
61
+ EMPTY_STRUCT = Libmemcached::MemcachedSt.new
62
+ Libmemcached.memcached_create(EMPTY_STRUCT)
20
63
 
21
64
  # Generate exception classes
22
- Libmemcached::MEMCACHED_MAXIMUM_RETURN.times do |exception_index|
23
- description = Libmemcached.memcached_strerror(@@empty_struct, exception_index)
65
+ Libmemcached::MEMCACHED_MAXIMUM_RETURN.times do |index|
66
+ description = Libmemcached.memcached_strerror(EMPTY_STRUCT, index)
24
67
  exception_class = eval("class #{camelize(description)} < Error; self; end")
25
- @@exceptions << exception_class
68
+ EXCEPTIONS << exception_class
26
69
  end
27
70
 
28
71
  # Verify library version
29
- # XXX Impossible with current libmemcached
72
+ # XXX Waiting on libmemcached 0.14
73
+
74
+ #:startdoc:
30
75
  end