ohm 0.0.11 → 0.0.12

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/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