mongoid-tree 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/README.rdoc +16 -2
- data/Rakefile +2 -1
- data/lib/mongoid/tree.rb +15 -19
- data/lib/mongoid/tree/ordering.rb +4 -16
- data/spec/mongoid/tree/ordering_spec.rb +1 -1
- data/spec/mongoid/tree_spec.rb +37 -7
- data/spec/support/models/node.rb +14 -2
- metadata +31 -46
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -5,7 +5,7 @@ A tree structure for Mongoid documents using the materialized path pattern
|
|
5
5
|
|
6
6
|
== Requirements
|
7
7
|
|
8
|
-
* mongoid (
|
8
|
+
* mongoid (~> 2.0.0)
|
9
9
|
|
10
10
|
|
11
11
|
== Install
|
@@ -154,6 +154,20 @@ Example:
|
|
154
154
|
end
|
155
155
|
|
156
156
|
|
157
|
+
=== Validations
|
158
|
+
|
159
|
+
Mongoid::Tree currently does not validate the document's children or parent associations by default. To explicitly enable validation for children and parent documents it's required to add a <tt>validates_associated</tt> validation.
|
160
|
+
|
161
|
+
Example
|
162
|
+
|
163
|
+
class Node
|
164
|
+
include Mongoid::Document
|
165
|
+
include Mongoid::Tree
|
166
|
+
|
167
|
+
validates_associated :parent, :children
|
168
|
+
end
|
169
|
+
|
170
|
+
|
157
171
|
== Known issues
|
158
172
|
|
159
173
|
See https://github.com/benedikt/mongoid-tree/issues
|
@@ -171,4 +185,4 @@ See a list of all contributors at https://github.com/benedikt/mongoid-tree/contr
|
|
171
185
|
|
172
186
|
== Copyright
|
173
187
|
|
174
|
-
Copyright (c) 2010 Benedikt Deicke. See LICENSE for details.
|
188
|
+
Copyright (c) 2010-2011 Benedikt Deicke. See LICENSE for details.
|
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'rspec/core/rake_task'
|
2
|
-
require '
|
2
|
+
require 'rdoc/task'
|
3
3
|
|
4
4
|
spec = Gem::Specification.load("mongoid-tree.gemspec")
|
5
5
|
|
@@ -8,6 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
|
|
8
8
|
task :default => :spec
|
9
9
|
|
10
10
|
Rake::RDocTask.new do |rdoc|
|
11
|
+
rdoc.generator = 'hanna'
|
11
12
|
rdoc.rdoc_dir = 'doc'
|
12
13
|
rdoc.title = "#{spec.name} #{spec.version}"
|
13
14
|
rdoc.options += spec.rdoc_options
|
data/lib/mongoid/tree.rb
CHANGED
@@ -83,17 +83,9 @@ module Mongoid # :nodoc:
|
|
83
83
|
autoload :Traversal, 'mongoid/tree/traversal'
|
84
84
|
|
85
85
|
included do
|
86
|
-
references_many :children, :class_name => self.name, :foreign_key => :parent_id, :inverse_of => :parent
|
87
|
-
def <<(*objects) # :nodoc:
|
88
|
-
super
|
89
|
-
objects.each do |c|
|
90
|
-
c.parent = @parent
|
91
|
-
c.save
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
86
|
+
references_many :children, :class_name => self.name, :foreign_key => :parent_id, :inverse_of => :parent, :autosave => true, :validate => false
|
95
87
|
|
96
|
-
referenced_in :parent, :class_name => self.name, :inverse_of => :children, :index => true
|
88
|
+
referenced_in :parent, :class_name => self.name, :inverse_of => :children, :index => true, :validate => false
|
97
89
|
|
98
90
|
field :parent_ids, :type => Array, :default => []
|
99
91
|
index :parent_ids
|
@@ -194,17 +186,21 @@ module Mongoid # :nodoc:
|
|
194
186
|
##
|
195
187
|
# Returns this document's root node
|
196
188
|
def root
|
197
|
-
|
189
|
+
if parent_ids.present?
|
190
|
+
return base_class.find(parent_ids.first)
|
191
|
+
else
|
192
|
+
return self.root? ? self : self.parent.root
|
193
|
+
end
|
198
194
|
end
|
199
195
|
|
200
196
|
##
|
201
|
-
# Returns this document's ancestors
|
197
|
+
# Returns a chainable criteria for this document's ancestors
|
202
198
|
def ancestors
|
203
199
|
base_class.where(:_id.in => parent_ids)
|
204
200
|
end
|
205
201
|
|
206
202
|
##
|
207
|
-
# Returns this document's ancestors and itself
|
203
|
+
# Returns an array of this document's ancestors and itself
|
208
204
|
def ancestors_and_self
|
209
205
|
ancestors + [self]
|
210
206
|
end
|
@@ -216,13 +212,13 @@ module Mongoid # :nodoc:
|
|
216
212
|
end
|
217
213
|
|
218
214
|
##
|
219
|
-
# Returns this document's descendants
|
215
|
+
# Returns a chainable criteria for this document's descendants
|
220
216
|
def descendants
|
221
217
|
base_class.where(:parent_ids => self.id)
|
222
218
|
end
|
223
219
|
|
224
220
|
##
|
225
|
-
# Returns this document's descendants and itself
|
221
|
+
# Returns and array of this document's descendants and itself
|
226
222
|
def descendants_and_self
|
227
223
|
[self] + descendants
|
228
224
|
end
|
@@ -272,7 +268,7 @@ module Mongoid # :nodoc:
|
|
272
268
|
##
|
273
269
|
# Nullifies all children's parent_id
|
274
270
|
def nullify_children
|
275
|
-
children.
|
271
|
+
children.nullify_all
|
276
272
|
end
|
277
273
|
|
278
274
|
##
|
@@ -309,11 +305,11 @@ module Mongoid # :nodoc:
|
|
309
305
|
|
310
306
|
def rearrange_children
|
311
307
|
@rearrange_children = false
|
312
|
-
self.children.
|
308
|
+
self.children.each { |c| c.save }
|
313
309
|
end
|
314
310
|
|
315
311
|
def position_in_tree
|
316
312
|
errors.add(:parent_id, :invalid) if self.parent_ids.include?(self.id)
|
317
313
|
end
|
318
|
-
end
|
319
|
-
end
|
314
|
+
end
|
315
|
+
end
|
@@ -33,27 +33,15 @@ module Mongoid
|
|
33
33
|
extend ActiveSupport::Concern
|
34
34
|
|
35
35
|
included do
|
36
|
-
reflect_on_association(:children).options[:default_order] = :position.asc
|
37
|
-
|
38
36
|
field :position, :type => Integer
|
39
37
|
|
38
|
+
default_scope asc(:position)
|
39
|
+
|
40
40
|
before_save :assign_default_position
|
41
41
|
before_save :reposition_former_siblings, :if => :sibling_reposition_required?
|
42
42
|
after_destroy :move_lower_siblings_up
|
43
43
|
end
|
44
44
|
|
45
|
-
##
|
46
|
-
# :singleton-method: roots
|
47
|
-
# Returns all root documents ordered by position
|
48
|
-
|
49
|
-
module ClassMethods # :nodoc:
|
50
|
-
|
51
|
-
def roots
|
52
|
-
super.order_by(:position.asc)
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
45
|
##
|
58
46
|
# Returns siblings below the current document.
|
59
47
|
# Siblings with a position greater than this documents's position.
|
@@ -71,13 +59,13 @@ module Mongoid
|
|
71
59
|
##
|
72
60
|
# Returns the lowest sibling (could be self)
|
73
61
|
def last_sibling_in_list
|
74
|
-
siblings_and_self.
|
62
|
+
siblings_and_self.last
|
75
63
|
end
|
76
64
|
|
77
65
|
##
|
78
66
|
# Returns the highest sibling (could be self)
|
79
67
|
def first_sibling_in_list
|
80
|
-
siblings_and_self.
|
68
|
+
siblings_and_self.first
|
81
69
|
end
|
82
70
|
|
83
71
|
##
|
data/spec/mongoid/tree_spec.rb
CHANGED
@@ -7,19 +7,18 @@ describe Mongoid::Tree do
|
|
7
7
|
it "should reference many children as inverse of parent with index" do
|
8
8
|
a = Node.reflect_on_association(:children)
|
9
9
|
a.should be
|
10
|
-
a.
|
11
|
-
a.
|
12
|
-
a.
|
10
|
+
a.macro.should eql(:references_many)
|
11
|
+
a.class_name.should eql('Node')
|
12
|
+
a.foreign_key.should eql('parent_id')
|
13
13
|
Node.index_options.should have_key('parent_id')
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should be referenced in one parent as inverse of children" do
|
17
17
|
a = Node.reflect_on_association(:parent)
|
18
18
|
a.should be
|
19
|
-
a.
|
20
|
-
a.
|
21
|
-
a.
|
22
|
-
a.options.index.should be_true
|
19
|
+
a.macro.should eql(:referenced_in)
|
20
|
+
a.class_name.should eql('Node')
|
21
|
+
a.inverse_of.should eql(:children)
|
23
22
|
end
|
24
23
|
|
25
24
|
it "should store parent_ids as Array with [] as default with index" do
|
@@ -36,6 +35,19 @@ describe Mongoid::Tree do
|
|
36
35
|
expect { root.children << child; root.save! }.to_not raise_error(Mongoid::Errors::DocumentNotFound)
|
37
36
|
child.should be_persisted
|
38
37
|
end
|
38
|
+
|
39
|
+
it "should not be saved when parent is not saved" do
|
40
|
+
root = Node.new(:name => 'root'); child = Node.new(:name => 'child')
|
41
|
+
child.should_not_receive(:save)
|
42
|
+
root.children << child
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should save its unsaved children" do
|
46
|
+
root = Node.new(:name => 'root'); child = Node.new(:name => 'child')
|
47
|
+
root.children << child
|
48
|
+
child.should_receive(:save)
|
49
|
+
root.save
|
50
|
+
end
|
39
51
|
end
|
40
52
|
|
41
53
|
describe 'when saved' do
|
@@ -104,6 +116,12 @@ describe Mongoid::Tree do
|
|
104
116
|
child.should_not be_valid
|
105
117
|
child.errors[:parent_id].should_not be_nil
|
106
118
|
end
|
119
|
+
|
120
|
+
it "should save its children when added" do
|
121
|
+
new_child = Node.new(:name => 'new_child')
|
122
|
+
node(:root).children << new_child
|
123
|
+
new_child.should be_persisted
|
124
|
+
end
|
107
125
|
end
|
108
126
|
|
109
127
|
describe 'when subclassed' do
|
@@ -237,6 +255,18 @@ describe Mongoid::Tree do
|
|
237
255
|
it "should return the root for this document" do
|
238
256
|
node(:subchild).root.should == node(:root)
|
239
257
|
end
|
258
|
+
|
259
|
+
it "should return itself when there is no root" do
|
260
|
+
new_node = Node.new
|
261
|
+
new_node.root.should be(new_node)
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should return it root when it's not saved yet" do
|
265
|
+
root = Node.new(:name => 'root')
|
266
|
+
new_node = Node.new(:name => 'child')
|
267
|
+
new_node.parent = root
|
268
|
+
new_node.root.should be(root)
|
269
|
+
end
|
240
270
|
end
|
241
271
|
|
242
272
|
describe 'ancestors' do
|
data/spec/support/models/node.rb
CHANGED
@@ -11,6 +11,18 @@ end
|
|
11
11
|
class SubclassedNode < Node
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
# Adding ordering on subclasses currently doesn't work as expected.
|
15
|
+
#
|
16
|
+
# class OrderedNode < Node
|
17
|
+
# include Mongoid::Tree::Ordering
|
18
|
+
# end
|
19
|
+
class OrderedNode
|
20
|
+
include Mongoid::Document
|
21
|
+
include Mongoid::Tree
|
22
|
+
include Mongoid::Tree::Traversal
|
15
23
|
include Mongoid::Tree::Ordering
|
16
|
-
|
24
|
+
|
25
|
+
field :name
|
26
|
+
|
27
|
+
attr_accessible :name
|
28
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid-tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 5
|
9
|
-
- 0
|
10
|
-
version: 0.5.0
|
4
|
+
prerelease:
|
5
|
+
version: 0.6.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Benedikt Deicke
|
@@ -15,74 +10,64 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date:
|
13
|
+
date: 2011-03-30 00:00:00 +02:00
|
19
14
|
default_executable:
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
22
17
|
name: mongoid
|
23
|
-
prerelease: false
|
24
18
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
19
|
none: false
|
26
20
|
requirements:
|
27
|
-
- -
|
21
|
+
- - ~>
|
28
22
|
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
segments:
|
31
|
-
- 2
|
32
|
-
- 0
|
33
|
-
- 0
|
34
|
-
- beta
|
35
|
-
- 20
|
36
|
-
version: 2.0.0.beta.20
|
23
|
+
version: 2.0.0
|
37
24
|
type: :runtime
|
25
|
+
prerelease: false
|
38
26
|
version_requirements: *id001
|
39
27
|
- !ruby/object:Gem::Dependency
|
40
|
-
name:
|
41
|
-
prerelease: false
|
28
|
+
name: rake
|
42
29
|
requirement: &id002 !ruby/object:Gem::Requirement
|
43
30
|
none: false
|
44
31
|
requirements:
|
45
|
-
- -
|
32
|
+
- - ">="
|
46
33
|
- !ruby/object:Gem::Version
|
47
|
-
|
48
|
-
segments:
|
49
|
-
- 2
|
50
|
-
- 3
|
51
|
-
version: "2.3"
|
34
|
+
version: 0.8.7
|
52
35
|
type: :development
|
36
|
+
prerelease: false
|
53
37
|
version_requirements: *id002
|
54
38
|
- !ruby/object:Gem::Dependency
|
55
|
-
name:
|
56
|
-
prerelease: false
|
39
|
+
name: rspec
|
57
40
|
requirement: &id003 !ruby/object:Gem::Requirement
|
58
41
|
none: false
|
59
42
|
requirements:
|
60
|
-
- -
|
43
|
+
- - ~>
|
61
44
|
- !ruby/object:Gem::Version
|
62
|
-
|
63
|
-
segments:
|
64
|
-
- 4
|
65
|
-
- 3
|
66
|
-
- 2
|
67
|
-
version: 4.3.2
|
45
|
+
version: "2.3"
|
68
46
|
type: :development
|
47
|
+
prerelease: false
|
69
48
|
version_requirements: *id003
|
70
49
|
- !ruby/object:Gem::Dependency
|
71
|
-
name:
|
72
|
-
prerelease: false
|
50
|
+
name: autotest
|
73
51
|
requirement: &id004 !ruby/object:Gem::Requirement
|
74
52
|
none: false
|
75
53
|
requirements:
|
76
54
|
- - ">="
|
77
55
|
- !ruby/object:Gem::Version
|
78
|
-
|
79
|
-
segments:
|
80
|
-
- 0
|
81
|
-
- 1
|
82
|
-
- 12
|
83
|
-
version: 0.1.12
|
56
|
+
version: 4.3.2
|
84
57
|
type: :development
|
58
|
+
prerelease: false
|
85
59
|
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: hanna-nouveau
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.2.2
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: *id005
|
86
71
|
description: A tree structure for Mongoid documents using the materialized path pattern
|
87
72
|
email:
|
88
73
|
- benedikt@synatic.net
|
@@ -124,7 +109,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
124
109
|
requirements:
|
125
110
|
- - ">="
|
126
111
|
- !ruby/object:Gem::Version
|
127
|
-
hash:
|
112
|
+
hash: 1216210944947938384
|
128
113
|
segments:
|
129
114
|
- 0
|
130
115
|
version: "0"
|
@@ -133,14 +118,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
118
|
requirements:
|
134
119
|
- - ">="
|
135
120
|
- !ruby/object:Gem::Version
|
136
|
-
hash:
|
121
|
+
hash: 1216210944947938384
|
137
122
|
segments:
|
138
123
|
- 0
|
139
124
|
version: "0"
|
140
125
|
requirements: []
|
141
126
|
|
142
127
|
rubyforge_project:
|
143
|
-
rubygems_version: 1.
|
128
|
+
rubygems_version: 1.6.2
|
144
129
|
signing_key:
|
145
130
|
specification_version: 3
|
146
131
|
summary: A tree structure for Mongoid documents
|