redis-objects 0.1.0
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/ATOMICITY.rdoc +154 -0
- data/README.rdoc +144 -0
- data/lib/redis/counter.rb +105 -0
- data/lib/redis/data_types.rb +84 -0
- data/lib/redis/list.rb +95 -0
- data/lib/redis/lock.rb +47 -0
- data/lib/redis/objects.rb +103 -0
- data/lib/redis/objects/core.rb +0 -0
- data/lib/redis/objects/counters.rb +113 -0
- data/lib/redis/objects/lists.rb +34 -0
- data/lib/redis/objects/locks.rb +56 -0
- data/lib/redis/objects/sets.rb +9 -0
- data/lib/redis/objects/values.rb +37 -0
- data/lib/redis/set.rb +7 -0
- data/lib/redis/value.rb +39 -0
- data/spec/redis_objects_model_spec.rb +278 -0
- data/spec/spec_helper.rb +5 -0
- metadata +73 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
# This is the class loader, for use as "include Redis::Objects::Values"
|
2
|
+
# For the object itself, see "Redis::Value"
|
3
|
+
require 'redis/value'
|
4
|
+
class Redis
|
5
|
+
module Objects
|
6
|
+
module Values
|
7
|
+
def self.included(klass)
|
8
|
+
klass.instance_variable_set('@values', {})
|
9
|
+
klass.send :include, InstanceMethods
|
10
|
+
klass.extend ClassMethods
|
11
|
+
end
|
12
|
+
|
13
|
+
# Class methods that appear in your class when you include Redis::Objects.
|
14
|
+
module ClassMethods
|
15
|
+
attr_reader :values
|
16
|
+
|
17
|
+
# Define a new simple value. It will function like a regular instance
|
18
|
+
# method, so it can be used alongside ActiveRecord, DataMapper, etc.
|
19
|
+
def value(name, options={})
|
20
|
+
@values[name] = options
|
21
|
+
class_eval <<-EndMethods
|
22
|
+
def #{name}
|
23
|
+
@#{name} ||= Redis::Value.new(field_key(:#{name}), self.class.values[:#{name}].merge(:redis => redis))
|
24
|
+
end
|
25
|
+
def #{name}=(value)
|
26
|
+
#{name}.value = value
|
27
|
+
end
|
28
|
+
EndMethods
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Instance methods that appear in your class when you include Redis::Objects.
|
33
|
+
module InstanceMethods
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/redis/set.rb
ADDED
data/lib/redis/value.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
class Redis
|
2
|
+
#
|
3
|
+
# Class representing a simple value. You can use standard Ruby operations on it.
|
4
|
+
#
|
5
|
+
class Value
|
6
|
+
attr_reader :key, :options, :redis
|
7
|
+
def initialize(key, options={})
|
8
|
+
@key = key
|
9
|
+
@options = options
|
10
|
+
@redis = options[:redis] || $redis || Redis::Objects.redis
|
11
|
+
@redis.setnx(key, @options[:default]) if @options[:default]
|
12
|
+
end
|
13
|
+
|
14
|
+
def value
|
15
|
+
@value ||= get
|
16
|
+
end
|
17
|
+
|
18
|
+
def value=(val)
|
19
|
+
redis.set(key, val)
|
20
|
+
@value = val
|
21
|
+
end
|
22
|
+
|
23
|
+
def get
|
24
|
+
@value = redis.get(key)
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete
|
28
|
+
redis.del(key)
|
29
|
+
@value = nil
|
30
|
+
end
|
31
|
+
alias_method :del, :delete
|
32
|
+
|
33
|
+
def to_s; value.to_s; end
|
34
|
+
alias_method :to_str, :to_s
|
35
|
+
|
36
|
+
def ==(x); value == x; end
|
37
|
+
def nil?; value.nil?; end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
3
|
+
|
4
|
+
class Roster
|
5
|
+
include Redis::Objects
|
6
|
+
counter :available_slots, :start => 10
|
7
|
+
counter :pitchers, :limit => :max_pitchers
|
8
|
+
counter :basic
|
9
|
+
counter :all_players_online, :global => true
|
10
|
+
lock :resort, :timeout => 2
|
11
|
+
value :starting_pitcher
|
12
|
+
list :player_stats
|
13
|
+
|
14
|
+
def initialize(id=1) @id = id end
|
15
|
+
def id; @id; end
|
16
|
+
def max_pitchers; 3; end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Redis::Objects do
|
20
|
+
before :all do
|
21
|
+
@roster = Roster.new
|
22
|
+
@roster2 = Roster.new
|
23
|
+
end
|
24
|
+
|
25
|
+
before :each do
|
26
|
+
@roster.available_slots.reset
|
27
|
+
@roster.pitchers.reset
|
28
|
+
@roster.basic.reset
|
29
|
+
@roster.resort_lock.clear
|
30
|
+
@roster.starting_pitcher.delete
|
31
|
+
@roster.player_stats.clear
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should provide a connection method" do
|
35
|
+
Roster.redis.should == Redis::Objects.redis
|
36
|
+
Roster.redis.should be_kind_of(Redis)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should create counter accessors" do
|
40
|
+
[:available_slots, :pitchers, :basic].each do |m|
|
41
|
+
@roster.respond_to?(m).should == true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should support increment/decrement of counters" do
|
46
|
+
@roster.available_slots.key.should == 'roster:1:available_slots'
|
47
|
+
@roster.available_slots.should == 10
|
48
|
+
|
49
|
+
# math proxy ops
|
50
|
+
(@roster.available_slots == 10).should be_true
|
51
|
+
(@roster.available_slots <= 10).should be_true
|
52
|
+
(@roster.available_slots < 11).should be_true
|
53
|
+
(@roster.available_slots > 9).should be_true
|
54
|
+
(@roster.available_slots >= 10).should be_true
|
55
|
+
"#{@roster.available_slots}".should == "10"
|
56
|
+
|
57
|
+
@roster.available_slots.increment.should == 11
|
58
|
+
@roster.available_slots.increment.should == 12
|
59
|
+
@roster2.available_slots.increment.should == 13
|
60
|
+
@roster2.available_slots.increment(2).should == 15
|
61
|
+
@roster.available_slots.decrement.should == 14
|
62
|
+
@roster2.available_slots.decrement.should == 13
|
63
|
+
@roster.available_slots.decrement.should == 12
|
64
|
+
@roster2.available_slots.decrement(4).should == 8
|
65
|
+
@roster.available_slots.should == 12
|
66
|
+
@roster.available_slots.get.should == 8
|
67
|
+
@roster.available_slots.reset.should == 10
|
68
|
+
@roster.available_slots.should == 10
|
69
|
+
@roster.available_slots.reset(15).should == 15
|
70
|
+
@roster.available_slots.should == 15
|
71
|
+
@roster.pitchers.increment.should == 1
|
72
|
+
@roster.basic.increment.should == 1
|
73
|
+
@roster2.basic.decrement.should == 0
|
74
|
+
@roster.basic.get.should == 0
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should support class-level increment/decrement of counters" do
|
78
|
+
Roster.get_counter(:available_slots, @roster.id).should == 10
|
79
|
+
Roster.increment_counter(:available_slots, @roster.id).should == 11
|
80
|
+
Roster.increment_counter(:available_slots, @roster.id, 3).should == 14
|
81
|
+
Roster.decrement_counter(:available_slots, @roster.id, 2).should == 12
|
82
|
+
Roster.decrement_counter(:available_slots, @roster.id).should == 11
|
83
|
+
Roster.reset_counter(:available_slots, @roster.id).should == true
|
84
|
+
Roster.get_counter(:available_slots, @roster.id).should == 10
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should take an atomic block for increment/decrement" do
|
88
|
+
a = false
|
89
|
+
@roster.available_slots.should == 10
|
90
|
+
@roster.available_slots.decr do |cnt|
|
91
|
+
if cnt >= 0
|
92
|
+
a = true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
@roster.available_slots.should == 9
|
96
|
+
a.should be_true
|
97
|
+
|
98
|
+
@roster.available_slots.should == 9
|
99
|
+
@roster.available_slots.decr do |cnt|
|
100
|
+
@roster.available_slots.should == 8
|
101
|
+
false
|
102
|
+
end
|
103
|
+
@roster.available_slots.should == 8
|
104
|
+
|
105
|
+
@roster.available_slots.should == 8
|
106
|
+
@roster.available_slots.decr do |cnt|
|
107
|
+
@roster.available_slots.should == 7
|
108
|
+
nil # should rewind
|
109
|
+
end
|
110
|
+
@roster.available_slots.should == 8
|
111
|
+
|
112
|
+
@roster.available_slots.should == 8
|
113
|
+
@roster.available_slots.incr do |cnt|
|
114
|
+
if 1 == 2 # should rewind
|
115
|
+
true
|
116
|
+
end
|
117
|
+
end
|
118
|
+
@roster.available_slots.should == 8
|
119
|
+
|
120
|
+
@roster.available_slots.should == 8
|
121
|
+
@roster.available_slots.incr do |cnt|
|
122
|
+
@roster.available_slots.should == 9
|
123
|
+
[]
|
124
|
+
end
|
125
|
+
@roster.available_slots.should == 9
|
126
|
+
|
127
|
+
@roster.available_slots.should == 9
|
128
|
+
begin
|
129
|
+
@roster.available_slots.decr do |cnt|
|
130
|
+
@roster.available_slots.should == 8
|
131
|
+
raise 'oops'
|
132
|
+
end
|
133
|
+
rescue
|
134
|
+
end
|
135
|
+
@roster.available_slots.should == 9
|
136
|
+
|
137
|
+
# check return value from the block
|
138
|
+
value =
|
139
|
+
@roster.available_slots.decr do |cnt|
|
140
|
+
@roster.available_slots.should == 8
|
141
|
+
42
|
142
|
+
end
|
143
|
+
value.should == 42
|
144
|
+
@roster.available_slots.should == 8
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should take an atomic block for increment/decrement class methods" do
|
148
|
+
a = false
|
149
|
+
Roster.get_counter(:available_slots, @roster.id).should == 10
|
150
|
+
Roster.decrement_counter(:available_slots, @roster.id) do |cnt|
|
151
|
+
if cnt >= 0
|
152
|
+
a = true
|
153
|
+
end
|
154
|
+
end
|
155
|
+
Roster.get_counter(:available_slots, @roster.id).should == 9
|
156
|
+
a.should be_true
|
157
|
+
|
158
|
+
Roster.get_counter(:available_slots, @roster.id).should == 9
|
159
|
+
Roster.decrement_counter(:available_slots, @roster.id) do |cnt|
|
160
|
+
Roster.get_counter(:available_slots, @roster.id).should == 8
|
161
|
+
false
|
162
|
+
end
|
163
|
+
Roster.get_counter(:available_slots, @roster.id).should == 8
|
164
|
+
|
165
|
+
Roster.get_counter(:available_slots, @roster.id).should == 8
|
166
|
+
Roster.decrement_counter(:available_slots, @roster.id) do |cnt|
|
167
|
+
Roster.get_counter(:available_slots, @roster.id).should == 7
|
168
|
+
nil # should rewind
|
169
|
+
end
|
170
|
+
Roster.get_counter(:available_slots, @roster.id).should == 8
|
171
|
+
|
172
|
+
Roster.get_counter(:available_slots, @roster.id).should == 8
|
173
|
+
Roster.increment_counter(:available_slots, @roster.id) do |cnt|
|
174
|
+
if 1 == 2 # should rewind
|
175
|
+
true
|
176
|
+
end
|
177
|
+
end
|
178
|
+
Roster.get_counter(:available_slots, @roster.id).should == 8
|
179
|
+
|
180
|
+
Roster.get_counter(:available_slots, @roster.id).should == 8
|
181
|
+
Roster.increment_counter(:available_slots, @roster.id) do |cnt|
|
182
|
+
Roster.get_counter(:available_slots, @roster.id).should == 9
|
183
|
+
[]
|
184
|
+
end
|
185
|
+
Roster.get_counter(:available_slots, @roster.id).should == 9
|
186
|
+
|
187
|
+
Roster.get_counter(:available_slots, @roster.id).should == 9
|
188
|
+
begin
|
189
|
+
Roster.decrement_counter(:available_slots, @roster.id) do |cnt|
|
190
|
+
Roster.get_counter(:available_slots, @roster.id).should == 8
|
191
|
+
raise 'oops'
|
192
|
+
end
|
193
|
+
rescue
|
194
|
+
end
|
195
|
+
Roster.get_counter(:available_slots, @roster.id).should == 9
|
196
|
+
|
197
|
+
# check return value from the block
|
198
|
+
value =
|
199
|
+
Roster.decrement_counter(:available_slots, @roster.id) do |cnt|
|
200
|
+
Roster.get_counter(:available_slots, @roster.id).should == 8
|
201
|
+
42
|
202
|
+
end
|
203
|
+
value.should == 42
|
204
|
+
Roster.get_counter(:available_slots, @roster.id).should == 8
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should properly throw errors on bad counters" do
|
208
|
+
error = nil
|
209
|
+
begin
|
210
|
+
Roster.increment_counter(:badness, 2)
|
211
|
+
rescue => error
|
212
|
+
end
|
213
|
+
error.should be_kind_of(Redis::Objects::UndefinedCounter)
|
214
|
+
|
215
|
+
error = nil
|
216
|
+
begin
|
217
|
+
Roster.obtain_lock(:badness, 2){}
|
218
|
+
rescue => error
|
219
|
+
end
|
220
|
+
error.should be_kind_of(Redis::Objects::UndefinedLock)
|
221
|
+
|
222
|
+
error = nil
|
223
|
+
begin
|
224
|
+
@roster.available_slots = 42
|
225
|
+
rescue => error
|
226
|
+
end
|
227
|
+
error.should be_kind_of(NoMethodError)
|
228
|
+
|
229
|
+
error = nil
|
230
|
+
begin
|
231
|
+
@roster.available_slots += 69
|
232
|
+
rescue => error
|
233
|
+
end
|
234
|
+
error.should be_kind_of(NoMethodError)
|
235
|
+
|
236
|
+
error = nil
|
237
|
+
begin
|
238
|
+
@roster.available_slots -= 15
|
239
|
+
rescue => error
|
240
|
+
end
|
241
|
+
error.should be_kind_of(NoMethodError)
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should handle simple values" do
|
245
|
+
@roster.starting_pitcher.should == nil
|
246
|
+
@roster.starting_pitcher = 'Trevor Hoffman'
|
247
|
+
@roster.starting_pitcher.should == 'Trevor Hoffman'
|
248
|
+
@roster.starting_pitcher.get.should == 'Trevor Hoffman'
|
249
|
+
@roster.starting_pitcher.del
|
250
|
+
@roster.starting_pitcher.should be_nil
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should handle lists of simple values" do
|
254
|
+
@roster.player_stats.should be_empty
|
255
|
+
@roster.player_stats << 'a'
|
256
|
+
@roster.player_stats.should == ['a']
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should provide a lock method that accepts a block" do
|
260
|
+
@roster.resort_lock.key.should == 'roster:1:resort_lock'
|
261
|
+
a = false
|
262
|
+
@roster.resort_lock.lock do
|
263
|
+
a = true
|
264
|
+
end
|
265
|
+
a.should be_true
|
266
|
+
end
|
267
|
+
|
268
|
+
xit "should raise an exception if the timeout is exceeded" do
|
269
|
+
@roster.redis.set(@roster.resort_lock.key, 1)
|
270
|
+
error = nil
|
271
|
+
begin
|
272
|
+
@roster.resort_lock.lock {}
|
273
|
+
rescue => error
|
274
|
+
end
|
275
|
+
error.should_not be_nil
|
276
|
+
error.should be_kind_of(Redis::Lock::LockTimeout)
|
277
|
+
end
|
278
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redis-objects
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nate Wiger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-24 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Redis::Objects is a lightweight library that lets you use Redis primitives as Ruby objects from any class or ORM
|
17
|
+
email: nate@wiger.org
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- ATOMICITY.rdoc
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- lib/redis/counter.rb
|
27
|
+
- lib/redis/data_types.rb
|
28
|
+
- lib/redis/list.rb
|
29
|
+
- lib/redis/lock.rb
|
30
|
+
- lib/redis/objects/core.rb
|
31
|
+
- lib/redis/objects/counters.rb
|
32
|
+
- lib/redis/objects/lists.rb
|
33
|
+
- lib/redis/objects/locks.rb
|
34
|
+
- lib/redis/objects/sets.rb
|
35
|
+
- lib/redis/objects/values.rb
|
36
|
+
- lib/redis/objects.rb
|
37
|
+
- lib/redis/set.rb
|
38
|
+
- lib/redis/value.rb
|
39
|
+
- spec/redis_objects_model_spec.rb
|
40
|
+
- spec/spec_helper.rb
|
41
|
+
- ATOMICITY.rdoc
|
42
|
+
- README.rdoc
|
43
|
+
has_rdoc: true
|
44
|
+
homepage: http://github.com/nateware/redis-objects
|
45
|
+
licenses: []
|
46
|
+
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --title
|
50
|
+
- Redis::Objects -- Use Redis types as Ruby objects
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project: redis-objects
|
68
|
+
rubygems_version: 1.3.5
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Lightweight map of Redis types to Ruby objects
|
72
|
+
test_files: []
|
73
|
+
|