ikai-jruby-memcache-client 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ nbproject/private
@@ -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 fredjean-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 'fredjean-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 =~ /fredjean-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.
@@ -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
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 5
3
+ :major: 1
4
+ :patch: 1
@@ -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.5.1"
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
@@ -0,0 +1,237 @@
1
+ require File.dirname(__FILE__) + '/java/java_memcached-release_2.0.1.jar'
2
+
3
+ class MemCache
4
+ include_class 'com.danga.MemCached.MemCachedClient'
5
+ include_class 'com.danga.MemCached.SockIOPool'
6
+
7
+ VERSION = '1.5.0'
8
+
9
+ ##
10
+ # Default options for the cache object.
11
+
12
+ DEFAULT_OPTIONS = {
13
+ :namespace => nil,
14
+ :readonly => false,
15
+ :multithread => true,
16
+ :pool_initial_size => 5,
17
+ :pool_min_size => 5,
18
+ :pool_max_size => 250,
19
+ :pool_max_idle => (1000 * 60 * 60 * 6),
20
+ :pool_maintenance_thread_sleep => 30,
21
+ :pool_use_nagle => false,
22
+ :pool_socket_timeout => 3000,
23
+ :pool_socket_connect_timeout => 3000,
24
+ :pool_name => 'default'
25
+ }
26
+
27
+ ## CHARSET for Marshalling
28
+ MARSHALLING_CHARSET = 'UTF-8'
29
+
30
+ ##
31
+ # Default memcached port.
32
+
33
+ DEFAULT_PORT = 11211
34
+
35
+ ##
36
+ # Default memcached server weight.
37
+
38
+ DEFAULT_WEIGHT = 1
39
+
40
+ attr_accessor :request_timeout
41
+
42
+ ##
43
+ # The namespace for this instance
44
+
45
+ attr_reader :namespace
46
+
47
+ ##
48
+ # The multithread setting for this instance
49
+
50
+ attr_reader :multithread
51
+
52
+ ##
53
+ # The configured socket pool name for this client.
54
+ attr_reader :pool_name
55
+
56
+ def initialize(*args)
57
+ @servers = []
58
+ opts = {}
59
+
60
+ case args.length
61
+ when 0 then # NOP
62
+ when 1 then
63
+ arg = args.shift
64
+ case arg
65
+ when Hash then opts = arg
66
+ when Array then @servers = arg
67
+ when String then @servers = [arg]
68
+ else raise ArgumentError, 'first argument must be Array, Hash or String'
69
+ end
70
+ when 2 then
71
+ @servers, opts = args
72
+ @servers = [@servers].flatten
73
+ else
74
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 2)"
75
+ end
76
+
77
+ opts = DEFAULT_OPTIONS.merge opts
78
+
79
+ @namespace = opts[:namespace] || opts["namespace"]
80
+ @pool_name = opts[:pool_name] || opts["pool_name"]
81
+
82
+ @client = MemCachedClient.new(@pool_name)
83
+
84
+ @client.primitiveAsString = true
85
+ @client.sanitizeKeys = false
86
+
87
+ weights = Array.new(@servers.size, DEFAULT_WEIGHT)
88
+
89
+ @pool = SockIOPool.getInstance(@pool_name)
90
+ unless @pool.initialized?
91
+ # // set the servers and the weights
92
+ @pool.servers = @servers.to_java(:string)
93
+ @pool.weights = weights.to_java(:Integer)
94
+
95
+ # // set some basic pool settings
96
+ # // 5 initial, 5 min, and 250 max conns
97
+ # // and set the max idle time for a conn
98
+ # // to 6 hours
99
+ @pool.initConn = opts[:pool_initial_size]
100
+ @pool.minConn = opts[:pool_min_size]
101
+ @pool.maxConn = opts[:pool_max_size]
102
+ @pool.maxIdle = opts[:pool_max_idle]
103
+
104
+ # // set the sleep for the maint thread
105
+ # // it will wake up every x seconds and
106
+ # // maintain the pool size
107
+ @pool.maintSleep = opts[:pool_maintenance_thread_sleep]
108
+ #
109
+ # // set some TCP settings
110
+ # // disable nagle
111
+ # // set the read timeout to 3 secs
112
+ # // and don't set a connect timeout
113
+ @pool.nagle = opts[:pool_use_nagle]
114
+ @pool.socketTO = opts[:pool_socket_timeout]
115
+ @pool.socketConnectTO = opts[:pool_socket_connect_timeout]
116
+ @pool.aliveCheck = true
117
+ @pool.initialize__method
118
+ end
119
+ end
120
+
121
+ def servers
122
+ @pool.get_servers.to_a rescue []
123
+ end
124
+
125
+ def alive?
126
+ @pool.servers.to_a.any?
127
+ end
128
+
129
+ def get(key, raw = false)
130
+ value = @client.get(make_cache_key(key))
131
+ return nil if value.nil?
132
+ unless raw
133
+ marshal_bytes = java.lang.String.new(value).getBytes(MARSHALLING_CHARSET)
134
+ value = Marshal.load(String.from_java_bytes(marshal_bytes))
135
+ end
136
+ value
137
+ end
138
+
139
+ alias :[] :get
140
+
141
+ def get_multi(keys, raw = false)
142
+ keys = keys.map {|k| make_cache_key(k)}
143
+ keys = keys.to_java :String
144
+ values = {}
145
+ values_j = @client.getMulti(keys)
146
+ values_j.to_a.each {|kv|
147
+ k,v = kv
148
+ next if v.nil?
149
+ unless raw
150
+ marshal_bytes = java.lang.String.new(v).getBytes(MARSHALLING_CHARSET)
151
+ v = Marshal.load(String.from_java_bytes(marshal_bytes))
152
+ end
153
+ values[k] = v
154
+ }
155
+ values
156
+ end
157
+
158
+ def set(key, value, expiry = 0, raw = false)
159
+ value = marshal_value(value) unless raw
160
+ key = make_cache_key(key)
161
+ if expiry == 0
162
+ @client.set key, value
163
+ else
164
+ @client.set key, value, expiration(expiry)
165
+ end
166
+ end
167
+
168
+ alias :[]= :set
169
+
170
+ def add(key, value, expiry = 0, raw = false)
171
+ value = marshal_value(value) unless raw
172
+ if expiry == 0
173
+ @client.add make_cache_key(key), value
174
+ else
175
+ @client.add make_cache_key(key), value, expiration(expiry)
176
+ end
177
+ end
178
+
179
+ def delete(key, expiry = 0)
180
+ @client.delete(make_cache_key(key))
181
+ end
182
+
183
+ def incr(key, amount = 1)
184
+ value = get(key) || 0
185
+ value += amount
186
+ set key, value
187
+ value
188
+ end
189
+
190
+ def decr(key, amount = 1)
191
+ value = get(key) || 0
192
+ value -= amount
193
+ set key, value
194
+ value
195
+ end
196
+
197
+ def flush_all
198
+ @client.flushAll
199
+ end
200
+
201
+ def stats
202
+ stats_hash = {}
203
+ @client.stats.each do |server, stats|
204
+ stats_hash[server] = Hash.new
205
+ stats.each do |key, value|
206
+ unless key == 'version'
207
+ value = value.to_f
208
+ value = value.to_i if value == value.ceil
209
+ end
210
+ stats_hash[server][key] = value
211
+ end
212
+ end
213
+ stats_hash
214
+ end
215
+
216
+ protected
217
+ def make_cache_key(key)
218
+ if namespace.nil? then
219
+ key
220
+ else
221
+ "#{@namespace}:#{key}"
222
+ end
223
+ end
224
+
225
+ def expiration(expiry)
226
+ java.util.Date.new((Time.now.to_i + expiry) * 1000)
227
+ end
228
+
229
+ def marshal_value(value)
230
+ marshal_bytes = Marshal.dump(value).to_java_bytes
231
+ java.lang.String.new(marshal_bytes, MARSHALLING_CHARSET)
232
+ end
233
+
234
+ class MemCacheError < RuntimeError; end
235
+
236
+ end
237
+
@@ -0,0 +1,208 @@
1
+ #require 'rubygems'
2
+ #require 'spec'
3
+
4
+ require File.dirname(__FILE__) + '/../lib/memcache'
5
+
6
+ describe MemCache do
7
+ before(:all) do
8
+ @server = "127.0.0.1:11211"
9
+ @client = MemCache.new @server
10
+ @client.flush_all
11
+ end
12
+
13
+ after(:each) do
14
+ @client.flush_all
15
+ end
16
+
17
+ it "should return nil for a non-existent key" do
18
+ @client.get('non-existent-key').should be_nil
19
+ end
20
+
21
+ describe "setting servers" do
22
+ it "should work if the instance is created with a single String argument" do
23
+ @client = MemCache.new @server
24
+ @client.servers.should == [@server]
25
+ end
26
+
27
+ it "should work if the instance is created with an Array" do
28
+ @client = MemCache.new [ @server ]
29
+ @client.servers.should == [ @server ]
30
+ end
31
+
32
+ it "should work if the instance is created with a Hash" do
33
+ @client = MemCache.new [ @server ], :namespace => 'test'
34
+ @client.servers.should == [ @server ]
35
+ end
36
+
37
+ it "should work with an explicit pool name" do
38
+ @client = MemCache.new([@server], :pool_name => 'new_pool')
39
+ @client.pool_name.should == 'new_pool'
40
+ end
41
+ end
42
+
43
+ describe "namespacing" do
44
+ before(:each) do
45
+ @ns = 'namespace'
46
+ @nsclient = MemCache.new [ @server ] , :namespace => @ns
47
+ @nsclient.flush_all
48
+ @nsclient.set "test", 333, 0
49
+ end
50
+
51
+ it "should set and get values transparently" do
52
+ @nsclient.get("test").to_i.should == 333
53
+ end
54
+
55
+ it "should set values to the given namespace" do
56
+ @client.get("#{@ns}:test").to_i.should == 333
57
+ end
58
+
59
+ it "should not set a value without the given namespace" do
60
+ @client.get("test").to_i.should_not == 333
61
+ end
62
+
63
+ it "should delete values in the given namespace" do
64
+ @nsclient.delete "test"
65
+ @nsclient.get("test").should be_nil
66
+ end
67
+
68
+ it "should increment in the given namespace" do
69
+ @nsclient.incr("test").to_i.should == 334
70
+ end
71
+
72
+ it "should decrement values in the given namespace" do
73
+ @nsclient.decr("test").should == 332
74
+ end
75
+ end
76
+
77
+ describe "after setting a value to MemCache" do
78
+ before(:each) do
79
+ @client.set 'key', 'value'
80
+ end
81
+
82
+ it "should be able to retrieve the value" do
83
+ @client.get('key').should == 'value'
84
+ end
85
+
86
+ it "should not be able to retrieve the value after deleting" do
87
+ @client.delete('key')
88
+ @client.get('key').should be_nil
89
+ end
90
+
91
+ it "should not be able to retrieve the value after flushing everything" do
92
+ @client.flush_all
93
+ @client.get("key").should be_nil
94
+ end
95
+
96
+ it "should work exactly the same if the []= operator were used" do
97
+ @client['key'] = 'val'
98
+ @client.get('key').should == 'val'
99
+ end
100
+ end
101
+
102
+ describe "using the Hash notation" do
103
+ before :each do
104
+ @client['key'] = 'value'
105
+ end
106
+
107
+ it "should be able to retrieve the value using []" do
108
+ @client['key'].should == 'value'
109
+ end
110
+
111
+ it "should be able to retrieve the value using get" do
112
+ @client.get('key').should == 'value'
113
+ end
114
+ end
115
+
116
+ describe "#stats" do
117
+ it "should return a hash" do
118
+ @client.stats.should be_instance_of(Hash)
119
+ end
120
+
121
+ # it "should return 0 for curr_items" do
122
+ # @client.stats[@server]['curr_items'].should == 0
123
+ # end
124
+
125
+ it "should return a float for rusage_system and rusage_user" do
126
+ @client.stats[@server]['rusage_system'].should be_instance_of(Float)
127
+ @client.stats[@server]['rusage_user'].should be_instance_of(Float)
128
+ end
129
+
130
+ it "should return a String for version" do
131
+ @client.stats[@server]['version'].should be_instance_of(String)
132
+ end
133
+
134
+ end
135
+
136
+ describe "#incr" do
137
+
138
+ it "should increment a value by 1 without a second parameter" do
139
+ @client.set 'incr', 100, 0
140
+ @client.incr 'incr'
141
+ @client.get('incr').to_i.should == 101
142
+ end
143
+
144
+ it "should increment a value by a given second parameter" do
145
+ @client.set 'incr', 100, 0
146
+ @client.incr 'incr', 20
147
+ @client.get('incr').to_i.should == 120
148
+ end
149
+ end
150
+
151
+ describe "#decr" do
152
+
153
+ it "should decrement a value by 1 without a second parameter" do
154
+ @client.set 'decr', 100, 0
155
+ @client.decr 'decr'
156
+ @client.get('decr').to_i.should == 99
157
+ end
158
+
159
+ it "should decrement a value by a given second parameter" do
160
+ @client.set 'decr', 100, 0
161
+ @client.decr 'decr', 20
162
+ @client.get('decr').to_i.should == 80
163
+ end
164
+ end
165
+
166
+ describe "with Ruby Objects" do
167
+ it "should be able to transparently set and get equivalent Ruby objects" do
168
+ obj = { :test => :hi }
169
+ @client.set('obj', obj)
170
+ @client.get('obj').should == obj
171
+ end
172
+ end
173
+
174
+ describe "using set with an expiration" do
175
+ it "should make a value unretrievable if the expiry is set to a negative value" do
176
+ @client.set('key', 'val', -1)
177
+ @client.get('key').should be_nil
178
+ end
179
+
180
+ it "should make a value retrievable for only the amount of time if a value is given" do
181
+ @client.set('key', 'val', 2)
182
+ @client.get('key').should == 'val'
183
+ sleep(3)
184
+ @client.get('key').should be_nil
185
+ end
186
+ end
187
+
188
+ describe "#get_multi" do
189
+ it "should get 2 keys" do
190
+ @client.set('key', 'val')
191
+ @client.set('key2', 'val2')
192
+ @client.get_multi(%w/key key2/).should == {'key' => 'val', 'key2' => 'val2'}
193
+ end
194
+
195
+ it "should ignore nil values" do
196
+ @client.set('key', 'val')
197
+ @client.set('key2', 'val2')
198
+ @client.get_multi(%w/key key2 key3/).should == {'key' => 'val', 'key2' => 'val2'}
199
+ end
200
+
201
+ it "should not marshall if requested" do
202
+ @client.set('key', 'val', 0, true)
203
+ @client.set('key2', 'val2', 0, true)
204
+ @client.get_multi(%w/key key2/, true).should == {'key' => 'val', 'key2' => 'val2'}
205
+ end
206
+ end
207
+ end
208
+
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ikai-jruby-memcache-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.5.1
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 -07: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
+ post_install_message:
41
+ rdoc_options:
42
+ - --charset=UTF-8
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ requirements: []
58
+
59
+ rubyforge_project:
60
+ rubygems_version: 1.3.5
61
+ signing_key:
62
+ specification_version: 2
63
+ summary: A drop in replacement for Ruby's memcache-client.
64
+ test_files:
65
+ - spec/jruby_memcache_spec.rb