ohm 0.0.11 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ohm.rb +67 -32
- data/lib/ohm/redis.rb +1 -1
- data/test/db/redis.pid +1 -1
- data/test/model_test.rb +95 -13
- metadata +2 -2
data/lib/ohm.rb
CHANGED
@@ -4,7 +4,7 @@ require File.join(File.dirname(__FILE__), "ohm", "validations")
|
|
4
4
|
|
5
5
|
module Ohm
|
6
6
|
|
7
|
-
# Provides access to the
|
7
|
+
# Provides access to the Redis database. This is shared accross all models and instances.
|
8
8
|
def redis
|
9
9
|
@redis
|
10
10
|
end
|
@@ -38,18 +38,57 @@ module Ohm
|
|
38
38
|
class Collection
|
39
39
|
include Enumerable
|
40
40
|
|
41
|
-
attr_accessor :key, :db
|
41
|
+
attr_accessor :key, :db, :model
|
42
42
|
|
43
|
-
def initialize(db, key)
|
43
|
+
def initialize(db, key, model = nil)
|
44
44
|
self.db = db
|
45
45
|
self.key = key
|
46
|
+
self.model = model
|
46
47
|
end
|
47
48
|
|
48
49
|
def each(&block)
|
49
50
|
all.each(&block)
|
50
51
|
end
|
51
52
|
|
52
|
-
|
53
|
+
# Return instances of model for all the ids contained in the collection.
|
54
|
+
def all
|
55
|
+
instantiate(raw)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Return the values as model instances, ordered by the options supplied.
|
59
|
+
# Check redis documentation to see what values you can provide to each option.
|
60
|
+
#
|
61
|
+
# @param options [Hash] options to sort the collection.
|
62
|
+
# @option options [#to_s] :by Model attribute to sort the instances by.
|
63
|
+
# @option options [#to_s] :order (ASC) Sorting order, which can be ASC or DESC.
|
64
|
+
# @option options [Integer] :limit (all) Number of items to return.
|
65
|
+
# @option options [Integer] :start (0) An offset from where the limit will be applied.
|
66
|
+
# @example Get the first ten users sorted alphabetically by name:
|
67
|
+
# @event.attendees.sort(User, :by => :name, :order => "ALPHA", :limit => 10)
|
68
|
+
#
|
69
|
+
# @example Get five posts sorted by number of votes and starting from the number 5 (zero based):
|
70
|
+
# @blog.posts.sort(Post, :by => :votes, :start => 5, :limit => 10")
|
71
|
+
def sort(options = {})
|
72
|
+
options[:start] ||= 0
|
73
|
+
options[:limit] = [options[:start], options[:limit]] if options[:limit]
|
74
|
+
instantiate(db.sort(key, options))
|
75
|
+
end
|
76
|
+
|
77
|
+
def sort_by(att, options = {})
|
78
|
+
sort(options.merge(:by => model.key("*", att)))
|
79
|
+
end
|
80
|
+
|
81
|
+
def to_ary
|
82
|
+
all
|
83
|
+
end
|
84
|
+
|
85
|
+
def ==(other)
|
86
|
+
to_ary == other
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def instantiate(raw)
|
53
92
|
model ? raw.collect { |id| model[id] } : raw
|
54
93
|
end
|
55
94
|
end
|
@@ -74,7 +113,9 @@ module Ohm
|
|
74
113
|
db.rpush(key, value)
|
75
114
|
end
|
76
115
|
|
77
|
-
|
116
|
+
def empty?
|
117
|
+
db.llen(key).zero?
|
118
|
+
end
|
78
119
|
|
79
120
|
def raw
|
80
121
|
db.list(key)
|
@@ -113,14 +154,16 @@ module Ohm
|
|
113
154
|
db.srem(key, value)
|
114
155
|
end
|
115
156
|
|
157
|
+
def empty?
|
158
|
+
db.scard(key).zero?
|
159
|
+
end
|
160
|
+
|
116
161
|
def include?(value)
|
117
162
|
db.sismember(key, value)
|
118
163
|
end
|
119
164
|
|
120
|
-
private
|
121
|
-
|
122
165
|
def raw
|
123
|
-
db.smembers(key)
|
166
|
+
db.smembers(key)
|
124
167
|
end
|
125
168
|
end
|
126
169
|
end
|
@@ -185,8 +228,8 @@ module Ohm
|
|
185
228
|
# is created.
|
186
229
|
#
|
187
230
|
# @param name [Symbol] Name of the list.
|
188
|
-
def self.list(name)
|
189
|
-
attr_list_reader(name)
|
231
|
+
def self.list(name, model = nil)
|
232
|
+
attr_list_reader(name, model)
|
190
233
|
collections << name
|
191
234
|
end
|
192
235
|
|
@@ -195,8 +238,8 @@ module Ohm
|
|
195
238
|
# operations like union, join, and membership checks are important.
|
196
239
|
#
|
197
240
|
# @param name [Symbol] Name of the set.
|
198
|
-
def self.set(name)
|
199
|
-
attr_set_reader(name)
|
241
|
+
def self.set(name, model = nil)
|
242
|
+
attr_set_reader(name, model)
|
200
243
|
collections << name
|
201
244
|
end
|
202
245
|
|
@@ -225,20 +268,18 @@ module Ohm
|
|
225
268
|
indices << Array(attrs)
|
226
269
|
end
|
227
270
|
|
228
|
-
def self.attr_list_reader(name)
|
229
|
-
|
230
|
-
|
231
|
-
@#{name}
|
232
|
-
|
233
|
-
EOS
|
271
|
+
def self.attr_list_reader(name, model = nil)
|
272
|
+
define_method(name) do
|
273
|
+
instance_variable_get("@#{name}") ||
|
274
|
+
instance_variable_set("@#{name}", Attributes::List.new(db, key(name), model))
|
275
|
+
end
|
234
276
|
end
|
235
277
|
|
236
|
-
def self.attr_set_reader(name)
|
237
|
-
|
238
|
-
|
239
|
-
@#{name}
|
240
|
-
|
241
|
-
EOS
|
278
|
+
def self.attr_set_reader(name, model)
|
279
|
+
define_method(name) do
|
280
|
+
instance_variable_get("@#{name}") ||
|
281
|
+
instance_variable_set("@#{name}", Attributes::Set.new(db, key(name), model))
|
282
|
+
end
|
242
283
|
end
|
243
284
|
|
244
285
|
def self.[](id)
|
@@ -246,7 +287,7 @@ module Ohm
|
|
246
287
|
end
|
247
288
|
|
248
289
|
def self.all
|
249
|
-
|
290
|
+
@all ||= Attributes::Set.new(db, key(:all), self)
|
250
291
|
end
|
251
292
|
|
252
293
|
def self.attributes
|
@@ -272,7 +313,7 @@ module Ohm
|
|
272
313
|
end
|
273
314
|
|
274
315
|
def self.find(attribute, value)
|
275
|
-
|
316
|
+
Attributes::Set.new(db, key(attribute, encode(value)), self)
|
276
317
|
end
|
277
318
|
|
278
319
|
def self.encode(value)
|
@@ -376,12 +417,6 @@ module Ohm
|
|
376
417
|
Ohm.key(*args.unshift(self))
|
377
418
|
end
|
378
419
|
|
379
|
-
def self.filter(name)
|
380
|
-
db.smembers(key(name)).map do |id|
|
381
|
-
new(:id => id)
|
382
|
-
end
|
383
|
-
end
|
384
|
-
|
385
420
|
def self.exists?(id)
|
386
421
|
db.sismember(key(:all), id)
|
387
422
|
end
|
data/lib/ohm/redis.rb
CHANGED
@@ -94,7 +94,7 @@ module Ohm
|
|
94
94
|
cmd << "BY #{opts[:by]}" if opts[:by]
|
95
95
|
cmd << "GET #{[opts[:get]].flatten * ' GET '}" if opts[:get]
|
96
96
|
cmd << "#{opts[:order]}" if opts[:order]
|
97
|
-
cmd << "LIMIT #{opts[:limit].join(' ')}" if opts[:limit]
|
97
|
+
cmd << "LIMIT #{Array(opts[:limit]).join(' ')}" if opts[:limit]
|
98
98
|
call_command(cmd)
|
99
99
|
end
|
100
100
|
|
data/test/db/redis.pid
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
39163
|
data/test/model_test.rb
CHANGED
@@ -1,18 +1,13 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), "test_helper")
|
2
2
|
|
3
|
-
class
|
4
|
-
attribute :
|
5
|
-
|
6
|
-
set :attendees
|
3
|
+
class Post < Ohm::Model
|
4
|
+
attribute :body
|
5
|
+
list :comments
|
7
6
|
end
|
8
7
|
|
9
8
|
class User < Ohm::Model
|
10
9
|
attribute :email
|
11
|
-
|
12
|
-
|
13
|
-
class Post < Ohm::Model
|
14
|
-
attribute :body
|
15
|
-
list :comments
|
10
|
+
set :posts, Post
|
16
11
|
end
|
17
12
|
|
18
13
|
class Person < Ohm::Model
|
@@ -23,6 +18,13 @@ class Person < Ohm::Model
|
|
23
18
|
end
|
24
19
|
end
|
25
20
|
|
21
|
+
class Event < Ohm::Model
|
22
|
+
attribute :name
|
23
|
+
counter :votes
|
24
|
+
set :attendees, Person
|
25
|
+
end
|
26
|
+
|
27
|
+
|
26
28
|
class TestRedis < Test::Unit::TestCase
|
27
29
|
context "An event initialized with a hash of attributes" do
|
28
30
|
should "assign the passed attributes" do
|
@@ -169,6 +171,18 @@ class TestRedis < Test::Unit::TestCase
|
|
169
171
|
end
|
170
172
|
end
|
171
173
|
|
174
|
+
context "Sorting" do
|
175
|
+
should "sort all" do
|
176
|
+
Ohm.flush
|
177
|
+
Person.create :name => "D"
|
178
|
+
Person.create :name => "C"
|
179
|
+
Person.create :name => "B"
|
180
|
+
Person.create :name => "A"
|
181
|
+
|
182
|
+
assert_equal %w[A B C D], Person.all.sort_by(:name, :order => "ALPHA").map { |person| person.name }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
172
186
|
context "Loading attributes" do
|
173
187
|
setup do
|
174
188
|
event = Event.new
|
@@ -207,9 +221,9 @@ class TestRedis < Test::Unit::TestCase
|
|
207
221
|
@event.attendees << "1"
|
208
222
|
@event.attendees << "2"
|
209
223
|
@event.attendees << "3"
|
210
|
-
assert_equal ["1", "2", "3"], @event.attendees.
|
224
|
+
assert_equal ["1", "2", "3"], @event.attendees.raw.sort
|
211
225
|
@event.attendees.delete("2")
|
212
|
-
assert_equal ["1", "3"], Event[@event.id].attendees.
|
226
|
+
assert_equal ["1", "3"], Event[@event.id].attendees.raw.sort
|
213
227
|
end
|
214
228
|
|
215
229
|
should "return true if the set includes some member" do
|
@@ -226,7 +240,7 @@ class TestRedis < Test::Unit::TestCase
|
|
226
240
|
@person = Person.create :name => "albert"
|
227
241
|
@event.attendees << @person.id
|
228
242
|
|
229
|
-
assert_equal [@person], @event.attendees.all
|
243
|
+
assert_equal [@person], @event.attendees.all
|
230
244
|
end
|
231
245
|
|
232
246
|
should "insert the model instance id instead of the object if using add" do
|
@@ -234,7 +248,7 @@ class TestRedis < Test::Unit::TestCase
|
|
234
248
|
@person = Person.create :name => "albert"
|
235
249
|
@event.attendees.add(@person)
|
236
250
|
|
237
|
-
assert_equal [@person.id.to_s], @event.attendees.
|
251
|
+
assert_equal [@person.id.to_s], @event.attendees.raw
|
238
252
|
end
|
239
253
|
end
|
240
254
|
|
@@ -277,6 +291,74 @@ class TestRedis < Test::Unit::TestCase
|
|
277
291
|
end
|
278
292
|
end
|
279
293
|
|
294
|
+
context "Applying arbitrary transformations" do
|
295
|
+
class Calendar < Ohm::Model
|
296
|
+
list :holidays, lambda { |v| Date.parse(v) }
|
297
|
+
end
|
298
|
+
|
299
|
+
setup do
|
300
|
+
@calendar = Calendar.create
|
301
|
+
@calendar.holidays << "05/25/2009"
|
302
|
+
@calendar.holidays << "07/09/2009"
|
303
|
+
end
|
304
|
+
|
305
|
+
should "apply a transformation" do
|
306
|
+
assert_equal [Date.parse("2009-05-25"), Date.parse("2009-07-09")], @calendar.holidays
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
context "Sorting lists and sets" do
|
311
|
+
setup do
|
312
|
+
@post = Post.create(:body => "Lorem")
|
313
|
+
@post.comments << 2
|
314
|
+
@post.comments << 3
|
315
|
+
@post.comments << 1
|
316
|
+
end
|
317
|
+
|
318
|
+
should "sort values" do
|
319
|
+
assert_equal %w{1 2 3}, @post.comments.sort
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
context "Sorting lists and sets by model attributes" do
|
324
|
+
setup do
|
325
|
+
@event = Event.create(:name => "Ruby Tuesday")
|
326
|
+
@event.attendees << Person.create(:name => "D").id
|
327
|
+
@event.attendees << Person.create(:name => "C").id
|
328
|
+
@event.attendees << Person.create(:name => "B").id
|
329
|
+
@event.attendees << Person.create(:name => "A").id
|
330
|
+
end
|
331
|
+
|
332
|
+
should "sort the model instances by the values provided" do
|
333
|
+
people = @event.attendees.sort_by(:name, :order => "ALPHA")
|
334
|
+
assert_equal %w[A B C D], people.map { |person| person.name }
|
335
|
+
end
|
336
|
+
|
337
|
+
should "accept a number in the limit parameter" do
|
338
|
+
people = @event.attendees.sort_by(:name, :limit => 2, :order => "ALPHA")
|
339
|
+
assert_equal %w[A B], people.map { |person| person.name }
|
340
|
+
end
|
341
|
+
|
342
|
+
should "use the start parameter as an offset if the limit is provided" do
|
343
|
+
people = @event.attendees.sort_by(:name, :limit => 2, :start => 1, :order => "ALPHA")
|
344
|
+
assert_equal %w[B C], people.map { |person| person.name }
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
context "Collections initialized with a Model parameter" do
|
349
|
+
setup do
|
350
|
+
@user = User.create(:email => "albert@example.com")
|
351
|
+
@user.posts.add Post.create(:body => "D")
|
352
|
+
@user.posts.add Post.create(:body => "C")
|
353
|
+
@user.posts.add Post.create(:body => "B")
|
354
|
+
@user.posts.add Post.create(:body => "A")
|
355
|
+
end
|
356
|
+
|
357
|
+
should "return instances of the passed model" do
|
358
|
+
assert_equal Post, @user.posts.all.first.class
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
280
362
|
context "Counters" do
|
281
363
|
setup do
|
282
364
|
@event = Event.create(:name => "Ruby Tuesday")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ohm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michel Martens
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-07-
|
13
|
+
date: 2009-07-27 00:00:00 -03:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|