djsun-mongo_mapper 0.5.6.6 → 0.5.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/.gitignore +3 -1
  2. data/Rakefile +13 -8
  3. data/VERSION +1 -1
  4. data/djsun-mongo_mapper.gemspec +17 -21
  5. data/lib/mongo_mapper/associations/base.rb +32 -36
  6. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -2
  7. data/lib/mongo_mapper/associations/many_documents_proxy.rb +19 -10
  8. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +2 -2
  9. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +21 -36
  10. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +1 -1
  11. data/lib/mongo_mapper/associations/proxy.rb +3 -2
  12. data/lib/mongo_mapper/associations.rb +114 -8
  13. data/lib/mongo_mapper/callbacks.rb +18 -0
  14. data/lib/mongo_mapper/document.rb +173 -37
  15. data/lib/mongo_mapper/dynamic_finder.rb +1 -1
  16. data/lib/mongo_mapper/embedded_document.rb +9 -13
  17. data/lib/mongo_mapper/finder_options.rb +67 -44
  18. data/lib/mongo_mapper/pagination.rb +2 -0
  19. data/lib/mongo_mapper/serialization.rb +1 -1
  20. data/lib/mongo_mapper/serializers/json_serializer.rb +1 -1
  21. data/lib/mongo_mapper/support.rb +9 -0
  22. data/lib/mongo_mapper/validations.rb +12 -42
  23. data/lib/mongo_mapper.rb +11 -5
  24. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +5 -5
  25. data/test/functional/associations/test_belongs_to_proxy.rb +29 -31
  26. data/test/functional/associations/test_many_documents_as_proxy.rb +5 -5
  27. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +27 -3
  28. data/test/functional/associations/test_many_embedded_proxy.rb +58 -38
  29. data/test/functional/associations/test_many_polymorphic_proxy.rb +45 -3
  30. data/test/functional/associations/test_many_proxy.rb +61 -11
  31. data/test/functional/test_associations.rb +3 -3
  32. data/test/functional/test_binary.rb +1 -1
  33. data/test/functional/test_callbacks.rb +1 -1
  34. data/test/functional/test_dirty.rb +3 -3
  35. data/test/functional/test_document.rb +62 -58
  36. data/test/functional/test_embedded_document.rb +1 -1
  37. data/test/functional/test_pagination.rb +1 -1
  38. data/test/functional/test_rails_compatibility.rb +1 -1
  39. data/test/functional/test_validations.rb +46 -14
  40. data/test/models.rb +87 -35
  41. data/test/support/{test_timing.rb → timing.rb} +1 -1
  42. data/test/test_helper.rb +8 -13
  43. data/test/unit/serializers/test_json_serializer.rb +0 -4
  44. data/test/unit/test_association_base.rb +24 -8
  45. data/test/unit/test_document.rb +40 -71
  46. data/test/unit/test_embedded_document.rb +27 -67
  47. data/test/unit/test_finder_options.rb +16 -0
  48. data/test/unit/test_key.rb +5 -17
  49. data/test/unit/test_mongomapper.rb +2 -2
  50. data/test/unit/test_pagination.rb +4 -0
  51. metadata +10 -12
  52. data/mongo_mapper.gemspec +0 -170
  53. data/test/functional/associations/test_namespace.rb +0 -27
@@ -13,12 +13,12 @@ module MongoMapper
13
13
  extend Validations::Macros
14
14
  extend ClassMethods
15
15
  extend Finders
16
-
16
+
17
17
  def self.per_page
18
18
  25
19
19
  end unless respond_to?(:per_page)
20
20
  end
21
-
21
+
22
22
  descendants << model
23
23
  end
24
24
 
@@ -32,18 +32,30 @@ module MongoMapper
32
32
  create_indexes_for(key)
33
33
  key
34
34
  end
35
-
35
+
36
36
  def ensure_index(name_or_array, options={})
37
37
  keys_to_index = if name_or_array.is_a?(Array)
