mongo_doc 0.3.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.
Files changed (122) hide show
  1. data/.document +5 -0
  2. data/.gitignore +7 -0
  3. data/LICENSE +20 -0
  4. data/README.textile +174 -0
  5. data/Rakefile +135 -0
  6. data/TODO +31 -0
  7. data/VERSION +1 -0
  8. data/data/.gitignore +2 -0
  9. data/examples/simple_document.rb +35 -0
  10. data/examples/simple_object.rb +30 -0
  11. data/features/finders.feature +76 -0
  12. data/features/mongodb.yml +7 -0
  13. data/features/mongodoc_base.feature +128 -0
  14. data/features/new_record.feature +36 -0
  15. data/features/partial_updates.feature +105 -0
  16. data/features/removing_documents.feature +68 -0
  17. data/features/saving_an_object.feature +15 -0
  18. data/features/scopes.feature +66 -0
  19. data/features/step_definitions/collection_steps.rb +14 -0
  20. data/features/step_definitions/document_steps.rb +149 -0
  21. data/features/step_definitions/documents.rb +30 -0
  22. data/features/step_definitions/finder_steps.rb +15 -0
  23. data/features/step_definitions/json_steps.rb +9 -0
  24. data/features/step_definitions/object_steps.rb +50 -0
  25. data/features/step_definitions/objects.rb +24 -0
  26. data/features/step_definitions/partial_update_steps.rb +32 -0
  27. data/features/step_definitions/query_steps.rb +54 -0
  28. data/features/step_definitions/removing_documents_steps.rb +14 -0
  29. data/features/step_definitions/scope_steps.rb +18 -0
  30. data/features/step_definitions/util_steps.rb +7 -0
  31. data/features/support/support.rb +10 -0
  32. data/features/using_criteria.feature +128 -0
  33. data/lib/mongo_doc/associations/collection_proxy.rb +105 -0
  34. data/lib/mongo_doc/associations/document_proxy.rb +56 -0
  35. data/lib/mongo_doc/associations/hash_proxy.rb +98 -0
  36. data/lib/mongo_doc/associations/proxy_base.rb +53 -0
  37. data/lib/mongo_doc/attributes.rb +140 -0
  38. data/lib/mongo_doc/bson.rb +45 -0
  39. data/lib/mongo_doc/collection.rb +55 -0
  40. data/lib/mongo_doc/connection.rb +88 -0
  41. data/lib/mongo_doc/contexts/enumerable.rb +128 -0
  42. data/lib/mongo_doc/contexts/ids.rb +41 -0
  43. data/lib/mongo_doc/contexts/mongo.rb +232 -0
  44. data/lib/mongo_doc/contexts.rb +25 -0
  45. data/lib/mongo_doc/criteria.rb +38 -0
  46. data/lib/mongo_doc/cursor.rb +32 -0
  47. data/lib/mongo_doc/document.rb +216 -0
  48. data/lib/mongo_doc/ext/array.rb +5 -0
  49. data/lib/mongo_doc/ext/binary.rb +7 -0
  50. data/lib/mongo_doc/ext/boolean_class.rb +11 -0
  51. data/lib/mongo_doc/ext/date.rb +16 -0
  52. data/lib/mongo_doc/ext/date_time.rb +13 -0
  53. data/lib/mongo_doc/ext/dbref.rb +7 -0
  54. data/lib/mongo_doc/ext/hash.rb +7 -0
  55. data/lib/mongo_doc/ext/nil_class.rb +5 -0
  56. data/lib/mongo_doc/ext/numeric.rb +17 -0
  57. data/lib/mongo_doc/ext/object.rb +17 -0
  58. data/lib/mongo_doc/ext/object_id.rb +7 -0
  59. data/lib/mongo_doc/ext/regexp.rb +5 -0
  60. data/lib/mongo_doc/ext/string.rb +5 -0
  61. data/lib/mongo_doc/ext/symbol.rb +5 -0
  62. data/lib/mongo_doc/ext/time.rb +5 -0
  63. data/lib/mongo_doc/finders.rb +49 -0
  64. data/lib/mongo_doc/matchers.rb +35 -0
  65. data/lib/mongo_doc/query.rb +7 -0
  66. data/lib/mongo_doc/scope.rb +64 -0
  67. data/lib/mongo_doc/validations/macros.rb +11 -0
  68. data/lib/mongo_doc/validations/validates_embedded.rb +13 -0
  69. data/lib/mongo_doc.rb +19 -0
  70. data/lib/mongoid/contexts/paging.rb +42 -0
  71. data/lib/mongoid/criteria.rb +247 -0
  72. data/lib/mongoid/criterion/complex.rb +21 -0
  73. data/lib/mongoid/criterion/exclusion.rb +65 -0
  74. data/lib/mongoid/criterion/inclusion.rb +92 -0
  75. data/lib/mongoid/criterion/optional.rb +136 -0
  76. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  77. data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
  78. data/lib/mongoid/matchers/all.rb +11 -0
  79. data/lib/mongoid/matchers/default.rb +26 -0
  80. data/lib/mongoid/matchers/exists.rb +13 -0
  81. data/lib/mongoid/matchers/gt.rb +11 -0
  82. data/lib/mongoid/matchers/gte.rb +11 -0
  83. data/lib/mongoid/matchers/in.rb +11 -0
  84. data/lib/mongoid/matchers/lt.rb +11 -0
  85. data/lib/mongoid/matchers/lte.rb +11 -0
  86. data/lib/mongoid/matchers/ne.rb +11 -0
  87. data/lib/mongoid/matchers/nin.rb +11 -0
  88. data/lib/mongoid/matchers/size.rb +11 -0
  89. data/mongo_doc.gemspec +205 -0
  90. data/mongod.example.yml +2 -0
  91. data/mongodb.example.yml +14 -0
  92. data/perf/mongo_doc_runner.rb +90 -0
  93. data/perf/ruby_driver_runner.rb +64 -0
  94. data/script/console +8 -0
  95. data/spec/associations/collection_proxy_spec.rb +200 -0
  96. data/spec/associations/document_proxy_spec.rb +42 -0
  97. data/spec/associations/hash_proxy_spec.rb +163 -0
  98. data/spec/attributes_spec.rb +273 -0
  99. data/spec/bson_matchers.rb +54 -0
  100. data/spec/bson_spec.rb +196 -0
  101. data/spec/collection_spec.rb +161 -0
  102. data/spec/connection_spec.rb +147 -0
  103. data/spec/contexts/enumerable_spec.rb +274 -0
  104. data/spec/contexts/ids_spec.rb +49 -0
  105. data/spec/contexts/mongo_spec.rb +198 -0
  106. data/spec/contexts_spec.rb +28 -0
  107. data/spec/criteria_spec.rb +33 -0
  108. data/spec/cursor_spec.rb +91 -0
  109. data/spec/document_ext.rb +9 -0
  110. data/spec/document_spec.rb +664 -0
  111. data/spec/embedded_save_spec.rb +109 -0
  112. data/spec/finders_spec.rb +73 -0
  113. data/spec/hash_matchers.rb +27 -0
  114. data/spec/matchers_spec.rb +342 -0
  115. data/spec/mongodb.yml +6 -0
  116. data/spec/mongodb_pairs.yml +8 -0
  117. data/spec/new_record_spec.rb +128 -0
  118. data/spec/query_spec.rb +12 -0
  119. data/spec/scope_spec.rb +79 -0
  120. data/spec/spec.opts +2 -0
  121. data/spec/spec_helper.rb +13 -0
  122. metadata +290 -0
