jruby-memcached 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ Gemfile.lock
1
2
  *.gem
2
3
  *.rbc
3
4
  .bundle
@@ -23,3 +24,8 @@ target/surefire
23
24
  target/dependency-reduced-pom.xml
24
25
  target/original-spymemcached-ext-0.0.1.jar
25
26
  target/original-xmemcached-ext-0.0.1.jar
27
+
28
+ .idea/
29
+ out/
30
+ spymemcached-ext.iml
31
+ src/main/Main.iml
@@ -1,3 +1,17 @@
1
+ ## 0.5.0 (Aug 22, 2012)
2
+
3
+ Bugfixes:
4
+
5
+ - fix Memcached increment/decrement, which works with MarshalTranscoder
6
+ now
7
+
8
+ Features:
9
+
10
+ - update spymemcached to 2.8.3, which set shouldOptimize as false by
11
+ default
12
+ - add Memcached::ATimeoutOccurred exception
13
+ - accept exception_retry_limit option
14
+
1
15
  ## 0.4.1 (Aug 17, 2012)
2
16
 
3
17
  Bugfixes:
data/README.md CHANGED
@@ -35,6 +35,17 @@ You can get multiple values at once:
35
35
  $cache.get ['test', 'test2', 'missing']
36
36
  #=> {"test" => "hello", "test2" => "hello"}
37
37
 
38
+ You can set a counter and increment it. Note that you must initialize it
39
+ with an integer, encoded as an unmarshalled ASCII string:
40
+
41
+ $cache.increment 'counter' #=> 1
42
+ $cache.increment 'counter' #=> 2
43
+ $cache.get('counter').to_i #=> 2
44
+
45
+ You can get some server stats:
46
+
47
+ $cache.stats #=> {..., :bytes_written=>[62], :version=>["1.2.4"] ...}
48
+
38
49
  ## Rails
39
50
 
40
51
  # config/environment.rb
@@ -1,3 +1,3 @@
1
1
  class Memcached
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
data/pom.xml CHANGED
@@ -1,66 +1,81 @@
1
1
  <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3
- <modelVersion>4.0.0</modelVersion>
2
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3
+ <modelVersion>4.0.0</modelVersion>
4
4
 
5
- <groupId>net.spy</groupId>
6
- <artifactId>spymemcached-ext</artifactId>
7
- <version>0.0.1</version>
8
- <packaging>jar</packaging>
5
+ <groupId>net.spy</groupId>
6
+ <artifactId>spymemcached-ext</artifactId>
7
+ <version>0.0.1</version>
8
+ <packaging>jar</packaging>
9
9
 
10
- <name>spymemcached-ext</name>
11
- <url>http://maven.apache.org</url>
10
+ <name>spymemcached-ext</name>
11
+ <url>http://maven.apache.org</url>
12
12
 
13
- <properties>
14
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15
- </properties>
13
+ <properties>
14
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
15
+ </properties>
16
16
 
17
- <repositories>
18
- <repository>
19
- <id>spymemcached</id>
20
- <name>spymemcached extention</name>
21
- <layout>default</layout>
22
- <url>http://files.couchbase.com/maven2/</url>
23
- <snapshots>
24
- <enabled>false</enabled>
25
- </snapshots>
26
- </repository>
27
- </repositories>
17
+ <repositories>
18
+ <repository>
19
+ <id>spymemcached</id>
20
+ <name>spymemcached extention</name>
21
+ <layout>default</layout>
22
+ <url>http://files.couchbase.com/maven2/</url>
23
+ <snapshots>
24
+ <enabled>false</enabled>
25
+ </snapshots>
26
+ </repository>
27
+ </repositories>
28
28
 
29
- <dependencies>
30
- <dependency>
31
- <groupId>org.jruby</groupId>
32
- <artifactId>jruby</artifactId>
33
- <version>1.6.7.2</version>
34
- </dependency>
35
- <dependency>
36
- <groupId>spy</groupId>
37
- <artifactId>spymemcached</artifactId>
38
- <version>2.8.3</version>
39
- </dependency>
40
- </dependencies>
29
+ <dependencies>
30
+ <dependency>
31
+ <groupId>junit</groupId>
32
+ <artifactId>junit</artifactId>
33
+ <version>4.10</version>
34
+ <scope>test</scope>
35
+ </dependency>
36
+ <dependency>
37
+ <groupId>org.jruby</groupId>
38
+ <artifactId>jruby</artifactId>
39
+ <version>1.6.7.2</version>
40
+ </dependency>
41
+ <dependency>
42
+ <groupId>spy</groupId>
43
+ <artifactId>spymemcached</artifactId>
44
+ <version>2.8.3</version>
45
+ </dependency>
46
+ </dependencies>
41
47
 
42
- <build>
43
- <plugins>
44
- <plugin>
45
- <groupId>org.apache.maven.plugins</groupId>
46
- <artifactId>maven-shade-plugin</artifactId>
47
- <version>1.6</version>
48
- <executions>
49
- <execution>
50
- <phase>package</phase>
51
- <goals>
52
- <goal>shade</goal>
53
- </goals>
54
- <configuration>
55
- <artifactSet>
56
- <excludes>
57
- <exclude>org.jruby:jruby</exclude>
58
- </excludes>
59
- </artifactSet>
60
- </configuration>
61
- </execution>
62
- </executions>
63
- </plugin>
64
- </plugins>
65
- </build>
48
+ <build>
49
+ <plugins>
50
+ <plugin>
51
+ <groupId>org.apache.maven.plugins</groupId>
52
+ <artifactId>maven-surefire-plugin</artifactId>
53
+ <version>2.12.2</version>
54
+ <configuration>
55
+ <parallel>methods</parallel>
56
+ <threadCount>10</threadCount>
57
+ </configuration>
58
+ </plugin>
59
+ <plugin>
60
+ <groupId>org.apache.maven.plugins</groupId>
61
+ <artifactId>maven-shade-plugin</artifactId>
62
+ <version>1.6</version>
63
+ <executions>
64
+ <execution>
65
+ <phase>package</phase>
66
+ <goals>
67
+ <goal>shade</goal>
68
+ </goals>
69
+ <configuration>
70
+ <artifactSet>
71
+ <excludes>
72
+ <exclude>org.jruby:jruby</exclude>
73
+ </excludes>
74
+ </artifactSet>
75
+ </configuration>
76
+ </execution>
77
+ </executions>
78
+ </plugin>
79
+ </plugins>
80
+ </build>
66
81
  </project>
