mongoid-ordering 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Douwe Maan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,139 @@
1
+ # mongoid-ordering [![Build Status](https://secure.travis-ci.org/DouweM/mongoid-ordering.png?branch=master)](http://travis-ci.org/DouweM/mongoid-ordering)
2
+
3
+ mongoid-ordering makes it easy to keep your Mongoid documents in order.
4
+
5
+ Most of mongoid-ordering is based on the
6
+ `Mongoid::Tree::Ordering` module from the
7
+ [mongoid-tree](https://github.com/benedikt/mongoid-tree) gem. I thought
8
+ the ordering logic would be useful outside of the tree context as well, so I
9
+ extracted it into the gem you're looking at right now.
10
+
11
+ ## Features
12
+
13
+ * Automatically order your query results by a new `position` attribute.
14
+ * Allow documents to be ordered within a certain scope.
15
+ * Handle changes in position when a document is destroyed or when a document is
16
+ moved outside of this scope.
17
+ * Tons of utility methods to make working with ordered documents incredibly easy.
18
+
19
+ ## Requirements
20
+
21
+ * mongoid (~> 3.0)
22
+
23
+ ## Installation
24
+
25
+ Add the following to your Gemfile:
26
+
27
+ ```ruby
28
+ gem "mongoid-ordering"
29
+ ```
30
+
31
+ And tell Bundler to install the new gem:
32
+
33
+ ```
34
+ bundle install
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ Include the `Mongoid::Ordering` module in your document class:
40
+
41
+ ```ruby
42
+ class Book
43
+ include Mongoid::Document
44
+ include Mongoid::Ordering
45
+
46
+ ...
47
+ end
48
+ ```
49
+
50
+ This will take care of everything to get you going.
51
+
52
+ If you want to specify a scope within which to keep the documents in order,
53
+ you can like this:
54
+
55
+ ```ruby
56
+ class Book
57
+ include Mongoid::Document
58
+ include Mongoid::Ordering
59
+
60
+ belongs_to :author
61
+
62
+ ordered scope: :author
63
+
64
+ ...
65
+ end
66
+ ```
67
+
68
+ You will now have access to the following methods:
69
+
70
+ ```ruby
71
+ # Retrieve siblings positioned above this document.
72
+ book.higher_siblings
73
+ # Retrieve siblings positioned below this document.
74
+ book.lower_siblings
75
+ # Retrieve the highest sibling.
76
+ book.highest_sibling
77
+ # Retrieve the lowest sibling.
78
+ book.lowest_sibling
79
+
80
+ # Is this the highest sibling?
81
+ book.at_top?
82
+ # Is this the lowest sibling?
83
+ book.at_bottom?
84
+
85
+ # Move document to the top.
86
+ book.move_to_top
87
+ # Move document to the bottom.
88
+ book.move_to_bottom
89
+ # Move document one position up.
90
+ book.move_up
91
+ # Move document one position down.
92
+ book.move_down
93
+ # Move document above another document.
94
+ book.move_above(other_book)
95
+ # Move document below another document.
96
+ book.move_below(other_book)
97
+ ```
98
+
99
+ mongoid-ordering uses [mongoid-siblings](https://github.com/DouweM/mongoid-siblings) to get all of this to work, so you'll get the following methods as a bonus:
100
+
101
+ ```ruby
102
+ # Retrieve document's siblings
103
+ book.siblings
104
+ # Retrieve document's siblings and itself
105
+ book.siblings_and_self
106
+ # Is this document a sibling of the other document?
107
+ book.sibling_of?(other_book)
108
+ # Make document a sibling of the other document.
109
+ # This will move this book to the same scope as the other book.
110
+ book.sibling_of!(other_book)
111
+ ```
112
+
113
+ ## Full documentation
114
+ See [this project's RubyDoc.info page](http://rubydoc.info/github/DouweM/mongoid-ordering/master/frames).
115
+
116
+ ## Known issues
117
+ See [the GitHub Issues page](https://github.com/DouweM/mongoid-ordering/issues).
118
+
119
+ ## License
120
+ Copyright (c) 2012 Douwe Maan
121
+
122
+ Permission is hereby granted, free of charge, to any person obtaining
123
+ a copy of this software and associated documentation files (the
124
+ "Software"), to deal in the Software without restriction, including
125
+ without limitation the rights to use, copy, modify, merge, publish,
126
+ distribute, sublicense, and/or sell copies of the Software, and to
127
+ permit persons to whom the Software is furnished to do so, subject to
128
+ the following conditions:
129
+
130
+ The above copyright notice and this permission notice shall be
131
+ included in all copies or substantial portions of the Software.
132
+
133
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
134
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
135
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
136
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
137
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
138
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
139
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ require "rspec/core/rake_task"
2
+
3
+ spec = Gem::Specification.load("mongoid-ordering.gemspec")
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
8
+
9
+ desc "Build the .gem file"
10
+ task :build do
11
+ system "gem build #{spec.name}.gemspec"
12
+ end
13
+
14
+ desc "Push the .gem file to rubygems.org"
15
+ task release: :build do
16
+ system "gem push #{spec.name}-#{spec.version}.gem"
17
+ end
@@ -0,0 +1,255 @@
1
+ module Mongoid
2
+
3
+ # Add 'position' field, multiple methods and multiple callbacks to help with
4
+ # ordering your documents.
5
+ module Ordering
6
+ extend ActiveSupport::Concern
7
+ include Mongoid::Siblings
8
+
9
+ included do
10
+ cattr_accessor :ordering_scopes
11
+ self.ordering_scopes = []
12
+
13
+ field :position, type: Integer
14
+
15
+ default_scope asc(:position)
16
+
17
+ before_save :assign_default_position
18
+ before_save :reposition_former_siblings, if: :sibling_reposition_required?
19
+ after_destroy :move_lower_siblings_up
20
+ end
21
+
22
+ module ClassMethods
23
+ # Sets options used for ordering.
24
+ #
25
+ # @example Set options.
26
+ # class Book
27
+ # include Mongoid::Document
28
+ # include Mongoid::Ordering
29
+ #
30
+ # belongs_to :author
31
+ #
32
+ # ordered scope: :author
33
+ # end
34
+ #
35
+ # @param [ Hash ] options The options.
36
+ #
37
+ # @option options [ Array<Symbol>, Symbol ] scope One or more relations or
38
+ # attributes that will determine the scope within which to keep the
39
+ # documents in order.
40
+ def ordered(options = {})
41
+ self.default_sibling_scope = self.ordering_scopes = Array.wrap(options[:scope]).compact
42
+ end
43
+ end
44
+
45
+ # Returns siblings positioned above this document.
46
+ # Siblings with a position lower than this document's position.
47
+ #
48
+ # @example Retrieve siblings positioned above this document.
49
+ # book.higher_siblings
50
+ #
51
+ # @return [ Mongoid::Criteria ] Criteria to retrieve the document's higher siblings.
52
+ def higher_siblings
53
+ self.siblings.where(:position.lt => self.position)
54
+ end
55
+
56
+ # Returns siblings positioned below this document.
57
+ # Siblings with a position greater than this document's position.
58
+ #
59
+ # @example Retrieve siblings positioned below this document.
60
+ # book.lower_siblings
61
+ #
62
+ # @return [ Mongoid::Criteria ] Criteria to retrieve the document's lower siblings.
63
+ def lower_siblings
64
+ self.siblings.where(:position.gt => self.position)
65
+ end
66
+
67
+ # Returns the highest sibling (could be self).
68
+ #
69
+ # @example Retrieve the highest sibling.
70
+ # book.highest_sibling
71
+ #
72
+ # @return [ Mongoid::Document ] The highest sibling.
73
+ def highest_sibling
74
+ self.siblings_and_self.first
75
+ end
76
+
77
+ # Returns the lowest sibling (could be self).
78
+ #
79
+ # @example Retrieve the lowest sibling.
80
+ # book.lowest_sibling
81
+ #
82
+ # @return [ Mongoid::Document ] The lowest sibling
83
+ def lowest_sibling
84
+ self.siblings_and_self.last
85
+ end
86
+
87
+ # Is this the highest sibling?
88
+ #
89
+ # @example Is this the highest sibling?
90
+ # book.at_top?
91
+ #
92
+ # @return [ Boolean ] True if this document is the highest sibling.
93
+ def at_top?
94
+ self.higher_siblings.empty?
95
+ end
96
+
97
+ # Is this the lowest sibling?
98
+ #
99
+ # @example Is this the lowest sibling?
100
+ # book.at_bottom?
101
+ #
102
+ # @return [ Boolean ] True if this document is the lowest sibling.
103
+ def at_bottom?
104
+ self.lower_siblings.empty?
105
+ end
106
+
107
+ # Moves this document above all of its siblings.
108
+ #
109
+ # @example Move document to the top.
110
+ # book.move_to_top
111
+ #
112
+ # @return [ Boolean ] True if the document was moved to the top or was
113
+ # already there.
114
+ def move_to_top
115
+ return true if at_top?
116
+ self.move_above(self.highest_sibling)
117
+ end
118
+
119
+ # Moves this document below all of its siblings.
120
+ #
121
+ # @example Move document to the bottom.
122
+ # book.move_to_bottom
123
+ #
124
+ # @return [ Boolean ] True if the document was moved to the bottom or was
125
+ # already there.
126
+ def move_to_bottom
127
+ return true if at_bottom?
128
+ self.move_below(self.lowest_sibling)
129
+ end
130
+
131
+ # Moves this document one position up.
132
+ #
133
+ # @example Move document one position up.
134
+ # book.move_up
135
+ def move_up
136
+ return if at_top?
137
+ self.siblings.where(position: self.position - 1).first.inc(:position, 1)
138
+ self.inc(:position, -1)
139
+ end
140
+
141
+ # Moves this document one position down.
142
+ #
143
+ # @example Move document one position down.
144
+ # book.move_down
145
+ def move_down
146
+ return if at_bottom?
147
+ self.siblings.where(position: self.position + 1).first.inc(:position, -1)
148
+ self.inc(:position, 1)
149
+ end
150
+
151
+ # Moves this document above the specified document.
152
+ #
153
+ # This method changes this document's scope values if necessary.
154
+ #
155
+ # @example Move document above another document.
156
+ # book.move_above(other_book)
157
+ #
158
+ # @param [ Mongoid::Document ] other The document to Moves this document
159
+ # above.
160
+ def move_above(other)
161
+ return false unless self.sibling_of!(other)
162
+
163
+ if self.position > other.position
164
+ new_position = other.position
165
+ other.lower_siblings.and(:position.lt => self.position).each { |s| s.inc(:position, 1) }
166
+ other.inc(:position, 1)
167
+ else
168
+ new_position = other.position - 1
169
+ other.higher_siblings.and(:position.gt => self.position).each { |s| s.inc(:position, -1) }
170
+ end
171
+ self.position = new_position
172
+
173
+ self.save!
174
+ end
175
+
176
+ # Moves this document below the specified document.
177
+ #
178
+ # This method changes this document's scope values if necessary.
179
+ #
180
+ # @example Move document below another document.
181
+ # book.move_below(other_book)
182
+ #
183
+ # @param [ Mongoid::Document ] other The document to Moves this document
184
+ # below.
185
+ def move_below(other)
186
+ return false unless self.sibling_of!(other)
187
+
188
+ if self.position > other.position
189
+ new_position = other.position + 1
190
+ other.lower_siblings.and(:position.lt => self.position).each { |s| s.inc(:position, 1) }
191
+ else
192
+ new_position = other.position
193
+ other.higher_siblings.and(:position.gt => self.position).each { |s| s.inc(:position, -1) }
194
+ other.inc(:position, -1)
195
+ end
196
+ self.position = new_position
197
+
198
+ self.save!
199
+ end
200
+
201
+ private
202
+
203
+ def move_lower_siblings_up
204
+ self.lower_siblings.each { |s| s.inc(:position, -1) }
205
+ end
206
+
207
+ def sibling_reposition_required?
208
+ return false if self.ordering_scopes.empty?
209
+ self.ordering_scopes.any? { |scope| attribute_changed?(key_for_scope(scope)) } && persisted?
210
+ end
211
+
212
+ def reposition_former_siblings
213
+ return if self.ordering_scopes.empty?
214
+
215
+ old_scope_values = {}
216
+ self.ordering_scopes.each do |scope|
217
+ scope_metadata = self.reflect_on_association(scope)
218
+ scope_key = scope_metadata ? scope_metadata.key : scope.to_s
219
+
220
+ if attribute_changed?(scope_key)
221
+ old_value = attribute_was(scope_key)
222
+
223
+ old_scope_values[scope] = if scope_metadata && old_value
224
+ model = scope_metadata.inverse_type ? attribute_was(scope_metadata.inverse_type) : scope_metadata.klass
225
+ scope_metadata.criteria(old_value, model).first
226
+ else
227
+ old_value
228
+ end
229
+ end
230
+ end
231
+
232
+ former_siblings = self.siblings(scope_values: old_scope_values).where(:position.gt => (attribute_was("position") || 0))
233
+ former_siblings.each { |s| s.inc(:position, -1) }
234
+ end
235
+
236
+ def assign_default_position
237
+ return unless self.position.nil? ||
238
+ (self.ordering_scopes.any? { |scope| attribute_changed?(key_for_scope(scope)) } &&
239
+ !new_record?)
240
+
241
+ siblings = self.siblings
242
+ self.position = if siblings.empty? || siblings.map(&:position).compact.empty?
243
+ 0
244
+ else
245
+ siblings.max(:position).to_i + 1
246
+ end
247
+ end
248
+
249
+ def key_for_scope(scope)
250
+ return nil if scope.nil?
251
+ metadata = self.reflect_on_association(scope)
252
+ metadata ? metadata.key : scope.to_s
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,291 @@
1
+ require "spec_helper.rb"
2
+
3
+ describe Mongoid::Ordering do
4
+
5
+ describe ".ordered" do
6
+
7
+ let(:test_class) {
8
+ Class.new do
9
+ include Mongoid::Document
10
+ include Mongoid::Ordering
11
+
12
+ ordered scope: [:main, :fallback]
13
+ end
14
+ }
15
+
16
+ it "sets the default sibling scope and the ordering scopes to the specified scope" do
17
+ test_class.default_sibling_scope.should eq([:main, :fallback])
18
+ test_class.ordering_scopes.should eq([:main, :fallback])
19
+ end
20
+ end
21
+
22
+ describe "Instance methods" do
23
+
24
+ let!(:sibling1) { DummyParentDocument.create }
25
+ let!(:sibling2) { DummyParentDocument.create }
26
+ let!(:sibling3) { DummyParentDocument.create }
27
+
28
+ describe "#lower_siblings" do
29
+
30
+ it "returns the siblings with a higher position" do
31
+ sibling1.lower_siblings.should eq([sibling2, sibling3])
32
+ end
33
+ end
34
+
35
+ describe "#higher_siblings" do
36
+
37
+ it "returns the siblings with a lower position" do
38
+ sibling3.higher_siblings.should eq([sibling1, sibling2])
39
+ end
40
+ end
41
+
42
+ describe "#highest_sibling" do
43
+
44
+ it "returns the first sibling" do
45
+ sibling2.highest_sibling.should eq(sibling1)
46
+ end
47
+ end
48
+
49
+ describe "#lowest_sibling" do
50
+
51
+ it "returns the last sibling" do
52
+ sibling2.lowest_sibling.should eq(sibling3)
53
+ end
54
+ end
55
+
56
+ describe "#at_top?" do
57
+
58
+ context "when the subject is the first sibling" do
59
+
60
+ it "returns true" do
61
+ sibling1.should be_at_top
62
+ end
63
+ end
64
+
65
+ context "when the subject is not the first sibling" do
66
+
67
+ it "returns false" do
68
+ sibling2.should_not be_at_top
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#at_bottom?" do
74
+
75
+ context "when the subject is the last sibling" do
76
+
77
+ it "returns true" do
78
+ sibling3.should be_at_bottom
79
+ end
80
+ end
81
+
82
+ context "when the subject is not the last sibling" do
83
+
84
+ it "returns false" do
85
+ sibling2.should_not be_at_bottom
86
+ end
87
+ end
88
+ end
89
+
90
+ describe "#move_to_top" do
91
+
92
+ it "rearranges the siblings" do
93
+ sibling3.move_to_top
94
+
95
+ sibling3.siblings_and_self.should eq([sibling3, sibling1, sibling2])
96
+ end
97
+
98
+ it "properly sets the positions" do
99
+ sibling3.move_to_top
100
+
101
+ sibling3.reload.position.should eq(0)
102
+ sibling1.reload.position.should eq(1)
103
+ sibling2.reload.position.should eq(2)
104
+ end
105
+ end
106
+
107
+ describe "#move_to_bottom" do
108
+
109
+ it "rearranges the siblings" do
110
+ sibling1.move_to_bottom
111
+
112
+ sibling1.siblings_and_self.should eq([sibling2, sibling3, sibling1])
113
+ end
114
+
115
+ it "properly sets the positions" do
116
+ sibling1.move_to_bottom
117
+
118
+ sibling2.reload.position.should eq(0)
119
+ sibling3.reload.position.should eq(1)
120
+ sibling1.reload.position.should eq(2)
121
+ end
122
+ end
123
+
124
+ describe "#move_up" do
125
+
126
+ it "rearranges the siblings" do
127
+ sibling3.move_up
128
+
129
+ sibling3.siblings_and_self.should eq([sibling1, sibling3, sibling2])
130
+ end
131
+
132
+ it "properly sets the positions" do
133
+ sibling3.move_up
134
+
135
+ sibling1.reload.position.should eq(0)
136
+ sibling3.reload.position.should eq(1)
137
+ sibling2.reload.position.should eq(2)
138
+ end
139
+ end
140
+
141
+ describe "#move_down" do
142
+
143
+ it "rearranges the siblings" do
144
+ sibling1.move_down
145
+
146
+ sibling1.siblings_and_self.should eq([sibling2, sibling1, sibling3])
147
+ end
148
+
149
+ it "properly sets the positions" do
150
+ sibling1.move_down
151
+
152
+ sibling2.reload.position.should eq(0)
153
+ sibling1.reload.position.should eq(1)
154
+ sibling3.reload.position.should eq(2)
155
+ end
156
+ end
157
+
158
+ describe "#move_above" do
159
+
160
+ context "when the subject was somewhere above the other object" do
161
+
162
+ it "rearranges the siblings" do
163
+ sibling1.move_above(sibling3)
164
+
165
+ sibling1.siblings_and_self.should eq([sibling2, sibling1, sibling3])
166
+ end
167
+
168
+ it "properly sets the positions" do
169
+ sibling1.move_above(sibling3)
170
+
171
+ sibling2.reload.position.should eq(0)
172
+ sibling1.reload.position.should eq(1)
173
+ sibling3.reload.position.should eq(2)
174
+ end
175
+ end
176
+
177
+ context "when the subject was somewhere below the other object" do
178
+
179
+ it "rearranges the siblings" do
180
+ sibling3.move_above(sibling2)
181
+
182
+ sibling3.siblings_and_self.should eq([sibling1, sibling3, sibling2])
183
+ end
184
+
185
+ it "properly sets the positions" do
186
+ sibling3.move_above(sibling2)
187
+
188
+ sibling1.reload.position.should eq(0)
189
+ sibling3.reload.position.should eq(1)
190
+ sibling2.reload.position.should eq(2)
191
+ end
192
+ end
193
+ end
194
+
195
+ describe "#move_below" do
196
+
197
+ context "when the subject was somewhere above the other object" do
198
+
199
+ it "rearranges the siblings" do
200
+ sibling1.move_below(sibling2)
201
+
202
+ sibling1.siblings_and_self.should eq([sibling2, sibling1, sibling3])
203
+ end
204
+
205
+ it "properly sets the positions" do
206
+ sibling1.move_below(sibling2)
207
+
208
+ sibling2.reload.position.should eq(0)
209
+ sibling1.reload.position.should eq(1)
210
+ sibling3.reload.position.should eq(2)
211
+ end
212
+ end
213
+ end
214
+
215
+ context "when the subject was somewhere below the other object" do
216
+
217
+ it "rearranges the siblings" do
218
+ sibling3.move_below(sibling1)
219
+
220
+ sibling3.siblings_and_self.should eq([sibling1, sibling3, sibling2])
221
+ end
222
+
223
+ it "properly sets the positions" do
224
+ sibling3.move_below(sibling1)
225
+
226
+ sibling1.reload.position.should eq(0)
227
+ sibling3.reload.position.should eq(1)
228
+ sibling2.reload.position.should eq(2)
229
+ end
230
+ end
231
+ end
232
+
233
+ describe "creating a document" do
234
+
235
+ context "when no siblings exist yet" do
236
+
237
+ it "sets the subject's position to 0" do
238
+ DummyParentDocument.create.position.should eq(0)
239
+ end
240
+ end
241
+
242
+ context "when a sibling already exist" do
243
+
244
+ let!(:sibling) { DummyParentDocument.create }
245
+
246
+ it "sets the subject's position to the highest position plus 1" do
247
+ DummyParentDocument.create.position.should eq(1)
248
+ end
249
+ end
250
+ end
251
+
252
+ describe "moving a document to another parent" do
253
+
254
+ let!(:parent1) { DummyParentDocument.create }
255
+ let!(:parent1_child1) { DummyChildDocument.create(parent: parent1) }
256
+ let!(:parent1_child2) { DummyChildDocument.create(parent: parent1) }
257
+ let!(:parent1_child3) { DummyChildDocument.create(parent: parent1) }
258
+ let!(:parent2) { DummyParentDocument.create }
259
+ let!(:parent2_child1) { DummyChildDocument.create(parent: parent2) }
260
+ let!(:parent2_child2) { DummyChildDocument.create(parent: parent2) }
261
+ let!(:parent2_child3) { DummyChildDocument.create(parent: parent2) }
262
+
263
+ before(:each) do
264
+ parent1_child2.parent = parent2
265
+ parent1_child2.save
266
+ end
267
+
268
+ it "moves lower siblings up" do
269
+ parent1_child1.reload.position.should eq(0)
270
+ parent1_child3.reload.position.should eq(1)
271
+ end
272
+
273
+ it "sets the subject's position to the highest position under the new parent plus 1" do
274
+ parent1_child2.reload.position.should eq(3)
275
+ end
276
+ end
277
+
278
+ describe "destroying a document" do
279
+
280
+ let!(:sibling1) { DummyParentDocument.create }
281
+ let!(:sibling2) { DummyParentDocument.create }
282
+ let!(:sibling3) { DummyParentDocument.create }
283
+
284
+ it "moves lower siblings up" do
285
+ sibling2.destroy
286
+
287
+ sibling1.reload.position.should eq(0)
288
+ sibling3.reload.position.should eq(1)
289
+ end
290
+ end
291
+ end
@@ -0,0 +1,20 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require "mongoid"
5
+ require "mongoid/siblings"
6
+ require "mongoid/ordering"
7
+
8
+ require "rspec"
9
+
10
+ Mongoid.configure do |config|
11
+ config.connect_to "mongoid_ordering_test"
12
+ end
13
+
14
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
15
+
16
+ RSpec.configure do |config|
17
+ config.after :each do
18
+ Mongoid::Config.purge!
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ class DummyParentDocument
2
+ include Mongoid::Document
3
+ include Mongoid::Ordering
4
+
5
+ ordered scope: nil
6
+
7
+ has_many :children, class_name: "DummyChildDocument",
8
+ inverse_of: :parent
9
+ end
10
+
11
+ class DummyChildDocument
12
+ include Mongoid::Document
13
+ include Mongoid::Ordering
14
+
15
+ ordered scope: :parent
16
+
17
+ belongs_to :parent, class_name: DummyParentDocument.to_s,
18
+ inverse_of: :children
19
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongoid-ordering
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Douwe Maan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mongoid
16
+ requirement: &70134351207600 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70134351207600
25
+ - !ruby/object:Gem::Dependency
26
+ name: mongoid-siblings
27
+ requirement: &70134351205960 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.1.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70134351205960
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70134351204840 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70134351204840
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &70134351203100 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70134351203100
58
+ description: mongoid-ordering makes it easy to keep your Mongoid documents in order.
59
+ email: douwe@selenight.nl
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - lib/mongoid/ordering.rb
65
+ - LICENSE
66
+ - README.md
67
+ - Rakefile
68
+ - Gemfile
69
+ - spec/mongoid/ordering_spec.rb
70
+ - spec/spec_helper.rb
71
+ - spec/support/models.rb
72
+ homepage: https://github.com/DouweM/mongoid-ordering
73
+ licenses:
74
+ - MIT
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ segments:
86
+ - 0
87
+ hash: -533634391627392618
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ segments:
95
+ - 0
96
+ hash: -533634391627392618
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 1.8.6
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: Easy ordering of your Mongoid documents.
103
+ test_files:
104
+ - spec/mongoid/ordering_spec.rb
105
+ - spec/spec_helper.rb
106
+ - spec/support/models.rb