djsun-mongo_mapper 0.5.6.6 → 0.5.8.1

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.
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 == ''