@@ -19,11 +19,15 @@ describe Memcached do
19
19
  end
20
20
 
21
21
  it "should raise error with unsupported option hash" do
22
- lambda { Memcached.new("127.0.0.1:11211", :hash => :unknown) }.should raise_error(Memcached::NotSupport)
22
+ expect { Memcached.new("127.0.0.1:11211", :hash => :unknown) }.to raise_error(Memcached::NotSupport)
23
23
  end
24
24
 
25
25
  it "should raise error with unsupported option distribution" do
26
- lambda { Memcached.new("127.0.0.1:11211", :distribution => :unknown) }.should raise_error(Memcached::NotSupport)
26
+ expect { Memcached.new("127.0.0.1:11211", :distribution => :unknown) }.to raise_error(Memcached::NotSupport)
27
+ end
28
+
29
+ it "should ignore nil value" do
30
+ expect { Memcached.new("127.0.0.1:11211", :prefix => nil) }.not_to raise_error
27
31
  end
28
32
  end
29
33
 
@@ -47,7 +51,7 @@ describe Memcached do
47
51
 
48
52
  it "should get missing" do
49
53
  @memcached.delete "key" rescue nil
50
- lambda { @memcached.get "key" }.should raise_error(Memcached::NotFound)
54
+ expect { @memcached.get "key" }.to raise_error(Memcached::NotFound)
51
55
  end
52
56
 
53
57
  context "multiget" do
@@ -74,7 +78,7 @@ describe Memcached do
74
78
  @memcached.set "key", "value", 1
75
79
  @memcached.get("key").should == "value"
76
80
  sleep 1
77
- lambda { @memcached.get("key") }.should raise_error(Memcached::NotFound)
81
+ expect { @memcached.get("key") }.to raise_error(Memcached::NotFound)
78
82
  end
79
83
  end
80
84
 
@@ -87,7 +91,7 @@ describe Memcached do
87
91
 
88
92
  it "should not add existing key" do
89
93
  @memcached.set "key", "value"
90
- lambda { @memcached.add "key", "value" }.should raise_error(Memcached::NotStored)
94
+ expect { @memcached.add "key", "value" }.to raise_error(Memcached::NotStored)
91
95
  end
92
96
 
93
97
  it "should add expiry" do
@@ -95,7 +99,7 @@ describe Memcached do
95
99
  @memcached.add "key", "value", 1
96
100
  @memcached.get "key"
97
101
  sleep 1
98
- lambda { @memcached.get "key" }.should raise_error(Memcached::NotFound)
102
+ expect { @memcached.get "key" }.to raise_error(Memcached::NotFound)
99
103
  end
100
104
  end
101
105
 
@@ -108,8 +112,8 @@ describe Memcached do
108
112
 
109
113
  it "should not replace with new key" do
110
114
  @memcached.delete "key" rescue nil
111
- lambda { @memcached.replace "key", "value" }.should raise_error(Memcached::NotStored)
112
- lambda { @memcached.get "key" }.should raise_error(Memcached::NotFound)
115
+ expect { @memcached.replace "key", "value" }.to raise_error(Memcached::NotStored)
116
+ expect { @memcached.get "key" }.to raise_error(Memcached::NotFound)
113
117
  end
114
118
  end
115
119
 
@@ -117,12 +121,12 @@ describe Memcached do
117
121
  it "should delete with existing key" do
118
122
  @memcached.set "key", "value"
119
123
  @memcached.delete "key"
120
- lambda { @memcached.get "key" }.should raise_error(Memcached::NotFound)
124
+ expect { @memcached.get "key" }.to raise_error(Memcached::NotFound)
121
125
  end
122
126
 
123
127
  it "should not delete with new key" do
124
128
  @memcached.delete "key" rescue nil
125
- lambda { @memcached.delete "key" }.should raise_error(Memcached::NotFound)
129
+ expect { @memcached.delete "key" }.to raise_error(Memcached::NotFound)
126
130
  end
127
131
  end
128
132
 
@@ -176,8 +180,8 @@ describe Memcached do
176
180
  @memcached.set "key1", "value2"
177
181
  @memcached.set "key2", "value2"
178
182
  @memcached.flush
179
- lambda { @memcached.get "key1" }.should raise_error(Memcached::NotFound)
180
- lambda { @memcached.get "key2" }.should raise_error(Memcached::NotFound)
183
+ expect { @memcached.get "key1" }.to raise_error(Memcached::NotFound)
184
+ expect { @memcached.get "key2" }.to raise_error(Memcached::NotFound)
181
185
  end
182
186
  end
183
187
 
@@ -209,7 +213,7 @@ describe Memcached do
209
213
  it "should delete with prefix_key" do
210
214
  @prefix_memcached.set "key", "value"
211
215
  @prefix_memcached.delete "key"
212
- lambda { @memcached.get("jrubykey") }.should raise_error(Memcached::NotFound)
216
+ expect { @memcached.get("jrubykey") }.to raise_error(Memcached::NotFound)
213
217
  end
214
218
 
215
219
  it "should multiget with prefix_key" do
@@ -227,48 +231,5 @@ describe Memcached do
227
231
  end
228
232
  end
229
233
  end
