ohm 0.0.34 → 0.0.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/ohm.rb +63 -36
- data/lib/ohm/collection.rb +1 -1
- data/lib/ohm/compat-1.8.6.rb +16 -1
- data/test/benchmarks.rb +15 -37
- data/test/model_test.rb +93 -26
- metadata +31 -8
- data/Thorfile +0 -20
- data/lib/ohm/redis.rb +0 -305
- data/test/redis_test.rb +0 -432
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 35
|
9
|
+
version: 0.0.35
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Michel Martens
|
@@ -15,10 +15,36 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-04-
|
18
|
+
date: 2010-04-09 00:00:00 -03:00
|
19
19
|
default_executable:
|
20
|
-
dependencies:
|
21
|
-
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: redis
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 0
|
31
|
+
- 4
|
32
|
+
version: 1.0.4
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: contest
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ~>
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
- 1
|
45
|
+
version: "0.1"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
22
48
|
description: Ohm is a library that allows to store an object in Redis, a persistent key-value database. It includes an extensible list of validations and has very good performance.
|
23
49
|
email:
|
24
50
|
- michel@soveran.com
|
@@ -33,13 +59,11 @@ files:
|
|
33
59
|
- lib/ohm/collection.rb
|
34
60
|
- lib/ohm/compat-1.8.6.rb
|
35
61
|
- lib/ohm/key.rb
|
36
|
-
- lib/ohm/redis.rb
|
37
62
|
- lib/ohm/validations.rb
|
38
63
|
- lib/ohm.rb
|
39
64
|
- README.markdown
|
40
65
|
- LICENSE
|
41
66
|
- Rakefile
|
42
|
-
- Thorfile
|
43
67
|
- test/1.8.6_test.rb
|
44
68
|
- test/all_tests.rb
|
45
69
|
- test/benchmarks.rb
|
@@ -48,7 +72,6 @@ files:
|
|
48
72
|
- test/indices_test.rb
|
49
73
|
- test/model_test.rb
|
50
74
|
- test/mutex_test.rb
|
51
|
-
- test/redis_test.rb
|
52
75
|
- test/test_helper.rb
|
53
76
|
- test/validations_test.rb
|
54
77
|
- test/test.conf
|
data/Thorfile
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
class Ohm < Thor
|
4
|
-
desc "doc", "Generate YARD documentation"
|
5
|
-
method_options :open => false
|
6
|
-
def doc
|
7
|
-
require "yard"
|
8
|
-
|
9
|
-
opts = ["--protected", "--title", "Ohm – Object-hash mapping library for Redis"]
|
10
|
-
|
11
|
-
YARD::CLI::Yardoc.run(*opts)
|
12
|
-
|
13
|
-
system "open doc/index.html" if options[:open]
|
14
|
-
end
|
15
|
-
|
16
|
-
desc "deploy", "Deploy documentation"
|
17
|
-
def deploy
|
18
|
-
system "rsync -az doc/* ohm.keyvalue.org:deploys/ohm.keyvalue.org/"
|
19
|
-
end
|
20
|
-
end
|
data/lib/ohm/redis.rb
DELETED
@@ -1,305 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
# Redis client based on RubyRedis, original work of Salvatore Sanfilippo
|
4
|
-
# http://github.com/antirez/redis/blob/4a327b4af9885d89b5860548f44569d1d2bde5ab/client-libraries/ruby_2/rubyredis.rb
|
5
|
-
#
|
6
|
-
# Some improvements where inspired by the Redis-rb library, including the testing suite.
|
7
|
-
# http://github.com/ezmobius/redis-rb/
|
8
|
-
require 'socket'
|
9
|
-
|
10
|
-
module Ohm
|
11
|
-
begin
|
12
|
-
if (RUBY_VERSION >= '1.9')
|
13
|
-
require 'timeout'
|
14
|
-
RedisTimer = Timeout
|
15
|
-
else
|
16
|
-
require 'system_timer'
|
17
|
-
RedisTimer = SystemTimer
|
18
|
-
end
|
19
|
-
rescue LoadError
|
20
|
-
RedisTimer = nil
|
21
|
-
end
|
22
|
-
|
23
|
-
class Redis
|
24
|
-
class ProtocolError < RuntimeError
|
25
|
-
def initialize(reply_type)
|
26
|
-
super("Protocol error, got '#{reply_type}' as initial reply byte")
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
BULK_COMMANDS = {
|
31
|
-
:echo => true,
|
32
|
-
:getset => true,
|
33
|
-
:lpush => true,
|
34
|
-
:lrem => true,
|
35
|
-
:lset => true,
|
36
|
-
:rpush => true,
|
37
|
-
:sadd => true,
|
38
|
-
:set => true,
|
39
|
-
:setnx => true,
|
40
|
-
:sismember => true,
|
41
|
-
:smove => true,
|
42
|
-
:srem => true,
|
43
|
-
:zadd => true,
|
44
|
-
:zincrby => true,
|
45
|
-
:zrem => true,
|
46
|
-
:zscore => true
|
47
|
-
}
|
48
|
-
|
49
|
-
MULTI_BULK_COMMANDS = {
|
50
|
-
:mset => true,
|
51
|
-
:msetnx => true
|
52
|
-
}
|
53
|
-
|
54
|
-
PROCESSOR_IDENTITY = lambda { |reply| reply }
|
55
|
-
PROCESSOR_CONVERT_TO_BOOL = lambda { |reply| reply == 0 ? false : reply }
|
56
|
-
PROCESSOR_SPLIT_KEYS = lambda { |reply| reply.respond_to?(:split) ? reply.split(" ") : reply }
|
57
|
-
PROCESSOR_INFO = lambda { |reply| Hash[*(reply.lines.map { |l| l.chomp.split(":", 2) }.flatten)] }
|
58
|
-
|
59
|
-
REPLY_PROCESSOR = {
|
60
|
-
:exists => PROCESSOR_CONVERT_TO_BOOL,
|
61
|
-
:sismember=> PROCESSOR_CONVERT_TO_BOOL,
|
62
|
-
:sadd=> PROCESSOR_CONVERT_TO_BOOL,
|
63
|
-
:srem=> PROCESSOR_CONVERT_TO_BOOL,
|
64
|
-
:smove=> PROCESSOR_CONVERT_TO_BOOL,
|
65
|
-
:zadd => PROCESSOR_CONVERT_TO_BOOL,
|
66
|
-
:zrem => PROCESSOR_CONVERT_TO_BOOL,
|
67
|
-
:move=> PROCESSOR_CONVERT_TO_BOOL,
|
68
|
-
:setnx=> PROCESSOR_CONVERT_TO_BOOL,
|
69
|
-
:del=> PROCESSOR_CONVERT_TO_BOOL,
|
70
|
-
:renamenx=> PROCESSOR_CONVERT_TO_BOOL,
|
71
|
-
:expire=> PROCESSOR_CONVERT_TO_BOOL,
|
72
|
-
:keys => PROCESSOR_SPLIT_KEYS,
|
73
|
-
:info => PROCESSOR_INFO
|
74
|
-
}
|
75
|
-
|
76
|
-
REPLY_PROCESSOR.send(:initialize) do |hash, key|
|
77
|
-
hash[key] = PROCESSOR_IDENTITY
|
78
|
-
end
|
79
|
-
|
80
|
-
def initialize(options = {})
|
81
|
-
@host = options[:host] || '127.0.0.1'
|
82
|
-
@port = options[:port] || 6379
|
83
|
-
@db = options[:db] || 0
|
84
|
-
@timeout = options[:timeout] || 0
|
85
|
-
@password = options[:password]
|
86
|
-
connect
|
87
|
-
end
|
88
|
-
|
89
|
-
def version
|
90
|
-
@version ||= info["redis_version"]
|
91
|
-
end
|
92
|
-
|
93
|
-
def support_mset?
|
94
|
-
@support_mset.nil? ?
|
95
|
-
@support_mset = version >= "1.05" :
|
96
|
-
@support_mset
|
97
|
-
end
|
98
|
-
|
99
|
-
def to_s
|
100
|
-
"Redis Client connected to #{@host}:#{@port} against DB #{@db}"
|
101
|
-
end
|
102
|
-
|
103
|
-
# Shorthand for getting all the elements in a list.
|
104
|
-
def list(key)
|
105
|
-
call_command([:lrange, key, 0, -1])
|
106
|
-
end
|
107
|
-
|
108
|
-
# We need to define type because otherwise it will escape method_missing.
|
109
|
-
def type(key)
|
110
|
-
call_command([:type, key])
|
111
|
-
end
|
112
|
-
|
113
|
-
def sort(key, opts = {})
|
114
|
-
cmd = []
|
115
|
-
cmd << "SORT #{key}"
|
116
|
-
cmd << "BY #{opts[:by]}" if opts[:by]
|
117
|
-
cmd << "GET #{[opts[:get]].flatten * ' GET '}" if opts[:get]
|
118
|
-
cmd << "#{opts[:order]}" if opts[:order]
|
119
|
-
cmd << "LIMIT #{Array(opts[:limit]).join(' ')}" if opts[:limit]
|
120
|
-
call_command(cmd)
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
|
125
|
-
def connect
|
126
|
-
connect_to(@host, @port, @timeout == 0 ? nil : @timeout)
|
127
|
-
call_command([:auth, @password]) if @password
|
128
|
-
call_command([:select, @db]) if @db != 0
|
129
|
-
@sock
|
130
|
-
end
|
131
|
-
|
132
|
-
def connect_to(host, port, timeout = nil)
|
133
|
-
|
134
|
-
# We support connect() timeout only if system_timer is availabe or
|
135
|
-
# if we are running against Ruby >= 1.9. Timeout reading from the
|
136
|
-
# socket instead will be supported anyway.
|
137
|
-
if @timeout != 0 and RedisTimer
|
138
|
-
begin
|
139
|
-
@sock = TCPSocket.new(host, port)
|
140
|
-
rescue Timeout::Error
|
141
|
-
@sock = nil
|
142
|
-
raise Timeout::Error, "Timeout connecting to the server"
|
143
|
-
end
|
144
|
-
else
|
145
|
-
@sock = TCPSocket.new(host, port)
|
146
|
-
end
|
147
|
-
|
148
|
-
@sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
149
|
-
|
150
|
-
# If the timeout is set we configure the low level socket options in
|
151
|
-
# order to make sure a blocking read will return after the specified
|
152
|
-
# number of seconds. This hack is from the Memcached Ruby client.
|
153
|
-
if timeout
|
154
|
-
secs = Integer(timeout)
|
155
|
-
usecs = Integer((timeout - secs) * 1_000_000)
|
156
|
-
optval = [secs, usecs].pack("l_2")
|
157
|
-
@sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
|
158
|
-
@sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
|
159
|
-
end
|
160
|
-
rescue Errno::ECONNREFUSED
|
161
|
-
raise Errno::ECONNREFUSED, "Unable to connect to Redis on #{host}:#{port}"
|
162
|
-
end
|
163
|
-
|
164
|
-
def connected?
|
165
|
-
!! @sock
|
166
|
-
end
|
167
|
-
|
168
|
-
def disconnect
|
169
|
-
@sock.close
|
170
|
-
@sock = nil
|
171
|
-
true
|
172
|
-
end
|
173
|
-
|
174
|
-
def reconnect
|
175
|
-
disconnect and connect
|
176
|
-
end
|
177
|
-
|
178
|
-
def method_missing(*argv)
|
179
|
-
call_command(argv)
|
180
|
-
end
|
181
|
-
|
182
|
-
# Wrap raw_call_command to handle reconnection on socket error. We
|
183
|
-
# try to reconnect just one time, otherwise let the error araise.
|
184
|
-
def call_command(argv)
|
185
|
-
connect unless connected?
|
186
|
-
raw_call_command(argv.dup)
|
187
|
-
rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED
|
188
|
-
if reconnect
|
189
|
-
raw_call_command(argv.dup)
|
190
|
-
else
|
191
|
-
raise Errno::ECONNRESET
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
def raw_call_command(argv)
|
196
|
-
bulk_command?(argv) ?
|
197
|
-
process_bulk_command(argv) :
|
198
|
-
multi_bulk_command?(argv) ?
|
199
|
-
process_multi_bulk_command(argv) :
|
200
|
-
process_command(argv)
|
201
|
-
process_reply(argv[0])
|
202
|
-
end
|
203
|
-
|
204
|
-
def process_command(argv)
|
205
|
-
@sock.write("#{argv.join(" ")}\r\n")
|
206
|
-
end
|
207
|
-
|
208
|
-
def process_bulk_command(argv)
|
209
|
-
bulk = argv.pop.to_s
|
210
|
-
argv.push ssize(bulk)
|
211
|
-
@sock.write("#{argv.join(" ")}\r\n")
|
212
|
-
@sock.write("#{bulk}\r\n")
|
213
|
-
end
|
214
|
-
|
215
|
-
def process_multi_bulk_command(argv)
|
216
|
-
params = argv.pop.to_a.flatten
|
217
|
-
params.unshift(argv[0])
|
218
|
-
|
219
|
-
command = ["*#{params.size}"]
|
220
|
-
params.each do |param|
|
221
|
-
param = param.to_s
|
222
|
-
command << "$#{ssize(param)}"
|
223
|
-
command << param
|
224
|
-
end
|
225
|
-
|
226
|
-
@sock.write(command.map { |cmd| "#{cmd}\r\n"}.join)
|
227
|
-
end
|
228
|
-
|
229
|
-
def bulk_command?(argv)
|
230
|
-
BULK_COMMANDS[argv[0]] and argv.length > 1
|
231
|
-
end
|
232
|
-
|
233
|
-
def multi_bulk_command?(argv)
|
234
|
-
MULTI_BULK_COMMANDS[argv[0]]
|
235
|
-
end
|
236
|
-
|
237
|
-
def process_reply(command)
|
238
|
-
REPLY_PROCESSOR[command][read_reply]
|
239
|
-
end
|
240
|
-
|
241
|
-
def read_reply
|
242
|
-
|
243
|
-
# We read the first byte using read() mainly because gets() is
|
244
|
-
# immune to raw socket timeouts.
|
245
|
-
begin
|
246
|
-
reply_type = @sock.read(1)
|
247
|
-
rescue Errno::EAGAIN
|
248
|
-
|
249
|
-
# We want to make sure it reconnects on the next command after the
|
250
|
-
# timeout. Otherwise the server may reply in the meantime leaving
|
251
|
-
# the protocol in a desync status.
|
252
|
-
@sock = nil
|
253
|
-
raise Errno::EAGAIN, "Timeout reading from the socket"
|
254
|
-
end
|
255
|
-
|
256
|
-
raise Errno::ECONNRESET, "Connection lost" unless reply_type
|
257
|
-
|
258
|
-
format_reply(reply_type, @sock.gets)
|
259
|
-
end
|
260
|
-
|
261
|
-
def format_reply(reply_type, line)
|
262
|
-
case reply_type
|
263
|
-
when "-" then format_error_reply(line)
|
264
|
-
when "+" then format_status_reply(line)
|
265
|
-
when ":" then format_integer_reply(line)
|
266
|
-
when "$" then format_bulk_reply(line)
|
267
|
-
when "*" then format_multi_bulk_reply(line)
|
268
|
-
else raise ProtocolError.new(reply_type)
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
def format_error_reply(line)
|
273
|
-
raise "-" + line.strip
|
274
|
-
end
|
275
|
-
|
276
|
-
def format_status_reply(line)
|
277
|
-
line.strip
|
278
|
-
end
|
279
|
-
|
280
|
-
def format_integer_reply(line)
|
281
|
-
line.to_i
|
282
|
-
end
|
283
|
-
|
284
|
-
def format_bulk_reply(line)
|
285
|
-
bulklen = line.to_i
|
286
|
-
return if bulklen == -1
|
287
|
-
reply = @sock.read(bulklen)
|
288
|
-
@sock.read(2) # Discard CRLF.
|
289
|
-
|
290
|
-
reply.respond_to?(:force_encoding) ?
|
291
|
-
reply.force_encoding("UTF-8") :
|
292
|
-
reply
|
293
|
-
end
|
294
|
-
|
295
|
-
def format_multi_bulk_reply(line)
|
296
|
-
reply = []
|
297
|
-
line.to_i.times { reply << read_reply }
|
298
|
-
reply
|
299
|
-
end
|
300
|
-
|
301
|
-
def ssize(string)
|
302
|
-
string.respond_to?(:bytesize) ? string.bytesize : string.size
|
303
|
-
end
|
304
|
-
end
|
305
|
-
end
|
data/test/redis_test.rb
DELETED
@@ -1,432 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "test_helper")
|
2
|
-
|
3
|
-
# This test suit is based on the Redis-rb spec,
|
4
|
-
# located at http://github.com/ezmobius/redis-rb/
|
5
|
-
class Foo
|
6
|
-
attr_accessor :bar
|
7
|
-
def initialize(bar)
|
8
|
-
@bar = bar
|
9
|
-
end
|
10
|
-
|
11
|
-
def ==(other)
|
12
|
-
@bar == other.bar
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class RedisTest < Test::Unit::TestCase
|
17
|
-
setup do
|
18
|
-
@legacy ||= begin
|
19
|
-
Ohm.redis.info["redis_version"] <= "1.02"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "redis" do
|
24
|
-
setup do
|
25
|
-
@r ||= Ohm.redis
|
26
|
-
@r.set("foo", "bar")
|
27
|
-
end
|
28
|
-
|
29
|
-
teardown do
|
30
|
-
@r.flushdb
|
31
|
-
end
|
32
|
-
|
33
|
-
should "be able to GET a key" do
|
34
|
-
assert_equal "bar", @r.get("foo")
|
35
|
-
end
|
36
|
-
|
37
|
-
should "be able to SET a key" do
|
38
|
-
@r.set("foo", "nik")
|
39
|
-
assert_equal "nik", @r.get("foo")
|
40
|
-
end
|
41
|
-
|
42
|
-
should "be able to SETNX(setnx)" do
|
43
|
-
@r.set("foo", "nik")
|
44
|
-
assert_equal "nik", @r.get("foo")
|
45
|
-
@r.setnx("foo", "bar")
|
46
|
-
assert_equal "nik", @r.get("foo")
|
47
|
-
end
|
48
|
-
|
49
|
-
should "be able to MSET keys" do
|
50
|
-
unless @legacy
|
51
|
-
@r.mset(:foo => "foobar", :bar => 1000)
|
52
|
-
assert_equal ["foobar", "1000"], @r.mget("foo", "bar")
|
53
|
-
assert_equal ["foobar", "1000", nil], @r.mget("foo", "bar", "baz")
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
should "be able to MGET keys" do
|
58
|
-
@r.set("foo", 1000)
|
59
|
-
@r.set("bar", 2000)
|
60
|
-
assert_equal ["1000", "2000"], @r.mget("foo", "bar")
|
61
|
-
assert_equal ["1000", "2000", nil], @r.mget("foo", "bar", "baz")
|
62
|
-
end
|
63
|
-
|
64
|
-
should "be able to INCR(increment) a key" do
|
65
|
-
@r.del("counter")
|
66
|
-
assert_equal 1, @r.incr("counter")
|
67
|
-
assert_equal 2, @r.incr("counter")
|
68
|
-
assert_equal 3, @r.incr("counter")
|
69
|
-
end
|
70
|
-
|
71
|
-
should "be able to DECR(decrement) a key" do
|
72
|
-
@r.del("counter")
|
73
|
-
assert_equal 1, @r.incr("counter")
|
74
|
-
assert_equal 2, @r.incr("counter")
|
75
|
-
assert_equal 3, @r.incr("counter")
|
76
|
-
assert_equal 2, @r.decr("counter")
|
77
|
-
assert_equal 0, @r.decrby("counter", 2)
|
78
|
-
end
|
79
|
-
|
80
|
-
should "be able to RANDKEY(return a random key)" do
|
81
|
-
assert_not_nil @r.randomkey
|
82
|
-
end
|
83
|
-
|
84
|
-
should "be able to RENAME a key" do
|
85
|
-
@r.del "foo"
|
86
|
-
@r.del "bar"
|
87
|
-
@r.set("foo", "hi")
|
88
|
-
@r.rename "foo", "bar"
|
89
|
-
assert_equal "hi", @r.get("bar")
|
90
|
-
end
|
91
|
-
|
92
|
-
should "be able to RENAMENX(rename unless the new key already exists) a key" do
|
93
|
-
@r.del "foo"
|
94
|
-
@r.del "bar"
|
95
|
-
@r.set("foo", "hi")
|
96
|
-
@r.set("bar", "ohai")
|
97
|
-
|
98
|
-
@r.renamenx "foo", "bar"
|
99
|
-
|
100
|
-
assert_equal "ohai", @r.get("bar")
|
101
|
-
end
|
102
|
-
|
103
|
-
should "be able to EXISTS(check if key exists)" do
|
104
|
-
@r.set("foo", "nik")
|
105
|
-
assert @r.exists("foo")
|
106
|
-
@r.del "foo"
|
107
|
-
assert_equal false, @r.exists("foo")
|
108
|
-
end
|
109
|
-
|
110
|
-
should "be able to KEYS(glob for keys)" do
|
111
|
-
@r.keys("f*").each do |key|
|
112
|
-
@r.del key
|
113
|
-
end
|
114
|
-
@r.set("f", "nik")
|
115
|
-
@r.set("fo", "nak")
|
116
|
-
@r.set("foo", "qux")
|
117
|
-
assert_equal ["f","fo", "foo"], @r.keys("f*").sort
|
118
|
-
end
|
119
|
-
|
120
|
-
should "be able to check the TYPE of a key" do
|
121
|
-
@r.set("foo", "nik")
|
122
|
-
assert_equal "string", @r.type("foo")
|
123
|
-
@r.del "foo"
|
124
|
-
assert_equal "none", @r.type("foo")
|
125
|
-
end
|
126
|
-
|
127
|
-
should "be able to push to the head of a list" do
|
128
|
-
@r.lpush "list", "hello"
|
129
|
-
@r.lpush "list", 42
|
130
|
-
assert_equal "list", @r.type("list")
|
131
|
-
assert_equal 2, @r.llen("list")
|
132
|
-
assert_equal "42", @r.lpop("list")
|
133
|
-
@r.del("list")
|
134
|
-
end
|
135
|
-
|
136
|
-
should "be able to push to the tail of a list" do
|
137
|
-
@r.rpush "list", "hello"
|
138
|
-
assert_equal "list", @r.type("list")
|
139
|
-
assert_equal 1, @r.llen("list")
|
140
|
-
@r.del("list")
|
141
|
-
end
|
142
|
-
|
143
|
-
should "be able to pop the tail of a list" do
|
144
|
-
@r.rpush "list", "hello"
|
145
|
-
@r.rpush "list", "goodbye"
|
146
|
-
assert_equal "list", @r.type("list")
|
147
|
-
assert_equal 2, @r.llen("list")
|
148
|
-
assert_equal "goodbye", @r.rpop("list")
|
149
|
-
@r.del("list")
|
150
|
-
end
|
151
|
-
|
152
|
-
should "be able to pop the head of a list" do
|
153
|
-
@r.rpush "list", "hello"
|
154
|
-
@r.rpush "list", "goodbye"
|
155
|
-
assert_equal "list", @r.type("list")
|
156
|
-
assert_equal 2, @r.llen("list")
|
157
|
-
assert_equal "hello", @r.lpop("list")
|
158
|
-
@r.del("list")
|
159
|
-
end
|
160
|
-
|
161
|
-
should "be able to get the length of a list" do
|
162
|
-
@r.rpush "list", "hello"
|
163
|
-
@r.rpush "list", "goodbye"
|
164
|
-
assert_equal "list", @r.type("list")
|
165
|
-
assert_equal 2, @r.llen("list")
|
166
|
-
@r.del("list")
|
167
|
-
end
|
168
|
-
|
169
|
-
should "be able to get a range of values from a list" do
|
170
|
-
@r.rpush "list", "hello"
|
171
|
-
@r.rpush "list", "goodbye"
|
172
|
-
@r.rpush "list", "1"
|
173
|
-
@r.rpush "list", "2"
|
174
|
-
@r.rpush "list", "3"
|
175
|
-
assert_equal "list", @r.type("list")
|
176
|
-
assert_equal 5, @r.llen("list")
|
177
|
-
assert_equal ["1", "2", "3"], @r.lrange("list", 2, -1)
|
178
|
-
@r.del("list")
|
179
|
-
end
|
180
|
-
|
181
|
-
should "be able to get all the values from a list" do
|
182
|
-
@r.rpush "list", "1"
|
183
|
-
@r.rpush "list", "2"
|
184
|
-
@r.rpush "list", "3"
|
185
|
-
assert_equal "list", @r.type("list")
|
186
|
-
assert_equal 3, @r.llen("list")
|
187
|
-
assert_equal ["1", "2", "3"], @r.list("list")
|
188
|
-
@r.del("list")
|
189
|
-
end
|
190
|
-
|
191
|
-
should "be able to trim a list" do
|
192
|
-
@r.rpush "list", "hello"
|
193
|
-
@r.rpush "list", "goodbye"
|
194
|
-
@r.rpush "list", "1"
|
195
|
-
@r.rpush "list", "2"
|
196
|
-
@r.rpush "list", "3"
|
197
|
-
assert_equal "list", @r.type("list")
|
198
|
-
assert_equal 5, @r.llen("list")
|
199
|
-
@r.ltrim "list", 0, 1
|
200
|
-
assert_equal 2, @r.llen("list")
|
201
|
-
assert_equal ["hello", "goodbye"], @r.lrange("list", 0, -1)
|
202
|
-
@r.del("list")
|
203
|
-
end
|
204
|
-
|
205
|
-
should "be able to get a value by indexing into a list" do
|
206
|
-
@r.rpush "list", "hello"
|
207
|
-
@r.rpush "list", "goodbye"
|
208
|
-
assert_equal "list", @r.type("list")
|
209
|
-
assert_equal 2, @r.llen("list")
|
210
|
-
assert_equal "goodbye", @r.lindex("list", 1)
|
211
|
-
@r.del("list")
|
212
|
-
end
|
213
|
-
|
214
|
-
should "be able to set a value by indexing into a list" do
|
215
|
-
@r.rpush "list", "hello"
|
216
|
-
@r.rpush "list", "hello"
|
217
|
-
assert_equal "list", @r.type("list")
|
218
|
-
assert_equal 2, @r.llen("list")
|
219
|
-
assert @r.lset("list", 1, "goodbye")
|
220
|
-
assert_equal "goodbye", @r.lindex("list", 1)
|
221
|
-
@r.del("list")
|
222
|
-
end
|
223
|
-
|
224
|
-
should "be able to remove values from a list LREM" do
|
225
|
-
@r.rpush "list", "hello"
|
226
|
-
@r.rpush "list", "goodbye"
|
227
|
-
assert_equal "list", @r.type("list")
|
228
|
-
assert_equal 2, @r.llen("list")
|
229
|
-
assert_equal 1, @r.lrem("list", 1, "hello")
|
230
|
-
assert_equal ["goodbye"], @r.lrange("list", 0, -1)
|
231
|
-
@r.del("list")
|
232
|
-
end
|
233
|
-
|
234
|
-
should "be able to pop values from a list and push them onto a temp list with RPOPLPUSH" do
|
235
|
-
unless @legacy
|
236
|
-
@r.rpush "list", 'one'
|
237
|
-
@r.rpush "list", 'two'
|
238
|
-
@r.rpush "list", 'three'
|
239
|
-
assert_equal "list", @r.type('list')
|
240
|
-
assert_equal 3, @r.llen('list')
|
241
|
-
assert_equal %w(one two three), @r.lrange('list',0,-1)
|
242
|
-
assert_equal [], @r.lrange('tmp',0,-1)
|
243
|
-
assert_equal "three", @r.rpoplpush('list', 'tmp')
|
244
|
-
assert_equal %w(three), @r.lrange('tmp',0,-1)
|
245
|
-
assert_equal "two", @r.rpoplpush('list', 'tmp')
|
246
|
-
assert_equal %w(two three), @r.lrange('tmp',0,-1)
|
247
|
-
assert_equal "one", @r.rpoplpush('list', 'tmp')
|
248
|
-
assert_equal %w(one two three), @r.lrange('tmp',0,-1)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
should "be able add members to a set" do
|
253
|
-
@r.sadd "set", "key1"
|
254
|
-
@r.sadd "set", "key2"
|
255
|
-
assert_equal "set", @r.type("set")
|
256
|
-
assert_equal 2, @r.scard("set")
|
257
|
-
assert_equal ["key1", "key2"], @r.smembers("set").sort
|
258
|
-
@r.del("set")
|
259
|
-
end
|
260
|
-
|
261
|
-
should "be able delete members to a set" do
|
262
|
-
@r.sadd "set", "key1"
|
263
|
-
@r.sadd "set", "key2"
|
264
|
-
assert_equal "set", @r.type("set")
|
265
|
-
assert_equal 2, @r.scard("set")
|
266
|
-
assert_equal ["key1", "key2"], @r.smembers("set").sort
|
267
|
-
@r.srem("set", "key1")
|
268
|
-
assert_equal 1, @r.scard("set")
|
269
|
-
assert_equal ["key2"], @r.smembers("set")
|
270
|
-
@r.del("set")
|
271
|
-
end
|
272
|
-
|
273
|
-
should "be able count the members of a set" do
|
274
|
-
@r.sadd "set", "key1"
|
275
|
-
@r.sadd "set", "key2"
|
276
|
-
assert_equal "set", @r.type("set")
|
277
|
-
assert_equal 2, @r.scard("set")
|
278
|
-
@r.del("set")
|
279
|
-
end
|
280
|
-
|
281
|
-
should "be able test for set membership" do
|
282
|
-
@r.sadd "set", "key1"
|
283
|
-
@r.sadd "set", "key2"
|
284
|
-
assert_equal "set", @r.type("set")
|
285
|
-
assert_equal 2, @r.scard("set")
|
286
|
-
assert @r.sismember("set", "key1")
|
287
|
-
assert @r.sismember("set", "key2")
|
288
|
-
assert_equal false, @r.sismember("set", "notthere")
|
289
|
-
@r.del("set")
|
290
|
-
end
|
291
|
-
|
292
|
-
should "be able to do set intersection" do
|
293
|
-
@r.sadd "set", "key1"
|
294
|
-
@r.sadd "set", "key2"
|
295
|
-
@r.sadd "set2", "key2"
|
296
|
-
assert_equal ["key2"], @r.sinter("set", "set2")
|
297
|
-
@r.del("set")
|
298
|
-
end
|
299
|
-
|
300
|
-
should "be able to do set intersection and store the results in a key" do
|
301
|
-
@r.sadd "set", "key1"
|
302
|
-
@r.sadd "set", "key2"
|
303
|
-
@r.sadd "set2", "key2"
|
304
|
-
@r.sinterstore("newone", "set", "set2")
|
305
|
-
assert_equal ["key2"], @r.smembers("newone")
|
306
|
-
@r.del("set")
|
307
|
-
end
|
308
|
-
|
309
|
-
should "be able to do crazy SORT queries" do
|
310
|
-
@r.set("dog_1", "louie")
|
311
|
-
@r.rpush "dogs", 1
|
312
|
-
@r.set("dog_2", "lucy")
|
313
|
-
@r.rpush "dogs", 2
|
314
|
-
@r.set("dog_3", "max")
|
315
|
-
@r.rpush "dogs", 3
|
316
|
-
@r.set("dog_4", "taj")
|
317
|
-
@r.rpush "dogs", 4
|
318
|
-
assert_equal ["louie"], @r.sort("dogs", :get => "dog_*", :limit => [0,1])
|
319
|
-
assert_equal ["taj"], @r.sort("dogs", :get => "dog_*", :limit => [0,1], :order => "desc alpha")
|
320
|
-
end
|
321
|
-
|
322
|
-
should "be able add members to a zset ZADD" do
|
323
|
-
unless @legacy
|
324
|
-
@r.zadd 'zset', 1, 'set'
|
325
|
-
assert_equal %w(set), @r.zrange('zset', 0, 1)
|
326
|
-
assert_equal 1, @r.zcard('zset')
|
327
|
-
@r.del('zset')
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
should "be able count the members of a zset ZCARD" do
|
332
|
-
unless @legacy
|
333
|
-
@r.zadd 'zset', 1, 'foo'
|
334
|
-
@r.zcard('zset')
|
335
|
-
@r.del('zset')
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
|
340
|
-
should "be able delete members of a zset ZREM" do
|
341
|
-
unless @legacy
|
342
|
-
@r.zadd 'zset', 1, 'set'
|
343
|
-
assert_equal 1, @r.zcard('zset')
|
344
|
-
@r.zadd 'zset', 2, 'set2'
|
345
|
-
assert_equal 2, @r.zcard('zset')
|
346
|
-
@r.zrem 'zset', 'set'
|
347
|
-
assert_equal 1, @r.zcard('zset')
|
348
|
-
@r.del('zset')
|
349
|
-
end
|
350
|
-
end
|
351
|
-
|
352
|
-
should "be able to get a range of values from a zset ZRANGE" do
|
353
|
-
unless @legacy
|
354
|
-
@r.zadd 'zset', 1, 'set'
|
355
|
-
@r.zadd 'zset', 2, 'set2'
|
356
|
-
@r.zadd 'zset', 3, 'set3'
|
357
|
-
assert_equal 3, @r.zcard('zset')
|
358
|
-
assert_equal %w(set set2 set3), @r.zrange('zset', 0, 3)
|
359
|
-
@r.del('set')
|
360
|
-
@r.del('set2')
|
361
|
-
@r.del('set3')
|
362
|
-
@r.del('zset')
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
should "be able to get a reverse range of values from a zset ZREVRANGE" do
|
367
|
-
unless @legacy
|
368
|
-
@r.zadd 'zset', 1, 'set'
|
369
|
-
@r.zadd 'zset', 2, 'set2'
|
370
|
-
@r.zadd 'zset', 3, 'set3'
|
371
|
-
assert_equal 3, @r.zcard('zset')
|
372
|
-
assert_equal %w(set3 set2 set), @r.zrevrange('zset', 0, 3)
|
373
|
-
@r.del('zset')
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
should "be able to get a range by score of values from a zset ZRANGEBYSCORE" do
|
378
|
-
unless @legacy
|
379
|
-
@r.zadd 'zset', 1, 'set'
|
380
|
-
@r.zadd 'zset', 2, 'set2'
|
381
|
-
@r.zadd 'zset', 3, 'set3'
|
382
|
-
@r.zadd 'zset', 4, 'set4'
|
383
|
-
assert_equal 4, @r.zcard('zset')
|
384
|
-
assert_equal %w(set2 set3), @r.zrangebyscore('zset', 2, 3)
|
385
|
-
@r.del('zset')
|
386
|
-
end
|
387
|
-
end
|
388
|
-
|
389
|
-
should "increment by a certain amount the score of a zset ZINCRBY" do
|
390
|
-
assert_equal 0, @r.zcard("league")
|
391
|
-
|
392
|
-
@r.zincrby "league", 1, "foo"
|
393
|
-
assert_equal "1", @r.zscore("league", "foo")
|
394
|
-
|
395
|
-
assert_equal 1, @r.zcard("league")
|
396
|
-
|
397
|
-
@r.zincrby "league", 10, "foo"
|
398
|
-
assert_equal "11", @r.zscore("league", "foo")
|
399
|
-
|
400
|
-
@r.set "bar", "2"
|
401
|
-
assert_raises(RuntimeError) do
|
402
|
-
@r.zincrby "bar", 2, "baz"
|
403
|
-
end
|
404
|
-
end
|
405
|
-
|
406
|
-
should "provide info" do
|
407
|
-
%w(last_save_time redis_version total_connections_received connected_clients total_commands_processed connected_slaves uptime_in_seconds used_memory uptime_in_days changes_since_last_save).each do |x|
|
408
|
-
assert @r.info.keys.include?(x)
|
409
|
-
end
|
410
|
-
end
|
411
|
-
|
412
|
-
should "be able to flush the database" do
|
413
|
-
@r.set("key1", "keyone")
|
414
|
-
@r.set("key2", "keytwo")
|
415
|
-
assert_equal ["foo", "key1", "key2"], @r.keys("*").sort #foo from before
|
416
|
-
@r.flushdb
|
417
|
-
assert_equal [], @r.keys("*")
|
418
|
-
end
|
419
|
-
|
420
|
-
should "be able to provide the last save time" do
|
421
|
-
savetime = @r.lastsave
|
422
|
-
assert_equal Time, Time.at(savetime).class
|
423
|
-
assert Time.at(savetime) <= Time.now
|
424
|
-
end
|
425
|
-
|
426
|
-
should "bgsave" do
|
427
|
-
assert_nothing_raised do
|
428
|
-
@r.bgsave
|
429
|
-
end
|
430
|
-
end
|
431
|
-
end
|
432
|
-
end
|