@@ -0,0 +1,216 @@
1
+ require 'mongo_doc/bson'
2
+ require 'mongo_doc/query'
3
+ require 'mongo_doc/attributes'
4
+ require 'mongo_doc/criteria'
5
+ require 'mongo_doc/finders'
6
+ require 'mongo_doc/scope'
7
+ require 'mongo_doc/validations/macros'
8
+
9
+ module MongoDoc
10
+ class UnsupportedOperation < RuntimeError; end
11
+ class DocumentInvalidError < RuntimeError; end
12
+ class NotADocumentError < RuntimeError; end
13
+
14
+ module Document
15
+
16
+ def self.included(klass)
17
+ klass.class_eval do
18
+ include Attributes
19
+ extend ClassMethods
20
+ extend Criteria
21
+ extend Finders
22
+ extend Scope
23
+ include ::Validatable
24
+ extend Validations::Macros
25
+
26
+ alias :id :_id
27
+ end
28
+ end
29
+
30
+ def initialize(attrs = {})
31
+ self.attributes = attrs
32
+ end
33
+
34
+ def ==(other)
35
+ return false unless self.class === other
36
+ self.class._attributes.all? {|var| self.send(var) == other.send(var)}
37
+ end
38
+
39
+ def attributes
40
+ hash = {}
41
+ self.class._attributes.each do |attr|
42
+ hash[attr] = send(attr)
43
+ end
44
+ hash
45
+ end
46
+
47
+ def attributes=(attrs)
48
+ attrs.each do |key, value|
49
+ send("#{key}=", value)
50
+ end
51
+ end
52
+
53
+ def new_record?
54
+ _id.nil?
55
+ end
56
+
57
+ def remove
58
+ raise UnsupportedOperation.new('Document#remove is not supported for embedded documents') if _root
59
+ remove_document
60
+ end
61
+
62
+ def remove_document
63
+ return _root.remove_document if _root
64
+ _remove
65
+ end
66
+
67
+ def save(validate = true)
68
+ return _root.save(validate) if _root
69
+ return _save(false) unless validate and not valid?
70
+ false
71
+ end
72
+
73
+ def save!
74
+ return _root.save! if _root
75
+ raise DocumentInvalidError unless valid?
76
+ _save(true)
77
+ end
78
+
79
+ def to_bson(*args)
80
+ {MongoDoc::BSON::CLASS_KEY => self.class.name}.tap do |bson_hash|
81
+ bson_hash['_id'] = _id unless new_record?
82
+ self.class._attributes.each do |name|
83
+ bson_hash[name.to_s] = send(name).to_bson(args)
84
+ end
85
+ end
86
+ end
87
+
88
+ def to_param
89
+ _id.to_s
90
+ end
91
+
92
+ def update_attributes(attrs)
93
+ strict = attrs.delete(:__strict__)
94
+ self.attributes = attrs
95
+ return save if new_record?
96
+ return false unless valid?
97
+ if strict
98
+ _strict_update_attributes(_path_to_root(self, attrs), false)
99
+ else
100
+ _naive_update_attributes(_path_to_root(self, attrs), false)
101
+ end
102
+ end
103
+
104
+ def update_attributes!(attrs)
105
+ strict = attrs.delete(:__strict__)
106
+ self.attributes = attrs
107
+ return save! if new_record?
108
+ raise DocumentInvalidError unless valid?
109
+ if strict
110
+ _strict_update_attributes(_path_to_root(self, attrs), true)
111
+ else
112
+ _naive_update_attributes(_path_to_root(self, attrs), true)
113
+ end
114
+ end
115
+
116
+ module ClassMethods
117
+ def bson_create(bson_hash, options = {})
118
+ new.tap do |obj|
119
+ bson_hash.each do |name, value|
120
+ obj.send("#{name}=", MongoDoc::BSON.decode(value, options))
121
+ end
122
+ end
123
+ end
124
+
125
+ def collection
126
+ @collection ||= MongoDoc::Collection.new(collection_name)
127
+ end
128
+
129
+ def collection_name
130
+ self.to_s.tableize.gsub('/', '.')
131
+ end
132
+
133
+ def create(attrs = {})
134
+ instance = new(attrs)
135
+ instance.save(false)
136
+ instance
137
+ end
138
+
139
+ def create!(attrs = {})
140
+ instance = new(attrs)
141
+ instance.save!(true)
142
+ instance
143
+ end
144
+ end
145
+
146
+ protected
147
+
148
+ def _collection
149
+ self.class.collection
150
+ end
151
+
152
+ def _naive_update_attributes(attrs, safe)
153
+ return _root.send(:_naive_update_attributes, attrs, safe) if _root
154
+ _update({}, attrs, safe)
155
+ end
156
+
157
+ def _remove
158
+ _collection.remove({'_id' => _id})
159
+ end
160
+
161
+ def _strict_update_attributes(attrs, safe, selector = {})
162
+ return _root.send(:_strict_update_attributes, attrs, safe, _path_to_root(self, '_id' => _id)) if _root
163
+ _update(selector, attrs, safe)
164
+ end
165
+
166
+ def _update(selector, data, safe)
167
+ _collection.update({'_id' => _id}.merge(selector), MongoDoc::Query.set_modifier(data), :safe => safe)
168
+ end
169
+
170
+ def _save(safe)
171
+ notify_before_save_observers
172
+ self._id = _collection.save(self, :safe => safe)
173
+ notify_save_success_observers
174
+ self._id
175
+ rescue Mongo::MongoDBError => e
176
+ notify_save_failed_observers
177
+ raise e
178
+ end
179
+
180
+ def before_save_callback(root)
181
+ self._id = Mongo::ObjectID.new if new_record?
182
+ end
183
+
184
+ def save_failed_callback(root)
185
+ self._id = nil
186
+ end
187
+
188
+ def save_success_callback(root)
189
+ root.unregister_save_observer(self)
190
+ end
191
+
192
+ def save_observers
193
+ @save_observers ||= []
194
+ end
195
+
196
+ def register_save_observer(child)
197
+ save_observers << child
198
+ end
199
+
200
+ def unregister_save_observer(child)
201
+ save_observers.delete(child)
202
+ end
203
+
204
+ def notify_before_save_observers
205
+ save_observers.each {|obs| obs.before_save_callback(self) }
206
+ end
207
+
208
+ def notify_save_success_observers
209
+ save_observers.each {|obs| obs.save_success_callback(self) }
210
+ end
211
+
212
+ def notify_save_failed_observers
213
+ save_observers.each {|obs| obs.save_failed_callback(self) }
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,5 @@
1
+ class Array
2
+ def to_bson(*args)
3
+ map {|item| item.to_bson(args)}
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module Mongo
2
+ class Binary
3
+ def to_bson(*args)
4
+ self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ class FalseClass
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
6
+
7
+ class TrueClass
8
+ def to_bson(*args)
9
+ self
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ class Date
2
+ def to_bson(*args)
3
+ {
4
+ MongoDoc::BSON::CLASS_KEY => self.class.name,
5
+ 'dt' => strftime,
6
+ 'sg' => start
7
+ }
8
+ end
9
+
10
+ alias start sg unless method_defined?(:start)
11
+
12
+ def self.bson_create(bson_hash, options = nil)
13
+ Date.parse(*bson_hash.values_at('dt', 'sg'))
14
+ end
15
+
16
+ end
@@ -0,0 +1,13 @@
1
+ class DateTime
2
+ def to_bson(*args)
3
+ {
4
+ MongoDoc::BSON::CLASS_KEY => self.class.name,
5
+ 'dt' => strftime,
6
+ 'sg' => start
7
+ }
8
+ end
9
+
10
+ def self.bson_create(bson_hash, options = nil)
11
+ DateTime.parse(*bson_hash.values_at('dt', 'sg'))
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ module Mongo
2
+ class DBRef
3
+ def to_bson(*args)
4
+ self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ class Hash
2
+ def to_bson(*args)
3
+ {}.tap do |hash|
4
+ each {|key, value| hash[key.to_s] = value.to_bson}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class NilClass
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
@@ -0,0 +1,17 @@
1
+ class Numeric
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
6
+
7
+ class Float
8
+ def to_bson(*args)
9
+ self
10
+ end
11
+ end
12
+
13
+ class Integer
14
+ def to_bson(*args)
15
+ self
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ class Object
2
+ def to_bson(*args)
3
+ {MongoDoc::BSON::CLASS_KEY => self.class.name}.tap do |bson_hash|
4
+ instance_variables.each do |name|
5
+ bson_hash[name[1..-1]] = instance_variable_get(name).to_bson(args)
6
+ end
7
+ end
8
+ end
9
+
10
+ def self.bson_create(bson_hash, options = {})
11
+ new.tap do |obj|
12
+ bson_hash.each do |name, value|
13
+ obj.instance_variable_set("@#{name}", MongoDoc::BSON.decode(value, options))
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module Mongo
2
+ class ObjectID
3
+ def to_bson(*args)
4
+ self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class Regexp
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class String
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Symbol
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Time
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
@@ -0,0 +1,49 @@
1
+ require 'mongo_doc/criteria'
2
+
3
+ module MongoDoc
4
+ module Finders
5
+ def self.extended(base)
6
+ base.extend(Criteria) unless base === Criteria
7
+ end
8
+
9
+ %w(count first last).each do |name|
10
+ module_eval <<-RUBY
11
+ # #{name.humanize} for this +Document+ class
12
+ #
13
+ # <tt>Person.#{name}</tt>
14
+ def #{name}
15
+ criteria.#{name}
16
+ end
17
+ RUBY
18
+ end
19
+
20
+ # Find a +Document+ based on id (+String+ or +Mongo::ObjectID+)
21
+ #
22
+ # <tt>Person.find('1')</tt>
23
+ # <tt>Person.find(obj_id_1, obj_id_2)</tt>
24
+ def find(*args)
25
+ criteria.id(*args)
26
+ end
27
+ #
28
+ # Find all +Document+s in the collections
29
+ #
30
+ # <tt>Person.find_all</tt>
31
+ def find_all
32
+ criteria
33
+ end
34
+
35
+ # Find a +Document+ based on id (+String+ or +Mongo::ObjectID+)
36
+ # or conditions
37
+ #
38
+ # <tt>Person.find_one('1')</tt>
39
+ # <tt>Person.find_one(:where => {:age.gt > 25})</tt>
40
+ def find_one(conditions_or_id)
41
+ if Hash === conditions_or_id
42
+ Mongoid::Criteria.translate(self, conditions_or_id).one
43
+ else
44
+ Mongoid::Criteria.translate(self, conditions_or_id)
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ require "mongoid/matchers/default"
2
+ require "mongoid/matchers/all"
3
+ require "mongoid/matchers/exists"
4
+ require "mongoid/matchers/gt"
5
+ require "mongoid/matchers/gte"
6
+ require "mongoid/matchers/in"
7
+ require "mongoid/matchers/lt"
8
+ require "mongoid/matchers/lte"
9
+ require "mongoid/matchers/ne"
10
+ require "mongoid/matchers/nin"
11
+ require "mongoid/matchers/size"
12
+
13
+ module MongoDoc #:nodoc:
14
+ module Matchers
15
+ # Determines if this document has the attributes to match the supplied
16
+ # MongoDB selector. Used for matching on embedded associations.
17
+ def matches?(selector)
18
+ selector.each_pair do |key, value|
19
+ return false unless matcher(key, value).matches?(value)
20
+ end
21
+ true
22
+ end
23
+
24
+ protected
25
+ # Get the matcher for the supplied key and value. Will determine the class
26
+ # name from the key.
27
+ def matcher(key, value)
28
+ if value.is_a?(Hash)
29
+ name = "Mongoid::Matchers::#{value.keys.first.gsub("$", "").camelize}"
30
+ return name.constantize.new(send(key))
31
+ end
32
+ Mongoid::Matchers::Default.new(send(key))
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,7 @@
1
+ module MongoDoc
2
+ module Query
3
+ def self.set_modifier(bson_hash)
4
+ {'$set' => bson_hash}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,64 @@
1
+ # Based on ActiveRecord::NamedScope
2
+ module MongoDoc
3
+ module Scope
4
+ def scopes
5
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
6
+ end
7
+
8
+ def scope(name, *args, &block)
9
+ options = args.extract_options!
10
+ raise ArgumentError if args.size != 1
11
+ criteria = args.first
12
+ name = name.to_sym
13
+ scopes[name] = lambda do |parent_scope, *args|
14
+ CriteriaProxy.new(parent_scope, Mongoid::Criteria === criteria ? criteria : criteria.call(*args), options, &block)
15
+ end
16
+ (class << self; self; end).class_eval <<-EOT
17
+ def #{name}(*args)
18
+ scopes[:#{name}].call(self, *args)
19
+ end
20
+ EOT
21
+ end
22
+
23
+ class CriteriaProxy
24
+ attr_accessor :criteria, :klass, :parent_scope
25
+
26
+ delegate :scopes, :to => :parent_scope
27
+
28
+ def initialize(parent_scope, criteria, options, &block)
29
+ [options.delete(:extend)].flatten.each { |extension| extend extension } if options.include?(:extend)
30
+ extend Module.new(&block) if block_given?
31
+ if CriteriaProxy === parent_scope
32
+ chained = Mongoid::Criteria.new(klass)
33
+ chained.merge(parent_scope)
34
+ chained.merge(criteria)
35
+ self.criteria = chained
36
+ self.klass = criteria.klass
37
+ else
38
+ self.criteria = criteria
39
+ self.klass = parent_scope
40
+ end
41
+
42
+ self.parent_scope = parent_scope
43
+ end
44
+
45
+ def respond_to?(method, include_private = false)
46
+ return true if scopes.include?(method)
47
+ criteria.respond_to?(method, include_private)
48
+ end
49
+
50
+ private
51
+
52
+ def method_missing(method, *args, &block)
53
+ if scopes.include?(method)
54
+ scopes[method].call(self, *args)
55
+ else
56
+ chained = Mongoid::Criteria.new(klass)
57
+ chained.merge(criteria)
58
+ chained.send(method, *args, &block)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
@@ -0,0 +1,11 @@
1
+ require 'mongo_doc/validations/validates_embedded'
2
+
3
+ module MongoDoc
4
+ module Validations
5
+ module Macros
6
+ def validates_embedded(*args)
7
+ add_validations(args, MongoDoc::Validations::ValidatesEmbedded)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module MongoDoc
2
+ module Validations
3
+ class ValidatesEmbedded < ::Validatable::ValidationBase
4
+ def valid?(instance)
5
+ instance.send(attribute).valid?
6
+ end
7
+
8
+ def message(instance)
9
+ super || "is invalid"
10
+ end
11
+ end
12
+ end
13
+ end
data/lib/mongo_doc.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+
3
+ gem 'mongo', '0.19'
4
+ gem 'mongo_ext', '0.19'
5
+ gem 'durran-validatable', '2.0.1'
6
+ gem 'leshill-will_paginate', '2.3.11'
7
+
8
+ require 'mongo'
9
+ require 'active_support'
10
+ require 'validatable'
11
+ require 'will_paginate/collection'
12
+
13
+ module MongoDoc
14
+ VERSION = '0.3.0'
15
+ end
16
+
17
+ require 'mongo_doc/connection'
18
+ require 'mongo_doc/collection'
19
+ require 'mongo_doc/document'
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Contexts #:nodoc:
4
+ module Paging
5
+ # Paginates the documents.
6
+ #
7
+ # Example:
8
+ #
9
+ # <tt>context.paginate</tt>
10
+ #
11
+ # Returns:
12
+ #
13
+ # A collection of documents paginated.
14
+ def paginate
15
+ @collection ||= execute(true)
16
+ WillPaginate::Collection.create(page, per_page, count) do |pager|
17
+ pager.replace(@collection.to_a)
18
+ end
19
+ end
20
+
21
+ # Either returns the page option and removes it from the options, or
22
+ # returns a default value of 1.
23
+ #
24
+ # Returns:
25
+ #
26
+ # An +Integer+ page number.
27
+ def page
28
+ skips, limits = options[:skip], options[:limit]
29
+ (skips && limits) ? (skips + limits) / limits : 1
30
+ end
31
+
32
+ # Get the number of results per page or the default of 20.
33
+ #
34
+ # Returns:
35
+ #
36
+ # The +Integer+ number of documents in each page.
37
+ def per_page
38
+ (options[:limit] || 20).to_i
39
+ end
40
+ end
41
+ end
42
+ end