38
38
  name_or_array.map { |pair| [pair[0], pair[1]] }
39
39
  else
40
40
  name_or_array
41
41
  end
42
-
42
+
43
43
  MongoMapper.ensure_index(self, keys_to_index, options)
44
44
  end
45
-
46
- def find(*args)
45
+
46
+ # @overload find(:first, options)
47
+ # @see Document.first
48
+ #
49
+ # @overload find(:last, options)
50
+ # @see Document.last
51
+ #
52
+ # @overload find(:all, options)
53
+ # @see Document.all
54
+ #
55
+ # @overload find(ids, options)
56
+ #
57
+ # @raise DocumentNotFound raised when no ID or arguments are provided
58
+ def find!(*args)
47
59
  options = args.extract_options!
48
60
  case args.first
49
61
  when :first then first(options)
@@ -61,6 +73,12 @@ module MongoMapper
61
73
  end
62
74
  end
63
75
  end
76
+
77
+ def find(*args)
78
+ find!(*args)
79
+ rescue DocumentNotFound
80
+ nil
81
+ end
64
82
 
65
83
  def paginate(options)
66
84
  per_page = options.delete(:per_page) || self.per_page
@@ -73,15 +91,39 @@ module MongoMapper
73
91
  pagination
74
92
  end
75
93
 
94
+ # @param [Hash] options any conditions understood by
95
+ # FinderOptions.to_mongo_criteria
96
+ #
97
+ # @return the first document in the ordered collection as described by
98
+ # +options+
99
+ #
100
+ # @see FinderOptions
76
101
  def first(options={})
77
102
  find_one(options)
78
103
  end
79
104
 
105
+ # @param [Hash] options any conditions understood by
106
+ # FinderOptions.to_mongo_criteria
107
+ # @option [String] :order this *mandatory* option describes how to
108
+ # identify the ordering of the documents in your collection. Note that
109
+ # the *last* document in this collection will be selected.
110
+ #
111
+ # @return the last document in the ordered collection as described by
112
+ # +options+
113
+ #
114
+ # @raise Exception when no <tt>:order</tt> option has been defined
80
115
  def last(options={})
81
116
  raise ':order option must be provided when using last' if options[:order].blank?
82
117
  find_one(options.merge(:order => invert_order_clause(options[:order])))
83
118
  end
84
119
 
120
+ # @param [Hash] options any conditions understood by
121
+ # FinderOptions.to_mongo_criteria
122
+ #
123
+ # @return [Array] all documents in your collection that match the
124
+ # provided conditions
125
+ #
126
+ # @see FinderOptions
85
127
  def all(options={})
86
128
  find_every(options)
87
129
  end
@@ -98,18 +140,51 @@ module MongoMapper
98
140
  !count(options).zero?
99
141
  end
100
142
 
143
+ # @overload create(doc_attributes)
144
+ # Create a single new document
145
+ # @param [Hash] doc_attributes key/value pairs to create a new
146
+ # document
147
+ #
148
+ # @overload create(docs_attributes)
149
+ # Create many new documents
150
+ # @param [Array<Hash>] provide many Hashes of key/value pairs to create
151
+ # multiple documents
152
+ #
153
+ # @example Creating a single document
154
+ # MyModel.create({ :foo => "bar" })
155
+ #
156
+ # @example Creating multiple documents
157
+ # MyModel.create([{ :foo => "bar" }, { :foo => "baz" })
158
+ #
159
+ # @return [Boolean] when a document is successfully created, +true+ will
160
+ # be returned. If a document fails to create, +false+ will be returned.
101
161
  def create(*docs)
102
162
  initialize_each(*docs) { |doc| doc.save }
103
163
  end
104
164
 
165
+ # @see Document.create
166
+ #
167
+ # @raise [DocumentNotValid] raised if a document fails to create
105
168
  def create!(*docs)
106
169
  initialize_each(*docs) { |doc| doc.save! }
107
170
  end
108
171
 
