closure_tree 3.8.2 → 3.9.0
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.
- checksums.yaml +7 -0
- data/README.md +13 -9
- data/lib/closure_tree/model.rb +6 -4
- data/lib/closure_tree/version.rb +1 -1
- data/spec/label_spec.rb +13 -0
- data/spec/support/models.rb +3 -1
- data/spec/tag_spec.rb +12 -5
- data/spec/user_spec.rb +8 -0
- metadata +94 -187
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA512:
|
3
|
+
metadata.gz: 4eba6a7034297fd15958c27428782adc3a1b36abc1f0723039583418c33eb08377e3b5cfa744aae985cdd2b1b2cbd91138486e2a0591c0ff2f9c1fcb9893361d
|
4
|
+
data.tar.gz: 8f8f339d462f846bfb59c260756d94ad8328a9bea1f4bf9ad2d9d00317f05efd7f8d099eee2b1c1a8e661ccef827fcbb46cb9f5a22f9e0f816bd5b8118fea9c4
|
5
|
+
SHA1:
|
6
|
+
metadata.gz: f04e325774ddd75fddfaeb47753095903350aed8
|
7
|
+
data.tar.gz: 66ed5c26efe5cac30d3bb3e3d1d128ae67d4e184
|
data/README.md
CHANGED
@@ -15,8 +15,8 @@ closure_tree has some great features:
|
|
15
15
|
* Fetch your whole ancestor lineage in 1 SELECT.
|
16
16
|
* Grab all your descendants in 1 SELECT.
|
17
17
|
* Get all your siblings in 1 SELECT.
|
18
|
-
* Fetch all [
|
19
|
-
* [Find a node by path](#find_or_create_by_path) in 1 SELECT.
|
18
|
+
* Fetch all [descendants as a nested hash](#nested-hashes) in 1 SELECT.
|
19
|
+
* [Find a node by ancestry path](#find_or_create_by_path) in 1 SELECT.
|
20
20
|
* __Best-in-class mutation performance__:
|
21
21
|
* 2 SQL INSERTs on node creation
|
22
22
|
* 3 SQL INSERT/UPDATEs on node reparenting
|
@@ -26,7 +26,6 @@ closure_tree has some great features:
|
|
26
26
|
* ```find_or_create_by_path``` for [building out hierarchies quickly and conveniently](#find_or_create_by_path)
|
27
27
|
* Support for [deterministic ordering](#deterministic-ordering) of children
|
28
28
|
* Support for [preordered](http://en.wikipedia.org/wiki/Tree_traversal#Pre-order) traversal of descendants
|
29
|
-
* Support for single-select depth-limited [nested hashes](#nested-hashes)
|
30
29
|
* Excellent [test coverage](#testing) in a variety of environments
|
31
30
|
|
32
31
|
See [Bill Karwin](http://karwin.blogspot.com/)'s excellent
|
@@ -115,12 +114,6 @@ Child nodes are created by appending to the children collection:
|
|
115
114
|
parent = grandparent.children.create(:name => 'Parent')
|
116
115
|
```
|
117
116
|
|
118
|
-
Or by giving the parent to the constructor:
|
119
|
-
|
120
|
-
```ruby
|
121
|
-
child1 = Tag.create(:name => 'First Child', :parent => parent)
|
122
|
-
```
|
123
|
-
|
124
117
|
Or by appending to the children collection:
|
125
118
|
|
126
119
|
```ruby
|
@@ -250,6 +243,7 @@ When you include ```acts_as_tree``` in your model, you can provide a hash to ove
|
|
250
243
|
* ```tag.depth``` returns the depth, or "generation", for this node in the tree. A root node will have a value of 0.
|
251
244
|
* ```tag.parent``` returns the node's immediate parent. Root nodes will return nil.
|
252
245
|
* ```tag.children``` is a ```has_many``` of immediate children (just those nodes whose parent is the current node).
|
246
|
+
* ```tag.child_ids``` is an array of the IDs of the children.
|
253
247
|
* ```tag.ancestors``` is a ordered scope of [ parent, grandparent, great grandparent, … ]. Note that the size of this array will always equal ```tag.depth```.
|
254
248
|
* ```tag.ancestor_ids``` is an array of the IDs of the ancestors.
|
255
249
|
* ```tag.self_and_ancestors``` returns a scope containing self, parent, grandparent, great grandparent, etc.
|
@@ -426,6 +420,16 @@ Parallelism is not tested with Rails 3.0.x nor 3.1.x due to this
|
|
426
420
|
|
427
421
|
## Change log
|
428
422
|
|
423
|
+
### 3.9.0
|
424
|
+
|
425
|
+
* Added ```.child_ids```.
|
426
|
+
* Removed ```dependent => destroy``` on the descendant_hierarchy and ancestor_hierarchy collections
|
427
|
+
(they were a mistake).
|
428
|
+
* Clarified documentation for creation and child associations.
|
429
|
+
Because ```Tag.create!(:parent => ...)``` requires a ```.reload```, I removed it as an example.
|
430
|
+
|
431
|
+
All three of these improvements were suggested by Andrew Bromwich. Thanks!
|
432
|
+
|
429
433
|
### 3.8.2
|
430
434
|
|
431
435
|
* find_by_path uses 1 SELECT now. BOOM.
|
data/lib/closure_tree/model.rb
CHANGED
@@ -27,8 +27,7 @@ module ClosureTree
|
|
27
27
|
has_many :ancestor_hierarchies,
|
28
28
|
:class_name => hierarchy_class_name,
|
29
29
|
:foreign_key => "descendant_id",
|
30
|
-
:order => "#{quoted_hierarchy_table_name}.generations asc"
|
31
|
-
:dependent => :destroy
|
30
|
+
:order => "#{quoted_hierarchy_table_name}.generations asc"
|
32
31
|
|
33
32
|
has_many :self_and_ancestors,
|
34
33
|
:through => :ancestor_hierarchies,
|
@@ -38,8 +37,7 @@ module ClosureTree
|
|
38
37
|
has_many :descendant_hierarchies,
|
39
38
|
:class_name => hierarchy_class_name,
|
40
39
|
:foreign_key => "ancestor_id",
|
41
|
-
:order => "#{quoted_hierarchy_table_name}.generations asc"
|
42
|
-
:dependent => :destroy
|
40
|
+
:order => "#{quoted_hierarchy_table_name}.generations asc"
|
43
41
|
# TODO: FIXME: this collection currently ignores sort_order
|
44
42
|
# (because the quoted_table_named would need to be joined in to get to the order column)
|
45
43
|
|
@@ -94,6 +92,10 @@ module ClosureTree
|
|
94
92
|
self_and_ancestors.reverse.collect { |n| n.send to_s_column.to_sym }
|
95
93
|
end
|
96
94
|
|
95
|
+
def child_ids
|
96
|
+
ids_from(children)
|
97
|
+
end
|
98
|
+
|
97
99
|
def descendants
|
98
100
|
without_self(self_and_descendants)
|
99
101
|
end
|
data/lib/closure_tree/version.rb
CHANGED
data/spec/label_spec.rb
CHANGED
@@ -43,6 +43,19 @@ def create_preorder_tree
|
|
43
43
|
end
|
44
44
|
|
45
45
|
describe Label do
|
46
|
+
|
47
|
+
context "destruction" do
|
48
|
+
it "properly destroys descendents" do
|
49
|
+
c = Label.find_or_create_by_path %w(a b c)
|
50
|
+
b = c.parent
|
51
|
+
a = c.root
|
52
|
+
a.destroy
|
53
|
+
Label.exists?(a).should be_false
|
54
|
+
Label.exists?(b).should be_false
|
55
|
+
Label.exists?(c).should be_false
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
46
59
|
context "Base Label class" do
|
47
60
|
it "should find or create by path" do
|
48
61
|
# class method:
|
data/spec/support/models.rb
CHANGED
@@ -44,7 +44,9 @@ end
|
|
44
44
|
|
45
45
|
class Label < ActiveRecord::Base
|
46
46
|
attr_accessible :name # < - make sure order doesn't matter
|
47
|
-
acts_as_tree :order => "sort_order",
|
47
|
+
acts_as_tree :order => "sort_order",
|
48
|
+
:parent_column_name => "mother_id",
|
49
|
+
:dependent => :destroy
|
48
50
|
|
49
51
|
def to_s
|
50
52
|
"#{self.class}: #{name}"
|
data/spec/tag_spec.rb
CHANGED
@@ -33,11 +33,19 @@ shared_examples_for "Tag (1)" do
|
|
33
33
|
end
|
34
34
|
|
35
35
|
context "2 tag db" do
|
36
|
+
before :each do
|
37
|
+
@root = Tag.create!(:name => "root")
|
38
|
+
@leaf = @root.add_child(Tag.create!(:name => "leaf"))
|
39
|
+
end
|
36
40
|
it "should return a simple root and leaf" do
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
+
Tag.roots.should == [@root]
|
42
|
+
Tag.leaves.should == [@leaf]
|
43
|
+
end
|
44
|
+
it "should return child_ids for root" do
|
45
|
+
@root.child_ids.should == [@leaf.id]
|
46
|
+
end
|
47
|
+
it "should return an empty array for leaves" do
|
48
|
+
@leaf.child_ids.should be_empty
|
41
49
|
end
|
42
50
|
end
|
43
51
|
|
@@ -220,7 +228,6 @@ shared_examples_for "Tag (1)" do
|
|
220
228
|
a.find_or_create_by_path(%w{b c}).ancestry_path.should == %w{a b c}
|
221
229
|
end
|
222
230
|
end
|
223
|
-
|
224
231
|
end
|
225
232
|
|
226
233
|
shared_examples_for "Tag (2)" do
|
data/spec/user_spec.rb
CHANGED
@@ -125,4 +125,12 @@ describe "empty db" do
|
|
125
125
|
a.siblings.should be_empty
|
126
126
|
b1.siblings.should =~ [b2, b3]
|
127
127
|
end
|
128
|
+
|
129
|
+
it "properly nullifies descendents" do
|
130
|
+
c = User.find_or_create_by_path %w(a b c)
|
131
|
+
b = c.parent
|
132
|
+
c.root.destroy
|
133
|
+
b.reload.should be_root
|
134
|
+
b.child_ids.should == [c.id]
|
135
|
+
end
|
128
136
|
end
|
metadata
CHANGED
@@ -1,215 +1,129 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: closure_tree
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
5
|
-
prerelease:
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 3.9.0
|
6
5
|
platform: ruby
|
7
|
-
authors:
|
6
|
+
authors:
|
8
7
|
- Matthew McEachen
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
|
12
|
+
date: 2013-03-06 00:00:00 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: 3.0.0
|
22
16
|
type: :runtime
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
- - ! '>='
|
28
|
-
- !ruby/object:Gem::Version
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
29
21
|
version: 3.0.0
|
30
|
-
|
22
|
+
version_requirements: *id001
|
23
|
+
prerelease: false
|
24
|
+
- !ruby/object:Gem::Dependency
|
31
25
|
name: with_advisory_lock
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: 0.0.6
|
38
26
|
type: :runtime
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
- - ! '>='
|
44
|
-
- !ruby/object:Gem::Version
|
27
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
45
31
|
version: 0.0.6
|
46
|
-
|
32
|
+
version_requirements: *id002
|
33
|
+
prerelease: false
|
34
|
+
- !ruby/object:Gem::Dependency
|
47
35
|
name: rake
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
|
-
requirements:
|
51
|
-
- - ! '>='
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0'
|
54
36
|
type: :development
|
37
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- &id004
|
40
|
+
- ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
version_requirements: *id003
|
55
44
|
prerelease: false
|
56
|
-
|
57
|
-
none: false
|
58
|
-
requirements:
|
59
|
-
- - ! '>='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
- !ruby/object:Gem::Dependency
|
45
|
+
- !ruby/object:Gem::Dependency
|
63
46
|
name: yard
|
64
|
-
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
|
-
requirements:
|
67
|
-
- - ! '>='
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '0'
|
70
47
|
type: :development
|
48
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- *id004
|
51
|
+
version_requirements: *id005
|
71
52
|
prerelease: false
|
72
|
-
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - ! '>='
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: '0'
|
78
|
-
- !ruby/object:Gem::Dependency
|
53
|
+
- !ruby/object:Gem::Dependency
|
79
54
|
name: rspec
|
80
|
-
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
|
-
requirements:
|
83
|
-
- - ! '>='
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
version: '0'
|
86
55
|
type: :development
|
56
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- *id004
|
59
|
+
version_requirements: *id006
|
87
60
|
prerelease: false
|
88
|
-
|
89
|
-
none: false
|
90
|
-
requirements:
|
91
|
-
- - ! '>='
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
version: '0'
|
94
|
-
- !ruby/object:Gem::Dependency
|
61
|
+
- !ruby/object:Gem::Dependency
|
95
62
|
name: rails
|
96
|
-
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
|
-
requirements:
|
99
|
-
- - ! '>='
|
100
|
-
- !ruby/object:Gem::Version
|
101
|
-
version: '0'
|
102
63
|
type: :development
|
64
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- *id004
|
67
|
+
version_requirements: *id007
|
103
68
|
prerelease: false
|
104
|
-
|
105
|
-
none: false
|
106
|
-
requirements:
|
107
|
-
- - ! '>='
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
version: '0'
|
110
|
-
- !ruby/object:Gem::Dependency
|
69
|
+
- !ruby/object:Gem::Dependency
|
111
70
|
name: rspec-rails
|
112
|
-
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
|
-
requirements:
|
115
|
-
- - ! '>='
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '0'
|
118
71
|
type: :development
|
72
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- *id004
|
75
|
+
version_requirements: *id008
|
119
76
|
prerelease: false
|
120
|
-
|
121
|
-
none: false
|
122
|
-
requirements:
|
123
|
-
- - ! '>='
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: '0'
|
126
|
-
- !ruby/object:Gem::Dependency
|
77
|
+
- !ruby/object:Gem::Dependency
|
127
78
|
name: mysql2
|
128
|
-
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
|
-
requirements:
|
131
|
-
- - ! '>='
|
132
|
-
- !ruby/object:Gem::Version
|
133
|
-
version: '0'
|
134
79
|
type: :development
|
80
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- *id004
|
83
|
+
version_requirements: *id009
|
135
84
|
prerelease: false
|
136
|
-
|
137
|
-
none: false
|
138
|
-
requirements:
|
139
|
-
- - ! '>='
|
140
|
-
- !ruby/object:Gem::Version
|
141
|
-
version: '0'
|
142
|
-
- !ruby/object:Gem::Dependency
|
85
|
+
- !ruby/object:Gem::Dependency
|
143
86
|
name: pg
|
144
|
-
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
|
-
requirements:
|
147
|
-
- - ! '>='
|
148
|
-
- !ruby/object:Gem::Version
|
149
|
-
version: '0'
|
150
87
|
type: :development
|
88
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- *id004
|
91
|
+
version_requirements: *id010
|
151
92
|
prerelease: false
|
152
|
-
|
153
|
-
none: false
|
154
|
-
requirements:
|
155
|
-
- - ! '>='
|
156
|
-
- !ruby/object:Gem::Version
|
157
|
-
version: '0'
|
158
|
-
- !ruby/object:Gem::Dependency
|
93
|
+
- !ruby/object:Gem::Dependency
|
159
94
|
name: sqlite3
|
160
|
-
requirement: !ruby/object:Gem::Requirement
|
161
|
-
none: false
|
162
|
-
requirements:
|
163
|
-
- - ! '>='
|
164
|
-
- !ruby/object:Gem::Version
|
165
|
-
version: '0'
|
166
95
|
type: :development
|
96
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- *id004
|
99
|
+
version_requirements: *id011
|
167
100
|
prerelease: false
|
168
|
-
|
169
|
-
none: false
|
170
|
-
requirements:
|
171
|
-
- - ! '>='
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '0'
|
174
|
-
- !ruby/object:Gem::Dependency
|
101
|
+
- !ruby/object:Gem::Dependency
|
175
102
|
name: uuidtools
|
176
|
-
requirement: !ruby/object:Gem::Requirement
|
177
|
-
none: false
|
178
|
-
requirements:
|
179
|
-
- - ! '>='
|
180
|
-
- !ruby/object:Gem::Version
|
181
|
-
version: '0'
|
182
103
|
type: :development
|
104
|
+
requirement: &id012 !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- *id004
|
107
|
+
version_requirements: *id012
|
183
108
|
prerelease: false
|
184
|
-
|
185
|
-
none: false
|
186
|
-
requirements:
|
187
|
-
- - ! '>='
|
188
|
-
- !ruby/object:Gem::Version
|
189
|
-
version: '0'
|
190
|
-
- !ruby/object:Gem::Dependency
|
109
|
+
- !ruby/object:Gem::Dependency
|
191
110
|
name: strong_parameters
|
192
|
-
requirement: !ruby/object:Gem::Requirement
|
193
|
-
none: false
|
194
|
-
requirements:
|
195
|
-
- - ! '>='
|
196
|
-
- !ruby/object:Gem::Version
|
197
|
-
version: '0'
|
198
111
|
type: :development
|
112
|
+
requirement: &id013 !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- *id004
|
115
|
+
version_requirements: *id013
|
199
116
|
prerelease: false
|
200
|
-
version_requirements: !ruby/object:Gem::Requirement
|
201
|
-
none: false
|
202
|
-
requirements:
|
203
|
-
- - ! '>='
|
204
|
-
- !ruby/object:Gem::Version
|
205
|
-
version: '0'
|
206
117
|
description: Easily and efficiently make your ActiveRecord model support hierarchies
|
207
|
-
email:
|
118
|
+
email:
|
208
119
|
- matthew-github@mceachen.org
|
209
120
|
executables: []
|
121
|
+
|
210
122
|
extensions: []
|
123
|
+
|
211
124
|
extra_rdoc_files: []
|
212
|
-
|
125
|
+
|
126
|
+
files:
|
213
127
|
- lib/closure_tree/acts_as_tree.rb
|
214
128
|
- lib/closure_tree/columns.rb
|
215
129
|
- lib/closure_tree/deterministic_ordering.rb
|
@@ -236,35 +150,28 @@ files:
|
|
236
150
|
- spec/user_spec.rb
|
237
151
|
homepage: http://matthew.mceachen.us/closure_tree
|
238
152
|
licenses: []
|
153
|
+
|
154
|
+
metadata: {}
|
155
|
+
|
239
156
|
post_install_message:
|
240
157
|
rdoc_options: []
|
241
|
-
|
158
|
+
|
159
|
+
require_paths:
|
242
160
|
- lib
|
243
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
segments:
|
250
|
-
- 0
|
251
|
-
hash: 625197628069455012
|
252
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
253
|
-
none: false
|
254
|
-
requirements:
|
255
|
-
- - ! '>='
|
256
|
-
- !ruby/object:Gem::Version
|
257
|
-
version: '0'
|
258
|
-
segments:
|
259
|
-
- 0
|
260
|
-
hash: 625197628069455012
|
161
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- *id004
|
164
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- *id004
|
261
167
|
requirements: []
|
168
|
+
|
262
169
|
rubyforge_project:
|
263
|
-
rubygems_version:
|
170
|
+
rubygems_version: 2.0.0
|
264
171
|
signing_key:
|
265
|
-
specification_version:
|
172
|
+
specification_version: 4
|
266
173
|
summary: Easily and efficiently make your ActiveRecord model support hierarchies
|
267
|
-
test_files:
|
174
|
+
test_files:
|
268
175
|
- spec/cuisine_type_spec.rb
|
269
176
|
- spec/db/database.yml
|
270
177
|
- spec/db/schema.rb
|