jruby-memcache-client 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ nbproject/private
data/MIT-LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2008 Abhi Yerra <abhi@traytwo.com>
2
+ Copyright (c) 2009 Ikai Lan <ikai.lan@gmail.com>
3
+ Copyright (c) 2009 Tiago Bastos <comechao@gmail.com>
4
+ Copyright (c) 2009 Frederic Jean <frederic.jean@sun.com>
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining
7
+ a copy of this software and associated documentation files (the
8
+ "Software"), to deal in the Software without restriction, including
9
+ without limitation the rights to use, copy, modify, merge, publish,
10
+ distribute, sublicense, and/or sell copies of the Software, and to
11
+ permit persons to whom the Software is furnished to do so, subject to
12
+ the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+
data/README ADDED
@@ -0,0 +1,69 @@
1
+ This projects provides memcached based stores for JRuby. It is a gem based on Ikai Lan's jruby-memcache-client project hosted at http://github.com/ikai/jruby-memcache-client/tree
2
+
3
+ This project is a JRuby wrapper of the Java MemCache library by Greg Whalin
4
+
5
+ http://www.whalin.com/memcached/
6
+
7
+ In production, the standard Ruby MemCache client can cause a thread to hang. In the Glassfish application server, by default there are 5 Grizzly connectors that handle incoming requests. A site that uses MemCache heavily can quickly cause all Grizzly connectors to block and take down a site. I'm hoping that this work I am doing here will help others adopt JRuby as a production platform for their Ruby on Rails applications.
8
+
9
+ The Ruby MemCache library was never written with threaded applications in mind. All threads use the same socket, and multithreaded mode basically wraps the IO with a Mutex. The Java library provides several features that are not available in the Ruby MemCache library:
10
+
11
+ - connection pooling
12
+ - socket timeouts. In forks of the Ruby MemCache library this is achieved either with a Mongrel timeout or use of the Ruby Timeout class, which, at least at the writing of this README, will work unpredictably when being used as a failsafe against hanging IO.
13
+
14
+ As of right now this code only provides a very minimal amount of functionality, but it is enough to use with the Rails cache and cache_fu.
15
+
16
+ Installation
17
+ ------------
18
+ This is a ruby gem that can be installed.
19
+
20
+ gem sources -a http://gems.github.com
21
+ gem install ikai-jruby-memcache-client --remote
22
+
23
+ Replacing Rail's MemCache Client
24
+ --------------------------------
25
+
26
+ Rails ships with a bundled copy of the MemCache client. This client will prevent you from using this gem instead. Adding the following code into your environment.rb file:
27
+
28
+ if RUBY_PLATFORM =~ /java/i
29
+ # Based on instructions from http://www.mikeperham.com/2009/03/03/using-memcache-client-16x-in-rails-23/
30
+ # Brain surgery to use our own version of memcache-client without
31
+ # having to modify activesupport directly.
32
+ # Unload any previous instance of the class
33
+ if Object.const_defined? :MemCache
34
+ Object.instance_eval { remove_const :MemCache }
35
+ end
36
+ # Pull in the exact version we want
37
+ gem 'ikai-jruby-memcache-client', '1.5.0'
38
+
39
+ # Ensure that the memcache-client path is at the front of the loadpath
40
+ $LOAD_PATH.each do |path|
41
+ if path =~ /ikai-jruby-memcache-client/
42
+ $LOAD_PATH.delete(path)
43
+ $LOAD_PATH.unshift(path)
44
+ end
45
+ end
46
+ # If Ruby thinks it's already loaded memcache.rb, force
47
+ # a reload otherwise just require.
48
+ if $".find { |file| file =~ /\Amemcache.rb\Z/ }
49
+ load 'memcache.rb'
50
+ else
51
+ require 'memcache'
52
+ end
53
+ end
54
+
55
+ This will remove the original MemCache client and load our version of the MemCache class instead.
56
+
57
+ Configuration
58
+ -------------
59
+ The JRuby MemCache client uses the same configuration options as the regular MemCache client. Here is how to build the configuration in your environment.rb file:
60
+
61
+ memcache_options = {
62
+ :namespace => 'fortaleza:production_live:',
63
+ }
64
+ memcached_servers = [ ENV['MEMCACHED_LOCATION'] || '0.0.0.0:11211']
65
+
66
+ # Constant used by libs
67
+ CACHE = MemCache.new memcached_servers, memcache_options if RUBY_PLATFORM =~ /java/
68
+
69
+ Note that this may vary based on your particular configuration method and environment.
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "jruby-memcache-client"
5
+ gemspec.summary = "A drop in replacement for Ruby's memcache-client."
6
+ gemspec.email = "abhi@traytwo.com"
7
+ gemspec.homepage = "http://github.com/abhiyerra/jruby-memcache-client"
8
+ gemspec.description = "A drop in replacement for Ruby's memcache-client."
9
+ gemspec.authors = ["Abhi Yerra", "Ikai Lan", "Frederic Jean", "Lennon Day-Reynolds"]
10
+ end
11
+ rescue LoadError
12
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
13
+ end
14
+
15
+ if RUBY_PLATFORM =~ /java/i
16
+ begin
17
+ require 'spec/rake/spectask'
18
+
19
+ task :default => :spec
20
+
21
+ desc "Run the specs for the jruby-memcache-client gem"
22
+ Spec::Rake::SpecTask.new
23
+ rescue LoadError
24
+ puts "You must have rspec installed in order to run the tests."
25
+ end
26
+ else
27
+ puts "You must run rake under JRuby."
28
+ end
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 6
3
+ :major: 1
4
+ :patch: 0
@@ -0,0 +1,45 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{jruby-memcache-client}
5
+ s.version = "1.6.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Abhi Yerra", "Ikai Lan", "Frederic Jean", "Lennon Day-Reynolds"]
9
+ s.date = %q{2009-05-20}
10
+ s.description = %q{A drop in replacement for Ruby's memcache-client.}
11
+ s.email = %q{abhi@traytwo.com}
12
+ s.extra_rdoc_files = [
13
+ "README"
14
+ ]
15
+ s.files = [
16
+ ".gitignore",
17
+ "MIT-LICENSE",
18
+ "README",
19
+ "Rakefile",
20
+ "VERSION.yml",
21
+ "jruby-memcache-client.gemspec",
22
+ "lib/java/java_memcached-release_2.0.1.jar",
23
+ "lib/memcache.rb",
24
+ "spec/jruby_memcache_spec.rb"
25
+ ]
26
+ s.has_rdoc = true
27
+ s.homepage = %q{http://github.com/ikai/jruby-memcache-client}
28
+ s.rdoc_options = ["--charset=UTF-8"]
29
+ s.require_paths = ["lib"]
30
+ s.rubygems_version = %q{1.3.1}
31
+ s.summary = %q{A drop in replacement for Ruby's memcache-client.}
32
+ s.test_files = [
33
+ "spec/jruby_memcache_spec.rb"
34
+ ]
35
+
36
+ if s.respond_to? :specification_version then
37
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
38
+ s.specification_version = 2
39
+
40
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
41
+ else
42
+ end
43
+ else
44
+ end
45
+ end
data/lib/memcache.rb ADDED
@@ -0,0 +1,306 @@
1
+ require 'java'
2
+
3
+ require File.dirname(__FILE__) + '/java/java_memcached-release_2.0.1.jar'
4
+
5
+ class MemCache
6
+ include_class 'com.danga.MemCached.MemCachedClient'
7
+ include_class 'com.danga.MemCached.SockIOPool'
8
+
9
+ VERSION = '1.6.0'
10
+
11
+ ##
12
+ # Default options for the cache object.
13
+
14
+ DEFAULT_OPTIONS = {
15
+ :namespace => nil,
16
+ :readonly => false,
17
+ :multithread => true,
18
+ :pool_initial_size => 5,
19
+ :pool_min_size => 5,
20
+ :pool_max_size => 250,
21
+ :pool_max_idle => (1000 * 60 * 60 * 6),
22
+ :pool_maintenance_thread_sleep => 30,
23
+ :pool_use_nagle => false,
24
+ :pool_socket_timeout => 3000,
25
+ :pool_socket_connect_timeout => 3000,
26
+ :pool_name => 'default'
27
+ }
28
+
29
+ ## CHARSET for Marshalling
30
+ MARSHALLING_CHARSET = 'UTF-8'
31
+
32
+ ##
33
+ # Default memcached port.
34
+
35
+ DEFAULT_PORT = 11211
36
+
37
+ ##
38
+ # Default memcached server weight.
39
+
40
+ DEFAULT_WEIGHT = 1
41
+
42
+ attr_accessor :request_timeout
43
+
44
+ ##
45
+ # The namespace for this instance
46
+
47
+ attr_reader :namespace
48
+
49
+ ##
50
+ # The multithread setting for this instance
51
+
52
+ attr_reader :multithread
53
+
54
+ ##
55
+ # The configured socket pool name for this client.
56
+ attr_reader :pool_name
57
+
58
+ ##
59
+ # Configures the client
60
+ def initialize(*args)
61
+ @servers = []
62
+ opts = {}
63
+
64
+ case args.length
65
+ when 0 then # NOP
66
+ when 1 then
67
+ arg = args.shift
68
+ case arg
69
+ when Hash then opts = arg
70
+ when Array then @servers = arg
71
+ when String then @servers = [arg]
72
+ else raise ArgumentError, 'first argument must be Array, Hash or String'
73
+ end
74
+ when 2 then
75
+ @servers, opts = args
76
+ @servers = [@servers].flatten
77
+ else
78
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 2)"
79
+ end
80
+
81
+ opts = DEFAULT_OPTIONS.merge opts
82
+
83
+ @namespace = opts[:namespace] || opts["namespace"]
84
+ @pool_name = opts[:pool_name] || opts["pool_name"]
85
+ @readonly = opts[:readonly] || opts["readonly"]
86
+
87
+ @client = MemCachedClient.new(@pool_name)
88
+
89
+ @client.primitiveAsString = true
90
+ @client.sanitizeKeys = false
91
+
92
+ weights = Array.new(@servers.size, DEFAULT_WEIGHT)
93
+
94
+ @pool = SockIOPool.getInstance(@pool_name)
95
+ unless @pool.initialized?
96
+ # // set the servers and the weights
97
+ @pool.servers = @servers.to_java(:string)
98
+ @pool.weights = weights.to_java(:Integer)
99
+
100
+ # // set some basic pool settings
101
+ # // 5 initial, 5 min, and 250 max conns
102
+ # // and set the max idle time for a conn
103
+ # // to 6 hours
104
+ @pool.initConn = opts[:pool_initial_size]
105
+ @pool.minConn = opts[:pool_min_size]
106
+ @pool.maxConn = opts[:pool_max_size]
107
+ @pool.maxIdle = opts[:pool_max_idle]
108
+
109
+ # // set the sleep for the maint thread
110
+ # // it will wake up every x seconds and
111
+ # // maintain the pool size
112
+ @pool.maintSleep = opts[:pool_maintenance_thread_sleep]
113
+ #
114
+ # // set some TCP settings
115
+ # // disable nagle
116
+ # // set the read timeout to 3 secs
117
+ # // and don't set a connect timeout
118
+ @pool.nagle = opts[:pool_use_nagle]
119
+ @pool.socketTO = opts[:pool_socket_timeout]
120
+ @pool.socketConnectTO = opts[:pool_socket_connect_timeout]
121
+ @pool.aliveCheck = true
122
+ @pool.initialize__method
123
+ end
124
+ end
125
+
126
+ def reset
127
+ @pool.shut_down
128
+ @pool.initialize__method
129
+ end
130
+
131
+ ##
132
+ # Returns the servers that the client has been configured to
133
+ # use. Injects an alive? method into the string so it works with the
134
+ # updated Rails MemCacheStore session store class.
135
+ def servers
136
+ @pool.servers.to_a.collect do |s|
137
+ s.instance_eval(<<-EOIE)
138
+ def alive?
139
+ #{!!stats[s]}
140
+ end
141
+ EOIE
142
+ s
143
+ end rescue []
144
+ end
145
+
146
+ ##
147
+ # Determines whether any of the connections to the servers is
148
+ # alive. We are alive if it is the case.
149
+ def alive?
150
+ servers.to_a.any? { |s| s.alive? }
151
+ end
152
+
153
+ alias :active? :alive?
154
+
155
+ ##
156
+ # Retrieves a value associated with the key from the
157
+ # cache. Retrieves the raw value if the raw parameter is set.
158
+ def get(key, raw = false)
159
+ value = @client.get(make_cache_key(key))
160
+ return nil if value.nil?
161
+ unless raw
162
+ marshal_bytes = java.lang.String.new(value).getBytes(MARSHALLING_CHARSET)
163
+ value = Marshal.load(String.from_java_bytes(marshal_bytes))
164
+ end
165
+ value
166
+ end
167
+
168
+ alias :[] :get
169
+
170
+ ##
171
+ # Retrieves the values associated with the keys parameter.
172
+ def get_multi(keys, raw = false)
173
+ keys = keys.map {|k| make_cache_key(k)}
174
+ keys = keys.to_java :String
175
+ values = {}
176
+ values_j = @client.getMulti(keys)
177
+ values_j.to_a.each {|kv|
178
+ k,v = kv
179
+ next if v.nil?
180
+ unless raw
181
+ marshal_bytes = java.lang.String.new(v).getBytes(MARSHALLING_CHARSET)
182
+ v = Marshal.load(String.from_java_bytes(marshal_bytes))
183
+ end
184
+ values[k] = v
185
+ }
186
+ values
187
+ end
188
+
189
+ ##
190
+ # Associates a value with a key in the cache. MemCached will expire
191
+ # the value if an expiration is provided. The raw parameter allows
192
+ # us to store a value without marshalling it first.
193
+ def set(key, value, expiry = 0, raw = false)
194
+ raise MemCacheError, "Update of readonly cache" if @readonly
195
+ value = marshal_value(value) unless raw
196
+ key = make_cache_key(key)
197
+ if expiry == 0
198
+ @client.set key, value
199
+ else
200
+ @client.set key, value, expiration(expiry)
201
+ end
202
+ end
203
+
204
+ alias :[]= :set
205
+
206
+ ##
207
+ # Add a new value to the cache following the same conventions that
208
+ # are used in the set method.
209
+ def add(key, value, expiry = 0, raw = false)
210
+ raise MemCacheError, "Update of readonly cache" if @readonly
211
+ value = marshal_value(value) unless raw
212
+ if expiry == 0
213
+ @client.add make_cache_key(key), value
214
+ else
215
+ @client.add make_cache_key(key), value, expiration(expiry)
216
+ end
217
+ end
218
+
219
+ ##
220
+ # Removes the value associated with the key from the cache. This
221
+ # will ignore values that are not already present in the cache,
222
+ # which makes this safe to use without first checking for the
223
+ # existance of the key in the cache first.
224
+ def delete(key, expires = 0)
225
+ raise MemCacheError, "Update of readonly cache" if @readonly
226
+ @client.delete(make_cache_key(key))
227
+ end
228
+
229
+ ##
230
+ # Replaces the value associated with a key in the cache if it
231
+ # already is stored. It will not add the value to the cache if it
232
+ # isn't already present.
233
+ def replace(key, value, expiry = 0, raw = false)
234
+ raise MemCacheError, "Update of readonly cache" if @readonly
235
+ value = marshal_value(value) unless raw
236
+ if expiry == 0
237
+ @client.replace make_cache_key(key), value
238
+ else
239
+ @client.replace make_cache_key(key), value
240
+ end
241
+ end
242
+
243
+ ##
244
+ # Increments the value associated with the key by a certain amount.
245
+ def incr(key, amount = 1)
246
+ raise MemCacheError, "Update of readonly cache" if @readonly
247
+ value = get(key) || 0
248
+ value += amount
249
+ set key, value
250
+ value
251
+ end
252
+
253
+ ##
254
+ # Decrements the value associated with the key by a certain amount.
255
+ def decr(key, amount = 1)
256
+ raise MemCacheError, "Update of readonly cache" if @readonly
257
+ value = get(key) || 0
258
+ value -= amount
259
+ set key, value
260
+ value
261
+ end
262
+
263
+ ##
264
+ # Clears the cache.
265
+ def flush_all
266
+ @client.flush_all
267
+ end
268
+
269
+ ##
270
+ # Reports statistics on the cache.
271
+ def stats
272
+ stats_hash = {}
273
+ @client.stats.each do |server, stats|
274
+ stats_hash[server] = Hash.new
275
+ stats.each do |key, value|
276
+ unless key == 'version'
277
+ value = value.to_f
278
+ value = value.to_i if value == value.ceil
279
+ end
280
+ stats_hash[server][key] = value
281
+ end
282
+ end
283
+ stats_hash
284
+ end
285
+
286
+ class MemCacheError < RuntimeError; end
287
+
288
+ protected
289
+ def make_cache_key(key)
290
+ if namespace.nil? then
291
+ key
292
+ else
293
+ "#{@namespace}:#{key}"
294
+ end
295
+ end
296
+
297
+ def expiration(expiry)
298
+ java.util.Date.new((Time.now.to_i + expiry) * 1000)
299
+ end
300
+
301
+ def marshal_value(value)
302
+ marshal_bytes = Marshal.dump(value).to_java_bytes
303
+ java.lang.String.new(marshal_bytes, MARSHALLING_CHARSET)
304
+ end
305
+ end
306
+
@@ -0,0 +1,243 @@
1
+ require 'java'
2
+ require File.dirname(__FILE__) + '/../lib/memcache'
3
+
4
+ describe MemCache do
5
+ before(:all) do
6
+ @server = "127.0.0.1:11211"
7
+ @client = MemCache.new @server
8
+ @client.flush_all
9
+ end
10
+
11
+ after(:each) do
12
+ @client.flush_all
13
+ end
14
+
15
+ it "should return nil for a non-existent key" do
16
+ @client.get('non-existent-key').should be_nil
17
+ end
18
+
19
+ describe "setting servers" do
20
+ it "should work if the instance is created with a single String argument" do
21
+ @client = MemCache.new @server
22
+ @client.servers.should == [@server]
23
+ end
24
+
25
+ it "should work if the instance is created with an Array" do
26
+ @client = MemCache.new [ @server ]
27
+ @client.servers.should == [ @server ]
28
+ end
29
+
30
+ it "should work if the instance is created with a Hash" do
31
+ @client = MemCache.new [ @server ], :namespace => 'test'
32
+ @client.servers.should == [ @server ]
33
+ end
34
+
35
+ it "should work with an explicit pool name" do
36
+ @client = MemCache.new([@server], :pool_name => 'new_pool')
37
+ @client.pool_name.should == 'new_pool'
38
+ end
39
+ end
40
+
41
+ describe "namespacing" do
42
+ before(:each) do
43
+ @ns = 'namespace'
44
+ @nsclient = MemCache.new [ @server ] , :namespace => @ns
45
+ @nsclient.flush_all
46
+ @nsclient.set "test", 333, 0
47
+ end
48
+
49
+ it "should set and get values transparently" do
50
+ @nsclient.get("test").to_i.should == 333
51
+ end
52
+
53
+ it "should set values to the given namespace" do
54
+ @client.get("#{@ns}:test").to_i.should == 333
55
+ end
56
+
57
+ it "should not set a value without the given namespace" do
58
+ @client.get("test").to_i.should_not == 333
59
+ end
60
+
61
+ it "should delete values in the given namespace" do
62
+ @nsclient.delete "test"
63
+ @nsclient.get("test").should be_nil
64
+ end
65
+
66
+ it "should increment in the given namespace" do
67
+ @nsclient.incr("test").to_i.should == 334
68
+ end
69
+
70
+ it "should decrement values in the given namespace" do
71
+ @nsclient.decr("test").should == 332
72
+ end
73
+ end
74
+
75
+ describe "after setting a value to MemCache" do
76
+ before(:each) do
77
+ @client.set 'key', 'value'
78
+ end
79
+
80
+ it "should be able to retrieve the value" do
81
+ @client.get('key').should == 'value'
82
+ end
83
+
84
+ it "should not be able to retrieve the value after deleting" do
85
+ @client.delete('key')
86
+ @client.get('key').should be_nil
87
+ end
88
+
89
+ it "should not be able to retrieve the value after flushing everything" do
90
+ @client.flush_all
91
+ @client.get("key").should be_nil
92
+ end
93
+
94
+ it "should work exactly the same if the []= operator were used" do
95
+ @client['key'] = 'val'
96
+ @client.get('key').should == 'val'
97
+ end
98
+ end
99
+
100
+ describe "replacing values from the cache." do
101
+ before :each do
102
+ @client['key'] = 'value'
103
+ end
104
+
105
+ it "should be able to replace the stored value." do
106
+ @client.replace('key', 'new value').should be_true
107
+ @client['key'].should == 'new value'
108
+ end
109
+
110
+ it "should not replace values that are not in the cache." do
111
+ @client.replace('notthere', 'value').should be_false
112
+ end
113
+ end
114
+
115
+ describe "using the Hash notation" do
116
+ before :each do
117
+ @client['key'] = 'value'
118
+ end
119
+
120
+ it "should be able to retrieve the value using []" do
121
+ @client['key'].should == 'value'
122
+ end
123
+
124
+ it "should be able to retrieve the value using get" do
125
+ @client.get('key').should == 'value'
126
+ end
127
+ end
128
+
129
+ describe "#stats" do
130
+ it "should return a hash" do
131
+ @client.stats.should be_instance_of(Hash)
132
+ end
133
+
134
+ # it "should return 0 for curr_items" do
135
+ # @client.stats[@server]['curr_items'].should == 0
136
+ # end
137
+
138
+ it "should return a float for rusage_system and rusage_user" do
139
+ @client.stats[@server]['rusage_system'].should be_instance_of(Float)
140
+ @client.stats[@server]['rusage_user'].should be_instance_of(Float)
141
+ end
142
+
143
+ it "should return a String for version" do
144
+ @client.stats[@server]['version'].should be_instance_of(String)
145
+ end
146
+
147
+ end
148
+
149
+ describe "#incr" do
150
+
151
+ it "should increment a value by 1 without a second parameter" do
152
+ @client.set 'incr', 100, 0
153
+ @client.incr 'incr'
154
+ @client.get('incr').to_i.should == 101
155
+ end
156
+
157
+ it "should increment a value by a given second parameter" do
158
+ @client.set 'incr', 100, 0
159
+ @client.incr 'incr', 20
160
+ @client.get('incr').to_i.should == 120
161
+ end
162
+ end
163
+
164
+ describe "#decr" do
165
+
166
+ it "should decrement a value by 1 without a second parameter" do
167
+ @client.set 'decr', 100, 0
168
+ @client.decr 'decr'
169
+ @client.get('decr').to_i.should == 99
170
+ end
171
+
172
+ it "should decrement a value by a given second parameter" do
173
+ @client.set 'decr', 100, 0
174
+ @client.decr 'decr', 20
175
+ @client.get('decr').to_i.should == 80
176
+ end
177
+ end
178
+
179
+ describe "with Ruby Objects" do
180
+ it "should be able to transparently set and get equivalent Ruby objects" do
181
+ obj = { :test => :hi }
182
+ @client.set('obj', obj)
183
+ @client.get('obj').should == obj
184
+ end
185
+ end
186
+
187
+ describe "using set with an expiration" do
188
+ it "should make a value unretrievable if the expiry is set to a negative value" do
189
+ @client.set('key', 'val', -1)
190
+ @client.get('key').should be_nil
191
+ end
192
+
193
+ it "should make a value retrievable for only the amount of time if a value is given" do
194
+ @client.set('key', 'val', 2)
195
+ @client.get('key').should == 'val'
196
+ sleep(3)
197
+ @client.get('key').should be_nil
198
+ end
199
+ end
200
+
201
+ describe "#get_multi" do
202
+ it "should get 2 keys" do
203
+ @client.set('key', 'val')
204
+ @client.set('key2', 'val2')
205
+ @client.get_multi(%w/key key2/).should == {'key' => 'val', 'key2' => 'val2'}
206
+ end
207
+
208
+ it "should ignore nil values" do
209
+ @client.set('key', 'val')
210
+ @client.set('key2', 'val2')
211
+ @client.get_multi(%w/key key2 key3/).should == {'key' => 'val', 'key2' => 'val2'}
212
+ end
213
+
214
+ it "should not marshall if requested" do
215
+ @client.set('key', 'val', 0, true)
216
+ @client.set('key2', 'val2', 0, true)
217
+ @client.get_multi(%w/key key2/, true).should == {'key' => 'val', 'key2' => 'val2'}
218
+ end
219
+ end
220
+
221
+ describe "aliveness of the MemCache server." do
222
+ before :each do
223
+ @servers = ["localhost:11211", "localhost:11212", {:pool_name => "test"}]
224
+ @client = MemCache.new @servers
225
+ @client.flush_all
226
+ end
227
+
228
+ it "should report the client as being alive." do
229
+ @client.should be_alive
230
+ end
231
+
232
+ it "should report localhost:11211 as being alive." do
233
+ servers = @client.servers
234
+ servers.first.should be_alive
235
+ end
236
+
237
+ it "should report localhost:11212 as not being alive." do
238
+ servers = @client.servers
239
+ servers.find {|s| s.to_s == "localhost:11212"}.should be_nil
240
+ end
241
+ end
242
+ end
243
+
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jruby-memcache-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.6.0
5
+ platform: ruby
6
+ authors:
7
+ - Abhi Yerra
8
+ - Ikai Lan
9
+ - Frederic Jean
10
+ - Lennon Day-Reynolds
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+
15
+ date: 2009-05-20 00:00:00 -06:00
16
+ default_executable:
17
+ dependencies: []
18
+
19
+ description: A drop in replacement for Ruby's memcache-client.
20
+ email: abhi@traytwo.com
21
+ executables: []
22
+
23
+ extensions: []
24
+
25
+ extra_rdoc_files:
26
+ - README
27
+ files:
28
+ - .gitignore
29
+ - MIT-LICENSE
30
+ - README
31
+ - Rakefile
32
+ - VERSION.yml
33
+ - jruby-memcache-client.gemspec
34
+ - lib/java/java_memcached-release_2.0.1.jar
35
+ - lib/memcache.rb
36
+ - spec/jruby_memcache_spec.rb
37
+ has_rdoc: true
38
+ homepage: http://github.com/ikai/jruby-memcache-client
39
+ licenses: []
40
+
41
+ post_install_message:
42
+ rdoc_options:
43
+ - --charset=UTF-8
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.3.4
62
+ signing_key:
63
+ specification_version: 2
64
+ summary: A drop in replacement for Ruby's memcache-client.
65
+ test_files:
66
+ - spec/jruby_memcache_spec.rb