109
- # For updating single document
172
+ # @overload update(id, attributes)
173
+ # Update a single document
174
+ # @param id the ID of the document you wish to update
175
+ # @param [Hash] attributes the key to update on the document with a new
176
+ # value
177
+ #
178
+ # @overload update(ids_and_attributes)
179
+ # Update multiple documents
180
+ # @param [Hash] ids_and_attributes each key is the ID of some document
181
+ # you wish to update. The value each key points toward are those
182
+ # applied to the target document
183
+ #
184
+ # @example Updating single document
110
185
  # Person.update(1, {:foo => 'bar'})
111
186
  #
112
- # For updating multiple documents at once:
187
+ # @example Updating multiple documents at once:
113
188
  # Person.update({'1' => {:foo => 'bar'}, '2' => {:baz => 'wick'}})
114
189
  def update(*args)
115
190
  if args.length == 1
@@ -120,6 +195,10 @@ module MongoMapper
120
195
  end
121
196
  end
122
197
 
198
+ # Removes ("deletes") one or many documents from the collection. Note
199
+ # that this will bypass any +destroy+ hooks defined by your class.
200
+ #
201
+ # @param [Array] ids the ID or IDs of the records you wish to delete
123
202
  def delete(*ids)
124
203
  collection.remove(to_criteria(:_id => ids.flatten))
125
204
  end
@@ -128,6 +207,27 @@ module MongoMapper
128
207
  collection.remove(to_criteria(options))
129
208
  end
130
209
 
210
+ # Iterates over each document found by the provided IDs and calls their
211
+ # +destroy+ method. This has the advantage of processing your document's
212
+ # +destroy+ call-backs.
213
+ #
214
+ # @overload destroy(id)
215
+ # Destroy a single document by ID
216
+ # @param id the ID of the document to destroy
217
+ #
218
+ # @overload destroy(ids)
219
+ # Destroy many documents by their IDs
220
+ # @param [Array] the IDs of each document you wish to destroy
221
+ #
222
+ # @example Destroying a single document
223
+ # Person.destroy("34")
224
+ #
225
+ # @example Destroying multiple documents
226
+ # Person.destroy("34", "45", ..., "54")
227
+ #
228
+ # # OR...
229
+ #
230
+ # Person.destroy(["34", "45", ..., "54"])
131
231
  def destroy(*ids)
132
232
  find_some(ids.flatten).each(&:destroy)
133
233
  end
@@ -136,6 +236,14 @@ module MongoMapper
136
236
  all(options).each(&:destroy)
137
237
  end
138
238
 
239
+ # @overload connection()
240
+ # @return [Mongo::Connection] the connection used by your document class
241
+ #
242
+ # @overload connection(mongo_connection)
243
+ # @param [Mongo::Connection] mongo_connection a new connection for your
244
+ # document class to use
245
+ # @return [Mongo::Connection] a new Mongo::Connection for yoru document
246
+ # class
139
247
  def connection(mongo_connection=nil)
140
248
  if mongo_connection.nil?
141
249
  @connection ||= MongoMapper.connection
@@ -145,49 +253,73 @@ module MongoMapper
145
253
  @connection
146
254
  end
147
255
 
148
- def database(name=nil)
149
- if name.nil?
150
- @database ||= MongoMapper.database
256
+ # Changes the database name from the default to whatever you want
257
+ #
258
+ # @param [#to_s] name the new database name to use.
259
+ def set_database_name(name)
260
+ @database_name = name
261
+ end
262
+
263
+ # Returns the database name
264
+ #
265
+ # @return [String] the database name
266
+ def database_name
267
+ @database_name
268
+ end
269
+
270
+ # Returns the database the document should use. Defaults to
271
+ # MongoMapper.database if other database is not set.
272
+ #
273
+ # @return [Mongo::DB] the mongo database instance
274
+ def database
275
+ if database_name.nil?
276
+ MongoMapper.database
151
277
  else