230
-
231
- context "timeout" do
232
- before(:all) do
233
- @memcached = Memcached.new("127.0.0.1:11211")
234
- @timeout_memcached = Memcached.new("127.0.0.1:11211", :timeout => 1, :exception_retry_limit => 0)
235
- end
236
- after(:all) do
237
- @timeout_memcached.quit
238
- @memcached.quit
239
- end
240
-
241
- it "should set timeout" do
242
- lambda { @timeout_memcached.set "key", "new_value" }.should raise_error(Memcached::ATimeoutOccurred)
243
- end
244
-
245
- it "should add timeout" do
246
- @memcached.delete "key" rescue nil
247
- lambda { @timeout_memcached.add "key", "new_value" }.should raise_error(Memcached::ATimeoutOccurred)
248
- end
249
-
250
- it "should replace timeout" do
251
- @memcached.set "key", "value"
252
- lambda { @timeout_memcached.replace "key", "new_value" }.should raise_error(Memcached::ATimeoutOccurred)
253
- end
254
-
255
- it "should delete timeout" do
256
- @memcached.set "key", "value"
257
- lambda { @timeout_memcached.delete "key" }.should raise_error(Memcached::ATimeoutOccurred)
258
- end
259
-
260
- it "should get timeout" do
261
- @memcached.set "key", "value"
262
- lambda { @timeout_memcached.get "key" }.should raise_error(Memcached::ATimeoutOccurred)
263
- end
264
-
265
- it "should increment timeout" do
266
- lambda { @timeout_memcached.increment "intkey" }.should raise_error(Memcached::ATimeoutOccurred)
267
- end
268
-
269
- it "should decrement timeout" do
270
- lambda { @timeout_memcached.decrement "intkey" }.should raise_error(Memcached::ATimeoutOccurred)
271
- end
272
- end
273
234
  end
274
235
  end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ # This is a stupid way to test timeout cases.
4
+ #
5
+ # Originally, I want to mock MemcachedClient methods to throw OperationTimeout, like
6
+ #
7
+ # MemcachedClient.any_instance.stubs(:get).raises(OperationTimeout)
8
+ # lambda { @timeout_memcached.get "key" }.should raise_error(Memcached::ATimeoutOccurred)
9
+ #
10
+ # But it doesn't work.
11
+ #
12
+ # The current solution is to call @timeout_memcahced.get in an infinite loop until a
13
+ # Memcached::ATimeoutOccurred raised. It works, but really slow down the tests, I hate it.
14
+ #
15
+ # If you have a better solution, please let me know flyerhzm at gmail dot com, thanks.
16
+ describe Memcached do
17
+ before(:all) do
18
+ @memcached = Memcached.new("127.0.0.1:11211")
19
+ @timeout_memcached = Memcached.new("127.0.0.1:11211", :timeout => 1, :exception_retry_limit => 0)
20
+ end
21
+
22
+ after(:all) do
23
+ @timeout_memcached.quit
24
+ @memcached.quit
25
+ end
26
+
27
+ it "should set timeout" do
28
+ lambda {
29
+ while true
30
+ @timeout_memcached.set "key", "new_value"
31
+ end
32
+ }.should raise_error(Memcached::ATimeoutOccurred)
33
+ end
34
+
35
+ it "should add timeout" do
36
+ lambda {
37
+ while true
38
+ @memcached.delete "key" rescue nil
39
+ @timeout_memcached.add "key", "new_value"
40
+ end
41
+ }.should raise_error(Memcached::ATimeoutOccurred)
42
+ end
43
+
44
+ it "should replace timeout" do
45
+ @memcached.set "key", "value"
46
+ lambda {
47
+ while true
48
+ @timeout_memcached.replace "key", "new_value"
49
+ end
50
+ }.should raise_error(Memcached::ATimeoutOccurred)
51
+ end
52
+
53
+ it "should delete timeout" do
54
+ lambda {
55
+ while true
56
+ @memcached.set "key", "value"
57
+ @timeout_memcached.delete "key"
58
+ end
59
+ }.should raise_error(Memcached::ATimeoutOccurred)
60
+ end
61
+
62
+ it "should get timeout" do
63
+ @memcached.set "key", "value"
64
+ lambda {
65
+ while true
66
+ @timeout_memcached.get "key"
67
+ end
68
+ }.should raise_error(Memcached::ATimeoutOccurred)
69
+ end
70
+
71
+ it "should increment timeout" do
72
+ lambda {
73
+ while true
74
+ @timeout_memcached.increment "intkey"
75
+ end
76
+ }.should raise_error(Memcached::ATimeoutOccurred)
77
+ end
78
+
79
+ it "should decrement timeout" do
80
+ lambda {
81
+ while true
82
+ @timeout_memcached.decrement "intkey"
83
+ end
84
+ }.should raise_error(Memcached::ATimeoutOccurred)
85
+ end
86
+ end
@@ -1,7 +1,6 @@
1
1
  package com.openfeint.memcached;
2
2
 
3
3
  import com.openfeint.memcached.error.Error;
4
- import com.openfeint.memcached.error.NotFound;
5
4
  import com.openfeint.memcached.transcoder.MarshalTranscoder;
6
5
  import com.openfeint.memcached.transcoder.MarshalZlibTranscoder;
7
6
  import net.spy.memcached.AddrUtil;
@@ -30,6 +29,7 @@ import java.net.InetSocketAddress;
30
29
  import java.net.SocketAddress;
31
30
  import java.util.ArrayList;
32
31
  import java.util.List;
32
+ import java.util.HashMap;
33
33
  import java.util.Map;
34
34
  import java.util.concurrent.ExecutionException;
35
35
 
