ruby-redis-portertech 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,47 @@
1
+ module Redis
2
+ module Sender
3
+
4
+ def send_redis data
5
+ collect = []
6
+ if Symbol === data
7
+ collect << data
8
+ elsif NilClass === data
9
+ collect << :'$-1'
10
+ elsif FalseClass === data
11
+ collect << :':0'
12
+ elsif TrueClass === data
13
+ collect << :':1'
14
+ elsif Float === data and data.nan?
15
+ collect << :':0'
16
+ elsif Float === data and (data.infinite? || 0) > 0
17
+ collect << :':inf'
18
+ elsif Float === data and (data.infinite? || 0) < 0
19
+ collect << :':-inf'
20
+ elsif Hash === data
21
+ collect << "*#{data.size * 2}"
22
+ data.each do |key, value|
23
+ key = key.to_s
24
+ value = value.to_s
25
+ collect << "$#{key.bytesize}"
26
+ collect << key
27
+ collect << "$#{value.bytesize}"
28
+ collect << value
29
+ end
30
+ elsif Enumerable === data and !(String === data)
31
+ collect << "*#{data.size}"
32
+ data.each do |element|
33
+ element = element.to_s
34
+ collect << "$#{element.bytesize}"
35
+ collect << element
36
+ end
37
+ else
38
+ data = data.to_s
39
+ collect << "$#{data.bytesize}"
40
+ collect << data
41
+ end
42
+ collect << ''
43
+ send_data collect.join "\r\n"
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,60 @@
1
+ module Redis
2
+
3
+ module Server
4
+
5
+ def redis_FLUSHDB
6
+ @database.clear
7
+ :'+OK'
8
+ end
9
+
10
+ def redis_FLUSHALL
11
+ @databases.each do |database|
12
+ database.clear
13
+ end
14
+ :'+OK'
15
+ end
16
+
17
+ def redis_DBSIZE
18
+ @database.size
19
+ end
20
+
21
+ def redis_DEBUG type, key=nil
22
+ if type.upcase == 'OBJECT'
23
+ "#{@database[key].class}"
24
+ value = @database[key]
25
+ # encoding values are meaningless, they make tcl tests pass
26
+ # and don't forget they need a trailing space
27
+ if String === value
28
+ "Value #{value.class}:#{value.object_id} encoding:raw encoding:int "
29
+ elsif Numeric === value
30
+ "Value #{value.class}:#{value.object_id} encoding:int "
31
+ elsif Array === value
32
+ "Value #{value.class}:#{value.object_id} encoding:ziplist encoding:linkedlist "
33
+ elsif Hash === value
34
+ "Value #{value.class}:#{value.object_id} encoding:zipmap encoding:hashtable "
35
+ elsif Set === value
36
+ "Value #{value.class}:#{value.object_id} encoding:intset encoding:hashtable "
37
+ else
38
+ "Value #{value.class}:#{value.object_id}"
39
+ end
40
+ elsif type.upcase == 'RELOAD'
41
+ "TODO: what is reload"
42
+ else
43
+ raise 'not supported'
44
+ end
45
+ end
46
+
47
+ def redis_INFO
48
+ [
49
+ "redis_version:%s\r\n",
50
+ "redis_git_sha1:%s\r\n",
51
+ "redis_git_dirty:%d\r\n",
52
+ ].join % [
53
+ Redis::VERSION,
54
+ "Ruby",
55
+ 1,
56
+ ]
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,104 @@
1
+ require 'set'
2
+
3
+ module Redis
4
+ module Sets
5
+
6
+ def redis_SADD key, member
7
+ record = (@database[key] ||= Set.new)
8
+ redis_t Set, record
9
+ return false if record.include? member
10
+ record.add member
11
+ true
12
+ end
13
+
14
+ def redis_SREM key, member
15
+ record = @database[key] || []
16
+ return false unless record.include? member
17
+ record.delete member
18
+ @database.delete key if record.empty?
19
+ return true
20
+ end
21
+
22
+ # Type checks are only to make tests pass
23
+ def redis_SMOVE source, destination, member
24
+ source_record = @database[source] || Set.new
25
+ dest_record = @database[destination]
26
+ redis_t Set, source_record
27
+ redis_t NilClass, Set, dest_record
28
+ return false unless source_record.include? member
29
+ (@database[destination] ||= Set.new).add member
30
+ source_record.delete member
31
+ @database.delete source if source_record.empty?
32
+ return true
33
+ end
34
+
35
+ def redis_SCARD key
36
+ (@database[key] || []).size
37
+ end
38
+
39
+ def redis_SISMEMBER key, member
40
+ (@database[key] || []).include? member
41
+ end
42
+
43
+ def redis_SMEMBERS key
44
+ (@database[key] || []).to_a
45
+ end
46
+
47
+ def redis_SINTER *keys
48
+ keys.each { |key| redis_t NilClass, Array, Set, @database[key] }
49
+ keys.reduce(nil) do |memo, key|
50
+ memo ? memo & (@database[key]||[]) : (@database[key]||Set.new)
51
+ end
52
+ end
53
+
54
+ def redis_SINTERSTORE destination, *keys
55
+ record = redis_SINTER *keys
56
+ if record.empty?
57
+ @database.delete destination
58
+ else
59
+ @database[destination] = record
60
+ end
61
+ record.size
62
+ end
63
+
64
+ def redis_SUNION *keys
65
+ keys.each { |key| redis_t NilClass, Array, Set, @database[key] }
66
+ keys.reduce(Set.new) { |memo, key| memo | (@database[key]||[]) }
67
+ end
68
+
69
+ def redis_SUNIONSTORE destination, *keys
70
+ record = redis_SUNION *keys
71
+ if record.empty?
72
+ @database.delete destination
73
+ else
74
+ @database[destination] = record
75
+ end
76
+ record.size
77
+ end
78
+
79
+ def redis_SDIFF *keys
80
+ keys.reduce(nil) { |memo, key| memo ? memo - (@database[key]||[]) : (@database[key]||Set.new) }
81
+ end
82
+
83
+ def redis_SDIFFSTORE destination, *keys
84
+ (@database[destination] = redis_SDIFF *keys).size
85
+ end
86
+
87
+ def redis_SPOP key
88
+ set = @database[key]
89
+ return nil unless set
90
+ rec = rand set.size
91
+ result = set.to_a[rec]
92
+ set.delete result
93
+ @database.delete key if set.empty?
94
+ result
95
+ end
96
+
97
+ def redis_SRANDMEMBER key
98
+ set = (@database[key] || [])
99
+ return nil if set.empty?
100
+ set.to_a[rand set.size]
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,65 @@
1
+ module Redis
2
+
3
+ # This is faster and allows for experimentation with duck-typing.
4
+ module NotStrict
5
+
6
+ def redis_t *args
7
+ end
8
+
9
+ def redis_f val, msg = nil
10
+ if Numeric === val
11
+ val
12
+ else
13
+ val_downcase = val.downcase
14
+ if val_downcase == '-inf'
15
+ -1.0/0
16
+ elsif val_downcase =~ /^[+]?inf$/
17
+ 1.0/0
18
+ else
19
+ val.to_f
20
+ end
21
+ end
22
+ end
23
+
24
+ def redis_i val, msg = nil
25
+ val.to_i
26
+ end
27
+
28
+ def redis_pos_i val, msg = 'value is negative'
29
+ val = redis_i val # may call strict
30
+ raise msg if val < 0
31
+ val
32
+ end
33
+
34
+ end
35
+
36
+ # Strict version allows the ruby-redis server to pass redis tests.
37
+ module Strict
38
+ include NotStrict
39
+
40
+ def redis_t *args
41
+ val = args.pop
42
+ msg = 'Operation against a key holding the wrong kind of value'
43
+ unless Class === args.last
44
+ msg = val
45
+ val = args.pop
46
+ end
47
+ args.each do |klass|
48
+ return if klass === val
49
+ end
50
+ raise msg
51
+ end
52
+
53
+ def redis_f val, msg = 'value is not a double'
54
+ raise msg+val.to_s.dump unless Numeric === val or val =~ /^[ +-]?([0-9.e-]*|inf)$/i
55
+ super
56
+ end
57
+
58
+ def redis_i val, msg = 'value is not an integer or out of range'
59
+ raise msg unless Integer === val or val =~ /^[ +-]?[0-9]*$/
60
+ super
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,142 @@
1
+ module Redis
2
+
3
+ # Note: Redis does not have a dedicated integer type.
4
+ # Integer operations will convert values to integers.
5
+
6
+ module Strings
7
+
8
+ def redis_GET key
9
+ value = @database[key]
10
+ redis_t NilClass, String, Numeric, value
11
+ value
12
+ end
13
+
14
+ def redis_APPEND key, value
15
+ new_value = redis_GET(key).to_s + value
16
+ @database[key] = new_value
17
+ new_value.size
18
+ end
19
+
20
+ def redis_SETRANGE key, offset, value
21
+ data = (redis_GET(key)||'').to_s
22
+ return data.size if value.empty?
23
+ offset = redis_pos_i offset, 'out of range'
24
+ raise 'maximum allowed size' if offset + value.size > 512*1024*1024
25
+ if data.size <= offset
26
+ data.concat 0.chr * (offset - data.size + value.size)
27
+ end
28
+ data[offset,value.size] = value
29
+ @database[key] = data
30
+ data.size
31
+ end
32
+
33
+ def redis_GETRANGE key, first, last
34
+ first = redis_i first
35
+ last = redis_i last
36
+ value = redis_GET(key) || ''
37
+ first = 0 if first < -value.size
38
+ value[first..last]
39
+ end
40
+
41
+ def redis_GETBIT key, offset
42
+ data = redis_GET key
43
+ return 0 unless data
44
+ data = data.to_s
45
+ offset = redis_pos_i offset
46
+ byte = offset / 8
47
+ bit = 0x80 >> offset % 8
48
+ return 0 if data.size <= byte
49
+ original_byte = data[byte].ord
50
+ original_bit = original_byte & bit
51
+ original_bit != 0
52
+ end
53
+
54
+ def redis_SETBIT key, offset, value
55
+ data = (redis_GET(key)||'').to_s
56
+ offset = redis_pos_i offset, 'out of range'
57
+ raise 'out of range' if offset >= 4*1024*1024*1024
58
+ byte = offset / 8
59
+ bit = 0x80 >> offset % 8
60
+ if data.size <= byte
61
+ data += 0.chr * (byte - data.size + 1)
62
+ end
63
+ original_byte = data[byte].ord
64
+ original_bit = original_byte & bit
65
+ if value == '0'
66
+ data[byte] = (original_byte & ~bit).chr
67
+ elsif value == '1'
68
+ data[byte] = (original_byte | bit).chr
69
+ else
70
+ raise 'out of range'
71
+ end
72
+ @database[key] = data
73
+ original_bit != 0
74
+ end
75
+
76
+ def redis_STRLEN key
77
+ value = redis_GET key
78
+ value ? value.size : 0
79
+ end
80
+
81
+ def redis_MGET *keys
82
+ keys.collect do |key|
83
+ value = @database[key]
84
+ (String === value) ? value : nil
85
+ end
86
+ end
87
+
88
+ def redis_GETSET key, value
89
+ old = redis_GET key
90
+ @database[key] = value
91
+ old
92
+ end
93
+
94
+ def redis_SET key, value
95
+ @database[key] = value
96
+ :'+OK'
97
+ end
98
+
99
+ def redis_SETEX key, seconds, value
100
+ @database[key] = value
101
+ @database.expire key, redis_pos_i(seconds, 'invalid expire time in SETEX')
102
+ :'+OK'
103
+ end
104
+
105
+ def redis_MSET *args
106
+ Hash[*args].each do |key, value|
107
+ @database[key] = value
108
+ end
109
+ :'+OK'
110
+ end
111
+
112
+ def redis_MSETNX *args
113
+ hash = Hash[*args]
114
+ hash.each do |key, value|
115
+ return false if @database.has_key? key
116
+ end
117
+ hash.each do |key, value|
118
+ @database[key] = value
119
+ end
120
+ true
121
+ end
122
+
123
+ def redis_SETNX key, value
124
+ return false if @database.has_key? key
125
+ @database[key] = value
126
+ true
127
+ end
128
+
129
+ def redis_INCR key
130
+ @database[key] = redis_i(@database[key] || 0) + 1
131
+ end
132
+
133
+ def redis_INCRBY key, value
134
+ @database[key] = redis_i(@database[key] || 0) + redis_i(value)
135
+ end
136
+
137
+ def redis_DECRBY key, value
138
+ @database[key] = redis_i(@database[key] || 0) - redis_i(value)
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,51 @@
1
+ require 'fiber'
2
+ require File.expand_path 'client', File.dirname(__FILE__)
3
+
4
+ module Redis
5
+
6
+ # Compatible with em-synchrony
7
+
8
+ def self.synchrony blk=nil, tail=nil, &block
9
+ blk ||= block
10
+ context = Proc.new { Fiber.new { blk.call }.resume }
11
+ EventMachine.run(context, tail)
12
+ end
13
+
14
+ class Synchrony
15
+ def self.sync(df)
16
+ f = Fiber.current
17
+ xback = proc {|r|
18
+ if f == Fiber.current
19
+ return r
20
+ else
21
+ f.resume r
22
+ end
23
+ }
24
+ df.callback &xback
25
+ df.errback &xback
26
+ Fiber.yield
27
+ end
28
+ def initialize redis
29
+ @redis = redis
30
+ end
31
+ def method_missing method, *args, &block
32
+ raise 'synchrony not allowed in multi' if @redis.in_multi? and method != :exec
33
+ result = @redis.send method, *args, &block
34
+ if result.respond_to? :callback and result.respond_to? :errback
35
+ result = Synchrony.sync result
36
+ raise result if Exception === result
37
+ end
38
+ result
39
+ end
40
+ end
41
+
42
+ class Client
43
+
44
+ def synchrony
45
+ raise 'you probably want Redis.synchrony instead' if block_given?
46
+ @synchrony ||= Synchrony.new self
47
+ end
48
+
49
+ end
50
+
51
+ end