152
- @database = connection.db(name)
278
+ connection.db(database_name)
153
279
  end
154
- @database
155
280
  end
156
-
281
+
157
282
  # Changes the collection name from the default to whatever you want
158
- def set_collection_name(name=nil)
159
- @collection = nil
283
+ #
284
+ # @param [#to_s] name the new collection name to use.
285
+ def set_collection_name(name)
160
286
  @collection_name = name
161
287
  end
162
-
288
+
163
289
  # Returns the collection name, if not set, defaults to class name tableized
290
+ #
291
+ # @return [String] the collection name, if not set, defaults to class
292
+ # name tableized
164
293
  def collection_name
165
- @collection_name ||= self.to_s.demodulize.tableize
294
+ @collection_name ||= self.to_s.tableize.gsub(/\//, '.')
166
295
  end
167
296
 
168
- # Returns the mongo ruby driver collection object
297
+ # @return the Mongo Ruby driver +collection+ object
169
298
  def collection
170
- @collection ||= database.collection(collection_name)
299
+ database.collection(collection_name)
171
300
  end
172
301
 
302
+ # Defines a +created_at+ and +updated_at+ attribute (with a +Time+
303
+ # value) on your document. These attributes are updated by an
304
+ # injected +update_timestamps+ +before_save+ hook.
173
305
  def timestamps!
174
306
  key :created_at, Time
175
307
  key :updated_at, Time
176
308
  class_eval { before_save :update_timestamps }
177
309
  end
178
-
310
+
179
311
  def single_collection_inherited?
180
312
  keys.has_key?('_type') && single_collection_inherited_superclass?
181
313
  end
182
-
314
+
183
315
  def single_collection_inherited_superclass?
184
316
  superclass.respond_to?(:keys) && superclass.keys.has_key?('_type')
185
317
  end
186
-
318
+
187
319
  protected
188
320
  def method_missing(method, *args)
189
321
  finder = DynamicFinder.new(method)
190
-
322
+
191
323
  if finder.found?
192
324
  meta_def(finder.method) { |*args| dynamic_find(finder, args) }
193
325
  send(finder.method, *args)
@@ -200,7 +332,7 @@ module MongoMapper
200
332
  def create_indexes_for(key)
201
333
  ensure_index key.name if key.options[:index]
202
334
  end
203
-
335
+
204
336
  def initialize_each(*docs)
205
337
  instances = []
206
338
  docs = [{}] if docs.blank?
@@ -211,7 +343,7 @@ module MongoMapper
211
343
  end
212
344
  instances.size == 1 ? instances[0] : instances
213
345
  end
214
-
346
+
215
347
  def initialize_doc(doc)
216
348
  begin
217
349
  klass = doc['_type'].present? ? doc['_type'].constantize : self
@@ -220,38 +352,38 @@ module MongoMapper
220
352
  new(doc)
221
353
  end
222
354
  end
223
-
355
+
224
356
  def find_every(options)
225
357
  criteria, options = to_finder_options(options)
226
358
  collection.find(criteria, options).to_a.map do |doc|
227
359
  initialize_doc(doc)
228
360
  end
229
361
  end
230
-
362
+
231
363
  def find_some(ids, options={})
232
364
  ids = ids.flatten.compact.uniq
233
365
  documents = find_every(options.merge(:_id => ids))
234
-
366
+
235
367
  if ids.size == documents.size
236
368
  documents
237
369
  else
238
370
  raise DocumentNotFound, "Couldn't find all of the ids (#{ids.to_sentence}). Found #{documents.size}, but was expecting #{ids.size}"
239
371
  end
240
372
  end
241
-
373
+
242
374
  def find_one(options={})
243
375
  criteria, options = to_finder_options(options)
244
376
  if doc = collection.find_one(criteria, options)
245
377
  initialize_doc(doc)
246
378
  end
247
379
  end
248
-
380
+
249
381
  def find_one!(options={})
250
382
  find_one(options) || raise(DocumentNotFound, "Document match #{options.inspect} does not exist in #{collection.name} collection")
251
383
  end
252
384
 
253
385
  def invert_order_clause(order)
254
- order.split(',').map do |order_segment|
386
+ order.split(',').map do |order_segment|
255
387
  if order_segment =~ /\sasc/i
256
388
  order_segment.sub /\sasc/i, ' desc'
257
389
  elsif order_segment =~ /\sdesc/i
@@ -281,17 +413,17 @@ module MongoMapper
281
413
  docs.each_pair { |id, attrs| instances << update(id, attrs) }
282
414
  instances
283
415
  end
284
-
416
+
285
417
  def to_criteria(options={})
286
418
  FinderOptions.new(self, options).criteria
287
419
  end
288
-
420
+
289
421
  def to_finder_options(options={})
290
422
  FinderOptions.new(self, options).to_a
291
423
  end
292
424
  end
293
425
 
294
- module InstanceMethods
426
+ module InstanceMethods
295
427
  def collection
296
428
  self.class.collection
297
429
  end
@@ -314,6 +446,10 @@ module MongoMapper
314
446
  freeze
315
447
  end
316
448
 
449
+ def reload
450
+ self.class.find(id)
451
+ end
452
+
317
453
  private
318
454
  def create_or_update
319
455
  result = new? ? create : update
@@ -324,7 +460,7 @@ module MongoMapper
324
460
  assign_id
325
461
  save_to_collection
326
462
  end
327
-
463
+
328
464
  def assign_id
329
465
  if read_attribute(:_id).blank?
330
466
  write_attribute(:_id, Mongo::ObjectID.new.to_s)
@@ -345,7 +481,7 @@ module MongoMapper
345
481
  write_attribute('created_at', now) if new?
346
482
  write_attribute('updated_at', now)
347
483
  end
348
-
484
+
349
485
  def clear_custom_id_flag
350
486
  @using_custom_id = nil
351
487
  end
@@ -14,7 +14,7 @@ module MongoMapper
14
14
  end
15
15
 
16
16
  protected
17
- def match
17
+ def match
18
18
  case method.to_s
19
19
  when /^find_(all_by|by)_([_a-zA-Z]\w*)$/
20
20
  @finder = :all if $1 == 'all_by'
@@ -241,7 +241,7 @@ module MongoMapper
241
241
 
242
242
  _keys.each_pair do |name, key|
243
243
  value = key.set(read_attribute(key.name))
244
- attrs[name] = value
244
+ attrs[name] = value unless value.nil?
245
245
  end
246
246
 
247
247
  embedded_associations.each do |association|
@@ -269,13 +269,7 @@ module MongoMapper
269
269
  end
270
270
 
271
271
  def ==(other)
272
- return false unless other.is_a?(EmbeddedDocument)
273
- ignore = { '_id' => nil }
274
- attributes.merge(ignore) == other.attributes.merge(ignore)
275
- end
276
-
277
- def eql?(other)
278
- other.is_a?(self.class) && (self == other)
272
+ other.is_a?(self.class) && id == other.id
279
273
  end
280
274
 
281
275
  def id
@@ -337,11 +331,13 @@ module MongoMapper
337
331
  end
338
332
 
339
333
  def read_attribute(name)
340
- key = _keys[name]
341
- raise KeyNotFound, "Could not find key: #{name.inspect}" unless key
342
- value = key.get(instance_variable_get("@#{name}"))
343
- instance_variable_set "@#{name}", value if !frozen?
344
- value
334
+ if key = _keys[name]
335
+ value = key.get(instance_variable_get("@#{name}"))
336
+ instance_variable_set "@#{name}", value if !frozen?
337
+ value
338
+ else
339
+ raise KeyNotFound, "Could not find key: #{name.inspect}"
340
+ end
345
341
  end
346
342
 
347
343
  def read_attribute_before_typecast(name)
@@ -1,15 +1,35 @@
1
1
  module MongoMapper
2
+ # Controls the parsing and handling of options used by finders.
3
+ #
4
+ # == Important Note
5
+ #
6
+ # This class is private to MongoMapper and should not be considered part of
7
+ # MongoMapper's public API. Some documentation herein, however, may prove
8
+ # useful for understanding how MongoMapper handles the parsing of finder
9
+ # conditions and options.
10
+ #
11
+ # @private
12
+ class FinderOperator
13
+ def initialize(field, operator)
14
+ @field, @operator = field, operator
15
+ end
16
+
17
+ def to_criteria(value)
18
+ {@field => {@operator => value}}
19
+ end
20
+ end
21
+
2
22
  class FinderOptions
3
23
  OptionKeys = [:fields, :select, :skip, :offset, :limit, :sort, :order]
4
-
5
- attr_reader :model, :options
6
-
24
+
7
25
  def initialize(model, options)
8
- raise ArgumentError, "FinderOptions must be a hash" unless options.is_a?(Hash)
26
+ raise ArgumentError, "Options must be a hash" unless options.is_a?(Hash)
9
27
  options.symbolize_keys!
10
28
 
11
- @model, @options, @conditions = model, {}, options.delete(:conditions) || {}
12
-
29
+ @model = model
30
+ @options = {}
31
+ @conditions = options.delete(:conditions) || {}
32
+
13
33
  options.each_pair do |key, value|
14
34
  if OptionKeys.include?(key)
15
35
  @options[key] = value
@@ -17,37 +37,50 @@ module MongoMapper
17
37
  @conditions[key] = value
18
38
  end
19
39
  end
40
+
41
+ add_sci_scope
20
42
  end
21
43
 
44
+ # @return [Hash] Mongo compatible criteria options
45
+ #
46
+ # @see FinderOptions#to_mongo_criteria
22
47
  def criteria
23
- to_mongo_criteria(model, @conditions)
48
+ to_mongo_criteria(@conditions)
24
49
  end
25
50
 
51
+ # @return [Hash] Mongo compatible options
26
52
  def options
27
- to_mongo_options(model, @options)
53
+ options = @options.dup
54
+
55
+ fields = options.delete(:fields) || options.delete(:select)
56
+ skip = options.delete(:skip) || options.delete(:offset) || 0
57
+ limit = options.delete(:limit) || 0
58
+ sort = options.delete(:sort) || convert_order_to_sort(options.delete(:order))
59
+
60
+ {:fields => to_mongo_fields(fields), :skip => skip.to_i, :limit => limit.to_i, :sort => sort}
28
61
  end
29
62
 
63
+ # @return [Array<Hash>] Mongo criteria and options enclosed in an Array
30
64
  def to_a
31
65
  [criteria, options]
32
66
  end
33
-
67
+
34
68
  private
35
- def to_mongo_criteria(model, conditions, parent_key=nil)
69
+ def to_mongo_criteria(conditions, parent_key=nil)
36
70
  criteria = {}
37
- add_sci_scope(model, criteria)
38
71
 
39
72
  conditions.each_pair do |field, value|
40
- field = field_normalized(field)
73
+ field = normalized_field(field)
74
+ if field.is_a?(FinderOperator)
75
+ criteria.merge!(field.to_criteria(value))
76
+ next
77
+ end
41
78
  case value
42
79
  when Array
43
- operator_present = field.to_s =~ /^\$/
44
- criteria[field] = if operator_present
45
- value
46
- else
47
- {'$in' => value}
48
- end
80
+ operator_present = field.to_s =~ /^\$/
81
+ criteria[field] = operator?(field) ? value : {'$in' => value}
49
82
  when Hash
50
- criteria[field] = to_mongo_criteria(model, value, field)
83
+ criteria[field] = to_mongo_criteria(value, field)
51
84
  else
52
85
  criteria[field] = value
53
86
  end
@@ -55,48 +88,38 @@ module MongoMapper
55
88
 
56
89
  criteria
57
90
  end
58
-
59
- def field_normalized(field)
60
- if field.to_s == 'id'
61
- :_id
62
- else
63
- field
64
- end
91
+
92
+ def operator?(field)
93
+ field.to_s =~ /^\$/
94
+ end
95
+
96
+ def normalized_field(field)
97
+ field.to_s == 'id' ? :_id : field
65
98
  end
66
99
 
67
100
  # adds _type single collection inheritance scope for models that need it
68
- def add_sci_scope(model, criteria)
69
- if model.single_collection_inherited?
70
- criteria[:_type] = model.to_s
101
+ def add_sci_scope
102
+ if @model.single_collection_inherited?
103
+ @conditions[:_type] = @model.to_s
71
104
  end
72
105
  end
73
106
 
74
- def to_mongo_options(model, options)
75
- options = options.dup
76
- {
77
- :fields => to_mongo_fields(options.delete(:fields) || options.delete(:select)),
78
- :skip => (options.delete(:skip) || options.delete(:offset) || 0).to_i,
79
- :limit => (options.delete(:limit) || 0).to_i,
80
- :sort => options.delete(:sort) || to_mongo_sort(options.delete(:order))
81
- }
82
- end
83
-
84
107
  def to_mongo_fields(fields)
85
108
  return if fields.blank?
86
-
109
+
87
110
  if fields.is_a?(String)
88
111
  fields.split(',').map { |field| field.strip }
89
112
  else
90
113
  fields.flatten.compact
91
114
  end
92
115
  end
93
-
94
- def to_mongo_sort(sort)
116
+
117
+ def convert_order_to_sort(sort)
95
118
  return if sort.blank?
96
119
  pieces = sort.split(',')
97
120
  pieces.map { |s| to_mongo_sort_piece(s) }
98
121
  end
99
-
122
+
100
123
  def to_mongo_sort_piece(str)
101
124
  field, direction = str.strip.split(' ')
102
125
  direction ||= 'ASC'
@@ -104,4 +127,4 @@ module MongoMapper
104
127
  [field, direction]
105
128
  end
106
129
  end
107
- end
130
+ end
@@ -30,6 +30,8 @@ module MongoMapper
30
30
  def skip
31
31
  (current_page - 1) * per_page
32
32
  end
33
+ alias offset skip # for will paginate support
34
+
33
35
 
34
36
  def method_missing(name, *args, &block)
35
37
  @subject.send(name, *args, &block)
@@ -5,7 +5,7 @@ module MongoMapper #:nodoc:
5
5
  class Serializer #:nodoc:
6
6
  attr_reader :options
7
7
 
8
- def initialize(record, options = {})
8
+ def initialize(record, options={})
9
9
  @record, @options = record, options.dup
10
10
  end
11
11
 
@@ -49,7 +49,7 @@ module MongoMapper #:nodoc:
49
49
  # # => {"id": 1, "name": "Konata Izumi", "age": 16,
50
50
  # "created_at": "2006/08/01", "awesome": true,
51
51
  # "permalink": "1-konata-izumi"}
52
- def to_json(options = {})
52
+ def to_json(options={})
53
53
  apply_to_json_defaults(options)
54
54
 
55
55
  if include_root_in_json
@@ -1,4 +1,5 @@
1
1
  class BasicObject #:nodoc:
2
+ alias_method :proxy_extend, :extend
2
3
  instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|^methods$|instance_eval|proxy_|^object_id$)/ }
3
4
  end unless defined?(BasicObject)
4
5
 
@@ -129,6 +130,14 @@ class String
129
130
  end
130
131
  end
131
132
 
133
+ class Symbol
134
+ %w{gt lt gte lte ne in nin mod size where exists}.each do |operator|
135
+ define_method operator do
136
+ MongoMapper::FinderOperator.new(self, "$#{operator}")
137
+ end
138
+ end
139
+ end
140
+
132
141
  class Time
133
142
  def self.to_mongo(value)
134
143
  if value.nil? || value == ''