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