em-redislite 0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,2 @@
1
+ require_relative 'em/redis'
2
+ require_relative 'em/redis/sugar'
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
+