acts_as_happy_tree 1.0.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.
- data/README +28 -0
- data/Rakefile +73 -0
- data/VERSION +1 -0
- data/acts_as_happy_tree.gemspec +41 -0
- data/init.rb +1 -0
- data/rails/init.rb +1 -0
- data/test/acts_as_happy_tree_test.rb +515 -0
- metadata +56 -0
data/README
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
acts_as_happy_tree
|
2
|
+
============
|
3
|
+
|
4
|
+
Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children
|
5
|
+
association. This requires that you have a foreign key column, which by default is called +parent_id+.
|
6
|
+
|
7
|
+
class Category < ActiveRecord::Base
|
8
|
+
acts_as_happy_tree :order => "name"
|
9
|
+
end
|
10
|
+
|
11
|
+
Example:
|
12
|
+
root
|
13
|
+
\_ child1
|
14
|
+
\_ subchild1
|
15
|
+
\_ subchild2
|
16
|
+
|
17
|
+
root = Category.create("name" => "root")
|
18
|
+
child1 = root.children.create("name" => "child1")
|
19
|
+
subchild1 = child1.children.create("name" => "subchild1")
|
20
|
+
|
21
|
+
root.parent # => nil
|
22
|
+
child1.parent # => root
|
23
|
+
root.children # => [child1]
|
24
|
+
root.children.first.children.first # => subchild1
|
25
|
+
|
26
|
+
Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
|
27
|
+
|
28
|
+
Includes patch from http://dev.rubyonrails.org/ticket/1924
|
data/Rakefile
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "acts_as_happy_tree"
|
8
|
+
gem.summary = %Q{acts_as_happy_tree as a gem}
|
9
|
+
gem.description = %Q{acts_as_happy_tree as a gem}
|
10
|
+
gem.email = "jim@saturnflyer.com"
|
11
|
+
gem.homepage = "http://github.com/saturnflyer/acts_as_happy_tree"
|
12
|
+
gem.authors = ["David Heinemeier Hansson",'and others']
|
13
|
+
# gem.add_development_dependency "thoughtbot-shoulda"
|
14
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
|
+
end
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake/testtask'
|
21
|
+
Rake::TestTask.new(:test) do |test|
|
22
|
+
test.libs << 'lib' << 'test'
|
23
|
+
test.test_files = FileList['test/*_test.rb']
|
24
|
+
test.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
task 'test:ar30' do
|
28
|
+
ENV['AR_VERSION'] = '3.0.10'
|
29
|
+
Rake::Task["test"].execute
|
30
|
+
end
|
31
|
+
|
32
|
+
task 'test:ar31' do
|
33
|
+
ENV['AR_VERSION'] = '3.1.2'
|
34
|
+
Rake::Task["test"].execute
|
35
|
+
end
|
36
|
+
|
37
|
+
task 'test:ar32' do
|
38
|
+
ENV['AR_VERSION'] = '3.2.1'
|
39
|
+
Rake::Task["test"].execute
|
40
|
+
end
|
41
|
+
|
42
|
+
task 'test:all' => ['test:ar32', 'test:ar31', 'test:ar30']
|
43
|
+
|
44
|
+
begin
|
45
|
+
require 'rcov/rcovtask'
|
46
|
+
Rcov::RcovTask.new do |test|
|
47
|
+
test.libs << 'test'
|
48
|
+
test.pattern = 'test/**/*_test.rb'
|
49
|
+
test.verbose = true
|
50
|
+
end
|
51
|
+
rescue LoadError
|
52
|
+
task :rcov do
|
53
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
task :test => :check_dependencies
|
58
|
+
|
59
|
+
task :default => :test
|
60
|
+
|
61
|
+
require 'rake/rdoctask'
|
62
|
+
Rake::RDocTask.new do |rdoc|
|
63
|
+
if File.exist?('VERSION')
|
64
|
+
version = File.read('VERSION')
|
65
|
+
else
|
66
|
+
version = ""
|
67
|
+
end
|
68
|
+
|
69
|
+
rdoc.rdoc_dir = 'rdoc'
|
70
|
+
rdoc.title = "acts_as_happy_tree #{version}"
|
71
|
+
rdoc.rdoc_files.include('README*')
|
72
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
73
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{acts_as_happy_tree}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["David Heinemeier Hansson", "Jim Gay", "thoughtafter", "and others"]
|
12
|
+
s.date = %q{2012-08-18}
|
13
|
+
s.description = %q{Forked from acts_as_tree this should be a drop in replacement but with more features and tuned for performance and efficiency.}
|
14
|
+
s.email = %q{thoughtafter@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"README",
|
20
|
+
"Rakefile",
|
21
|
+
"VERSION",
|
22
|
+
"acts_as_happy_tree.gemspec",
|
23
|
+
"init.rb",
|
24
|
+
"rails/init.rb",
|
25
|
+
"test/acts_as_happy_tree_test.rb"
|
26
|
+
]
|
27
|
+
s.homepage = %q{http://github.com/thoughtafter/acts_as_happy_tree}
|
28
|
+
s.require_paths = ["lib"]
|
29
|
+
s.rubygems_version = %q{1.0.0}
|
30
|
+
s.summary = %q{acts_as_happy_tree gem}
|
31
|
+
|
32
|
+
if s.respond_to? :specification_version then
|
33
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
34
|
+
s.specification_version = 3
|
35
|
+
|
36
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
37
|
+
else
|
38
|
+
end
|
39
|
+
else
|
40
|
+
end
|
41
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/rails/init"
|
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'acts_as_happy_tree'
|
@@ -0,0 +1,515 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
puts "Requested AR VER: #{ENV['AR_VERSION']}"
|
4
|
+
gem 'activerecord', ENV['AR_VERSION']
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'active_record'
|
8
|
+
|
9
|
+
puts "Activated AR VER: #{ActiveRecord::VERSION::STRING}"
|
10
|
+
|
11
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
12
|
+
require File.dirname(__FILE__) + '/../init'
|
13
|
+
|
14
|
+
class Test::Unit::TestCase
|
15
|
+
def assert_queries(num = 1)
|
16
|
+
$query_count = 0
|
17
|
+
yield
|
18
|
+
ensure
|
19
|
+
assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed."
|
20
|
+
end
|
21
|
+
|
22
|
+
def assert_no_queries(&block)
|
23
|
+
assert_queries(0, &block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
28
|
+
|
29
|
+
# AR keeps printing annoying schema statements
|
30
|
+
$stdout = StringIO.new
|
31
|
+
|
32
|
+
def setup_db
|
33
|
+
ActiveRecord::Base.logger
|
34
|
+
ActiveRecord::Schema.define(:version => 1) do
|
35
|
+
create_table :mixins do |t|
|
36
|
+
t.column :type, :string
|
37
|
+
t.column :parent_id, :integer
|
38
|
+
t.column :children_count, :integer, :default => 0
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def teardown_db
|
44
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
45
|
+
ActiveRecord::Base.connection.drop_table(table)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Mixin < ActiveRecord::Base
|
50
|
+
end
|
51
|
+
|
52
|
+
class TreeMixin < Mixin
|
53
|
+
acts_as_happy_tree :foreign_key => "parent_id", :order => "id"
|
54
|
+
end
|
55
|
+
|
56
|
+
class TreeMixinWithCounterCache < Mixin
|
57
|
+
acts_as_happy_tree :foreign_key => "parent_id", :order => "id", :counter_cache => :children_count
|
58
|
+
end
|
59
|
+
|
60
|
+
class TreeMixinWithoutOrder < Mixin
|
61
|
+
acts_as_happy_tree :foreign_key => "parent_id"
|
62
|
+
end
|
63
|
+
|
64
|
+
class RecursivelyCascadedTreeMixin < Mixin
|
65
|
+
acts_as_happy_tree :foreign_key => "parent_id"
|
66
|
+
has_one :first_child, :class_name => 'RecursivelyCascadedTreeMixin', :foreign_key => :parent_id
|
67
|
+
end
|
68
|
+
|
69
|
+
class TreeMixinNullify < Mixin
|
70
|
+
acts_as_happy_tree :foreign_key => "parent_id", :order => "id", :dependent => :nullify
|
71
|
+
end
|
72
|
+
|
73
|
+
class TreeTest < Test::Unit::TestCase
|
74
|
+
|
75
|
+
def setup
|
76
|
+
setup_db
|
77
|
+
@root1 = TreeMixin.create!
|
78
|
+
@root_child1 = TreeMixin.create! :parent_id => @root1.id
|
79
|
+
@child1_child = TreeMixin.create! :parent_id => @root_child1.id
|
80
|
+
@root_child2 = TreeMixin.create! :parent_id => @root1.id
|
81
|
+
@root2 = TreeMixin.create!
|
82
|
+
@root3 = TreeMixin.create!
|
83
|
+
@root_child1.reload # need to reload to recognize children
|
84
|
+
end
|
85
|
+
|
86
|
+
def teardown
|
87
|
+
teardown_db
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_children
|
91
|
+
assert_equal @root1.reload.children, [@root_child1, @root_child2]
|
92
|
+
assert_equal @root_child1.reload.children, [@child1_child]
|
93
|
+
assert_equal @child1_child.reload.children, []
|
94
|
+
assert_equal @root_child2.reload.children, []
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_parent
|
98
|
+
assert_equal @root_child1.parent, @root1
|
99
|
+
assert_equal @root_child1.parent, @root_child2.parent
|
100
|
+
assert_nil @root1.parent
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_nullify
|
104
|
+
root4 = TreeMixinNullify.create!
|
105
|
+
root4_child = TreeMixinNullify.create! :parent_id => root4.id
|
106
|
+
assert_equal 2, TreeMixinNullify.count
|
107
|
+
assert_equal root4.id, root4_child.parent_id
|
108
|
+
root4.destroy
|
109
|
+
assert_equal 1, TreeMixinNullify.count
|
110
|
+
assert_nil root4_child.reload.parent_id
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_delete
|
114
|
+
assert_equal 6, TreeMixin.count
|
115
|
+
@root1.destroy
|
116
|
+
assert_equal 2, TreeMixin.count
|
117
|
+
@root2.destroy
|
118
|
+
@root3.destroy
|
119
|
+
assert_equal 0, TreeMixin.count
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_insert
|
123
|
+
@extra = @root1.children.create
|
124
|
+
|
125
|
+
assert @extra
|
126
|
+
|
127
|
+
assert_equal @extra.parent, @root1
|
128
|
+
|
129
|
+
assert_equal 3, @root1.reload.children.count
|
130
|
+
assert @root1.children.include?(@extra)
|
131
|
+
assert @root1.children.include?(@root_child1)
|
132
|
+
assert @root1.children.include?(@root_child2)
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_ancestors
|
136
|
+
assert_equal [], @root1.ancestors
|
137
|
+
assert_equal [@root1], @root_child1.ancestors
|
138
|
+
assert_equal [@root_child1, @root1], @child1_child.ancestors
|
139
|
+
assert_equal [@root1], @root_child2.ancestors
|
140
|
+
assert_equal [], @root2.ancestors
|
141
|
+
assert_equal [], @root3.ancestors
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_ancestor_ids
|
145
|
+
assert_equal [], @root1.ancestor_ids
|
146
|
+
assert_equal [@root1.id], @root_child1.ancestor_ids
|
147
|
+
assert_equal [@root_child1.id, @root1.id], @child1_child.ancestor_ids
|
148
|
+
assert_equal [@root1.id], @root_child2.ancestor_ids
|
149
|
+
assert_equal [], @root2.ancestor_ids
|
150
|
+
assert_equal [], @root3.ancestor_ids
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_ancestors_count
|
154
|
+
assert_equal 0, @root1.ancestors_count
|
155
|
+
assert_equal 1, @root_child1.ancestors_count
|
156
|
+
assert_equal 2, @child1_child.ancestors_count
|
157
|
+
assert_equal 1, @root_child2.ancestors_count
|
158
|
+
assert_equal 0, @root2.ancestors_count
|
159
|
+
assert_equal 0, @root3.ancestors_count
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_class_root
|
163
|
+
assert_equal @root1, TreeMixin.root
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_root
|
167
|
+
assert_equal @root1, @root1.root
|
168
|
+
assert_equal @root1, @root_child1.root
|
169
|
+
assert_equal @root1, @child1_child.root
|
170
|
+
assert_equal @root1, @root_child2.root
|
171
|
+
assert_equal @root2, @root2.root
|
172
|
+
assert_equal @root3, @root3.root
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_root_id
|
176
|
+
assert_equal @root1.id, @root1.root_id
|
177
|
+
assert_equal @root1.id, @root_child1.root_id
|
178
|
+
assert_equal @root1.id, @child1_child.root_id
|
179
|
+
assert_equal @root1.id, @root_child2.root_id
|
180
|
+
assert_equal @root2.id, @root2.root_id
|
181
|
+
assert_equal @root3.id, @root3.root_id
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_roots
|
185
|
+
assert_equal [@root1, @root2, @root3], TreeMixin.roots
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_siblings
|
189
|
+
assert_equal [@root2, @root3], @root1.siblings
|
190
|
+
assert_equal [@root_child2], @root_child1.siblings
|
191
|
+
assert_equal [], @child1_child.siblings
|
192
|
+
assert_equal [@root_child1], @root_child2.siblings
|
193
|
+
assert_equal [@root1, @root3], @root2.siblings
|
194
|
+
assert_equal [@root1, @root2], @root3.siblings
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_self_and_siblings
|
198
|
+
assert_equal [@root1, @root2, @root3], @root1.self_and_siblings
|
199
|
+
assert_equal [@root_child1, @root_child2], @root_child1.self_and_siblings
|
200
|
+
assert_equal [@child1_child], @child1_child.self_and_siblings
|
201
|
+
assert_equal [@root_child1, @root_child2], @root_child2.self_and_siblings
|
202
|
+
assert_equal [@root1, @root2, @root3], @root2.self_and_siblings
|
203
|
+
assert_equal [@root1, @root2, @root3], @root3.self_and_siblings
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_root?
|
207
|
+
assert @root1.root?
|
208
|
+
assert @root2.root?
|
209
|
+
assert @root3.root?
|
210
|
+
assert !@root_child1.root?
|
211
|
+
assert !@root_child2.root?
|
212
|
+
assert !@child1_child.root?
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_child?
|
216
|
+
assert !@root1.child?
|
217
|
+
assert !@root2.child?
|
218
|
+
assert !@root3.child?
|
219
|
+
assert @root_child1.child?
|
220
|
+
assert @root_child2.child?
|
221
|
+
assert @child1_child.child?
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_parent?
|
225
|
+
assert @root1.parent?
|
226
|
+
assert !@root2.parent?
|
227
|
+
assert !@root3.parent?
|
228
|
+
assert @root_child1.parent?
|
229
|
+
assert !@root_child2.parent?
|
230
|
+
assert !@child1_child.parent?
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_leaf?
|
234
|
+
assert !@root1.leaf?
|
235
|
+
assert @root2.leaf?
|
236
|
+
assert @root3.leaf?
|
237
|
+
assert !@root_child1.leaf?
|
238
|
+
assert @root_child2.leaf?
|
239
|
+
assert @child1_child.leaf?
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_ancestor_of?
|
243
|
+
assert_equal false, @root1.ancestor_of?(nil)
|
244
|
+
assert_equal false, @root_child1.ancestor_of?(nil)
|
245
|
+
assert_equal false, @root_child2.ancestor_of?(nil)
|
246
|
+
assert_equal false, @child1_child.ancestor_of?(nil)
|
247
|
+
|
248
|
+
assert_equal false, @root1.ancestor_of?(0)
|
249
|
+
assert_equal false, @root_child1.ancestor_of?("foo")
|
250
|
+
assert_equal false, @root_child2.ancestor_of?(:bar)
|
251
|
+
assert_equal false, @child1_child.ancestor_of?(TreeMixin.new)
|
252
|
+
|
253
|
+
assert_equal true, @root1.ancestor_of?(@root_child1)
|
254
|
+
assert_equal true, @root1.ancestor_of?(@root_child2)
|
255
|
+
assert_equal true, @root1.ancestor_of?(@child1_child)
|
256
|
+
|
257
|
+
assert_equal false, @root_child1.ancestor_of?(@root1)
|
258
|
+
assert_equal false, @root_child2.ancestor_of?(@root1)
|
259
|
+
assert_equal false, @child1_child.ancestor_of?(@root1)
|
260
|
+
|
261
|
+
assert_equal false, @root1.ancestor_of?(@root1)
|
262
|
+
assert_equal false, @root1.ancestor_of?(@root2)
|
263
|
+
assert_equal false, @root1.ancestor_of?(@root3)
|
264
|
+
|
265
|
+
assert_equal true, @root_child1.ancestor_of?(@child1_child)
|
266
|
+
assert_equal false, @child1_child.ancestor_of?(@root_child1)
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_descendant_of?
|
270
|
+
assert_equal false, @root1.descendant_of?(nil)
|
271
|
+
assert_equal false, @root_child1.descendant_of?(nil)
|
272
|
+
assert_equal false, @root_child2.descendant_of?(nil)
|
273
|
+
assert_equal false, @child1_child.descendant_of?(nil)
|
274
|
+
|
275
|
+
assert_equal false, @root1.descendant_of?(0)
|
276
|
+
assert_equal false, @root_child1.descendant_of?("foo")
|
277
|
+
assert_equal false, @root_child2.descendant_of?(:bar)
|
278
|
+
assert_equal false, @child1_child.descendant_of?(TreeMixin.new)
|
279
|
+
|
280
|
+
assert_equal false, @root1.descendant_of?(@root_child1)
|
281
|
+
assert_equal false, @root1.descendant_of?(@root_child2)
|
282
|
+
assert_equal false, @root1.descendant_of?(@child1_child)
|
283
|
+
|
284
|
+
assert_equal true, @root_child1.descendant_of?(@root1)
|
285
|
+
assert_equal true, @root_child2.descendant_of?(@root1)
|
286
|
+
assert_equal true, @child1_child.descendant_of?(@root1)
|
287
|
+
|
288
|
+
assert_equal false, @root1.descendant_of?(@root1)
|
289
|
+
assert_equal false, @root1.descendant_of?(@root2)
|
290
|
+
assert_equal false, @root1.descendant_of?(@root3)
|
291
|
+
|
292
|
+
assert_equal false, @root_child1.descendant_of?(@child1_child)
|
293
|
+
assert_equal true, @child1_child.descendant_of?(@root_child1)
|
294
|
+
end
|
295
|
+
|
296
|
+
def test_child_ids
|
297
|
+
assert_equal [@root_child1.id, @root_child2.id], @root1.child_ids
|
298
|
+
assert_equal [@child1_child.id], @root_child1.child_ids
|
299
|
+
end
|
300
|
+
|
301
|
+
def do_test_descendants_dfs(method, *args)
|
302
|
+
assert_equal [@root_child1, @child1_child, @root_child2], @root1.send(method, *args)
|
303
|
+
assert_equal [@child1_child], @root_child1.send(method, *args)
|
304
|
+
end
|
305
|
+
|
306
|
+
def test_descendants
|
307
|
+
do_test_descendants_dfs('descendants')
|
308
|
+
end
|
309
|
+
|
310
|
+
def test_descendants_classic
|
311
|
+
do_test_descendants_dfs('descendants_classic')
|
312
|
+
do_test_descendants_dfs('descendants', :traversal=>:classic)
|
313
|
+
end
|
314
|
+
|
315
|
+
def test_descendants_dfs
|
316
|
+
do_test_descendants_dfs('descendants_dfs')
|
317
|
+
do_test_descendants_dfs('descendants', :traversal=>:dfs)
|
318
|
+
end
|
319
|
+
|
320
|
+
def test_descendants_dfs_rec
|
321
|
+
do_test_descendants_dfs('descendants_dfs_rec')
|
322
|
+
do_test_descendants_dfs('descendants', :traversal=>:dfs_rec)
|
323
|
+
end
|
324
|
+
|
325
|
+
def do_test_descendants_bfs(method, *params)
|
326
|
+
assert_equal [@root_child1, @root_child2, @child1_child], @root1.send(method, *params)
|
327
|
+
assert_equal [@child1_child], @root_child1.send(method, *params)
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_descendants_bfs
|
331
|
+
do_test_descendants_bfs('descendants_bfs')
|
332
|
+
do_test_descendants_bfs('descendants', :traversal=>:bfs)
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_descendants_bfs_rec
|
336
|
+
do_test_descendants_bfs('descendants_bfs_rec')
|
337
|
+
do_test_descendants_bfs('descendants', :traversal=>:bfs_rec)
|
338
|
+
end
|
339
|
+
|
340
|
+
def do_test_self_and_descendants_dfs(method)
|
341
|
+
assert_equal [@root1, @root_child1, @child1_child, @root_child2], @root1.send(method)
|
342
|
+
assert_equal [@root_child1, @child1_child], @root_child1.send(method)
|
343
|
+
end
|
344
|
+
|
345
|
+
def test_self_and_descendants
|
346
|
+
do_test_self_and_descendants_dfs('self_and_descendants')
|
347
|
+
end
|
348
|
+
|
349
|
+
def test_self_and_descendants_dfs
|
350
|
+
do_test_self_and_descendants_dfs('self_and_descendants_dfs')
|
351
|
+
end
|
352
|
+
|
353
|
+
def test_self_and_descendants_bfs
|
354
|
+
assert_equal [@root1, @root_child1, @root_child2, @child1_child], @root1.self_and_descendants_bfs
|
355
|
+
assert_equal [@root_child1, @child1_child], @root_child1.self_and_descendants_bfs
|
356
|
+
end
|
357
|
+
|
358
|
+
def do_test_descendant_ids_dfs(method)
|
359
|
+
assert_equal [@root_child1, @child1_child, @root_child2].map(&:id),
|
360
|
+
@root1.send(method)
|
361
|
+
assert_equal [@child1_child].map(&:id), @root_child1.send(method)
|
362
|
+
end
|
363
|
+
|
364
|
+
def test_descendant_ids
|
365
|
+
do_test_descendant_ids_dfs('descendant_ids')
|
366
|
+
end
|
367
|
+
|
368
|
+
def test_descendant_ids_dfs
|
369
|
+
do_test_descendant_ids_dfs('descendant_ids_dfs')
|
370
|
+
end
|
371
|
+
|
372
|
+
def test_descendant_ids_dfs_rec
|
373
|
+
do_test_descendant_ids_dfs('descendant_ids_dfs_rec')
|
374
|
+
end
|
375
|
+
|
376
|
+
def do_test_descendant_ids_bfs(method)
|
377
|
+
assert_equal [@root_child1, @root_child2, @child1_child].map(&:id),
|
378
|
+
@root1.send(method)
|
379
|
+
assert_equal [@child1_child].map(&:id), @root_child1.send(method)
|
380
|
+
end
|
381
|
+
|
382
|
+
def test_descendant_ids_bfs
|
383
|
+
do_test_descendant_ids_bfs('descendant_ids_bfs')
|
384
|
+
end
|
385
|
+
|
386
|
+
def test_descendant_ids_bfs_rec
|
387
|
+
do_test_descendant_ids_bfs('descendant_ids_bfs_rec')
|
388
|
+
end
|
389
|
+
|
390
|
+
def do_test_descendants_count(counter)
|
391
|
+
assert_equal 3, @root1.send(counter)
|
392
|
+
assert_equal 0, @root2.send(counter)
|
393
|
+
assert_equal 0, @root3.send(counter)
|
394
|
+
assert_equal 1, @root_child1.send(counter)
|
395
|
+
assert_equal 0, @root_child2.send(counter)
|
396
|
+
assert_equal 0, @child1_child.send(counter)
|
397
|
+
end
|
398
|
+
|
399
|
+
def test_descendants_count
|
400
|
+
do_test_descendants_count(:descendants_count)
|
401
|
+
end
|
402
|
+
|
403
|
+
def test_descendants_count_dfs
|
404
|
+
do_test_descendants_count(:descendants_count_dfs)
|
405
|
+
end
|
406
|
+
|
407
|
+
def test_descendants_count_bfs
|
408
|
+
do_test_descendants_count(:descendants_count_bfs)
|
409
|
+
end
|
410
|
+
|
411
|
+
def test_descendants_count_dfs_rec
|
412
|
+
do_test_descendants_count(:descendants_count_dfs_rec)
|
413
|
+
end
|
414
|
+
|
415
|
+
def test_descendants_count_bfs_rec
|
416
|
+
do_test_descendants_count(:descendants_count_bfs_rec)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
class TreeTestWithCounterCache < Test::Unit::TestCase
|
421
|
+
def setup
|
422
|
+
teardown_db
|
423
|
+
setup_db
|
424
|
+
@root = TreeMixinWithCounterCache.create!
|
425
|
+
@child1 = TreeMixinWithCounterCache.create! :parent_id => @root.id
|
426
|
+
@child1_child1 = TreeMixinWithCounterCache.create! :parent_id => @child1.id
|
427
|
+
@child2 = TreeMixinWithCounterCache.create! :parent_id => @root.id
|
428
|
+
end
|
429
|
+
|
430
|
+
def teardown
|
431
|
+
teardown_db
|
432
|
+
end
|
433
|
+
|
434
|
+
def test_counter_cache
|
435
|
+
assert_equal 2, @root.reload.children_count
|
436
|
+
assert_equal 1, @child1.reload.children_count
|
437
|
+
end
|
438
|
+
|
439
|
+
def test_update_parents_counter_cache
|
440
|
+
@child1_child1.update_attributes(:parent_id => @root.id)
|
441
|
+
assert_equal 3, @root.reload.children_count
|
442
|
+
assert_equal 0, @child1.reload.children_count
|
443
|
+
end
|
444
|
+
|
445
|
+
end
|
446
|
+
|
447
|
+
|
448
|
+
class TreeTestWithEagerLoading < Test::Unit::TestCase
|
449
|
+
|
450
|
+
def setup
|
451
|
+
teardown_db
|
452
|
+
setup_db
|
453
|
+
@root1 = TreeMixin.create!
|
454
|
+
@root_child1 = TreeMixin.create! :parent_id => @root1.id
|
455
|
+
@child1_child = TreeMixin.create! :parent_id => @root_child1.id
|
456
|
+
@root_child2 = TreeMixin.create! :parent_id => @root1.id
|
457
|
+
@root2 = TreeMixin.create!
|
458
|
+
@root3 = TreeMixin.create!
|
459
|
+
|
460
|
+
@rc1 = RecursivelyCascadedTreeMixin.create!
|
461
|
+
@rc2 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc1.id
|
462
|
+
@rc3 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc2.id
|
463
|
+
@rc4 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc3.id
|
464
|
+
end
|
465
|
+
|
466
|
+
def teardown
|
467
|
+
teardown_db
|
468
|
+
end
|
469
|
+
|
470
|
+
def test_eager_association_loading
|
471
|
+
roots = TreeMixin.find(:all, :include => :children, :conditions => "mixins.parent_id IS NULL", :order => "mixins.id")
|
472
|
+
assert_equal [@root1, @root2, @root3], roots
|
473
|
+
assert_no_queries do
|
474
|
+
assert_equal 2, roots[0].children.count
|
475
|
+
assert_equal 0, roots[1].children.count
|
476
|
+
assert_equal 0, roots[2].children.count
|
477
|
+
end
|
478
|
+
end
|
479
|
+
|
480
|
+
def test_eager_association_loading_with_recursive_cascading_three_levels_has_many
|
481
|
+
root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :children => { :children => :children } }, :order => 'mixins.id')
|
482
|
+
assert_equal @rc4, assert_no_queries { root_node.children.first.children.first.children.first }
|
483
|
+
end
|
484
|
+
|
485
|
+
def test_eager_association_loading_with_recursive_cascading_three_levels_has_one
|
486
|
+
root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :first_child => { :first_child => :first_child } }, :order => 'mixins.id')
|
487
|
+
assert_equal @rc4, assert_no_queries { root_node.first_child.first_child.first_child }
|
488
|
+
end
|
489
|
+
|
490
|
+
def test_eager_association_loading_with_recursive_cascading_three_levels_belongs_to
|
491
|
+
leaf_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :parent => { :parent => :parent } }, :order => 'mixins.id DESC')
|
492
|
+
assert_equal @rc1, assert_no_queries { leaf_node.parent.parent.parent }
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
class TreeTestWithoutOrder < Test::Unit::TestCase
|
497
|
+
|
498
|
+
def setup
|
499
|
+
setup_db
|
500
|
+
@root1 = TreeMixinWithoutOrder.create!
|
501
|
+
@root2 = TreeMixinWithoutOrder.create!
|
502
|
+
end
|
503
|
+
|
504
|
+
def teardown
|
505
|
+
teardown_db
|
506
|
+
end
|
507
|
+
|
508
|
+
def test_root
|
509
|
+
assert [@root1, @root2].include?(TreeMixinWithoutOrder.root)
|
510
|
+
end
|
511
|
+
|
512
|
+
def test_roots
|
513
|
+
assert_equal [], [@root1, @root2] - TreeMixinWithoutOrder.roots
|
514
|
+
end
|
515
|
+
end
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: acts_as_happy_tree
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- David Heinemeier Hansson
|
9
|
+
- Jim Gay
|
10
|
+
- thoughtafter
|
11
|
+
- and others
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
date: 2012-08-18 00:00:00.000000000 Z
|
16
|
+
dependencies: []
|
17
|
+
description: Forked from acts_as_tree this should be a drop in replacement but with
|
18
|
+
more features and tuned for performance and efficiency.
|
19
|
+
email: thoughtafter@gmail.com
|
20
|
+
executables: []
|
21
|
+
extensions: []
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- Rakefile
|
27
|
+
- VERSION
|
28
|
+
- acts_as_happy_tree.gemspec
|
29
|
+
- init.rb
|
30
|
+
- rails/init.rb
|
31
|
+
- test/acts_as_happy_tree_test.rb
|
32
|
+
homepage: http://github.com/thoughtafter/acts_as_happy_tree
|
33
|
+
licenses: []
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirements: []
|
51
|
+
rubyforge_project:
|
52
|
+
rubygems_version: 1.8.11
|
53
|
+
signing_key:
|
54
|
+
specification_version: 3
|
55
|
+
summary: acts_as_happy_tree gem
|
56
|
+
test_files: []
|