perpetuity 0.3.1 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## Version 0.4
2
+
3
+ - Mapper select DSL now more closely resembles `Enumerable` syntax
4
+ - Instead of `mapper.select { published_at < Time.now }` you would write `mapper.select { |article| article.published_at < Time.now }`
5
+ - It's a little more typing, but it eliminates a lot of problems that came from calling instance_exec on the block. It meant we couldn't call methods on the current object (they would be invoked on the `Query` object) or use instance variables from the current object.
6
+ - Explained more in [issue #19](https://github.com/jgaskins/perpetuity/issues/19)
7
+
8
+ ## Version 0.3.1
9
+
10
+ - Access object state via instance methods to store actual object state, rather than treating all objects as value objects
11
+ - Use `Object.allocate` rather than `Object.new` when restoring state to an object from the database
12
+
1
13
  ## Version 0.3
2
14
 
3
15
  - Use `Perpetuity[]` instead of `Perpetuity::Mapper[]` to get mapper instances
data/README.md CHANGED
@@ -72,18 +72,16 @@ You can load specific objects by calling the `find` method with an ID param on t
72
72
 
73
73
  ```ruby
74
74
  article = Perpetuity[Article].find params[:id]
75
- users = Perpetuity[User].select { email == 'me@example.com' }
76
- articles = Perpetuity[Article].select { published_at < Time.now }
77
- comments = Perpetuity[Comment].select { article_id.in articles.map(&:id) }
75
+ users = Perpetuity[User].select { |user| user.email == 'me@example.com' }
76
+ articles = Perpetuity[Article].select { |article| article.published_at < Time.now }
77
+ comments = Perpetuity[Comment].select { |comment| comment.article_id.in articles.map(&:id) }
78
78
  ```
79
79
 
80
- Unfortunately, due to limitations in the Ruby language itself, this is as close as I could get to a true `Enumerable`-style select method. Once I can override `&&` and `||`, we can put more Rubyesque code in here.
81
-
82
80
  These methods will return a Perpetuity::Retrieval object, which will lazily retrieve the objects from the database. They will wait to hit the DB when you begin iterating over the objects so you can continue chaining methods.
83
81
 
84
82
  ```ruby
85
83
  article_mapper = Perpetuity[Article]
86
- articles = article_mapper.select { published_at < Time.now }
84
+ articles = article_mapper.select { |article| article.published_at < Time.now }
87
85
  articles = articles.sort(:published_at).reverse
88
86
  articles = articles.page(2).per_page(10) # built-in pagination
89
87
 
@@ -92,6 +90,14 @@ articles.each do |article| # This is when the DB gets hit
92
90
  end
93
91
  ```
94
92
 
93
+ Unfortunately, due to limitations in the Ruby language itself, we cannot get a true `Enumerable`-style select method. The limitation shows itself when needing to have multiple criteria for a query, as in this super-secure example:
94
+
95
+ ```ruby
96
+ user = Perpetuity[User].select { |user| (user.email == params[:email]) & (user.password == params[:password]) }
97
+ ```
98
+
99
+ Notice that we have to use a single `&` and surround each criterion with parentheses. If we could override `&&` and `||`, we could put more Rubyesque code in here, but until then, we have to operate within the boundaries of the operators that can be overridden.
100
+
95
101
  ## Associations with Other Objects
96
102
 
97
103
  The database can natively serialize some objects. For example, MongoDB can serialize `String`, `Numeric`, `Array`, `Hash`, `Time`, `nil`, `true`, `false`, and a few others. If an object references another type of object (such as an article referencing its author, a `User` object), the association is declared just as any other attribute. No special treatment is required.
@@ -4,7 +4,7 @@ module Perpetuity
4
4
  class MongoDB
5
5
  class Query
6
6
  def initialize &block
7
- @query = instance_exec(&block)
7
+ @query = block.call(self)
8
8
  end
9
9
 
10
10
  def to_db
@@ -1,3 +1,3 @@
1
1
  module Perpetuity
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4"
3
3
  end
@@ -5,33 +5,33 @@ module Perpetuity
5
5
  let(:query) { MongoDB::Query }
6
6
 
7
7
  it 'generates Mongo equality expressions' do
8
- query.new{name == 'Jamie'}.to_db.should == {name: 'Jamie'}
8
+ query.new{ |user| user.name == 'Jamie' }.to_db.should == {name: 'Jamie'}
9
9
  end
10
10
 
11
11
  it 'generates Mongo less-than expressions' do
12
- query.new{quantity < 10}.to_db.should == {quantity: { '$lt' => 10}}
12
+ query.new{ |v| v.quantity < 10 }.to_db.should == {quantity: { '$lt' => 10}}
13
13
  end
14
14
 
15
15
  it 'generates Mongo less-than-or-equal expressions' do
16
- query.new{quantity <= 10}.to_db.should == {quantity: { '$lte' => 10}}
16
+ query.new{ |v| v.quantity <= 10 }.to_db.should == {quantity: { '$lte' => 10}}
17
17
  end
18
18
 
19
19
  it 'generates Mongo greater-than expressions' do
20
- query.new{quantity > 10}.to_db.should == {quantity: { '$gt' => 10}}
20
+ query.new{ |v| v.quantity > 10 }.to_db.should == {quantity: { '$gt' => 10}}
21
21
  end
22
22
 
23
23
  it 'generates Mongo greater-than-or-equal expressions' do
24
- query.new{quantity >= 10}.to_db.should == {quantity: { '$gte' => 10}}
24
+ query.new{ |v| v.quantity >= 10 }.to_db.should == {quantity: { '$gte' => 10}}
25
25
  end
26
26
 
27
27
  it 'generates Mongo inequality expressions' do
28
- query.new{name.not_equal? 'Jamie'}.to_db.should == {
28
+ query.new{ |user| user.name.not_equal? 'Jamie' }.to_db.should == {
29
29
  name: {'$ne' => 'Jamie'}
30
30
  }
31
31
  end
32
32
 
33
33
  it 'generates Mongo regexp expressions' do
34
- query.new{name =~ /Jamie/}.to_db.should == {name: /Jamie/}
34
+ query.new{ |user| user.name =~ /Jamie/ }.to_db.should == {name: /Jamie/}
35
35
  end
36
36
  end
37
37
  end
@@ -163,55 +163,55 @@ describe Perpetuity do
163
163
  end
164
164
 
165
165
  it 'selects objects using equality' do
166
- selected = Perpetuity[Article].select { title == 'Published' }
166
+ selected = Perpetuity[Article].select { |article| article.title == 'Published' }
167
167
  selected.map(&:id).should include published.id
168
168
  selected.map(&:id).should_not include draft.id
169
169
  end
170
170
 
171
171
  it 'selects objects using greater-than' do
172
- selected = Perpetuity[Article].select { published_at < Time.now }
172
+ selected = Perpetuity[Article].select { |article| article.published_at < Time.now }
173
173
  ids = selected.map(&:id)
174
174
  ids.should include published.id
175
175
  ids.should_not include draft.id
176
176
  end
177
177
 
178
178
  it 'selects objects using greater-than-or-equal' do
179
- selected = Perpetuity[Article].select { views >= 3 }
179
+ selected = Perpetuity[Article].select { |article| article.views >= 3 }
180
180
  ids = selected.map(&:id)
181
181
  ids.should include published.id
182
182
  ids.should_not include draft.id
183
183
  end
184
184
 
185
185
  it 'selects objects using less-than' do
186
- selected = Perpetuity[Article].select { views < 3 }
186
+ selected = Perpetuity[Article].select { |article| article.views < 3 }
187
187
  ids = selected.map(&:id)
188
188
  ids.should include draft.id
189
189
  ids.should_not include published.id
190
190
  end
191
191
 
192
192
  it 'selects objects using less-than-or-equal' do
193
- selected = Perpetuity[Article].select { views <= 0 }
193
+ selected = Perpetuity[Article].select { |article| article.views <= 0 }
194
194
  ids = selected.map(&:id)
195
195
  ids.should include draft.id
196
196
  ids.should_not include published.id
197
197
  end
198
198
 
199
199
  it 'selects objects using inequality' do
200
- selected = Perpetuity[Article].select { title.not_equal? 'Draft' }
200
+ selected = Perpetuity[Article].select { |article| article.title.not_equal? 'Draft' }
201
201
  ids = selected.map(&:id)
202
202
  ids.should_not include draft.id
203
203
  ids.should include published.id
204
204
  end
205
205
 
206
206
  it 'selects objects using regular expressions' do
207
- selected = Perpetuity[Article].select { title =~ /Pub/ }
207
+ selected = Perpetuity[Article].select { |article| article.title =~ /Pub/ }
208
208
  ids = selected.map(&:id)
209
209
  ids.should include published.id
210
210
  ids.should_not include draft.id
211
211
  end
212
212
 
213
213
  it 'selects objects using inclusion' do
214
- selected = Perpetuity[Article].select { title.in %w( Published ) }
214
+ selected = Perpetuity[Article].select { |article| article.title.in %w( Published ) }
215
215
  ids = selected.map(&:id)
216
216
  ids.should include published.id
217
217
  ids.should_not include draft.id
data/spec/test_classes.rb CHANGED
@@ -31,11 +31,13 @@ class ArticleMapper < Perpetuity::Mapper
31
31
  attribute :views
32
32
 
33
33
  def published
34
- select { (published_at.not_equal? nil) & (published_at < Time.now) }
34
+ select { |article| (article.published_at.not_equal? nil) &
35
+ (article.published_at < Time.now) }
35
36
  end
36
37
 
37
38
  def unpublished
38
- select { (published_at == nil) | (published_at > Time.now) }
39
+ select { |article| (article.published_at == nil) |
40
+ (article.published_at > Time.now) }
39
41
  end
40
42
  end
41
43
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perpetuity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: '0.4'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-02 00:00:00.000000000 Z
12
+ date: 2013-01-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake