memcached 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
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