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 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 redis database. This is shared accross all models and instances.
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
- def all(model = nil)
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
- private
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).sort
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
- class_eval <<-EOS
230
- def #{name}
231
- @#{name} ||= Attributes::List.new(db, key("#{name}"))
232
- end
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
- class_eval <<-EOS
238
- def #{name}
239
- @#{name} ||= Attributes::Set.new(db, key("#{name}"))
240
- end
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
- filter(:all)
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
- filter(Ohm.key(attribute, encode(value)))
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
- 6331
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 Event < Ohm::Model
4
- attribute :name
5
- counter :votes
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
- end
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.all
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.all
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(Person)
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.all
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.11
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-24 00:00:00 -03:00
13
+ date: 2009-07-27 00:00:00 -03:00
14
14
  default_executable:
15
15
  dependencies: []
16
16