mongoid-list 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ Gemfile.lock
3
+ pkg/
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2@mongoid-list
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,12 @@
1
+ guard 'spork' do
2
+ watch('Gemfile')
3
+ watch('Gemfile.lock')
4
+ watch('test/test_helper.rb')
5
+ end
6
+
7
+ guard 'minitest' do
8
+ watch(%r|^test/test_(.*)\.rb|)
9
+ watch(%r|^test/(.*)_test\.rb|)
10
+ watch(%r|^lib/(.*)([^/]+)\.rb|) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
11
+ watch(%r|^test/test_helper\.rb|) { "test" }
12
+ end
data/LICENSE ADDED
File without changes
data/README.md ADDED
@@ -0,0 +1 @@
1
+ Needs Documentation
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ spec = Gem::Specification.load("mongoid-list.gemspec")
5
+
6
+ Rake::TestTask.new(:test) do |test|
7
+ test.libs << 'test'
8
+ test.pattern = 'test/**/*_test.rb'
9
+ test.verbose = true
10
+ end
11
+
12
+ desc "Run tests"
13
+ task :default => :test
@@ -0,0 +1 @@
1
+ require 'mongoid/list'
@@ -0,0 +1,80 @@
1
+ require "mongoid/list/scoping"
2
+
3
+ module Mongoid
4
+
5
+
6
+ module List
7
+ extend ActiveSupport::Concern
8
+ include Mongoid::List::Scoping
9
+
10
+ autoload :Collection, 'mongoid/list/collection'
11
+ autoload :Embedded, 'mongoid/list/embedded'
12
+
13
+ included do
14
+ field :position, type: Integer
15
+
16
+ validates :position, numericality: true, on: :update
17
+
18
+ index [ include?(Mongoid::Paranoia) ? [ :deleted_at, 1 ] : nil, [ :position, -1 ] ].compact # TODO: MONGOID: Apply a patch
19
+
20
+ before_create :set_initial_position_in_list
21
+ before_update :mark_for_update_processing_of_list, if: :position_changed?
22
+ after_update :update_positions_in_list!, if: :_process_list_change
23
+ before_destroy :mark_for_removal_processing_from_list
24
+ after_destroy :update_positions_in_list!, if: :_process_list_change
25
+
26
+ scope :ordered, order_by: :position.asc
27
+ end
28
+
29
+
30
+ module ClassMethods
31
+
32
+ def update_positions_in_list!(elements)
33
+ return false if elements.size < count
34
+ elements.each_with_index do |element, idx|
35
+ id = element.kind_of?(Hash) ? element['id'] : element
36
+ self.collection.update({ id: id }, { '$set' => { position: (idx + 1) } })
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+
43
+ attr_accessor :_process_list_change
44
+
45
+
46
+ private
47
+
48
+
49
+ def set_initial_position_in_list
50
+ self.position = list_count + 1
51
+ end
52
+
53
+ def mark_for_update_processing_of_list
54
+ self._process_list_change = if position_moving_up?
55
+ { min: position_was, max: position, by: -1 }
56
+ else
57
+ { min: position, max: position_was, by: 1 }
58
+ end
59
+ end
60
+
61
+ def position_moving_up?
62
+ position > position_was
63
+ end
64
+
65
+ def mark_for_removal_processing_from_list
66
+ self._process_list_change = { min: position, max: nil, by: -1 }
67
+ end
68
+
69
+ def update_positions_in_list!
70
+ embedded? ? Embedded.new(self).update_positions! : Collection.new(self).update_positions!
71
+ end
72
+
73
+ def list_count
74
+ embedded? ? Embedded.new(self).count : Collection.new(self).count
75
+ end
76
+
77
+
78
+ end
79
+
80
+ end
@@ -0,0 +1,32 @@
1
+ module Mongoid
2
+ module List
3
+ class Collection
4
+
5
+ attr_accessor :obj
6
+
7
+ def initialize(obj)
8
+ @obj = obj
9
+ end
10
+
11
+ def update_positions!
12
+ obj.class.collection.update(
13
+ criteria,
14
+ { '$inc' => { position: obj._process_list_change[:by] } },
15
+ multi: true
16
+ )
17
+ end
18
+
19
+ def count
20
+ obj.class.where(obj.list_scope_conditions).count
21
+ end
22
+
23
+ private
24
+
25
+ def criteria
26
+ position = { '$lte' => obj._process_list_change[:max], '$gte' => obj._process_list_change[:min] }.delete_if { |k, v| v.nil? }
27
+ obj.list_scope_conditions.merge({ _id: { '$ne' => obj.id }, position: position })
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,51 @@
1
+ module Mongoid
2
+ module List
3
+ class Embedded
4
+
5
+ attr_accessor :obj
6
+
7
+ def initialize(obj)
8
+ @obj = obj
9
+ end
10
+
11
+ def update_positions!
12
+ items.each do |item|
13
+ next unless should_operate_on_item?(item)
14
+ criteria = { "#{obj.metadata.name.to_sym}._id" => item.id }
15
+ changes = { '$inc' => { "#{obj.metadata.name.to_sym}.$.position" => obj._process_list_change[:by] } }
16
+ _embedded_list_container.class.collection.update(criteria, changes)
17
+ end
18
+ end
19
+
20
+ def count
21
+ _embedded_list_container.send(obj.metadata.name.to_sym).excludes(_id: obj.id).where(obj.list_scope_conditions).count
22
+ end
23
+
24
+
25
+ private
26
+
27
+
28
+ def items
29
+ _embedded_list_container.send(obj.metadata.name.to_sym)
30
+ end
31
+
32
+ def should_operate_on_item?(item)
33
+ # TODO: This includes duplicate logic from :list_scope_conditions
34
+ ![
35
+ item == obj,
36
+ obj._process_list_change[:min].present? && item.position < obj._process_list_change[:min],
37
+ obj._process_list_change[:max].present? && item.position > obj._process_list_change[:max],
38
+ obj.list_scoped? && item.list_scope_value != obj.list_scope_value
39
+ ].any?
40
+ end
41
+
42
+ def _embedded_list_container
43
+ # TODO: MONGOID: Mongoid is not currently setting up the metadata properly so we have to do some extra
44
+ # work with getting the values we need out of the partial information.
45
+ obj.send(obj.metadata.inverse_setter.sub('=', '').to_sym)
46
+ end
47
+
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,23 @@
1
+ module Mongoid
2
+ module List
3
+ module Scoping
4
+
5
+ def list_scoped?
6
+ fields["position"].options.has_key?(:scope)
7
+ end
8
+
9
+ def list_scope_field
10
+ fields["position"].options[:scope]
11
+ end
12
+
13
+ def list_scope_value
14
+ public_send(list_scope_field)
15
+ end
16
+
17
+ def list_scope_conditions
18
+ list_scoped? ? { list_scope_field.to_sym => list_scope_value } : {}
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ module Mongoid
2
+ module List
3
+ VERSION = "0.1.2"
4
+ end
5
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib/', __FILE__)
3
+ $:.unshift lib unless $:.include?(lib)
4
+
5
+ require "mongoid/list/version"
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'mongoid-list'
9
+ s.version = Mongoid::List::VERSION
10
+ s.date = '2011-10-28'
11
+ s.authors = [ 'Dave Krupinski' ]
12
+ s.email = 'dave@davekrupinski.com'
13
+ s.summary = 'Simple list behavior for Mongoid'
14
+
15
+ s.add_dependency('mongoid', [ '>= 2.0.0' ])
16
+
17
+ s.add_development_dependency('bson_ext')
18
+ s.add_development_dependency('minitest', [ '>= 2.7.0' ])
19
+ s.add_development_dependency('mini_shoulda', [ '>= 0.4.0' ])
20
+ s.add_development_dependency('spork', [ '>= 0.9.0.rc' ])
21
+ s.add_development_dependency('spork-testunit', [ '>= 0.0.6' ])
22
+ s.add_development_dependency('guard-minitest', [ '>= 0.4.0' ])
23
+ s.add_development_dependency('guard-spork', [ '>= 0.3.1' ])
24
+ s.add_development_dependency('turn', [ '>= 0.8.3' ])
25
+
26
+ s.files = `git ls-files`.split("\n")
27
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
29
+ s.require_paths = ["lib"]
30
+
31
+ end
@@ -0,0 +1,354 @@
1
+ require 'test_helper'
2
+
3
+ describe Mongoid::List::Scoping do
4
+
5
+ describe "#list_scope_field" do
6
+
7
+ let :obj do
8
+ Scoped.create
9
+ end
10
+
11
+ should "be :group" do
12
+ assert_equal :group, obj.list_scope_field
13
+ end
14
+
15
+ end
16
+
17
+
18
+ describe "#list_scope_conditions" do
19
+
20
+ context "when unscoped" do
21
+
22
+ let :obj do
23
+ Simple.new
24
+ end
25
+
26
+ let :expected_conditions do
27
+ { }
28
+ end
29
+
30
+ should "be an empty hash" do
31
+ assert_equal expected_conditions, obj.list_scope_conditions
32
+ end
33
+
34
+ end
35
+
36
+ context "when scoped" do
37
+
38
+ let :obj do
39
+ Scoped.new(group: "a grouping")
40
+ end
41
+
42
+ let :expected_conditions do
43
+ { group: "a grouping" }
44
+ end
45
+
46
+ should "have be for a :group of 'a grouping'" do
47
+ assert_equal expected_conditions, obj.list_scope_conditions
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+
54
+ describe "Initializing in multiple scopes" do
55
+
56
+ context "on a Collection" do
57
+
58
+ setup do
59
+ @group1_1 = Scoped.create(group: 1)
60
+ @group2_1 = Scoped.create(group: 2)
61
+ @group2_2 = Scoped.create(group: 2)
62
+ end
63
+
64
+ should "default @group1_1 to a :position of 1" do
65
+ assert_equal 1, @group1_1.position
66
+ end
67
+
68
+ should "default @group2_1 to a :position of 1" do
69
+ assert_equal 1, @group2_1.position
70
+ end
71
+
72
+ should "default @group2_2 to a :position of 2" do
73
+ assert_equal 2, @group2_2.position
74
+ end
75
+
76
+ end
77
+
78
+ context "on Embedded Documents" do
79
+
80
+ setup do
81
+ @container = Container.create
82
+ @group1_1 = @container.scoped_items.create(group: 1)
83
+ @group1_2 = @container.scoped_items.create(group: 1)
84
+ @group2_1 = @container.scoped_items.create(group: 2)
85
+ @group2_2 = @container.scoped_items.create(group: 2)
86
+ @group2_3 = @container.scoped_items.create(group: 2)
87
+ @group3_1 = @container.scoped_items.create(group: 3)
88
+ end
89
+
90
+ should "default @group1_1 to a :position of 1" do
91
+ assert_equal 1, @group1_1.position
92
+ end
93
+
94
+ should "default @group1_2 to a :position of 2" do
95
+ assert_equal 2, @group1_2.position
96
+ end
97
+
98
+ should "default @group2_1 to a :position of 1" do
99
+ assert_equal 1, @group2_1.position
100
+ end
101
+
102
+ should "default @group2_2 to a :position of 2" do
103
+ assert_equal 2, @group2_2.position
104
+ end
105
+
106
+ should "default @group2_3 to a :position of 3" do
107
+ assert_equal 3, @group2_3.position
108
+ end
109
+
110
+ should "default @group3_1 to a :position of 1" do
111
+ assert_equal 1, @group3_1.position
112
+ end
113
+
114
+ end
115
+ end
116
+
117
+
118
+
119
+ describe "#update :position" do
120
+
121
+ context "for Collection List" do
122
+
123
+ setup do
124
+ @group1_1 = Scoped.create(group: 1)
125
+ @group1_2 = Scoped.create(group: 1)
126
+ @group2_1 = Scoped.create(group: 2)
127
+ @group2_2 = Scoped.create(group: 2)
128
+ @group2_3 = Scoped.create(group: 2)
129
+ end
130
+
131
+ context "@group1_2 to :position 1" do
132
+
133
+ setup do
134
+ @group1_2.update_attribute(:position, 1)
135
+ end
136
+
137
+ should "have updated @group1_1 to :position of 2" do
138
+ assert_equal 1, @group1_1.position
139
+ assert_equal 2, @group1_1.reload.position
140
+ end
141
+
142
+ should "not have updated :group2_1's :position" do
143
+ assert_equal @group2_1.position, @group2_1.reload.position
144
+ end
145
+
146
+ should "not have updated :group2_2's :position" do
147
+ assert_equal @group2_2.position, @group2_2.reload.position
148
+ end
149
+
150
+ should "not have updated :group2_3's :position" do
151
+ assert_equal @group2_3.position, @group2_3.reload.position
152
+ end
153
+
154
+ end
155
+
156
+
157
+ context "@group2_2 to :position 3" do
158
+
159
+ setup do
160
+ @group2_2.update_attribute(:position, 3)
161
+ end
162
+
163
+ should "not have updated @group1_1's :position" do
164
+ assert_equal @group1_1.position, @group1_1.reload.position
165
+ end
166
+
167
+ should "not have updated @group1_2's :position" do
168
+ assert_equal @group1_2.position, @group1_2.reload.position
169
+ end
170
+
171
+ should "not have updated @group2_1's :position" do
172
+ assert_equal @group2_1.position, @group2_1.reload.position
173
+ end
174
+
175
+ should "have updated @group2_2's :position to 3" do
176
+ assert_equal 3, @group2_2.position
177
+ end
178
+
179
+ should "have updated @group2_3's :position to 2" do
180
+ assert_equal 3, @group2_3.position
181
+ assert_equal 2, @group2_3.reload.position
182
+ end
183
+ end
184
+
185
+ end
186
+
187
+
188
+ context "for an Embedded List" do
189
+
190
+ setup do
191
+ @container = Container.create
192
+ @group1_1 = @container.scoped_items.create(group: 1)
193
+ @group1_2 = @container.scoped_items.create(group: 1)
194
+ @group2_1 = @container.scoped_items.create(group: 2)
195
+ @group2_2 = @container.scoped_items.create(group: 2)
196
+ @group2_3 = @container.scoped_items.create(group: 2)
197
+ end
198
+
199
+ context "moving @group1_1 to :position 2" do
200
+
201
+ setup do
202
+ @group1_1.update_attributes(position: 2)
203
+ end
204
+
205
+ should "update @group1_1's :position to 2" do
206
+ assert_equal 2, @group1_1.position
207
+ end
208
+
209
+ should "update @group1_2's :position to 1" do
210
+ assert_equal 2, @group1_2.position
211
+ assert_equal 1, @group1_2.reload.position
212
+ end
213
+
214
+ should "not update @group2_1's :position" do
215
+ assert_equal 1, @group2_1.position
216
+ assert_equal 1, @group2_1.reload.position
217
+ end
218
+
219
+ should "not update @group2_2's :position" do
220
+ assert_equal 2, @group2_2.position
221
+ assert_equal 2, @group2_2.reload.position
222
+ end
223
+
224
+ should "not update @group2_3's :position" do
225
+ assert_equal 3, @group2_3.position
226
+ assert_equal 3, @group2_3.reload.position
227
+ end
228
+ end
229
+
230
+
231
+ context "moving @group2_3 to :position 1" do
232
+
233
+ setup do
234
+ @group2_3.update_attributes(position: 1)
235
+ end
236
+
237
+ should "not update @group1_1's :position" do
238
+ assert_equal 1, @group1_1.position
239
+ assert_equal 1, @group1_1.reload.position
240
+ end
241
+
242
+ should "not update @group1_2's :position" do
243
+ assert_equal 2, @group1_2.position
244
+ assert_equal 2, @group1_2.reload.position
245
+ end
246
+
247
+ should "update @group2_1's :position to 2" do
248
+ assert_equal 1, @group2_1.position
249
+ assert_equal 2, @group2_1.reload.position
250
+ end
251
+
252
+ should "update @group2_2's :position to 3" do
253
+ assert_equal 2, @group2_2.position
254
+ assert_equal 3, @group2_2.reload.position
255
+ end
256
+
257
+ should "update @group2_3's :position to 1" do
258
+ assert_equal 1, @group2_3.position
259
+ assert_equal 1, @group2_3.reload.position
260
+ end
261
+ end
262
+
263
+ end
264
+
265
+ end
266
+
267
+
268
+
269
+ describe "#destroy" do
270
+
271
+ context "from a Collection" do
272
+
273
+ setup do
274
+ @group1_1 = Scoped.create(group: 1)
275
+ @group1_2 = Scoped.create(group: 1)
276
+ @group2_1 = Scoped.create(group: 2)
277
+ @group2_2 = Scoped.create(group: 2)
278
+ @group2_3 = Scoped.create(group: 2)
279
+ end
280
+
281
+ context "for @group2_1" do
282
+
283
+ setup do
284
+ @group2_1.destroy
285
+ end
286
+
287
+ should "not update @group1_1's :position" do
288
+ assert_equal 1, @group1_1.position
289
+ assert_equal 1, @group1_1.reload.position
290
+ end
291
+
292
+ should "not update @group1_2's :position" do
293
+ assert_equal 2, @group1_2.position
294
+ assert_equal 2, @group1_2.reload.position
295
+ end
296
+
297
+ should "update @group2_2's :position to 1" do
298
+ assert_equal 2, @group2_2.position
299
+ assert_equal 1, @group2_2.reload.position
300
+ end
301
+
302
+ should "update @group2_3's :position to 2" do
303
+ assert_equal 3, @group2_3.position
304
+ assert_equal 2, @group2_3.reload.position
305
+ end
306
+ end
307
+
308
+ end
309
+
310
+
311
+ context "from an Embedded Collection" do
312
+
313
+ setup do
314
+ @container = Container.create
315
+ @group1_1 = @container.scoped_items.create(group: 1)
316
+ @group1_2 = @container.scoped_items.create(group: 1)
317
+ @group2_1 = @container.scoped_items.create(group: 2)
318
+ @group2_2 = @container.scoped_items.create(group: 2)
319
+ @group2_3 = @container.scoped_items.create(group: 2)
320
+ end
321
+
322
+ context "for @group2_2" do
323
+
324
+ setup do
325
+ @group2_2.destroy
326
+ end
327
+
328
+ should "not update @group1_1's :position" do
329
+ assert_equal 1, @group1_1.position
330
+ assert_equal 1, @group1_1.reload.position
331
+ end
332
+
333
+ should "not update @group1_2's :position" do
334
+ assert_equal 2, @group1_2.position
335
+ assert_equal 2, @group1_2.reload.position
336
+ end
337
+
338
+ should "not update @group2_1's :position" do
339
+ assert_equal 1, @group2_1.position
340
+ assert_equal 1, @group2_1.reload.position
341
+ end
342
+
343
+ should "update @group2_3's :position to 2" do
344
+ assert_equal 3, @group2_3.position
345
+ assert_equal 2, @container.reload.scoped_items.find(@group2_3.id).position
346
+ end
347
+ end
348
+
349
+ end
350
+
351
+
352
+ end
353
+
354
+ end
@@ -0,0 +1,339 @@
1
+ require 'test_helper'
2
+
3
+
4
+ describe Mongoid::List do
5
+
6
+
7
+ context "Setting Initial Position" do
8
+ setup do
9
+ @list1 = Simple.create
10
+ @list2 = Simple.create
11
+ end
12
+
13
+ should "have set @list1's position to 1" do
14
+ assert_equal 1, @list1.position
15
+ end
16
+
17
+ should "have set @list2's position to 2" do
18
+ assert_equal 2, @list2.position
19
+ end
20
+ end
21
+
22
+
23
+
24
+ context "Setting Initial Position in Embedded Collection" do
25
+ setup do
26
+ @container = Container.create
27
+ @list1 = @container.items.create
28
+ @list2 = @container.items.create
29
+ @list3 = @container.items.create
30
+ @unrelated_list = Container.create.items.create
31
+ end
32
+
33
+ should "have created the container" do
34
+ assert_equal 3, @container.items.count
35
+ end
36
+
37
+
38
+ should "have set the initial positions for each list item" do
39
+ assert_equal 1, @list1.position
40
+ assert_equal 2, @list2.position
41
+ assert_equal 3, @list3.position
42
+ end
43
+
44
+ should "have also set the @unrelated_list's position independently" do
45
+ assert_equal 1, @unrelated_list.position
46
+ end
47
+ end
48
+
49
+
50
+
51
+ context "Updating List Position" do
52
+ setup do
53
+ @list1 = Simple.create
54
+ @list2 = Simple.create
55
+ @list3 = Simple.create
56
+ @list4 = Simple.create
57
+ end
58
+
59
+ should "have set initial positions" do
60
+ assert_equal 1, @list1.position
61
+ assert_equal 2, @list2.position
62
+ assert_equal 3, @list3.position
63
+ assert_equal 4, @list4.position
64
+ end
65
+
66
+ context "for @list2 going to position of 1" do
67
+ setup do
68
+ @list2.update_attributes(:position => 1)
69
+ @list1.reload; @list2.reload; @list3.reload; @list4.reload
70
+ end
71
+
72
+ should "have updated everyone's :position" do
73
+ assert_equal 2, @list1.position
74
+ assert_equal 1, @list2.position
75
+ assert_equal 3, @list3.position
76
+ assert_equal 4, @list4.position
77
+ end
78
+ end
79
+
80
+ context "for @list3 going to position of 1" do
81
+ setup do
82
+ @list3.update_attributes(:position => 1)
83
+ @list1.reload; @list2.reload; @list3.reload; @list4.reload
84
+ end
85
+
86
+ should "have updated everyone's :position" do
87
+ assert_equal 2, @list1.position
88
+ assert_equal 3, @list2.position
89
+ assert_equal 1, @list3.position
90
+ assert_equal 4, @list4.position
91
+ end
92
+ end
93
+
94
+ context "for @list1 going to position of 2" do
95
+ setup do
96
+ @list1.update_attributes(:position => 2)
97
+ @list1.reload; @list2.reload; @list3.reload; @list4.reload
98
+ end
99
+
100
+ should "have updated everyone's :position" do
101
+ assert_equal 2, @list1.position
102
+ assert_equal 1, @list2.position
103
+ assert_equal 3, @list3.position
104
+ assert_equal 4, @list4.position
105
+ end
106
+ end
107
+
108
+ context "for @list1 going to position of 3" do
109
+ setup do
110
+ @list1.update_attributes(:position => 3)
111
+ @list1.reload; @list2.reload; @list3.reload; @list4.reload
112
+ end
113
+
114
+ should "have updated everyone's :position" do
115
+ assert_equal 3, @list1.position
116
+ assert_equal 1, @list2.position
117
+ assert_equal 2, @list3.position
118
+ assert_equal 4, @list4.position
119
+ end
120
+ end
121
+ end
122
+
123
+
124
+
125
+ context "Updating List Position in Embedded Collection" do
126
+ setup do
127
+ @container = Container.create
128
+ @list1 = @container.items.create
129
+ @list2 = @container.items.create
130
+ @list3 = @container.items.create
131
+ @list4 = @container.items.create
132
+ end
133
+
134
+ should "have set initial positions" do
135
+ assert_equal 1, @list1.position
136
+ assert_equal 2, @list2.position
137
+ assert_equal 3, @list3.position
138
+ assert_equal 4, @list4.position
139
+ end
140
+
141
+ context "for @list2 going to position of 1" do
142
+ setup do
143
+ @list2.update_attributes(:position => 1)
144
+ @container.reload
145
+ end
146
+
147
+ should "have updated everyone's :position" do
148
+ assert_equal 2, @container.items.find(@list1.id).position
149
+ assert_equal 1, @container.items.find(@list2.id).position
150
+ assert_equal 3, @container.items.find(@list3.id).position
151
+ assert_equal 4, @container.items.find(@list4.id).position
152
+ end
153
+ end
154
+
155
+ context "for @list3 going to position of 1" do
156
+ setup do
157
+ @list3.update_attributes(:position => 1)
158
+ @container.reload
159
+ end
160
+
161
+ should "have updated everyone's :position" do
162
+ assert_equal 2, @container.items.find(@list1.id).position
163
+ assert_equal 3, @container.items.find(@list2.id).position
164
+ assert_equal 1, @container.items.find(@list3.id).position
165
+ assert_equal 4, @container.items.find(@list4.id).position
166
+ end
167
+ end
168
+
169
+ context "for @list1 going to position of 2" do
170
+ setup do
171
+ @list1.update_attributes(:position => 2)
172
+ @container.reload
173
+ end
174
+
175
+ should "have updated everyone's :position" do
176
+ assert_equal 2, @container.items.find(@list1.id).position
177
+ assert_equal 1, @container.items.find(@list2.id).position
178
+ assert_equal 3, @container.items.find(@list3.id).position
179
+ assert_equal 4, @container.items.find(@list4.id).position
180
+ end
181
+ end
182
+
183
+ context "for @list1 going to position of 3" do
184
+ setup do
185
+ @list1.update_attributes(:position => 3)
186
+ @container.reload
187
+ end
188
+
189
+ should "have updated everyone's :position" do
190
+ assert_equal 3, @container.items.find(@list1.id).position
191
+ assert_equal 1, @container.items.find(@list2.id).position
192
+ assert_equal 2, @container.items.find(@list3.id).position
193
+ assert_equal 4, @container.items.find(@list4.id).position
194
+ end
195
+ end
196
+ end
197
+
198
+
199
+
200
+ context "Removing an Item from a List" do
201
+ setup do
202
+ @list1 = Simple.create
203
+ @list2 = Simple.create
204
+ @list3 = Simple.create
205
+ @list4 = Simple.create
206
+ end
207
+
208
+ context "from the first position" do
209
+ setup do
210
+ @list1.destroy
211
+ @list2.reload; @list3.reload; @list4.reload
212
+ end
213
+
214
+ should "have moved all other items up" do
215
+ assert_equal 1, @list2.position
216
+ assert_equal 2, @list3.position
217
+ assert_equal 3, @list4.position
218
+ end
219
+ end
220
+
221
+ context "removing from the 2nd position" do
222
+ setup do
223
+ @list2.destroy
224
+ @list1.reload; @list3.reload; @list4.reload
225
+ end
226
+
227
+ should "have kept @list1 where it was" do
228
+ assert_equal 1, @list1.position
229
+ end
230
+
231
+ should "have moved lower items up" do
232
+ assert_equal 2, @list3.position
233
+ assert_equal 3, @list4.position
234
+ end
235
+ end
236
+
237
+ context "removing from the 4th and last position" do
238
+ setup do
239
+ @list4.destroy
240
+ @list1.reload; @list2.reload; @list3.reload
241
+ end
242
+
243
+ should "have kept everything else where it was" do
244
+ assert_equal 1, @list1.position
245
+ assert_equal 2, @list2.position
246
+ assert_equal 3, @list3.position
247
+ end
248
+ end
249
+ end
250
+
251
+
252
+
253
+ context "Removing an Item from an Embedded List" do
254
+ setup do
255
+ @container = Container.create
256
+ @list1 = @container.items.create
257
+ @list2 = @container.items.create
258
+ @list3 = @container.items.create
259
+ @list4 = @container.items.create
260
+ end
261
+
262
+ context "from the first position" do
263
+ setup do
264
+ @list1.destroy
265
+ @container.reload
266
+ end
267
+
268
+ should "have moved all other items up" do
269
+ assert_equal 1, @container.items.find(@list2.id).position
270
+ assert_equal 2, @container.items.find(@list3.id).position
271
+ assert_equal 3, @container.items.find(@list4.id).position
272
+ end
273
+ end
274
+
275
+ context "removing from the 2nd position" do
276
+ setup do
277
+ @list2.destroy
278
+ @container.reload
279
+ end
280
+
281
+ should "have kept @list1 where it was" do
282
+ assert_equal 1, @container.items.find(@list1.id).position
283
+ end
284
+
285
+ should "have moved lower items up" do
286
+ assert_equal 2, @container.items.find(@list3.id).position
287
+ assert_equal 3, @container.items.find(@list4.id).position
288
+ end
289
+ end
290
+
291
+ context "removing from the 4th and last position" do
292
+ setup do
293
+ @list4.destroy
294
+ @container.reload
295
+ end
296
+
297
+ should "have kept everything else where it was" do
298
+ assert_equal 1, @container.items.find(@list1.id).position
299
+ assert_equal 2, @container.items.find(@list2.id).position
300
+ assert_equal 3, @container.items.find(@list3.id).position
301
+ end
302
+ end
303
+ end
304
+
305
+
306
+
307
+ context "#list_scoped?" do
308
+
309
+
310
+ context "for Simple (unscoped)" do
311
+
312
+ let(:obj) do
313
+ Simple.new
314
+ end
315
+
316
+ should "be nil" do
317
+ assert !obj.list_scoped?
318
+ end
319
+
320
+ end
321
+
322
+
323
+ context "for Scoped" do
324
+
325
+ let(:obj) do
326
+ Scoped.new
327
+ end
328
+
329
+ should "be :group" do
330
+ assert obj.list_scoped?
331
+ end
332
+
333
+ end
334
+
335
+ end
336
+
337
+
338
+ end
339
+
@@ -0,0 +1,8 @@
1
+ class Container
2
+
3
+ include Mongoid::Document
4
+
5
+ embeds_many :items, class_name: 'Embedded', order: :position
6
+ embeds_many :scoped_items, class_name: 'ScopedEmbedded', order: :position
7
+
8
+ end
@@ -0,0 +1,8 @@
1
+ class Embedded
2
+
3
+ include Mongoid::Document
4
+ include Mongoid::List
5
+
6
+ embedded_in :container
7
+
8
+ end
@@ -0,0 +1,9 @@
1
+ class Scoped
2
+
3
+ include Mongoid::Document
4
+ include Mongoid::List
5
+
6
+ field :group, type: String
7
+ field :position, type: Integer, scope: :group
8
+
9
+ end
@@ -0,0 +1,11 @@
1
+ class ScopedEmbedded
2
+
3
+ include Mongoid::Document
4
+ include Mongoid::List
5
+
6
+ embedded_in :container
7
+
8
+ field :group, type: String
9
+ field :position, type: Integer, scope: :group
10
+
11
+ end
@@ -0,0 +1,4 @@
1
+ class Simple
2
+ include Mongoid::Document
3
+ include Mongoid::List
4
+ end
@@ -0,0 +1,27 @@
1
+ gem 'minitest'
2
+
3
+ require 'mini_shoulda'
4
+ require 'minitest/autorun'
5
+ require 'turn'
6
+ require 'spork'
7
+ require 'mongoid'
8
+ require 'mongoid-list'
9
+
10
+ Mongoid.configure do |config|
11
+ database = Mongo::Connection.new.db("mongoid-list_test")
12
+ database.add_user("mongoid", "test")
13
+ config.master = database
14
+ config.logger = nil
15
+ end
16
+
17
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
18
+
19
+ Spork.prefork do
20
+ end
21
+
22
+ Spork.each_run do
23
+ end
24
+
25
+ MiniTest::Spec.add_teardown_hook do
26
+ Mongoid.purge!
27
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongoid-list
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dave Krupinski
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-28 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mongoid
16
+ requirement: &2161351780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.0.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2161351780
25
+ - !ruby/object:Gem::Dependency
26
+ name: bson_ext
27
+ requirement: &2161351360 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2161351360
36
+ - !ruby/object:Gem::Dependency
37
+ name: minitest
38
+ requirement: &2161350800 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 2.7.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2161350800
47
+ - !ruby/object:Gem::Dependency
48
+ name: mini_shoulda
49
+ requirement: &2161350280 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.4.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2161350280
58
+ - !ruby/object:Gem::Dependency
59
+ name: spork
60
+ requirement: &2161349740 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: 0.9.0.rc
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2161349740
69
+ - !ruby/object:Gem::Dependency
70
+ name: spork-testunit
71
+ requirement: &2161349160 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: 0.0.6
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *2161349160
80
+ - !ruby/object:Gem::Dependency
81
+ name: guard-minitest
82
+ requirement: &2161348560 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: 0.4.0
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *2161348560
91
+ - !ruby/object:Gem::Dependency
92
+ name: guard-spork
93
+ requirement: &2161347840 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: 0.3.1
99
+ type: :development
100
+ prerelease: false
101
+ version_requirements: *2161347840
102
+ - !ruby/object:Gem::Dependency
103
+ name: turn
104
+ requirement: &2161347060 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: 0.8.3
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: *2161347060
113
+ description:
114
+ email: dave@davekrupinski.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - .gitignore
120
+ - .rvmrc
121
+ - Gemfile
122
+ - Guardfile
123
+ - LICENSE
124
+ - README.md
125
+ - Rakefile
126
+ - lib/mongoid-list.rb
127
+ - lib/mongoid/list.rb
128
+ - lib/mongoid/list/collection.rb
129
+ - lib/mongoid/list/embedded.rb
130
+ - lib/mongoid/list/scoping.rb
131
+ - lib/mongoid/list/version.rb
132
+ - mongoid-list.gemspec
133
+ - test/mongoid/list/scoping_test.rb
134
+ - test/mongoid/list_test.rb
135
+ - test/support/models/container.rb
136
+ - test/support/models/embedded.rb
137
+ - test/support/models/scoped.rb
138
+ - test/support/models/scoped_embedded.rb
139
+ - test/support/models/simple.rb
140
+ - test/test_helper.rb
141
+ homepage:
142
+ licenses: []
143
+ post_install_message:
144
+ rdoc_options: []
145
+ require_paths:
146
+ - lib
147
+ required_ruby_version: !ruby/object:Gem::Requirement
148
+ none: false
149
+ requirements:
150
+ - - ! '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ! '>='
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ requirements: []
160
+ rubyforge_project:
161
+ rubygems_version: 1.8.10
162
+ signing_key:
163
+ specification_version: 3
164
+ summary: Simple list behavior for Mongoid
165
+ test_files:
166
+ - test/mongoid/list/scoping_test.rb
167
+ - test/mongoid/list_test.rb
168
+ - test/support/models/container.rb
169
+ - test/support/models/embedded.rb
170
+ - test/support/models/scoped.rb
171
+ - test/support/models/scoped_embedded.rb
172
+ - test/support/models/simple.rb
173
+ - test/test_helper.rb