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 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
+