em-redislite 0.1
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.rdoc +42 -0
- data/em-redislite.gemspec +16 -0
- data/lib/em/redis/sugar.rb +34 -0
- data/lib/em/redis.rb +102 -0
- data/lib/em-redislite.rb +2 -0
- data/tests/helper.rb +15 -0
- data/tests/test_command_expire.rb +21 -0
- data/tests/test_commands.rb +74 -0
- data/tests/test_connection.rb +22 -0
- metadata +83 -0
data/README.rdoc
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
= Redis Lite
|
2
|
+
|
3
|
+
Eventmachine based adapter that talks redis 2.0 protocol
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
gem install em-redislite
|
8
|
+
|
9
|
+
=== Dependencies
|
10
|
+
|
11
|
+
* Ruby >= 1.9.1
|
12
|
+
* eventmachine
|
13
|
+
|
14
|
+
== Usage
|
15
|
+
|
16
|
+
require 'em/redislite'
|
17
|
+
|
18
|
+
EM.run do
|
19
|
+
client = EM::Redis.connect # defaults to { host: '127.0.0.1', port: 6379 }
|
20
|
+
client.errback {|error| $stderr.puts "Redis Error: #{error}"; EM.stop }
|
21
|
+
|
22
|
+
r = client.command :get, "mykey"
|
23
|
+
r.callback {|value| p value }
|
24
|
+
r.errback {|error| p error }
|
25
|
+
|
26
|
+
# syntactic sugar for string and boolean commands
|
27
|
+
r = client.get "mykey"
|
28
|
+
r = client.set "mykey", "some value", 1800 # ttl
|
29
|
+
|
30
|
+
# you should be running redis in a private network or have it firewalled but ...
|
31
|
+
r = client.command :auth, "my super dooper password" # should work as well
|
32
|
+
end
|
33
|
+
|
34
|
+
== Testing
|
35
|
+
|
36
|
+
There are no tests at the moment coz I'm a lazy slob.
|
37
|
+
|
38
|
+
== License
|
39
|
+
|
40
|
+
GNU GPLv3, so its free and comes with no guarantees. If it brings down your website or burns down your house, I will
|
41
|
+
not be held responsible. Use it at your own risk. You can read all about GNU here: http://www.gnu.org and
|
42
|
+
GNU GPLv3 here: http://www.gnu.org/licenses/gpl.txt.
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{em-redislite}
|
5
|
+
s.version = '0.1'
|
6
|
+
s.summary = 'A lightweight EM based Redis adapter'
|
7
|
+
s.description = 'A very simple EventMachine based adapter that talks Redis protocol'
|
8
|
+
s.authors = [ 'Bharanee Rathna' ]
|
9
|
+
s.email = %q{deepfryed@gmail.com}
|
10
|
+
s.homepage = %q{http://github.com/deepfryed/em-redislite}
|
11
|
+
s.files = %w(README.rdoc em-redislite.gemspec) + Dir.glob("{lib,tests}/**/*")
|
12
|
+
s.require_paths = %w(lib)
|
13
|
+
s.platform = Gem::Platform::RUBY
|
14
|
+
|
15
|
+
s.add_dependency('eventmachine')
|
16
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class EM::Redis::Client
|
2
|
+
COMMANDS = {
|
3
|
+
string: %w(get strlen getset setnx setex setbit getbit mset msetnx mget incr incrby decr decrby
|
4
|
+
append setrange getrange),
|
5
|
+
boolean: %w(exists del type keys randomkey rename renamenx dbsize expire persist ttl select move
|
6
|
+
flushdb flushall),
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
COMMANDS[:string].each {|c| send(:define_method, c) {|*args| command(c, *args) }}
|
10
|
+
COMMANDS[:boolean].each {|c| send(:define_method, c) {|*args|
|
11
|
+
defer = EM::DefaultDeferrable.new
|
12
|
+
req = command(c, *args)
|
13
|
+
req.callback {|r| defer.succeed(r == '1') }
|
14
|
+
req.errback {|e| defer.fail(e) }
|
15
|
+
defer
|
16
|
+
}}
|
17
|
+
|
18
|
+
# set here is special since it combines :set and optional :expire
|
19
|
+
def set key, value, ttl = nil
|
20
|
+
if ttl
|
21
|
+
defer = EM::DefaultDeferrable.new
|
22
|
+
req = command(:set, key, value)
|
23
|
+
req.callback do
|
24
|
+
req = command(:expire, key, ttl)
|
25
|
+
req.callback {|r| defer.succeed(r == '1') }
|
26
|
+
req.errback {|e| defer.fail(e) }
|
27
|
+
end
|
28
|
+
req.errback {|e| defer.fail(e) }
|
29
|
+
defer
|
30
|
+
else
|
31
|
+
command(:set, key, value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/em/redis.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
module EM
|
3
|
+
module Redis
|
4
|
+
class Error < StandardError; end
|
5
|
+
|
6
|
+
DEFAULTS = { host: '127.0.0.1', port: 6379 }
|
7
|
+
|
8
|
+
def self.connect options = {}
|
9
|
+
options = DEFAULTS.merge(options)
|
10
|
+
begin
|
11
|
+
EM.connect options[:host], options[:port], Client, { host: options[:host], port: options[:port] }
|
12
|
+
rescue ConnectionError => e
|
13
|
+
client = Client.new ''
|
14
|
+
client.fail(Error.new(e.message))
|
15
|
+
client
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Client < Connection
|
20
|
+
include Deferrable
|
21
|
+
|
22
|
+
def initialize options
|
23
|
+
@options = options
|
24
|
+
end
|
25
|
+
|
26
|
+
def post_init
|
27
|
+
@buffer = ''
|
28
|
+
@want_bytes = 0
|
29
|
+
@want_lines = 0
|
30
|
+
@pool = []
|
31
|
+
@lines = []
|
32
|
+
end
|
33
|
+
|
34
|
+
def command name, *args
|
35
|
+
defer = DefaultDeferrable.new
|
36
|
+
@pool << defer
|
37
|
+
send_data "*#{args.length + 1}\r\n" +
|
38
|
+
"$#{name.length}\r\n#{name}\r\n" +
|
39
|
+
args.map(&:to_s).inject('') {|a,v| a + "$#{v.bytesize}\r\n#{v}\r\n"}
|
40
|
+
defer
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_error msg, dns_error = false
|
44
|
+
unbind(msg)
|
45
|
+
end
|
46
|
+
|
47
|
+
def reset_errback &block
|
48
|
+
@errbacks = [ block ]
|
49
|
+
end
|
50
|
+
|
51
|
+
def reconnect!
|
52
|
+
EM.reconnect @options[:host], @options[:port], self
|
53
|
+
end
|
54
|
+
|
55
|
+
def unbind msg = 'lost connection'
|
56
|
+
error = Error.new(msg)
|
57
|
+
@pool.each {|r| r.fail(error) }
|
58
|
+
@pool = []
|
59
|
+
fail error
|
60
|
+
end
|
61
|
+
|
62
|
+
def receive_data data
|
63
|
+
@buffer << data
|
64
|
+
while index = @buffer.index("\r\n")
|
65
|
+
if @want_bytes > 0
|
66
|
+
break unless @buffer.bytesize >= @want_bytes + 2
|
67
|
+
data = @buffer.slice!(0, @want_bytes + 2)
|
68
|
+
process_bytes(data[0..@want_bytes-1])
|
69
|
+
else
|
70
|
+
process_response @buffer.slice!(0, index+2).strip
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def process_bytes data
|
76
|
+
@want_bytes = 0
|
77
|
+
if @want_lines > 0
|
78
|
+
@lines.push(data)
|
79
|
+
if @lines.length == @want_lines
|
80
|
+
@pool.shift.succeed(@lines)
|
81
|
+
@lines, @want_lines = [], 0
|
82
|
+
end
|
83
|
+
else
|
84
|
+
@pool.shift.succeed(data)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_response data
|
89
|
+
case data[0]
|
90
|
+
when '+' then @pool.shift.succeed(data[1..-1])
|
91
|
+
when '-' then @pool.shift.fail(Error.new(data[1..-1]))
|
92
|
+
when ':' then @pool.shift.succeed(data[1..-1])
|
93
|
+
when '$' then @want_bytes = data[1..-1].to_i
|
94
|
+
when '*' then @want_lines = data[1..-1].to_i
|
95
|
+
else fail Error.new("Unknown data format: #{data}")
|
96
|
+
end
|
97
|
+
|
98
|
+
process_bytes(nil) if @want_bytes < 0
|
99
|
+
end
|
100
|
+
end # Client
|
101
|
+
end # Redis
|
102
|
+
end # EM
|
data/lib/em-redislite.rb
ADDED
data/tests/helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'minitest/spec'
|
2
|
+
require_relative '../lib/em-redislite'
|
3
|
+
|
4
|
+
class MiniTest::Unit::TestCase
|
5
|
+
def em_run &block
|
6
|
+
EM.run do
|
7
|
+
client = EM::Redis.connect
|
8
|
+
r = client.command :flushdb
|
9
|
+
r.callback {|value| block.yield(client) }
|
10
|
+
r.errback {|error| $stderr.puts error.inspect; Kernel.exit(1) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
MiniTest::Unit.autorun
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
describe 'Command Expire' do
|
4
|
+
it 'should support set with expiry' do
|
5
|
+
@success = false
|
6
|
+
em_run do |client|
|
7
|
+
r = client.set 'mykey', 'foobar', 1
|
8
|
+
r = client.get 'mykey'
|
9
|
+
r.callback do |value|
|
10
|
+
EM.stop unless value == 'foobar'
|
11
|
+
EM.add_timer(2) do
|
12
|
+
r = client.get 'mykey'
|
13
|
+
r.callback {|value| @success = assert_nil value; EM.stop }
|
14
|
+
r.errback {|error| EM.stop }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
r.errback {|error| EM.stop }
|
18
|
+
end
|
19
|
+
assert @success
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
describe 'Commands' do
|
4
|
+
it 'should support set' do
|
5
|
+
@success = false
|
6
|
+
em_run do |client|
|
7
|
+
r = client.set 'mykey', 'foobar'
|
8
|
+
r.callback {|value| @success = assert_equal 'OK', value; EM.stop }
|
9
|
+
r.errback {|error| EM.stop }
|
10
|
+
end
|
11
|
+
assert @success
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should support get' do
|
15
|
+
@success = false
|
16
|
+
em_run do |client|
|
17
|
+
r = client.set 'mykey', 'foo1234'
|
18
|
+
r = client.get 'mykey'
|
19
|
+
r.callback {|value| @success = assert_equal 'foo1234', value; EM.stop }
|
20
|
+
r.errback {|error| EM.stop }
|
21
|
+
end
|
22
|
+
assert @success
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should support get with nil' do
|
26
|
+
@success = false
|
27
|
+
em_run do |client|
|
28
|
+
r = client.get 'mykey1234'
|
29
|
+
r.callback {|value| @success = assert_nil value; EM.stop }
|
30
|
+
r.errback {|error| EM.stop }
|
31
|
+
end
|
32
|
+
assert @success
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should support mget' do
|
36
|
+
@success = false
|
37
|
+
em_run do |client|
|
38
|
+
r = client.set 'mykey1', 'foo1234'
|
39
|
+
r = client.set 'mykey2', 'bar1234'
|
40
|
+
r = client.mget 'mykey1', 'mykey2'
|
41
|
+
|
42
|
+
r.callback {|value| @success = assert_equal %w(foo1234 bar1234), value; EM.stop }
|
43
|
+
r.errback {|error| EM.stop }
|
44
|
+
end
|
45
|
+
assert @success
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should support incr and incrby' do
|
49
|
+
@success = false
|
50
|
+
em_run do |client|
|
51
|
+
client.incr 'mykey'
|
52
|
+
client.incrby 'mykey', 2
|
53
|
+
|
54
|
+
r = client.get 'mykey'
|
55
|
+
r.callback {|value| @success = assert_equal '3', value; EM.stop }
|
56
|
+
r.errback {|error| EM.stop }
|
57
|
+
end
|
58
|
+
assert @success
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should support decr and decrby' do
|
62
|
+
@success = false
|
63
|
+
em_run do |client|
|
64
|
+
client.set 'mykey', 5
|
65
|
+
client.decr 'mykey'
|
66
|
+
client.decrby 'mykey', 2
|
67
|
+
|
68
|
+
r = client.get 'mykey'
|
69
|
+
r.callback {|value| @success = assert_equal '2', value; EM.stop }
|
70
|
+
r.errback {|error| EM.stop }
|
71
|
+
end
|
72
|
+
assert @success
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
describe 'Connection' do
|
4
|
+
it 'should connect and return a client' do
|
5
|
+
EM.run {
|
6
|
+
client = EM::Redis.connect
|
7
|
+
assert_kind_of EM::Redis::Client, client
|
8
|
+
EM.stop
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should defer fail on failed connection' do
|
13
|
+
EM.run {
|
14
|
+
failed = false
|
15
|
+
client = EM::Redis.connect host: 'tardis', port: 0
|
16
|
+
assert_kind_of EM::Redis::Client, client
|
17
|
+
client.errback { failed = true }
|
18
|
+
assert failed
|
19
|
+
EM.stop
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: em-redislite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Bharanee Rathna
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2010-12-19 00:00:00 +11:00
|
17
|
+
default_executable:
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: eventmachine
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
type: :runtime
|
31
|
+
version_requirements: *id001
|
32
|
+
description: A very simple EventMachine based adapter that talks Redis protocol
|
33
|
+
email: deepfryed@gmail.com
|
34
|
+
executables: []
|
35
|
+
|
36
|
+
extensions: []
|
37
|
+
|
38
|
+
extra_rdoc_files: []
|
39
|
+
|
40
|
+
files:
|
41
|
+
- README.rdoc
|
42
|
+
- em-redislite.gemspec
|
43
|
+
- lib/em-redislite.rb
|
44
|
+
- lib/em/redis/sugar.rb
|
45
|
+
- lib/em/redis.rb
|
46
|
+
- tests/helper.rb
|
47
|
+
- tests/test_command_expire.rb
|
48
|
+
- tests/test_commands.rb
|
49
|
+
- tests/test_connection.rb
|
50
|
+
has_rdoc: true
|
51
|
+
homepage: http://github.com/deepfryed/em-redislite
|
52
|
+
licenses: []
|
53
|
+
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
version: "0"
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
requirements: []
|
76
|
+
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 1.3.7
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: A lightweight EM based Redis adapter
|
82
|
+
test_files: []
|
83
|
+
|