arboreal 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/arboreal/active_record_extensions.rb +18 -9
- data/lib/arboreal/version.rb +1 -1
- data/spec/arboreal_spec.rb +35 -35
- data/spec/spec_helper.rb +1 -11
- metadata +47 -46
@@ -1,6 +1,8 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
1
3
|
module Arboreal
|
2
4
|
module ActiveRecordExtensions
|
3
|
-
|
5
|
+
|
4
6
|
# Declares that this ActiveRecord::Base model has a tree-like structure.
|
5
7
|
def acts_arboreal
|
6
8
|
|
@@ -11,22 +13,29 @@ module Arboreal
|
|
11
13
|
include Arboreal::InstanceMethods
|
12
14
|
|
13
15
|
before_validation :populate_ancestry_string
|
14
|
-
|
16
|
+
|
15
17
|
validate do |record|
|
16
18
|
record.send(:validate_parent_not_ancestor)
|
17
19
|
end
|
18
20
|
|
19
21
|
before_save :detect_ancestry_change
|
20
22
|
after_save :apply_ancestry_change_to_descendants
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
|
24
|
+
case ActiveRecord::VERSION::MAJOR
|
25
|
+
|
26
|
+
when 3
|
27
|
+
scope :roots, where(:parent_id => nil)
|
28
|
+
|
29
|
+
when 2
|
30
|
+
named_scope :roots, {
|
31
|
+
:conditions => ["parent_id IS NULL"]
|
32
|
+
}
|
33
|
+
|
34
|
+
end
|
35
|
+
|
26
36
|
end
|
27
|
-
|
37
|
+
|
28
38
|
end
|
29
39
|
end
|
30
40
|
|
31
|
-
require 'active_record'
|
32
41
|
ActiveRecord::Base.extend(Arboreal::ActiveRecordExtensions)
|
data/lib/arboreal/version.rb
CHANGED
data/spec/arboreal_spec.rb
CHANGED
@@ -3,9 +3,9 @@ require 'spec_helper'
|
|
3
3
|
require 'arboreal'
|
4
4
|
|
5
5
|
class Node < ActiveRecord::Base
|
6
|
-
|
6
|
+
|
7
7
|
acts_arboreal
|
8
|
-
|
8
|
+
|
9
9
|
class Migration < ActiveRecord::Migration
|
10
10
|
|
11
11
|
def self.up
|
@@ -22,7 +22,7 @@ class Node < ActiveRecord::Base
|
|
22
22
|
end
|
23
23
|
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
end
|
27
27
|
|
28
28
|
describe "Arboreal hierarchy" do
|
@@ -30,7 +30,7 @@ describe "Arboreal hierarchy" do
|
|
30
30
|
before(:all) do
|
31
31
|
Node::Migration.up
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
after(:all) do
|
35
35
|
Node::Migration.down
|
36
36
|
end
|
@@ -42,9 +42,9 @@ describe "Arboreal hierarchy" do
|
|
42
42
|
@nsw = @australia.children.create!(:name => "New South Wales")
|
43
43
|
@sydney = @nsw.children.create!(:name => "Sydney")
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
describe "node" do
|
47
|
-
|
47
|
+
|
48
48
|
describe "#parent" do
|
49
49
|
it "returns the parent" do
|
50
50
|
@victoria.parent.should == @australia
|
@@ -62,7 +62,7 @@ describe "Arboreal hierarchy" do
|
|
62
62
|
@victoria.siblings.should == [@nsw]
|
63
63
|
end
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
it "cannot be it's own parent" do
|
67
67
|
lambda do
|
68
68
|
@australia.update_attributes!(:parent => @australia)
|
@@ -76,9 +76,9 @@ describe "Arboreal hierarchy" do
|
|
76
76
|
end
|
77
77
|
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
describe "root node" do
|
81
|
-
|
81
|
+
|
82
82
|
describe "#parent" do
|
83
83
|
it "returns nil" do
|
84
84
|
@australia.parent.should == nil
|
@@ -90,7 +90,7 @@ describe "Arboreal hierarchy" do
|
|
90
90
|
@australia.ancestors.should be_empty
|
91
91
|
end
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
describe "#ancestry_string" do
|
95
95
|
it "is a single dash" do
|
96
96
|
@australia.ancestry_string.should == "-"
|
@@ -140,15 +140,15 @@ describe "Arboreal hierarchy" do
|
|
140
140
|
end
|
141
141
|
|
142
142
|
describe "#root" do
|
143
|
-
|
143
|
+
|
144
144
|
it "is itself" do
|
145
145
|
@australia.root.should == @australia
|
146
146
|
end
|
147
|
-
|
147
|
+
|
148
148
|
end
|
149
|
-
|
149
|
+
|
150
150
|
end
|
151
|
-
|
151
|
+
|
152
152
|
describe "leaf node" do
|
153
153
|
|
154
154
|
describe "#ancestry_string" do
|
@@ -164,11 +164,11 @@ describe "Arboreal hierarchy" do
|
|
164
164
|
end
|
165
165
|
|
166
166
|
describe "#ancestors" do
|
167
|
-
|
167
|
+
|
168
168
|
it "returns all ancestors, depth-first" do
|
169
169
|
@melbourne.ancestors.all.should == [@australia, @victoria]
|
170
170
|
end
|
171
|
-
|
171
|
+
|
172
172
|
end
|
173
173
|
|
174
174
|
describe "#children" do
|
@@ -192,14 +192,14 @@ describe "Arboreal hierarchy" do
|
|
192
192
|
end
|
193
193
|
|
194
194
|
end
|
195
|
-
|
195
|
+
|
196
196
|
describe ".roots" do
|
197
|
-
|
197
|
+
|
198
198
|
it "returns root nodes" do
|
199
199
|
@nz = Node.create!(:name => "New Zealand")
|
200
200
|
Node.roots.to_set.should == [@australia, @nz].to_set
|
201
201
|
end
|
202
|
-
|
202
|
+
|
203
203
|
end
|
204
204
|
|
205
205
|
describe "when a node changes parent" do
|
@@ -209,9 +209,9 @@ describe "Arboreal hierarchy" do
|
|
209
209
|
@nz = Node.create!(:name => "New Zealand")
|
210
210
|
@victoria.update_attributes!(:parent => @nz)
|
211
211
|
end
|
212
|
-
|
212
|
+
|
213
213
|
describe "each descendant" do
|
214
|
-
|
214
|
+
|
215
215
|
it "follows" do
|
216
216
|
|
217
217
|
@melbourne.reload
|
@@ -223,30 +223,30 @@ describe "Arboreal hierarchy" do
|
|
223
223
|
@box_hill.ancestors.should_not include(@australia)
|
224
224
|
|
225
225
|
end
|
226
|
-
|
226
|
+
|
227
227
|
end
|
228
|
-
|
228
|
+
|
229
229
|
end
|
230
|
-
|
230
|
+
|
231
231
|
describe "node created using find_or_create_by" do
|
232
|
-
|
232
|
+
|
233
233
|
before do
|
234
234
|
@tasmania = @australia.children.find_or_create_by_name("Tasmania")
|
235
235
|
end
|
236
|
-
|
236
|
+
|
237
237
|
it "still has the right ancestry" do
|
238
238
|
@tasmania.ancestors.should == [@australia]
|
239
239
|
end
|
240
|
-
|
240
|
+
|
241
241
|
end
|
242
|
-
|
242
|
+
|
243
243
|
describe ".rebuild_ancestry" do
|
244
244
|
|
245
245
|
before do
|
246
246
|
Node.connection.update("UPDATE nodes SET ancestry_string = 'corrupt'")
|
247
247
|
Node.rebuild_ancestry
|
248
248
|
end
|
249
|
-
|
249
|
+
|
250
250
|
it "re-populates all ancestry_strings" do
|
251
251
|
Node.count(:conditions => {:ancestry_string => 'corrupt'}).should == 0
|
252
252
|
end
|
@@ -255,21 +255,21 @@ describe "Arboreal hierarchy" do
|
|
255
255
|
@melbourne.reload.ancestors.should == [@australia, @victoria]
|
256
256
|
@sydney.reload.ancestors.should == [@australia, @nsw]
|
257
257
|
end
|
258
|
-
|
258
|
+
|
259
259
|
end
|
260
|
-
|
260
|
+
|
261
261
|
end
|
262
262
|
|
263
263
|
class RedNode < Node; end
|
264
264
|
class GreenNode < Node; end
|
265
265
|
class BlueNode < Node; end
|
266
|
-
|
266
|
+
|
267
267
|
describe "polymorphic hierarchy" do
|
268
268
|
|
269
269
|
before(:all) do
|
270
270
|
Node::Migration.up
|
271
271
|
end
|
272
|
-
|
272
|
+
|
273
273
|
after(:all) do
|
274
274
|
Node::Migration.down
|
275
275
|
end
|
@@ -279,7 +279,7 @@ describe "polymorphic hierarchy" do
|
|
279
279
|
@green = GreenNode.create!(:parent => @red)
|
280
280
|
@blue = BlueNode.create!(:parent => @green)
|
281
281
|
end
|
282
|
-
|
282
|
+
|
283
283
|
describe "#descendants" do
|
284
284
|
it "includes nodes of other types" do
|
285
285
|
@red.descendants.should include(@green, @blue)
|
@@ -297,5 +297,5 @@ describe "polymorphic hierarchy" do
|
|
297
297
|
@blue.ancestors.should include(@red, @green)
|
298
298
|
end
|
299
299
|
end
|
300
|
-
|
300
|
+
|
301
301
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -39,14 +39,4 @@ DB_CONFIGS = {
|
|
39
39
|
test_adapter = (ENV["AR_ADAPTER"] || "sqlite3")
|
40
40
|
test_db_config = DB_CONFIGS[test_adapter].merge(:adapter => test_adapter)
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
config.before(:all) do
|
45
|
-
ActiveRecord::Base.establish_connection(test_db_config)
|
46
|
-
end
|
47
|
-
|
48
|
-
config.after(:all) do
|
49
|
-
ActiveRecord::Base.clear_active_connections!
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
42
|
+
ActiveRecord::Base.establish_connection(test_db_config)
|
metadata
CHANGED
@@ -1,57 +1,61 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: arboreal
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
4
5
|
prerelease:
|
5
|
-
version: 0.1.2
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Mike Williams
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-11-02 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
16
15
|
name: activerecord
|
17
|
-
|
18
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &70308116360600 !ruby/object:Gem::Requirement
|
19
17
|
none: false
|
20
|
-
requirements:
|
21
|
-
- -
|
22
|
-
- !ruby/object:Gem::Version
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
23
21
|
version: 2.3.0
|
24
22
|
type: :runtime
|
25
|
-
version_requirements: *id001
|
26
|
-
- !ruby/object:Gem::Dependency
|
27
|
-
name: activesupport
|
28
23
|
prerelease: false
|
29
|
-
|
24
|
+
version_requirements: *70308116360600
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70308116360000 !ruby/object:Gem::Requirement
|
30
28
|
none: false
|
31
|
-
requirements:
|
32
|
-
- -
|
33
|
-
- !ruby/object:Gem::Version
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
34
32
|
version: 2.3.0
|
35
33
|
type: :runtime
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70308116360000
|
36
|
+
description: ! 'Arboreal is yet another extension to ActiveRecord to support tree-shaped
|
37
|
+
data structures.
|
38
|
+
|
39
|
+
|
40
|
+
Internally, Arboreal maintains a computed "ancestry_string" column, which caches
|
41
|
+
the path from the root of
|
42
|
+
|
41
43
|
a tree to each node, allowing efficient retrieval of both ancestors and descendants.
|
42
|
-
|
43
|
-
|
44
|
+
|
45
|
+
|
46
|
+
Arboreal surfaces relationships within the tree like "children", "ancestors", "descendants",
|
47
|
+
and "siblings"
|
48
|
+
|
44
49
|
as scopes, so that additional filtering/pagination can be performed.
|
45
50
|
|
51
|
+
'
|
46
52
|
email: mdub@dogbiscuit.org
|
47
53
|
executables: []
|
48
|
-
|
49
54
|
extensions: []
|
50
|
-
|
51
|
-
extra_rdoc_files:
|
55
|
+
extra_rdoc_files:
|
52
56
|
- README.rdoc
|
53
57
|
- LICENSE
|
54
|
-
files:
|
58
|
+
files:
|
55
59
|
- lib/arboreal/active_record_extensions.rb
|
56
60
|
- lib/arboreal/class_methods.rb
|
57
61
|
- lib/arboreal/instance_methods.rb
|
@@ -64,33 +68,30 @@ files:
|
|
64
68
|
- LICENSE
|
65
69
|
homepage: http://github.com/mdub/arboreal
|
66
70
|
licenses: []
|
67
|
-
|
68
71
|
post_install_message:
|
69
|
-
rdoc_options:
|
72
|
+
rdoc_options:
|
70
73
|
- --title
|
71
74
|
- Arboreal
|
72
75
|
- --main
|
73
76
|
- README.rdoc
|
74
|
-
require_paths:
|
77
|
+
require_paths:
|
75
78
|
- lib
|
76
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
80
|
none: false
|
78
|
-
requirements:
|
79
|
-
- -
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
81
84
|
version: 1.8.7
|
82
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
86
|
none: false
|
84
|
-
requirements:
|
85
|
-
- -
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
version:
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
88
91
|
requirements: []
|
89
|
-
|
90
92
|
rubyforge_project:
|
91
|
-
rubygems_version: 1.
|
93
|
+
rubygems_version: 1.8.10
|
92
94
|
signing_key:
|
93
95
|
specification_version: 3
|
94
96
|
summary: Efficient tree structures for ActiveRecord
|
95
97
|
test_files: []
|
96
|
-
|