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 +3 -0
- data/.rvmrc +1 -0
- data/Gemfile +2 -0
- data/Guardfile +12 -0
- data/LICENSE +0 -0
- data/README.md +1 -0
- data/Rakefile +13 -0
- data/lib/mongoid-list.rb +1 -0
- data/lib/mongoid/list.rb +80 -0
- data/lib/mongoid/list/collection.rb +32 -0
- data/lib/mongoid/list/embedded.rb +51 -0
- data/lib/mongoid/list/scoping.rb +23 -0
- data/lib/mongoid/list/version.rb +5 -0
- data/mongoid-list.gemspec +31 -0
- data/test/mongoid/list/scoping_test.rb +354 -0
- data/test/mongoid/list_test.rb +339 -0
- data/test/support/models/container.rb +8 -0
- data/test/support/models/embedded.rb +8 -0
- data/test/support/models/scoped.rb +9 -0
- data/test/support/models/scoped_embedded.rb +11 -0
- data/test/support/models/simple.rb +4 -0
- data/test/test_helper.rb +27 -0
- metadata +173 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.9.2@mongoid-list
|
data/Gemfile
ADDED
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
|
data/lib/mongoid-list.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'mongoid/list'
|
data/lib/mongoid/list.rb
ADDED
@@ -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,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
|
+
|
data/test/test_helper.rb
ADDED
@@ -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
|