sinatra-redis 0.2.0 → 0.3.0
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/README.md +1 -1
- data/lib/sinatra/redis.rb +7 -6
- data/sinatra-redis.gemspec +1 -2
- metadata +25 -13
- data/lib/sinatra/redis/rubyredis.rb +0 -243
data/README.md
CHANGED
@@ -2,7 +2,7 @@ Sinatra Redis Extension
|
|
2
2
|
========================
|
3
3
|
|
4
4
|
Extends [Sinatra](http://www.sinatrarb.com/) with an extension method for
|
5
|
-
dealing with redis databases using the
|
5
|
+
dealing with redis databases using the [redis-rb](http://github.com/ezmobius/redis-rb) client library that
|
6
6
|
comes with the redis source (pre-packaged with this library for convenience).
|
7
7
|
You can Install the `sinatra-redis` with rip
|
8
8
|
|
data/lib/sinatra/redis.rb
CHANGED
@@ -4,7 +4,7 @@ require 'redis'
|
|
4
4
|
module Sinatra
|
5
5
|
module RedisHelper
|
6
6
|
def redis
|
7
|
-
|
7
|
+
settings.redis
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -16,9 +16,10 @@ module Sinatra
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def redis
|
19
|
-
url = URI(redis_url)
|
20
19
|
@redis ||= (
|
21
|
-
|
20
|
+
url = URI(redis_url)
|
21
|
+
|
22
|
+
base_settings = {
|
22
23
|
:host => url.host,
|
23
24
|
:port => url.port,
|
24
25
|
:db => url.path[1..-1],
|
@@ -26,8 +27,8 @@ module Sinatra
|
|
26
27
|
}
|
27
28
|
|
28
29
|
::Redis.new(
|
29
|
-
|
30
|
-
|
30
|
+
base_settings.merge(
|
31
|
+
redis_settings
|
31
32
|
)
|
32
33
|
)
|
33
34
|
)
|
@@ -37,7 +38,7 @@ module Sinatra
|
|
37
38
|
|
38
39
|
def self.registered(app)
|
39
40
|
app.set :redis_url, ENV['REDIS_URL'] || "redis://127.0.0.1:6379/0"
|
40
|
-
app.set :
|
41
|
+
app.set :redis_settings, {}
|
41
42
|
app.helpers RedisHelper
|
42
43
|
end
|
43
44
|
end
|
data/sinatra-redis.gemspec
CHANGED
@@ -3,7 +3,7 @@ Gem::Specification.new do |s|
|
|
3
3
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
4
|
|
5
5
|
s.name = 'sinatra-redis'
|
6
|
-
s.version = '0.
|
6
|
+
s.version = '0.3.0'
|
7
7
|
s.date = '2009-09-21'
|
8
8
|
|
9
9
|
s.description = "Extends Sinatra with redis helpers for instant redis use"
|
@@ -18,7 +18,6 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.files = %w[
|
19
19
|
README.md
|
20
20
|
lib/sinatra/redis.rb
|
21
|
-
lib/sinatra/redis/rubyredis.rb
|
22
21
|
sinatra-redis.gemspec
|
23
22
|
]
|
24
23
|
# = MANIFEST =
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinatra-redis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 3
|
8
|
+
- 0
|
9
|
+
version: 0.3.0
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Blake Mizerany
|
@@ -14,24 +19,30 @@ default_executable:
|
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: redis
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
23
29
|
version: "0"
|
24
|
-
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
25
32
|
- !ruby/object:Gem::Dependency
|
26
33
|
name: sinatra
|
27
|
-
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
36
|
requirements:
|
31
37
|
- - ">="
|
32
38
|
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
- 9
|
42
|
+
- 4
|
33
43
|
version: 0.9.4
|
34
|
-
|
44
|
+
type: :runtime
|
45
|
+
version_requirements: *id002
|
35
46
|
description: Extends Sinatra with redis helpers for instant redis use
|
36
47
|
email: blake.mizerany@gmail.com
|
37
48
|
executables: []
|
@@ -43,7 +54,6 @@ extra_rdoc_files:
|
|
43
54
|
files:
|
44
55
|
- README.md
|
45
56
|
- lib/sinatra/redis.rb
|
46
|
-
- lib/sinatra/redis/rubyredis.rb
|
47
57
|
- sinatra-redis.gemspec
|
48
58
|
has_rdoc: true
|
49
59
|
homepage: http://github.com/rtomayko/sinatra-redis
|
@@ -61,18 +71,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
61
71
|
requirements:
|
62
72
|
- - ">="
|
63
73
|
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 0
|
64
76
|
version: "0"
|
65
|
-
version:
|
66
77
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
78
|
requirements:
|
68
79
|
- - ">="
|
69
80
|
- !ruby/object:Gem::Version
|
81
|
+
segments:
|
82
|
+
- 0
|
70
83
|
version: "0"
|
71
|
-
version:
|
72
84
|
requirements: []
|
73
85
|
|
74
86
|
rubyforge_project: bmizerany
|
75
|
-
rubygems_version: 1.3.
|
87
|
+
rubygems_version: 1.3.6
|
76
88
|
signing_key:
|
77
89
|
specification_version: 2
|
78
90
|
summary: Extends Sinatra with redis helpers for instant redis use
|
@@ -1,243 +0,0 @@
|
|
1
|
-
# NOTE: This library is packaged with sinatra-redis for
|
2
|
-
# convenence. It's been copied from the redis repo.
|
3
|
-
|
4
|
-
# RubyRedis is an alternative implementatin of Ruby client library written
|
5
|
-
# by Salvatore Sanfilippo.
|
6
|
-
#
|
7
|
-
# The aim of this library is to create an alternative client library that is
|
8
|
-
# much simpler and does not implement every command explicitly but uses
|
9
|
-
# method_missing instead.
|
10
|
-
|
11
|
-
require 'socket'
|
12
|
-
require 'set'
|
13
|
-
|
14
|
-
begin
|
15
|
-
if (RUBY_VERSION >= '1.9')
|
16
|
-
require 'timeout'
|
17
|
-
RedisTimer = Timeout
|
18
|
-
else
|
19
|
-
require 'system_timer'
|
20
|
-
RedisTimer = SystemTimer
|
21
|
-
end
|
22
|
-
rescue LoadError
|
23
|
-
RedisTimer = nil
|
24
|
-
end
|
25
|
-
|
26
|
-
class RedisClient
|
27
|
-
BulkCommands = {
|
28
|
-
"set"=>true, "setnx"=>true, "rpush"=>true, "lpush"=>true, "lset"=>true,
|
29
|
-
"lrem"=>true, "sadd"=>true, "srem"=>true, "sismember"=>true,
|
30
|
-
"echo"=>true, "getset"=>true, "smove"=>true
|
31
|
-
}
|
32
|
-
|
33
|
-
ConvertToBool = lambda{|r| r == 0 ? false : r}
|
34
|
-
|
35
|
-
ReplyProcessor = {
|
36
|
-
"exists" => ConvertToBool,
|
37
|
-
"sismember"=> ConvertToBool,
|
38
|
-
"sadd"=> ConvertToBool,
|
39
|
-
"srem"=> ConvertToBool,
|
40
|
-
"smove"=> ConvertToBool,
|
41
|
-
"move"=> ConvertToBool,
|
42
|
-
"setnx"=> ConvertToBool,
|
43
|
-
"del"=> ConvertToBool,
|
44
|
-
"renamenx"=> ConvertToBool,
|
45
|
-
"expire"=> ConvertToBool,
|
46
|
-
"keys" => lambda{|r| r.split(" ")},
|
47
|
-
"info" => lambda{|r|
|
48
|
-
info = {}
|
49
|
-
r.each_line {|kv|
|
50
|
-
k,v = kv.split(":",2).map{|x| x.chomp}
|
51
|
-
info[k.to_sym] = v
|
52
|
-
}
|
53
|
-
info
|
54
|
-
}
|
55
|
-
}
|
56
|
-
|
57
|
-
Aliases = {
|
58
|
-
"flush_db" => "flushdb",
|
59
|
-
"flush_all" => "flushall",
|
60
|
-
"last_save" => "lastsave",
|
61
|
-
"key?" => "exists",
|
62
|
-
"delete" => "del",
|
63
|
-
"randkey" => "randomkey",
|
64
|
-
"list_length" => "llen",
|
65
|
-
"push_tail" => "rpush",
|
66
|
-
"push_head" => "lpush",
|
67
|
-
"pop_tail" => "rpop",
|
68
|
-
"pop_head" => "lpop",
|
69
|
-
"list_set" => "lset",
|
70
|
-
"list_range" => "lrange",
|
71
|
-
"list_trim" => "ltrim",
|
72
|
-
"list_index" => "lindex",
|
73
|
-
"list_rm" => "lrem",
|
74
|
-
"set_add" => "sadd",
|
75
|
-
"set_delete" => "srem",
|
76
|
-
"set_count" => "scard",
|
77
|
-
"set_member?" => "sismember",
|
78
|
-
"set_members" => "smembers",
|
79
|
-
"set_intersect" => "sinter",
|
80
|
-
"set_intersect_store" => "sinterstore",
|
81
|
-
"set_inter_store" => "sinterstore",
|
82
|
-
"set_union" => "sunion",
|
83
|
-
"set_union_store" => "sunionstore",
|
84
|
-
"set_diff" => "sdiff",
|
85
|
-
"set_diff_store" => "sdiffstore",
|
86
|
-
"set_move" => "smove",
|
87
|
-
"set_unless_exists" => "setnx",
|
88
|
-
"rename_unless_exists" => "renamenx"
|
89
|
-
}
|
90
|
-
|
91
|
-
def initialize(opts={})
|
92
|
-
@host = opts[:host] || '127.0.0.1'
|
93
|
-
@port = opts[:port] || 6379
|
94
|
-
@db = opts[:db] || 0
|
95
|
-
@timeout = opts[:timeout] || 0
|
96
|
-
@pass = opts[:pass] || ""
|
97
|
-
connect_to_server
|
98
|
-
end
|
99
|
-
|
100
|
-
def to_s
|
101
|
-
"Redis Client connected to #{@host}:#{@port} against DB #{@db}"
|
102
|
-
end
|
103
|
-
|
104
|
-
def connect_to_server
|
105
|
-
@sock = connect_to(@host,@port,@timeout == 0 ? nil : @timeout)
|
106
|
-
call_command(["auth",@pass]) if !@pass.empty?
|
107
|
-
call_command(["select",@db]) if @db != 0
|
108
|
-
end
|
109
|
-
|
110
|
-
def connect_to(host, port, timeout=nil)
|
111
|
-
# We support connect() timeout only if system_timer is availabe
|
112
|
-
# or if we are running against Ruby >= 1.9
|
113
|
-
# Timeout reading from the socket instead will be supported anyway.
|
114
|
-
if @timeout != 0 and RedisTimer
|
115
|
-
begin
|
116
|
-
sock = TCPSocket.new(host, port, 0)
|
117
|
-
rescue Timeout::Error
|
118
|
-
@sock = nil
|
119
|
-
raise Timeout::Error, "Timeout connecting to the server"
|
120
|
-
end
|
121
|
-
else
|
122
|
-
sock = TCPSocket.new(host, port, 0)
|
123
|
-
end
|
124
|
-
sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
|
125
|
-
|
126
|
-
# If the timeout is set we set the low level socket options in order
|
127
|
-
# to make sure a blocking read will return after the specified number
|
128
|
-
# of seconds. This hack is from memcached ruby client.
|
129
|
-
if timeout
|
130
|
-
secs = Integer(timeout)
|
131
|
-
usecs = Integer((timeout - secs) * 1_000_000)
|
132
|
-
optval = [secs, usecs].pack("l_2")
|
133
|
-
sock.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, optval
|
134
|
-
sock.setsockopt Socket::SOL_SOCKET, Socket::SO_SNDTIMEO, optval
|
135
|
-
end
|
136
|
-
sock
|
137
|
-
end
|
138
|
-
|
139
|
-
def method_missing(*argv)
|
140
|
-
call_command(argv)
|
141
|
-
end
|
142
|
-
|
143
|
-
def call_command(argv)
|
144
|
-
# this wrapper to raw_call_command handle reconnection on socket
|
145
|
-
# error. We try to reconnect just one time, otherwise let the error
|
146
|
-
# araise.
|
147
|
-
connect_to_server if !@sock
|
148
|
-
begin
|
149
|
-
raw_call_command(argv)
|
150
|
-
rescue Errno::ECONNRESET
|
151
|
-
@sock.close
|
152
|
-
connect_to_server
|
153
|
-
raw_call_command(argv)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def raw_call_command(argv)
|
158
|
-
bulk = nil
|
159
|
-
argv[0] = argv[0].to_s.downcase
|
160
|
-
argv[0] = Aliases[argv[0]] if Aliases[argv[0]]
|
161
|
-
if BulkCommands[argv[0]] and argv.length > 1
|
162
|
-
bulk = argv[-1].to_s
|
163
|
-
argv[-1] = bulk.length
|
164
|
-
end
|
165
|
-
@sock.write(argv.join(" ")+"\r\n")
|
166
|
-
@sock.write(bulk+"\r\n") if bulk
|
167
|
-
|
168
|
-
# Post process the reply if needed
|
169
|
-
processor = ReplyProcessor[argv[0]]
|
170
|
-
processor ? processor.call(read_reply) : read_reply
|
171
|
-
end
|
172
|
-
|
173
|
-
def select(*args)
|
174
|
-
raise "SELECT not allowed, use the :db option when creating the object"
|
175
|
-
end
|
176
|
-
|
177
|
-
def [](key)
|
178
|
-
get(key)
|
179
|
-
end
|
180
|
-
|
181
|
-
def []=(key,value)
|
182
|
-
set(key,value)
|
183
|
-
end
|
184
|
-
|
185
|
-
def sort(key, opts={})
|
186
|
-
cmd = []
|
187
|
-
cmd << "SORT #{key}"
|
188
|
-
cmd << "BY #{opts[:by]}" if opts[:by]
|
189
|
-
cmd << "GET #{[opts[:get]].flatten * ' GET '}" if opts[:get]
|
190
|
-
cmd << "#{opts[:order]}" if opts[:order]
|
191
|
-
cmd << "LIMIT #{opts[:limit].join(' ')}" if opts[:limit]
|
192
|
-
call_command(cmd)
|
193
|
-
end
|
194
|
-
|
195
|
-
def incr(key,increment=nil)
|
196
|
-
call_command(increment ? ["incrby",key,increment] : ["incr",key])
|
197
|
-
end
|
198
|
-
|
199
|
-
def decr(key,decrement=nil)
|
200
|
-
call_command(decrement ? ["decrby",key,decrement] : ["decr",key])
|
201
|
-
end
|
202
|
-
|
203
|
-
def read_reply
|
204
|
-
# We read the first byte using read() mainly because gets() is
|
205
|
-
# immune to raw socket timeouts.
|
206
|
-
begin
|
207
|
-
rtype = @sock.read(1)
|
208
|
-
rescue Errno::EAGAIN
|
209
|
-
# We want to make sure it reconnects on the next command after the
|
210
|
-
# timeout. Otherwise the server may reply in the meantime leaving
|
211
|
-
# the protocol in a desync status.
|
212
|
-
@sock = nil
|
213
|
-
raise Errno::EAGAIN, "Timeout reading from the socket"
|
214
|
-
end
|
215
|
-
|
216
|
-
raise Errno::ECONNRESET,"Connection lost" if !rtype
|
217
|
-
line = @sock.gets
|
218
|
-
case rtype
|
219
|
-
when "-"
|
220
|
-
raise "-"+line.strip
|
221
|
-
when "+"
|
222
|
-
line.strip
|
223
|
-
when ":"
|
224
|
-
line.to_i
|
225
|
-
when "$"
|
226
|
-
bulklen = line.to_i
|
227
|
-
return nil if bulklen == -1
|
228
|
-
data = @sock.read(bulklen)
|
229
|
-
@sock.read(2) # CRLF
|
230
|
-
data
|
231
|
-
when "*"
|
232
|
-
objects = line.to_i
|
233
|
-
return nil if bulklen == -1
|
234
|
-
res = []
|
235
|
-
objects.times {
|
236
|
-
res << read_reply
|
237
|
-
}
|
238
|
-
res
|
239
|
-
else
|
240
|
-
raise "Protocol error, got '#{rtype}' as initial reply byte"
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|