@@ -59,11 +59,14 @@ public class Memcached extends RubyObject {
59
59
  @JRubyMethod(name = "initialize", optional = 2)
60
60
  public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
61
61
  Ruby ruby = context.getRuntime();
62
- RubyHash options;
62
+ Map<String, String> options = new HashMap<String, String>();
63
63
  if (args.length > 1) {
64
- options = args[1].convertToHash();
65
- } else {
66
- options = new RubyHash(ruby);
64
+ RubyHash arguments = args[1].convertToHash();
65
+ for (Object key : arguments.keySet()) {
66
+ if (arguments.get(key) != null) {
67
+ options.put(key.toString(), arguments.get(key).toString());
68
+ }
69
+ }
67
70
  }
68
71
  List<String> servers = new ArrayList<String>();
69
72
  if (args.length > 0) {
@@ -102,8 +105,8 @@ public class Memcached extends RubyObject {
102
105
  int retry = 0;
103
106
  while (true) {
104
107
  try {
105
- boolean result = (Boolean) client.add(key, expiry, value, transcoder).get();
106
- if (result == false) {
108
+ Boolean result = (Boolean) client.add(key, expiry, value, transcoder).get();
109
+ if (!result) {
107
110
  throw Error.newNotStored(ruby, "not stored");
108
111
  }
109
112
  return context.nil;
@@ -115,7 +118,6 @@ public class Memcached extends RubyObject {
115
118
  throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
116
119
  }
117
120
  retry++;
118
- continue;
119
121
  } else {
120
122
  throw ruby.newRuntimeError(e.getLocalizedMessage());
121
123
  }
@@ -126,7 +128,6 @@ public class Memcached extends RubyObject {
126
128
  throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
127
129
  }
128
130
  retry++;
129
- continue;
130
131
  } else {
131
132
  throw ruby.newRuntimeError(e.getLocalizedMessage());
132
133
  }
@@ -145,8 +146,8 @@ public class Memcached extends RubyObject {
145
146
  int retry = 0;
146
147
  while (true) {
147
148
  try {
148
- boolean result = (Boolean) client.replace(key, expiry, value, transcoder).get();
149
- if (result == false) {
149
+ Boolean result = (Boolean) client.replace(key, expiry, value, transcoder).get();
150
+ if (!result) {
150
151
  throw Error.newNotStored(ruby, "not stored");
151
152
  }
152
153
  return context.nil;
@@ -158,7 +159,6 @@ public class Memcached extends RubyObject {
158
159
  throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
159
160
  }
160
161
  retry++;
161
- continue;
162
162
  } else {
163
163
  throw ruby.newRuntimeError(e.getLocalizedMessage());
164
164
  }
@@ -169,7 +169,6 @@ public class Memcached extends RubyObject {
169
169
  throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
170
170
  }
171
171
  retry++;
172
- continue;
173
172
  } else {
174
173
  throw ruby.newRuntimeError(e.getLocalizedMessage());
175
174
  }
@@ -188,8 +187,8 @@ public class Memcached extends RubyObject {
188
187
  int retry = 0;
189
188
  while (true) {
190
189
  try {
191
- boolean result = (Boolean) client.set(key, expiry, value, transcoder).get();
192
- if (result == false) {
190
+ Boolean result = (Boolean) client.set(key, expiry, value, transcoder).get();
191
+ if (!result) {
193
192
  throw Error.newNotStored(ruby, "not stored");
194
193
  }
195
194
  return context.nil;
@@ -201,7 +200,6 @@ public class Memcached extends RubyObject {
201
200
  throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
202
201
  }
203
202
  retry++;
204
- continue;
205
203
  } else {
206
204
  throw ruby.newRuntimeError(e.getLocalizedMessage());
207
205
  }
@@ -212,7 +210,6 @@ public class Memcached extends RubyObject {
212
210
  throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
213
211
  }
214
212
  retry++;
215
- continue;
216
213
  } else {
217
214
  throw ruby.newRuntimeError(e.getLocalizedMessage());
218
215
  }
@@ -244,10 +241,10 @@ public class Memcached extends RubyObject {
244
241
  } else if (keys instanceof RubyArray) {
245
242
  RubyHash results = RubyHash.newHash(ruby);
246
243
 
247
- Map<String, IRubyObject> bulkResults = client.getBulk(getFullKeys(keys.convertToArray()), transcoder);
244
+ Map<String, IRubyObject> bulkResults = (Map<String, IRubyObject>) client.getBulk(getFullKeys(keys.convertToArray()), transcoder);
248
245
  for (String key : (List<String>) keys.convertToArray()) {
249
246
  if (bulkResults.containsKey(getFullKey(key))) {
250
- results.put(key, (IRubyObject) bulkResults.get(getFullKey(key)));
247
+ results.put(key, bulkResults.get(getFullKey(key)));
251
248
  }
252
249
  }
253
250
  return results;
@@ -255,11 +252,13 @@ public class Memcached extends RubyObject {
255
252
  } catch (RaiseException e) {
256
253
  throw e;
257
254
  } catch (OperationTimeoutException e) {
258
- throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
255
+ if (retry == exceptionRetryLimit) {
256
+ throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
257
+ }
258
+ retry++;
259
259
  } catch (RuntimeException e) {
260
260
  throw ruby.newRuntimeError(e.getLocalizedMessage());
261
261
  }
262
- return context.nil;
263
262
  }
264
263
  }
265
264
 
@@ -279,7 +278,6 @@ public class Memcached extends RubyObject {
279
278
  throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
280
279
  }
281
280
  retry++;
282
- continue;
283
281
  }
284
282
  }
285
283
  }
@@ -300,7 +298,6 @@ public class Memcached extends RubyObject {
300
298
  throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
301
299
  }
302
300
  retry++;
303
- continue;
304
301
  }
305
302
  }
306
303
  }
@@ -312,7 +309,7 @@ public class Memcached extends RubyObject {
312
309
  while (true) {
313
310
  try {
314
311
  boolean result = client.delete(getFullKey(key.toString())).get();
315
- if (result == false) {
312
+ if (!result) {
316
313
  throw Error.newNotFound(ruby, "not found");
317
314
  }
318
315
  return context.nil;
@@ -324,7 +321,6 @@ public class Memcached extends RubyObject {
324
321
  throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
325
322
  }
326
323
  retry++;
327
- continue;
328
324
  } else {
329
325
  throw ruby.newRuntimeError(e.getLocalizedMessage());
330
326
  }
@@ -335,7 +331,6 @@ public class Memcached extends RubyObject {
335
331
  throw Error.newATimeoutOccurred(ruby, e.getLocalizedMessage());
336
332
  }
337
333
  retry++;
338
- continue;
339
334
  } else {
340
335
  throw ruby.newRuntimeError(e.getLocalizedMessage());
341
336
  }
@@ -385,7 +380,7 @@ public class Memcached extends RubyObject {
385
380
  return ttl;
386
381
  }
387
382
 
388
- protected IRubyObject init(ThreadContext context, List<String> servers, RubyHash options) {
383
+ protected IRubyObject init(ThreadContext context, List<String> servers, Map<String, String> opts) {
389
384
  Ruby ruby = context.getRuntime();
390
385
  List<InetSocketAddress> addresses = AddrUtil.getAddresses(servers);
391
386
  try {
@@ -393,40 +388,39 @@ public class Memcached extends RubyObject {
393
388
 
394
389
  String distributionValue = "ketama";
395
390
  String hashValue = "fnv1_32";
396
- RubyBoolean binaryValue = ruby.getFalse();
397
- RubyBoolean shouldOptimize = ruby.getFalse();
391
+ boolean binaryValue = false;
392
+ boolean shouldOptimize = false;
398
393
  String transcoderValue = null;
399
- if (!options.isEmpty()) {
400
- RubyHash opts = options.convertToHash();
401
- if (opts.containsKey(ruby.newSymbol("distribution"))) {
402
- distributionValue = opts.get(ruby.newSymbol("distribution")).toString();
394
+ if (!opts.isEmpty()) {
395
+ if (opts.containsKey("distribution")) {
396
+ distributionValue = opts.get("distribution");
403
397
  }
404
- if (opts.containsKey(ruby.newSymbol("hash"))) {
405
- hashValue = opts.get(ruby.newSymbol("hash")).toString();
398
+ if (opts.containsKey("hash")) {
399
+ hashValue = opts.get("hash");
406
400
  }
407
- if (opts.containsKey(ruby.newSymbol("binary_protocol"))) {
408
- binaryValue = (RubyBoolean) opts.get(ruby.newSymbol("binary_protocol"));
401
+ if (opts.containsKey("binary_protocol")) {
402
+ binaryValue = Boolean.parseBoolean(opts.get("binary_protocol"));
409
403
  }
410
- if (opts.containsKey(ruby.newSymbol("should_optimize"))) {
411
- shouldOptimize = (RubyBoolean) opts.get(ruby.newSymbol("should_optimize"));
404
+ if (opts.containsKey("should_optimize")) {
405
+ shouldOptimize = Boolean.parseBoolean(opts.get("should_optimize"));
412
406
  }
413
- if (opts.containsKey(ruby.newSymbol("default_ttl"))) {
414
- ttl = Integer.parseInt(opts.get(ruby.newSymbol("default_ttl")).toString());
407
+ if (opts.containsKey("default_ttl")) {
408
+ ttl = Integer.parseInt(opts.get("default_ttl"));
415
409
  }
416
- if (opts.containsKey(ruby.newSymbol("timeout"))) {
417
- timeout = Integer.parseInt(opts.get(ruby.newSymbol("timeout")).toString());
410
+ if (opts.containsKey("timeout")) {
411
+ timeout = Integer.parseInt(opts.get("timeout"));
418
412
  }
419
- if (opts.containsKey(ruby.newSymbol("exception_retry_limit"))) {
420
- exceptionRetryLimit = Integer.parseInt(opts.get(ruby.newSymbol("exception_retry_limit")).toString());
413
+ if (opts.containsKey("exception_retry_limit")) {
414
+ exceptionRetryLimit = Integer.parseInt(opts.get("exception_retry_limit"));
421
415
  }
422
- if (opts.containsKey(ruby.newSymbol("namespace"))) {
423
- prefixKey = opts.get(ruby.newSymbol("namespace")).toString();
416
+ if (opts.containsKey("namespace")) {
417
+ prefixKey = opts.get("namespace");
424
418
  }
425
- if (opts.containsKey(ruby.newSymbol("prefix_key"))) {
426
- prefixKey = opts.get(ruby.newSymbol("prefix_key")).toString();
419
+ if (opts.containsKey("prefix_key")) {
420
+ prefixKey = opts.get("prefix_key");
427
421
  }
428
- if (opts.containsKey(ruby.newSymbol("transcoder"))) {
429
- transcoderValue = opts.get(ruby.newSymbol("transcoder")).toString();
422
+ if (opts.containsKey("transcoder")) {
423
+ transcoderValue = opts.get("transcoder");
430
424
  }
431
425
  }
432
426
 
@@ -455,10 +449,10 @@ public class Memcached extends RubyObject {
455
449
  throw Error.newNotSupport(ruby, "hash not support");
456
450
  }
457
451
 
458
- if (ruby.getTrue() == binaryValue) {
452
+ if (binaryValue) {
459
453
  builder.setProtocol(Protocol.BINARY);
460
454
  }
461
- if (ruby.getTrue() == shouldOptimize) {
455
+ if (shouldOptimize) {
462
456
  builder.setShouldOptimize(true);
463
457
  }
464
458
 
@@ -474,11 +468,11 @@ public class Memcached extends RubyObject {
474
468
  builder.setTranscoder(transcoder);
475
469
 
476
470
  client = new MemcachedClient(builder.build(), addresses);
477
- } catch (IOException ioe) {
478
- throw ruby.newIOErrorFromException(ioe);
479
- }
480
471
 
481
- return context.nil;
472
+ return context.nil;
473
+ } catch (IOException e) {
474
+ throw ruby.newIOErrorFromException(e);
475
+ }
482
476
  }
483
477
 
484
478
  private int getExpiry(IRubyObject[] args) {
@@ -6,7 +6,6 @@ import org.jruby.RubyBoolean;
6
6
  import org.jruby.RubyClass;
7
7
  import org.jruby.RubyHash;
8
8
  import org.jruby.RubyFixnum;
9
- import org.jruby.RubyObject;
10
9
  import org.jruby.RubyString;
11
10
  import org.jruby.anno.JRubyClass;
12
11
  import org.jruby.anno.JRubyMethod;
@@ -17,6 +16,8 @@ import org.jruby.runtime.builtin.IRubyObject;
17
16
 
18
17
  import java.util.ArrayList;
19
18
  import java.util.List;
19
+ import java.util.HashMap;
20
+ import java.util.Map;
20
21
 
21
22
  @JRubyClass(name = "Memcached::Rails", parent = "Memcached")
22
23
  public class Rails extends Memcached {
@@ -31,12 +32,7 @@ public class Rails extends Memcached {
31
32
  @JRubyMethod(name = "initialize", rest = true)
32
33
  public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
33
34
  Ruby ruby = context.getRuntime();
34
- RubyHash opts;
35
- if (args[args.length - 1] instanceof RubyHash) {
36
- opts = (RubyHash) args[args.length - 1];
37
- } else {
38
- opts = new RubyHash(ruby);
39
- }
35
+
40
36
  List<String> servers = new ArrayList<String>();
41
37
  for (IRubyObject arg : args) {
42
38
  if (arg instanceof RubyString) {
@@ -45,20 +41,30 @@ public class Rails extends Memcached {
45
41
  servers.addAll((List<String>) arg.convertToArray());
46
42
  }
47
43
  }
48
- if (servers.isEmpty()) {
49
- IRubyObject serverNames = (IRubyObject) opts.get(ruby.newSymbol("servers"));
50
- servers.addAll((List<String>) serverNames.convertToArray());
44
+
45
+ Map<String, String> options = new HashMap<String, String>();
46
+ if (args[args.length - 1] instanceof RubyHash) {
47
+ RubyHash arguments = args[args.length - 1].convertToHash();
48
+ for (Object key : arguments.keySet()) {
49
+ if (!"servers".equals(key.toString())) {
50
+ options.put(key.toString(), arguments.get(key).toString());
51
+ }
52
+ }
53
+ if (servers.isEmpty()) {
54
+ IRubyObject serverNames = (IRubyObject) arguments.get(ruby.newSymbol("servers"));
55
+ servers.addAll((List<String>) serverNames.convertToArray());
56
+ }
51
57
  }
52
- if (opts.containsKey(ruby.newSymbol("namespace"))) {
53
- opts.put(ruby.newSymbol("prefix_key"), opts.get(ruby.newSymbol("namespace")));
58
+ if (options.containsKey("namespace")) {
59
+ options.put("prefix_key", options.get("namespace"));
54
60
  }
55
- if (opts.containsKey(ruby.newSymbol("namespace_separator"))) {
56
- opts.put(ruby.newSymbol("prefix_delimiter"), opts.get(ruby.newSymbol("namespace_separator")));
61
+ if (options.containsKey("namespace_separator")) {
62
+ options.put("prefix_delimiter", options.get("namespace_separator"));
57
63
  }
58
- if (opts.containsKey(ruby.newSymbol("string_return_types"))) {
64
+ if (options.containsKey("string_return_types")) {
59
65
  stringReturnTypes = true;
60
66
  }
61
- return super.init(context, servers, opts);
67
+ return super.init(context, servers, options);
62
68
  }
63
69
 
64
70
  @JRubyMethod(name = "active?")
@@ -72,7 +78,6 @@ public class Rails extends Memcached {
72
78
 
73
79
  @JRubyMethod(name = { "get", "[]" }, required = 1, optional = 1)
74
80
  public IRubyObject get(ThreadContext context, IRubyObject[] args) {
75
- Ruby ruby = context.getRuntime();
76
81
  IRubyObject key = args[0];
77
82
  RubyBoolean notRaw = notRaw(context, args, 1);
78
83
  try {
@@ -87,8 +92,6 @@ public class Rails extends Memcached {
87
92
 
88
93
  @JRubyMethod(name = "read", required = 1, optional = 1)
89
94
  public IRubyObject read(ThreadContext context, IRubyObject[] args) {
90
- Ruby ruby = context.getRuntime();
91
- RubyBoolean not_raw = ruby.getTrue();
92
95
  IRubyObject key = args[0];
93
96
  RubyBoolean notRaw = notRaw(context, args, 1);
94
97
  return get(context, new IRubyObject[] { key, notRaw });
@@ -107,7 +110,6 @@ public class Rails extends Memcached {
107
110
 
108
111
  @JRubyMethod(name = "get_multi", required = 1, optional = 1)
109
112
  public IRubyObject getMulti(ThreadContext context, IRubyObject[] args) {
110
- Ruby ruby = context.getRuntime();
111
113
  IRubyObject keys = args[0];
112
114
  RubyBoolean notRaw = notRaw(context, args, 1);
113
115
  return super.get(context, new IRubyObject[] { keys, notRaw });
@@ -130,7 +132,6 @@ public class Rails extends Memcached {
130
132
 
131
133
  @JRubyMethod(name = "write", required = 2, optional = 1)
132
134
  public IRubyObject write(ThreadContext context, IRubyObject[] args) {
133
- Ruby ruby = context.getRuntime();
134
135
  IRubyObject key = args[0];
135
136
  IRubyObject value = args[1];
136
137
  RubyFixnum ttl = getTTL(context, args, 2);
@@ -229,9 +230,8 @@ public class Rails extends Memcached {
229
230
  Ruby ruby = context.getRuntime();
230
231
  RubyBoolean notRaw = ruby.getTrue();
231
232
  if (args.length > index) {
232
- if (args[index] instanceof RubyBoolean && ruby.getTrue() == (RubyBoolean) args[index]) {
233
- notRaw = ruby.getFalse();
234
- } else if (args[index] instanceof RubyHash && ruby.getTrue() == ((RubyHash) args[index]).get(ruby.newSymbol("raw"))) {
233
+ if ((args[index] instanceof RubyBoolean && ruby.getTrue() == args[index]) ||
234
+ (args[index] instanceof RubyHash && ruby.getTrue() == ((RubyHash) args[index]).get(ruby.newSymbol("raw")))) {
235
235
  notRaw = ruby.getFalse();
236
236
  }
237
237
  }
@@ -1,21 +1,17 @@
1
1
  package com.openfeint.memcached.transcoder;
2
2
 
3
- import com.jcraft.jzlib.ZOutputStream;
4
- import com.jcraft.jzlib.ZInputStream;
5
3
  import com.jcraft.jzlib.JZlib;
4
+ import com.jcraft.jzlib.ZInputStream;
5
+ import com.jcraft.jzlib.ZOutputStream;
6
6
  import net.spy.memcached.CachedData;
7
- import net.spy.memcached.transcoders.Transcoder;
8
7
  import org.jruby.Ruby;
9
8
  import org.jruby.exceptions.RaiseException;
10
9
  import org.jruby.runtime.builtin.IRubyObject;
11
10
  import org.jruby.runtime.marshal.MarshalStream;
12
11
  import org.jruby.runtime.marshal.UnmarshalStream;
13
- import org.jruby.util.ByteList;
14
12
 
15
13
  import java.io.ByteArrayInputStream;
16
14
  import java.io.ByteArrayOutputStream;
17
- import java.io.ObjectInputStream;
18
- import java.io.ObjectOutputStream;
19
15
  import java.io.IOException;
20
16
 
21
17
  /**
@@ -36,6 +32,7 @@ public class MarshalZlibTranscoder extends MarshalTranscoder {
36
32
 
37
33
  public CachedData encode(Object o) {
38
34
  if (o instanceof IRubyObject) {
35
+ ZOutputStream zout = null;
39
36
  try {
40
37
  ByteArrayOutputStream out1 = new ByteArrayOutputStream();
41
38
  MarshalStream marshal = new MarshalStream(ruby, out1, Integer.MAX_VALUE);
@@ -44,9 +41,10 @@ public class MarshalZlibTranscoder extends MarshalTranscoder {
44
41
  byte[] bytes;
45
42
  if (getFlags() == COMPRESS_FLAG) {
46
43
  ByteArrayOutputStream out2 = new ByteArrayOutputStream();
47
- ZOutputStream zout = new ZOutputStream(out2, JZlib.Z_DEFAULT_COMPRESSION);
44
+ zout = new ZOutputStream(out2, JZlib.Z_DEFAULT_COMPRESSION);
48
45
  zout.write(out1.toByteArray());
49
- zout.close();
46
+ zout.flush();
47
+ zout.end();
50
48
  bytes = out2.toByteArray();
51
49
  } else {
52
50
  bytes = out1.toByteArray();
@@ -55,6 +53,13 @@ public class MarshalZlibTranscoder extends MarshalTranscoder {
55
53
  return new CachedData(super.getFlags(), bytes, bytes.length);
56
54
  } catch (IOException e) {
57
55
  throw ruby.newIOErrorFromException(e);
56
+ } finally {
57
+ if (zout != null) {
58
+ try {
59
+ zout.close();
60
+ } catch (IOException e) {}
61
+ zout = null;
62
+ }
58
63
  }
59
64
  } else {
60
65
  return super.encodeNumber(o);
@@ -62,11 +67,12 @@ public class MarshalZlibTranscoder extends MarshalTranscoder {
62
67
  }
63
68
 
64
69
  public Object decode(CachedData d) {
70
+ ZInputStream zin = null;
65
71
  try {
66
72
  byte[] bytes;
67
73
  if (d.getFlags() == COMPRESS_FLAG) {
68
74
  ByteArrayInputStream in = new ByteArrayInputStream(d.getData());
69
- ZInputStream zin = new ZInputStream(in);
75
+ zin = new ZInputStream(in);
70
76
 
71
77
  ByteArrayOutputStream buffer = new ByteArrayOutputStream();
72
78
  int nRead;
@@ -76,7 +82,6 @@ public class MarshalZlibTranscoder extends MarshalTranscoder {
76
82
  }
77
83
  buffer.flush();
78
84
  bytes = buffer.toByteArray();
79
- zin.close();
80
85
  } else {
81
86
  bytes = d.getData();
82
87
  }
@@ -86,6 +91,13 @@ public class MarshalZlibTranscoder extends MarshalTranscoder {
86
91
  return super.decodeNumber(d, e);
87
92
  } catch (IOException e) {
88
93
  return super.decodeNumber(d, e);
94
+ } finally {
95
+ if (zin != null) {
96
+ try {
97
+ zin.close();
98
+ } catch (IOException e) {}
99
+ zin = null;
100
+ }
89
101
  }
90
102
  }
91
103
  }
metadata CHANGED
@@ -1,106 +1,122 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: jruby-memcached
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.5.0
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.5.1
6
6
  platform: ruby
7
- authors:
8
- - Richard Huang
9
- autorequire:
7
+ authors:
8
+ - Richard Huang
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2012-08-22 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: rspec
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
19
- none: false
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
24
- type: :development
25
- version_requirements: *id001
26
- - !ruby/object:Gem::Dependency
27
- name: mocha
28
- prerelease: false
29
- requirement: &id002 !ruby/object:Gem::Requirement
30
- none: false
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: "0"
35
- type: :development
36
- version_requirements: *id002
12
+ date: 2012-11-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
20
+ version: !binary |-
21
+ MA==
22
+ none: false
23
+ requirement: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ! '>='
26
+ - !ruby/object:Gem::Version
27
+ version: !binary |-
28
+ MA==
29
+ none: false
30
+ prerelease: false
31
+ type: :development
32
+ - !ruby/object:Gem::Dependency
33
+ name: mocha
34
+ version_requirements: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: !binary |-
39
+ MA==
40
+ none: false
41
+ requirement: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: !binary |-
46
+ MA==
47
+ none: false
48
+ prerelease: false
49
+ type: :development
37
50
  description: jruby memcacached client which is compatible with memcached gem
38
- email:
39
- - flyerhzm@gmail.com
51
+ email:
52
+ - flyerhzm@gmail.com
40
53
  executables: []
41
-
42
54
  extensions: []
43
-
44
55
  extra_rdoc_files: []
45
-
46
- files:
47
- - .gitignore
48
- - .travis.yml
49
- - CHANGELOG.md
50
- - Gemfile
51
- - Gemfile.lock
52
- - MIT-LICENSE
53
- - README.md
54
- - Rakefile
55
- - benchmark.rb
56
- - jruby_memcached.gemspec
57
- - lib/memcached.rb
58
- - lib/memcached/version.rb
59
- - pom.xml
60
- - spec/memcached_spec.rb
61
- - spec/rails_spec.rb
62
- - spec/spec_helper.rb
63
- - src/main/java/com/openfeint/memcached/Memcached.java
64
- - src/main/java/com/openfeint/memcached/MemcachedService.java
65
- - src/main/java/com/openfeint/memcached/Rails.java
66
- - src/main/java/com/openfeint/memcached/error/ATimeoutOccurred.java
67
- - src/main/java/com/openfeint/memcached/error/Error.java
68
- - src/main/java/com/openfeint/memcached/error/NotFound.java
69
- - src/main/java/com/openfeint/memcached/error/NotStored.java
70
- - src/main/java/com/openfeint/memcached/error/NotSupport.java
71
- - src/main/java/com/openfeint/memcached/transcoder/MarshalTranscoder.java
72
- - src/main/java/com/openfeint/memcached/transcoder/MarshalZlibTranscoder.java
73
- - src/main/java/net/spy/memcached/KetamaNodeLocator.java
74
- - src/main/java/net/spy/memcached/util/DefaultKetamaNodeLocatorConfiguration.java
75
- - target/spymemcached-ext-0.0.1.jar
56
+ files:
57
+ - .gitignore
58
+ - .travis.yml
59
+ - CHANGELOG.md
60
+ - Gemfile
61
+ - MIT-LICENSE
62
+ - README.md
63
+ - Rakefile
64
+ - benchmark.rb
65
+ - jruby_memcached.gemspec
66
+ - lib/memcached.rb
67
+ - lib/memcached/version.rb
68
+ - pom.xml
69
+ - spec/memcached_spec.rb
70
+ - spec/rails_spec.rb
71
+ - spec/spec_helper.rb
72
+ - spec/timeout_spec.rb
73
+ - src/main/java/com/openfeint/memcached/Memcached.java
74
+ - src/main/java/com/openfeint/memcached/MemcachedService.java
75
+ - src/main/java/com/openfeint/memcached/Rails.java
76
+ - src/main/java/com/openfeint/memcached/error/ATimeoutOccurred.java
77
+ - src/main/java/com/openfeint/memcached/error/Error.java
78
+ - src/main/java/com/openfeint/memcached/error/NotFound.java
79
+ - src/main/java/com/openfeint/memcached/error/NotStored.java
80
+ - src/main/java/com/openfeint/memcached/error/NotSupport.java
81
+ - src/main/java/com/openfeint/memcached/transcoder/MarshalTranscoder.java
82
+ - src/main/java/com/openfeint/memcached/transcoder/MarshalZlibTranscoder.java
83
+ - src/main/java/net/spy/memcached/KetamaNodeLocator.java
84
+ - src/main/java/net/spy/memcached/util/DefaultKetamaNodeLocatorConfiguration.java
85
+ - target/spymemcached-ext-0.0.1.jar
76
86
  homepage: https://github.com/aurorafeint/jruby-memcached
77
87
  licenses: []
78
-
79
- post_install_message:
88
+ post_install_message:
80
89
  rdoc_options: []
81
-
82
- require_paths:
83
- - lib
84
- required_ruby_version: !ruby/object:Gem::Requirement
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ segments:
97
+ - 0
98
+ hash: 2
99
+ version: !binary |-
100
+ MA==
85
101
  none: false
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: "0"
90
- required_rubygems_version: !ruby/object:Gem::Requirement
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ segments:
107
+ - 0
108
+ hash: 2
109
+ version: !binary |-
110
+ MA==
91
111
  none: false
92
- requirements:
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- version: "0"
96
112
  requirements: []
97
-
98
- rubyforge_project:
113
+ rubyforge_project:
99
114
  rubygems_version: 1.8.24
100
- signing_key:
115
+ signing_key:
101
116
  specification_version: 3
102
117
  summary: jruby compatible memcached client
103
- test_files:
104
- - spec/memcached_spec.rb
105
- - spec/rails_spec.rb
106
- - spec/spec_helper.rb
118
+ test_files:
119
+ - spec/memcached_spec.rb
120
+ - spec/rails_spec.rb
121
+ - spec/spec_helper.rb
122
+ - spec/timeout_spec.rb
@@ -1,30 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- jruby-memcached (0.5.0)
5
-
6
- GEM
7
- remote: http://rubygems.org/
8
- specs:
9
- diff-lcs (1.1.3)
10
- metaclass (0.0.1)
11
- mocha (0.12.1)
12
- metaclass (~> 0.0.1)
13
- rake (0.9.2.2)
14
- rspec (2.11.0)
15
- rspec-core (~> 2.11.0)
16
- rspec-expectations (~> 2.11.0)
17
- rspec-mocks (~> 2.11.0)
18
- rspec-core (2.11.1)
19
- rspec-expectations (2.11.1)
20
- diff-lcs (~> 1.1.3)
21
- rspec-mocks (2.11.1)
22
-
23
- PLATFORMS
24
- java
25
-
26
- DEPENDENCIES
27
- jruby-memcached!
28
- mocha
29
- rake
30
- rspec