candy 0.2.8 → 0.2.9
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.markdown +11 -0
- data/README.markdown +1 -1
- data/VERSION +1 -1
- data/candy.gemspec +2 -2
- data/lib/candy/array.rb +1 -1
- data/lib/candy/crunch.rb +66 -9
- data/lib/candy/piece.rb +2 -34
- data/spec/candy/piece_spec.rb +24 -0
- data/spec/candy/wrapper_spec.rb +0 -1
- metadata +3 -3
data/HISTORY.markdown
CHANGED
@@ -3,6 +3,17 @@ Candy History
|
|
3
3
|
|
4
4
|
This document aims to provide only an overview. Further, we've only really been tracking things since **v0.2**. For obsessive detail, just check out the `git log`.
|
5
5
|
|
6
|
+
v0.2.9 - 2010-05-14 (the "+1" release)
|
7
|
+
--------------------------------------
|
8
|
+
Moved methods around again, placing more of the database update methods into Candy::Crunch. Also began support for two flavors of
|
9
|
+
atomic update methods:
|
10
|
+
|
11
|
+
1. _Safe_ methods that call the collection in "safe" mode, meaning that it's much slower but the update is verified and exceptions are returned by the Mongo driver. These methods also return the new values. So far supported are **set** and **inc**.
|
12
|
+
2. _Unsafe_ or _bang!_ methods that call the collection in "unsafe" mode, for maximum speed but without verification or new values returned. So far supported are **set!** and **inc!**.
|
13
|
+
|
14
|
+
* Refactored; added 'bang!' methods for atomic updates
|
15
|
+
|
16
|
+
|
6
17
|
v0.2.8 - 2010-05-13 (the "Holy crap, that was ten pomodoros" release)
|
7
18
|
---------------------------------------------------------------------
|
8
19
|
Major refactoring to fix a major bug: embedded documents weren't being loaded properly on document retrieval. This resulted in a lot of code being moved around, and some regrettable circular connascence between Piece and Wrapper that I hope to address later. Overall, though, it's simpler now.
|
data/README.markdown
CHANGED
@@ -29,7 +29,7 @@ We got 'em. Candy pieces can contain each other recursively, to any arbitrary d
|
|
29
29
|
seafood: 'Maryland blue crabs',
|
30
30
|
scotch: ['Glenmorangie Port Wood Finish',
|
31
31
|
'Balvenie Single Barrel']}
|
32
|
-
me.spouse = Person.
|
32
|
+
me.spouse = Person.piece(first_name: 'Anna', eyes: :blue)
|
33
33
|
me.spouse.eyes # => :blue
|
34
34
|
me.favorites.scotch[1] # => 'Balvenie Single Barrel'
|
35
35
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.9
|
data/candy.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{candy}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.9"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Stephen Eley"]
|
12
|
-
s.date = %q{2010-05-
|
12
|
+
s.date = %q{2010-05-14}
|
13
13
|
s.description = %q{Candy provides simple, transparent object persistence for the MongoDB database. Classes that
|
14
14
|
include Candy modules save all properties to Mongo automatically, can be recursively embedded,
|
15
15
|
and can retrieve records with chainable open-ended class methods, eliminating the need for
|
data/lib/candy/array.rb
CHANGED
@@ -48,7 +48,7 @@ module Candy
|
|
48
48
|
# (Thus supporting real-time concurrency for queue-like behavior.)
|
49
49
|
def shift(n=1)
|
50
50
|
doc = @__candy_parent.collection.find_and_modify query: {"_id" => @__candy_parent.id}, update: {'$pop' => {@__candy_parent_key => -1}}, new: false
|
51
|
-
@__candy = doc[@__candy_parent_key.to_s]
|
51
|
+
@__candy = from_candy(doc[@__candy_parent_key.to_s])
|
52
52
|
@__candy.shift
|
53
53
|
end
|
54
54
|
|
data/lib/candy/crunch.rb
CHANGED
@@ -212,18 +212,75 @@ module Candy
|
|
212
212
|
|
213
213
|
end
|
214
214
|
|
215
|
+
# HERE BEGINNETH THE MODULE PROPER.
|
216
|
+
# (The above were class methods.)
|
215
217
|
|
216
|
-
#
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
218
|
+
# The MongoDB collection object that everything saves to. Defaults to the class's
|
219
|
+
# collection, which in turn defaults to the classname.
|
220
|
+
def collection
|
221
|
+
@__candy_collection ||= self.class.collection
|
222
|
+
end
|
223
|
+
|
224
|
+
# This is normally set at the class level (with a default of the classname) but you
|
225
|
+
# can override it on a per-object basis if you need to.
|
226
|
+
def collection=(val)
|
227
|
+
@__candy_collection = val
|
228
|
+
end
|
229
|
+
|
230
|
+
### RETRIEVAL METHODS
|
231
|
+
# Returns the listed fields of the document. If no fields are given, returns the whole document.
|
232
|
+
def retrieve(*fields)
|
233
|
+
options = (fields.empty? ? {} : {fields: fields})
|
234
|
+
from_candy(collection.find_one({'_id' => id}, options)) if id
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
# A generic updater that performs the atomic operation specified on a value nested arbitrarily deeply.
|
239
|
+
# Operates in "unsafe" mode, meaning that no document errors will be returned and results are not
|
240
|
+
# guaranteed. The benefit is that it's very, very fast. Always returns true.
|
241
|
+
def operate!(operator, fields)
|
242
|
+
operate operator, fields, {safe: false} and true
|
243
|
+
end
|
244
|
+
|
245
|
+
# A generic updater that performs the atomic operation specified on a value nested arbitrarily deeply.
|
246
|
+
#
|
247
|
+
def operate(operator, fields, options={safe: true})
|
248
|
+
if @__candy_parent
|
249
|
+
@__candy_parent.operate operator, embedded(fields), options
|
250
|
+
else
|
251
|
+
@__candy_id = collection.insert({}) unless id # Ensure we have something to update
|
252
|
+
collection.update({'_id' => id}, {"$#{operator}" => Wrapper.wrap(fields)}, options)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
# Given a hash of property/value pairs, sets those values in Mongo using the atomic $set if
|
257
|
+
# we have a document ID. Otherwise inserts them and sets the object's ID. Operates in
|
258
|
+
# 'unsafe' mode, so database exceptions are not reported but updates are very fast.
|
259
|
+
def set!(fields)
|
260
|
+
operate! :set, fields
|
225
261
|
end
|
226
262
|
|
263
|
+
# Given a hash of property/value pairs, sets those values in Mongo using the atomic $set if
|
264
|
+
# we have a document ID. Otherwise inserts them and sets the object's ID. Returns the
|
265
|
+
# values passed to it.
|
266
|
+
def set(fields)
|
267
|
+
operate :set, fields
|
268
|
+
fields
|
269
|
+
end
|
270
|
+
|
271
|
+
# Increments the specified field by the specified amount (defaults to 1). Does not return the
|
272
|
+
# new value or any document errors.
|
273
|
+
def inc!(field, value=1)
|
274
|
+
operate! :inc, field: value
|
275
|
+
end
|
276
|
+
|
277
|
+
# Increments the specified field by the specified amount (defaults to 1) and returns the
|
278
|
+
# new value.
|
279
|
+
def inc(field, value=1)
|
280
|
+
operate :inc, field => value
|
281
|
+
retrieve(field)[field]
|
282
|
+
end
|
283
|
+
|
227
284
|
|
228
285
|
def self.included(receiver)
|
229
286
|
receiver.extend ClassMethods
|
data/lib/candy/piece.rb
CHANGED
@@ -101,16 +101,11 @@ module Candy
|
|
101
101
|
def id
|
102
102
|
@__candy_id
|
103
103
|
end
|
104
|
-
|
105
|
-
# Pull our document from the database if we know our ID.
|
106
|
-
def retrieve_document
|
107
|
-
from_candy(collection.find_one({'_id' => id})) if id
|
108
|
-
end
|
109
|
-
|
104
|
+
|
110
105
|
|
111
106
|
# Returns the hash of memoized values.
|
112
107
|
def candy
|
113
|
-
@__candy ||=
|
108
|
+
@__candy ||= retrieve || {}
|
114
109
|
end
|
115
110
|
|
116
111
|
# Objects are equal if they point to the same MongoDB record (unless both have IDs of nil, in which case
|
@@ -153,17 +148,6 @@ module Candy
|
|
153
148
|
self
|
154
149
|
end
|
155
150
|
|
156
|
-
# The MongoDB collection object that everything saves to. Defaults to the class's
|
157
|
-
# collection, which in turn defaults to the classname.
|
158
|
-
def collection
|
159
|
-
@__candy_collection ||= self.class.collection
|
160
|
-
end
|
161
|
-
|
162
|
-
# This is normally set at the class level (with a default of the classname) but you
|
163
|
-
# can override it on a per-object basis if you need to.
|
164
|
-
def collection=(val)
|
165
|
-
@__candy_collection = val
|
166
|
-
end
|
167
151
|
|
168
152
|
# Convenience method for debugging. Shows the class, the Mongo ID, and the saved state hash.
|
169
153
|
def to_s
|
@@ -189,22 +173,6 @@ module Candy
|
|
189
173
|
end
|
190
174
|
|
191
175
|
|
192
|
-
# Given a hash of property/value pairs, sets those values in Mongo using the atomic $set if
|
193
|
-
# we have a document ID. Otherwise inserts them and sets the object's ID.
|
194
|
-
def set(fields)
|
195
|
-
operate :set, fields
|
196
|
-
end
|
197
|
-
|
198
|
-
# A generic updater that performs the atomic operation specified on a value nested arbitrarily deeply.
|
199
|
-
#
|
200
|
-
def operate(operator, fields)
|
201
|
-
if @__candy_parent
|
202
|
-
@__candy_parent.operate operator, embedded(fields)
|
203
|
-
else
|
204
|
-
@__candy_id = collection.insert({}) unless id # Ensure we have something to update
|
205
|
-
collection.update({'_id' => id}, {"$#{operator}" => Wrapper.wrap(fields)})
|
206
|
-
end
|
207
|
-
end
|
208
176
|
|
209
177
|
private
|
210
178
|
|
data/spec/candy/piece_spec.rb
CHANGED
@@ -141,6 +141,14 @@ describe Candy::Piece do
|
|
141
141
|
that.intensity.should == :Yowza
|
142
142
|
end
|
143
143
|
|
144
|
+
it "can get particular attributes" do
|
145
|
+
@this.smell = "fruity"
|
146
|
+
@this.feel = "rough"
|
147
|
+
that = Zagnut(@this.id)
|
148
|
+
that.retrieve(:smell)[:smell].should == "fruity"
|
149
|
+
that.retrieve(:smell).should_not have_key(:feel)
|
150
|
+
end
|
151
|
+
|
144
152
|
# Test class for scoped magic method generation
|
145
153
|
class BabyRuth
|
146
154
|
include Candy::Piece
|
@@ -205,6 +213,22 @@ describe Candy::Piece do
|
|
205
213
|
@verifier.count.should == 3
|
206
214
|
Zagnut.crunchy(:not_quite).color.should == 'brown'
|
207
215
|
end
|
216
|
+
|
217
|
+
it "can increment a value simply" do
|
218
|
+
@this.inc(:ounces).should == 18
|
219
|
+
@verifier.find_one(ounces: 18)["crunchy"].should == :very
|
220
|
+
end
|
221
|
+
|
222
|
+
it "can increment a value by a specified positive amount" do
|
223
|
+
@this.inc(:ounces, 5).should == 22
|
224
|
+
@verifier.find_one(ounces: 22)["crunchy"].should == :very
|
225
|
+
end
|
226
|
+
|
227
|
+
it "can increment a value by a specified negative amount" do
|
228
|
+
@this.inc(:ounces, -5).should == 12
|
229
|
+
@verifier.find_one(ounces: 12)["crunchy"].should == :very
|
230
|
+
end
|
231
|
+
|
208
232
|
end
|
209
233
|
|
210
234
|
describe "embedding" do
|
data/spec/candy/wrapper_spec.rb
CHANGED
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 9
|
9
|
+
version: 0.2.9
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Stephen Eley
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-14 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|