jmonteiro-mongo_mapper 0.1.0
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/.gitignore +10 -0
- data/LICENSE +20 -0
- data/README.rdoc +38 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/bin/mmconsole +60 -0
- data/jmonteiro-mongo_mapper.gemspec +195 -0
- data/lib/mongo_mapper.rb +128 -0
- data/lib/mongo_mapper/descendant_appends.rb +44 -0
- data/lib/mongo_mapper/document.rb +402 -0
- data/lib/mongo_mapper/dynamic_finder.rb +74 -0
- data/lib/mongo_mapper/embedded_document.rb +61 -0
- data/lib/mongo_mapper/finder_options.rb +127 -0
- data/lib/mongo_mapper/plugins.rb +19 -0
- data/lib/mongo_mapper/plugins/associations.rb +104 -0
- data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +28 -0
- data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +23 -0
- data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +49 -0
- data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
- data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
- data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +66 -0
- data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
- data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
- data/lib/mongo_mapper/plugins/clone.rb +13 -0
- data/lib/mongo_mapper/plugins/descendants.rb +16 -0
- data/lib/mongo_mapper/plugins/dirty.rb +119 -0
- data/lib/mongo_mapper/plugins/equality.rb +11 -0
- data/lib/mongo_mapper/plugins/identity_map.rb +66 -0
- data/lib/mongo_mapper/plugins/inspect.rb +14 -0
- data/lib/mongo_mapper/plugins/keys.rb +295 -0
- data/lib/mongo_mapper/plugins/logger.rb +17 -0
- data/lib/mongo_mapper/plugins/pagination.rb +85 -0
- data/lib/mongo_mapper/plugins/protected.rb +31 -0
- data/lib/mongo_mapper/plugins/rails.rb +80 -0
- data/lib/mongo_mapper/plugins/serialization.rb +109 -0
- data/lib/mongo_mapper/plugins/validations.rb +48 -0
- data/lib/mongo_mapper/support.rb +213 -0
- data/performance/read_write.rb +52 -0
- data/specs.watchr +51 -0
- data/test/NOTE_ON_TESTING +1 -0
- data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
- data/test/functional/associations/test_belongs_to_proxy.rb +93 -0
- data/test/functional/associations/test_in_array_proxy.rb +309 -0
- data/test/functional/associations/test_many_documents_as_proxy.rb +246 -0
- data/test/functional/associations/test_many_documents_proxy.rb +437 -0
- data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +175 -0
- data/test/functional/associations/test_many_embedded_proxy.rb +216 -0
- data/test/functional/associations/test_many_polymorphic_proxy.rb +340 -0
- data/test/functional/associations/test_one_proxy.rb +149 -0
- data/test/functional/test_associations.rb +44 -0
- data/test/functional/test_binary.rb +27 -0
- data/test/functional/test_callbacks.rb +81 -0
- data/test/functional/test_dirty.rb +156 -0
- data/test/functional/test_document.rb +1171 -0
- data/test/functional/test_embedded_document.rb +125 -0
- data/test/functional/test_identity_map.rb +233 -0
- data/test/functional/test_logger.rb +20 -0
- data/test/functional/test_modifiers.rb +252 -0
- data/test/functional/test_pagination.rb +93 -0
- data/test/functional/test_protected.rb +41 -0
- data/test/functional/test_string_id_compatibility.rb +67 -0
- data/test/functional/test_validations.rb +329 -0
- data/test/models.rb +232 -0
- data/test/support/custom_matchers.rb +55 -0
- data/test/support/timing.rb +16 -0
- data/test/test_helper.rb +60 -0
- data/test/unit/associations/test_base.rb +207 -0
- data/test/unit/associations/test_proxy.rb +103 -0
- data/test/unit/serializers/test_json_serializer.rb +189 -0
- data/test/unit/test_descendant_appends.rb +71 -0
- data/test/unit/test_document.rb +203 -0
- data/test/unit/test_dynamic_finder.rb +125 -0
- data/test/unit/test_embedded_document.rb +628 -0
- data/test/unit/test_finder_options.rb +325 -0
- data/test/unit/test_keys.rb +169 -0
- data/test/unit/test_mongo_mapper.rb +65 -0
- data/test/unit/test_pagination.rb +127 -0
- data/test/unit/test_plugins.rb +42 -0
- data/test/unit/test_rails.rb +139 -0
- data/test/unit/test_rails_compatibility.rb +42 -0
- data/test/unit/test_serialization.rb +51 -0
- data/test/unit/test_support.rb +350 -0
- data/test/unit/test_time_zones.rb +39 -0
- data/test/unit/test_validations.rb +492 -0
- metadata +260 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module DescendantAppends
|
3
|
+
def included(model)
|
4
|
+
extra_extensions.each { |extension| model.extend(extension) }
|
5
|
+
extra_inclusions.each { |inclusion| model.send(:include, inclusion) }
|
6
|
+
descendants << model
|
7
|
+
end
|
8
|
+
|
9
|
+
# @api public
|
10
|
+
def descendants
|
11
|
+
@descendants ||= Set.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api public
|
15
|
+
def append_extensions(*extensions)
|
16
|
+
extra_extensions.concat extensions
|
17
|
+
|
18
|
+
# Add the extension to existing descendants
|
19
|
+
descendants.each do |model|
|
20
|
+
extensions.each { |extension| model.extend(extension) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @api public
|
25
|
+
def append_inclusions(*inclusions)
|
26
|
+
extra_inclusions.concat inclusions
|
27
|
+
|
28
|
+
# Add the inclusion to existing descendants
|
29
|
+
descendants.each do |model|
|
30
|
+
inclusions.each { |inclusion| model.send(:include, inclusion) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def extra_extensions
|
36
|
+
@extra_extensions ||= []
|
37
|
+
end
|
38
|
+
|
39
|
+
# @api private
|
40
|
+
def extra_inclusions
|
41
|
+
@extra_inclusions ||= []
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,402 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
module Document
|
3
|
+
extend DescendantAppends
|
4
|
+
|
5
|
+
def self.included(model)
|
6
|
+
model.class_eval do
|
7
|
+
include InstanceMethods
|
8
|
+
extend ClassMethods
|
9
|
+
extend Finders
|
10
|
+
|
11
|
+
extend Plugins
|
12
|
+
plugin Plugins::Associations
|
13
|
+
plugin Plugins::Clone
|
14
|
+
plugin Plugins::Descendants
|
15
|
+
plugin Plugins::Equality
|
16
|
+
plugin Plugins::Inspect
|
17
|
+
plugin Plugins::Keys
|
18
|
+
plugin Plugins::Dirty # for now dirty needs to be after keys
|
19
|
+
plugin Plugins::Logger
|
20
|
+
plugin Plugins::Pagination
|
21
|
+
plugin Plugins::Protected
|
22
|
+
plugin Plugins::Rails
|
23
|
+
plugin Plugins::Serialization
|
24
|
+
plugin Plugins::Validations
|
25
|
+
plugin Plugins::Callbacks # for now callbacks needs to be after validations
|
26
|
+
|
27
|
+
extend Plugins::Validations::DocumentMacros
|
28
|
+
end
|
29
|
+
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
def inherited(subclass)
|
35
|
+
subclass.set_collection_name(collection_name)
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
def ensure_index(name_or_array, options={})
|
40
|
+
keys_to_index = if name_or_array.is_a?(Array)
|
41
|
+
name_or_array.map { |pair| [pair[0], pair[1]] }
|
42
|
+
else
|
43
|
+
name_or_array
|
44
|
+
end
|
45
|
+
|
46
|
+
MongoMapper.ensure_index(self, keys_to_index, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def find!(*args)
|
50
|
+
options = args.extract_options!
|
51
|
+
case args.first
|
52
|
+
when :first then first(options)
|
53
|
+
when :last then last(options)
|
54
|
+
when :all then find_every(options)
|
55
|
+
when Array then find_some(args, options)
|
56
|
+
else
|
57
|
+
case args.size
|
58
|
+
when 0
|
59
|
+
raise DocumentNotFound, "Couldn't find without an ID"
|
60
|
+
when 1
|
61
|
+
find_one!(options.merge({:_id => args[0]}))
|
62
|
+
else
|
63
|
+
find_some(args, options)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def find(*args)
|
69
|
+
find!(*args)
|
70
|
+
rescue DocumentNotFound
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def first(options={})
|
75
|
+
find_one(options)
|
76
|
+
end
|
77
|
+
|
78
|
+
def last(options={})
|
79
|
+
raise ':order option must be provided when using last' if options[:order].blank?
|
80
|
+
find_one(options.merge(:order => invert_order_clause(options[:order])))
|
81
|
+
end
|
82
|
+
|
83
|
+
def all(options={})
|
84
|
+
find_every(options)
|
85
|
+
end
|
86
|
+
|
87
|
+
def find_by_id(id)
|
88
|
+
find(id)
|
89
|
+
end
|
90
|
+
|
91
|
+
def count(options={})
|
92
|
+
collection.find(to_criteria(options)).count
|
93
|
+
end
|
94
|
+
|
95
|
+
def exists?(options={})
|
96
|
+
!count(options).zero?
|
97
|
+
end
|
98
|
+
|
99
|
+
def create(*docs)
|
100
|
+
initialize_each(*docs) { |doc| doc.save }
|
101
|
+
end
|
102
|
+
|
103
|
+
def create!(*docs)
|
104
|
+
initialize_each(*docs) { |doc| doc.save! }
|
105
|
+
end
|
106
|
+
|
107
|
+
def update(*args)
|
108
|
+
if args.length == 1
|
109
|
+
update_multiple(args[0])
|
110
|
+
else
|
111
|
+
id, attributes = args
|
112
|
+
update_single(id, attributes)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def delete(*ids)
|
117
|
+
collection.remove(to_criteria(:_id => ids.flatten))
|
118
|
+
end
|
119
|
+
|
120
|
+
def delete_all(options={})
|
121
|
+
collection.remove(to_criteria(options))
|
122
|
+
end
|
123
|
+
|
124
|
+
def destroy(*ids)
|
125
|
+
find_some(ids.flatten).each(&:destroy)
|
126
|
+
end
|
127
|
+
|
128
|
+
def destroy_all(options={})
|
129
|
+
all(options).each(&:destroy)
|
130
|
+
end
|
131
|
+
|
132
|
+
def increment(*args)
|
133
|
+
modifier_update('$inc', args)
|
134
|
+
end
|
135
|
+
|
136
|
+
def decrement(*args)
|
137
|
+
criteria, keys = criteria_and_keys_from_args(args)
|
138
|
+
values, to_decrement = keys.values, {}
|
139
|
+
keys.keys.each_with_index { |k, i| to_decrement[k] = -values[i].abs }
|
140
|
+
collection.update(criteria, {'$inc' => to_decrement}, :multi => true)
|
141
|
+
end
|
142
|
+
|
143
|
+
def set(*args)
|
144
|
+
modifier_update('$set', args)
|
145
|
+
end
|
146
|
+
|
147
|
+
def push(*args)
|
148
|
+
modifier_update('$push', args)
|
149
|
+
end
|
150
|
+
|
151
|
+
def push_all(*args)
|
152
|
+
modifier_update('$pushAll', args)
|
153
|
+
end
|
154
|
+
|
155
|
+
def push_uniq(*args)
|
156
|
+
criteria, keys = criteria_and_keys_from_args(args)
|
157
|
+
keys.each { |key, value | criteria[key] = {'$ne' => value} }
|
158
|
+
collection.update(criteria, {'$push' => keys}, :multi => true)
|
159
|
+
end
|
160
|
+
|
161
|
+
def pull(*args)
|
162
|
+
modifier_update('$pull', args)
|
163
|
+
end
|
164
|
+
|
165
|
+
def pull_all(*args)
|
166
|
+
modifier_update('$pullAll', args)
|
167
|
+
end
|
168
|
+
|
169
|
+
def pop(*args)
|
170
|
+
modifier_update('$pop', args)
|
171
|
+
end
|
172
|
+
|
173
|
+
def modifier_update(modifier, args)
|
174
|
+
criteria, keys = criteria_and_keys_from_args(args)
|
175
|
+
modifiers = {modifier => keys}
|
176
|
+
collection.update(criteria, modifiers, :multi => true)
|
177
|
+
end
|
178
|
+
private :modifier_update
|
179
|
+
|
180
|
+
def criteria_and_keys_from_args(args)
|
181
|
+
keys = args.pop
|
182
|
+
criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
|
183
|
+
[to_criteria(criteria), keys]
|
184
|
+
end
|
185
|
+
private :criteria_and_keys_from_args
|
186
|
+
|
187
|
+
def embeddable?
|
188
|
+
false
|
189
|
+
end
|
190
|
+
|
191
|
+
def connection(mongo_connection=nil)
|
192
|
+
if mongo_connection.nil?
|
193
|
+
@connection ||= MongoMapper.connection
|
194
|
+
else
|
195
|
+
@connection = mongo_connection
|
196
|
+
end
|
197
|
+
@connection
|
198
|
+
end
|
199
|
+
|
200
|
+
def set_database_name(name)
|
201
|
+
@database_name = name
|
202
|
+
end
|
203
|
+
|
204
|
+
def database_name
|
205
|
+
@database_name
|
206
|
+
end
|
207
|
+
|
208
|
+
def database
|
209
|
+
if database_name.nil?
|
210
|
+
MongoMapper.database
|
211
|
+
else
|
212
|
+
connection.db(database_name)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def set_collection_name(name)
|
217
|
+
@collection_name = name
|
218
|
+
end
|
219
|
+
|
220
|
+
def collection_name
|
221
|
+
@collection_name ||= self.to_s.tableize.gsub(/\//, '.')
|
222
|
+
end
|
223
|
+
|
224
|
+
def collection
|
225
|
+
database.collection(collection_name)
|
226
|
+
end
|
227
|
+
|
228
|
+
def timestamps!
|
229
|
+
key :created_at, Time
|
230
|
+
key :updated_at, Time
|
231
|
+
class_eval { before_save :update_timestamps }
|
232
|
+
end
|
233
|
+
|
234
|
+
def userstamps!
|
235
|
+
key :creator_id, ObjectId
|
236
|
+
key :updater_id, ObjectId
|
237
|
+
belongs_to :creator, :class_name => 'User'
|
238
|
+
belongs_to :updater, :class_name => 'User'
|
239
|
+
end
|
240
|
+
|
241
|
+
def single_collection_inherited?
|
242
|
+
keys.key?(:_type) && single_collection_inherited_superclass?
|
243
|
+
end
|
244
|
+
|
245
|
+
def single_collection_inherited_superclass?
|
246
|
+
superclass.respond_to?(:keys) && superclass.keys.key?(:_type)
|
247
|
+
end
|
248
|
+
|
249
|
+
private
|
250
|
+
def initialize_each(*docs)
|
251
|
+
instances = []
|
252
|
+
docs = [{}] if docs.blank?
|
253
|
+
docs.flatten.each do |attrs|
|
254
|
+
doc = new(attrs)
|
255
|
+
yield(doc)
|
256
|
+
instances << doc
|
257
|
+
end
|
258
|
+
instances.size == 1 ? instances[0] : instances
|
259
|
+
end
|
260
|
+
|
261
|
+
def find_every(options)
|
262
|
+
criteria, options = to_finder_options(options)
|
263
|
+
collection.find(criteria, options).to_a.map do |doc|
|
264
|
+
load(doc)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
def find_some(ids, options={})
|
269
|
+
ids = ids.flatten.compact.uniq
|
270
|
+
documents = find_every(options.merge(:_id => ids))
|
271
|
+
|
272
|
+
if ids.size == documents.size
|
273
|
+
documents
|
274
|
+
else
|
275
|
+
raise DocumentNotFound, "Couldn't find all of the ids (#{ids.to_sentence}). Found #{documents.size}, but was expecting #{ids.size}"
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def find_one(options={})
|
280
|
+
criteria, options = to_finder_options(options)
|
281
|
+
if doc = collection.find_one(criteria, options)
|
282
|
+
load(doc)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def find_one!(options={})
|
287
|
+
find_one(options) || raise(DocumentNotFound, "Document match #{options.inspect} does not exist in #{collection.name} collection")
|
288
|
+
end
|
289
|
+
|
290
|
+
def invert_order_clause(order)
|
291
|
+
order.split(',').map do |order_segment|
|
292
|
+
if order_segment =~ /\sasc/i
|
293
|
+
order_segment.sub /\sasc/i, ' desc'
|
294
|
+
elsif order_segment =~ /\sdesc/i
|
295
|
+
order_segment.sub /\sdesc/i, ' asc'
|
296
|
+
else
|
297
|
+
"#{order_segment.strip} desc"
|
298
|
+
end
|
299
|
+
end.join(',')
|
300
|
+
end
|
301
|
+
|
302
|
+
def update_single(id, attrs)
|
303
|
+
if id.blank? || attrs.blank? || !attrs.is_a?(Hash)
|
304
|
+
raise ArgumentError, "Updating a single document requires an id and a hash of attributes"
|
305
|
+
end
|
306
|
+
|
307
|
+
doc = find(id)
|
308
|
+
doc.update_attributes(attrs)
|
309
|
+
doc
|
310
|
+
end
|
311
|
+
|
312
|
+
def update_multiple(docs)
|
313
|
+
unless docs.is_a?(Hash)
|
314
|
+
raise ArgumentError, "Updating multiple documents takes 1 argument and it must be hash"
|
315
|
+
end
|
316
|
+
|
317
|
+
instances = []
|
318
|
+
docs.each_pair { |id, attrs| instances << update(id, attrs) }
|
319
|
+
instances
|
320
|
+
end
|
321
|
+
|
322
|
+
def to_criteria(options={})
|
323
|
+
FinderOptions.new(self, options).criteria
|
324
|
+
end
|
325
|
+
|
326
|
+
def to_finder_options(options={})
|
327
|
+
FinderOptions.new(self, options).to_a
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
module InstanceMethods
|
332
|
+
def collection
|
333
|
+
self.class.collection
|
334
|
+
end
|
335
|
+
|
336
|
+
def database
|
337
|
+
self.class.database
|
338
|
+
end
|
339
|
+
|
340
|
+
def save(options={})
|
341
|
+
options.reverse_merge!(:validate => true)
|
342
|
+
perform_validations = options.delete(:validate)
|
343
|
+
!perform_validations || valid? ? create_or_update(options) : false
|
344
|
+
end
|
345
|
+
|
346
|
+
def save!
|
347
|
+
save || raise(DocumentNotValid.new(self))
|
348
|
+
end
|
349
|
+
|
350
|
+
def update_attributes(attrs={})
|
351
|
+
self.attributes = attrs
|
352
|
+
save
|
353
|
+
end
|
354
|
+
|
355
|
+
def update_attributes!(attrs={})
|
356
|
+
self.attributes = attrs
|
357
|
+
save!
|
358
|
+
end
|
359
|
+
|
360
|
+
def destroy
|
361
|
+
delete
|
362
|
+
end
|
363
|
+
|
364
|
+
def delete
|
365
|
+
self.class.delete(id) unless new?
|
366
|
+
end
|
367
|
+
|
368
|
+
def reload
|
369
|
+
doc = self.class.find(_id)
|
370
|
+
self.class.associations.each { |name, assoc| send(name).reset if respond_to?(name) }
|
371
|
+
self.attributes = doc.attributes
|
372
|
+
self
|
373
|
+
end
|
374
|
+
|
375
|
+
private
|
376
|
+
def create_or_update(options={})
|
377
|
+
result = new? ? create(options) : update(options)
|
378
|
+
result != false
|
379
|
+
end
|
380
|
+
|
381
|
+
def create(options={})
|
382
|
+
save_to_collection(options)
|
383
|
+
end
|
384
|
+
|
385
|
+
def update(options={})
|
386
|
+
save_to_collection(options)
|
387
|
+
end
|
388
|
+
|
389
|
+
def save_to_collection(options={})
|
390
|
+
safe = options.delete(:safe) || false
|
391
|
+
@new = false
|
392
|
+
collection.save(to_mongo, :safe => safe)
|
393
|
+
end
|
394
|
+
|
395
|
+
def update_timestamps
|
396
|
+
now = Time.now.utc
|
397
|
+
self[:created_at] = now if new? && !created_at?
|
398
|
+
self[:updated_at] = now
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end # Document
|
402
|
+
end # MongoMapper
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module MongoMapper
|
2
|
+
# @api private
|
3
|
+
module Finders
|
4
|
+
def dynamic_find(finder, args)
|
5
|
+
attributes = {}
|
6
|
+
finder.attributes.each_with_index do |attr, index|
|
7
|
+
attributes[attr] = args[index]
|
8
|
+
end
|
9
|
+
|
10
|
+
options = args.extract_options!.merge(attributes)
|
11
|
+
|
12
|
+
if result = find(finder.finder, options)
|
13
|
+
result
|
14
|
+
else
|
15
|
+
if finder.raise?
|
16
|
+
raise DocumentNotFound, "Couldn't find Document with #{attributes.inspect} in collection named #{collection.name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
if finder.instantiator
|
20
|
+
self.send(finder.instantiator, attributes)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
def method_missing(method, *args, &block)
|
27
|
+
finder = DynamicFinder.new(method)
|
28
|
+
|
29
|
+
if finder.found?
|
30
|
+
dynamic_find(finder, args)
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class DynamicFinder
|
38
|
+
attr_reader :method, :attributes, :finder, :bang, :instantiator
|
39
|
+
|
40
|
+
def initialize(method)
|
41
|
+
@method = method
|
42
|
+
@finder = :first
|
43
|
+
@bang = false
|
44
|
+
match
|
45
|
+
end
|
46
|
+
|
47
|
+
def found?
|
48
|
+
@finder.present?
|
49
|
+
end
|
50
|
+
|
51
|
+
def raise?
|
52
|
+
bang == true
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
def match
|
57
|
+
case method.to_s
|
58
|
+
when /^find_(all_by|by)_([_a-zA-Z]\w*)$/
|
59
|
+
@finder = :all if $1 == 'all_by'
|
60
|
+
names = $2
|
61
|
+
when /^find_by_([_a-zA-Z]\w*)\!$/
|
62
|
+
@bang = true
|
63
|
+
names = $1
|
64
|
+
when /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/
|
65
|
+
@instantiator = $1 == 'initialize' ? :new : :create
|
66
|
+
names = $2
|
67
|
+
else
|
68
|
+
@finder = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
@attributes = names && names.split('_and_')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|