ruby-redis-portertech 0.0.3

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.
@@ -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