mongoid-list 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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