acts_as_tree 0.1.1 → 0.2.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/.gitignore +5 -6
- data/.travis.yml +9 -0
- data/Gemfile +7 -0
- data/README.md +28 -0
- data/Rakefile +11 -44
- data/acts_as_tree.gemspec +20 -40
- data/init.rb +2 -0
- data/lib/acts_as_tree/active_record/acts/tree.rb +142 -0
- data/lib/acts_as_tree/version.rb +7 -0
- data/lib/acts_as_tree.rb +3 -96
- data/test/acts_as_tree_test.rb +97 -28
- metadata +87 -41
- data/.document +0 -2
- data/README.rdoc +0 -31
- data/VERSION +0 -1
data/.gitignore
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
*.
|
2
|
-
.
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
pkg
|
1
|
+
*.gem
|
2
|
+
.bundle
|
3
|
+
pkg/*
|
4
|
+
.rvmrc
|
5
|
+
Gemfile.lock
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
[](http://travis-ci.org/amerine/acts_as_tree)
|
2
|
+
|
3
|
+
# ActsAsTree
|
4
|
+
|
5
|
+
## Notes
|
6
|
+
Specify this `acts_as` extension if you want to model a tree structure by providing a parent association and a children association. This requires that you have a foreign key column, which by default is called `parent_id`.
|
7
|
+
|
8
|
+
class Category < ActiveRecord::Base
|
9
|
+
acts_as_tree :order => "name"
|
10
|
+
end
|
11
|
+
|
12
|
+
Example:
|
13
|
+
root
|
14
|
+
\_ child1
|
15
|
+
\_ subchild1
|
16
|
+
\_ subchild2
|
17
|
+
|
18
|
+
root = Category.create("name" => "root")
|
19
|
+
child1 = root.children.create("name" => "child1")
|
20
|
+
subchild1 = child1.children.create("name" => "subchild1")
|
21
|
+
|
22
|
+
root.parent # => nil
|
23
|
+
child1.parent # => root
|
24
|
+
root.children # => [child1]
|
25
|
+
root.children.first.children.first # => subchild1
|
26
|
+
|
27
|
+
|
28
|
+
Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
|
data/Rakefile
CHANGED
@@ -1,54 +1,21 @@
|
|
1
|
-
require '
|
2
|
-
require 'rake'
|
1
|
+
require 'bundler/gem_tasks'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
gem.summary = %Q{Gem version of acts_as_tree Rails plugin.}
|
9
|
-
gem.description = %Q{Specify this acts_as extension if you want to model a tree structure by providing a parent association and a children association.}
|
10
|
-
gem.email = "erik.dahlstrand@gmail.com"
|
11
|
-
gem.homepage = "http://github.com/erdah/acts_as_tree"
|
12
|
-
gem.authors = ["Erik Dahlstrand", "Rails Core"]
|
13
|
-
end
|
14
|
-
rescue LoadError
|
15
|
-
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
3
|
+
desc "Run the tests."
|
4
|
+
task :test do
|
5
|
+
$: << "lib" << "test"
|
6
|
+
Dir["test/*_test.rb"].each { |f| require f[5..-4] }
|
16
7
|
end
|
17
8
|
|
18
|
-
require 'rake/testtask'
|
19
|
-
Rake::TestTask.new(:test) do |test|
|
20
|
-
test.libs << 'lib' << 'test'
|
21
|
-
test.pattern = 'test/**/*_test.rb'
|
22
|
-
test.verbose = true
|
23
|
-
end
|
24
|
-
|
25
|
-
begin
|
26
|
-
require 'rcov/rcovtask'
|
27
|
-
Rcov::RcovTask.new do |test|
|
28
|
-
test.libs << 'test'
|
29
|
-
test.pattern = 'test/**/*_test.rb'
|
30
|
-
test.verbose = true
|
31
|
-
end
|
32
|
-
rescue LoadError
|
33
|
-
task :rcov do
|
34
|
-
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
task :test => :check_dependencies
|
39
|
-
|
40
9
|
task :default => :test
|
41
10
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
version = ""
|
48
|
-
end
|
11
|
+
# Run the rdoc task to generate rdocs for this gem
|
12
|
+
require 'rdoc/task'
|
13
|
+
RDoc::Task.new do |rdoc|
|
14
|
+
require "acts_as_tree/version"
|
15
|
+
version = ActiveRecord::Acts::Tree::VERSION
|
49
16
|
|
50
17
|
rdoc.rdoc_dir = 'rdoc'
|
51
|
-
rdoc.title = "acts_as_tree #{version}"
|
18
|
+
rdoc.title = "acts_as_tree-rails3 #{version}"
|
52
19
|
rdoc.rdoc_files.include('README*')
|
53
20
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
21
|
end
|
data/acts_as_tree.gemspec
CHANGED
@@ -1,47 +1,27 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "acts_as_tree/version"
|
5
4
|
|
6
5
|
Gem::Specification.new do |s|
|
7
|
-
s.name
|
8
|
-
s.version
|
9
|
-
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.
|
6
|
+
s.name = "acts_as_tree"
|
7
|
+
s.version = ActiveRecord::Acts::Tree::VERSION
|
8
|
+
s.authors = ["Erik Dahlstrand", "Rails Core", "Mark Turner", "Swanand Pagnis"]
|
9
|
+
s.email = ["erik.dahlstrand@gmail.com", "mark@amerine.net", "swanand.pagnis@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/amerine/acts_as_tree"
|
11
|
+
s.summary = %q{Provides a simple tree behaviour to active_record mdoels.}
|
13
12
|
s.description = %q{Specify this acts_as extension if you want to model a tree structure by providing a parent association and a children association.}
|
14
|
-
s.email = %q{erik.dahlstrand@gmail.com}
|
15
|
-
s.extra_rdoc_files = [
|
16
|
-
"README.rdoc"
|
17
|
-
]
|
18
|
-
s.files = [
|
19
|
-
".document",
|
20
|
-
".gitignore",
|
21
|
-
"README.rdoc",
|
22
|
-
"Rakefile",
|
23
|
-
"VERSION",
|
24
|
-
"acts_as_tree.gemspec",
|
25
|
-
"lib/acts_as_tree.rb",
|
26
|
-
"test/acts_as_tree_test.rb"
|
27
|
-
]
|
28
|
-
s.homepage = %q{http://github.com/erdah/acts_as_tree}
|
29
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
30
|
-
s.require_paths = ["lib"]
|
31
|
-
s.rubygems_version = %q{1.3.5}
|
32
|
-
s.summary = %q{Gem version of acts_as_tree Rails plugin.}
|
33
|
-
s.test_files = [
|
34
|
-
"test/acts_as_tree_test.rb"
|
35
|
-
]
|
36
13
|
|
37
|
-
|
38
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
39
|
-
s.specification_version = 3
|
14
|
+
s.rubyforge_project = "acts_as_tree"
|
40
15
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
47
21
|
|
22
|
+
# Dependencies (installed via 'bundle install')...
|
23
|
+
s.add_development_dependency("bundler", [">= 1.0.0"])
|
24
|
+
s.add_development_dependency("activerecord", [">= 1.15.4.7794"])
|
25
|
+
s.add_development_dependency("rdoc")
|
26
|
+
s.add_development_dependency("sqlite3")
|
27
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Acts #:nodoc:
|
3
|
+
module Tree #:nodoc:
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
# Specify this +acts_as+ extension if you want to model a tree structure
|
9
|
+
# by providing a parent association and a children association. This
|
10
|
+
# requires that you have a foreign key column, which by default is called
|
11
|
+
# +parent_id+.
|
12
|
+
#
|
13
|
+
# class Category < ActiveRecord::Base
|
14
|
+
# acts_as_tree :order => "name"
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Example:
|
18
|
+
# root
|
19
|
+
# \_ child1
|
20
|
+
# \_ subchild1
|
21
|
+
# \_ subchild2
|
22
|
+
#
|
23
|
+
# root = Category.create("name" => "root")
|
24
|
+
# child1 = root.children.create("name" => "child1")
|
25
|
+
# subchild1 = child1.children.create("name" => "subchild1")
|
26
|
+
#
|
27
|
+
# root.parent # => nil
|
28
|
+
# child1.parent # => root
|
29
|
+
# root.children # => [child1]
|
30
|
+
# root.children.first.children.first # => subchild1
|
31
|
+
#
|
32
|
+
# In addition to the parent and children associations, the following
|
33
|
+
# instance methods are added to the class after calling
|
34
|
+
# <tt>acts_as_tree</tt>:
|
35
|
+
# * <tt>siblings</tt> - Returns all the children of the parent, excluding
|
36
|
+
# the current node (<tt>[subchild2]</tt> when called
|
37
|
+
# on <tt>subchild1</tt>)
|
38
|
+
# * <tt>self_and_siblings</tt> - Returns all the children of the parent,
|
39
|
+
# including the current node (<tt>[subchild1, subchild2]</tt>
|
40
|
+
# when called on <tt>subchild1</tt>)
|
41
|
+
# * <tt>ancestors</tt> - Returns all the ancestors of the current node
|
42
|
+
# (<tt>[child1, root]</tt> when called on <tt>subchild2</tt>)
|
43
|
+
# * <tt>root</tt> - Returns the root of the current node (<tt>root</tt>
|
44
|
+
# when called on <tt>subchild2</tt>)
|
45
|
+
module ClassMethods
|
46
|
+
# Configuration options are:
|
47
|
+
#
|
48
|
+
# * <tt>foreign_key</tt> - specifies the column name to use for tracking
|
49
|
+
# of the tree (default: +parent_id+)
|
50
|
+
# * <tt>order</tt> - makes it possible to sort the children according to
|
51
|
+
# this SQL snippet.
|
52
|
+
# * <tt>counter_cache</tt> - keeps a count in a +children_count+ column
|
53
|
+
# if set to +true+ (default: +false+).
|
54
|
+
def acts_as_tree(options = {})
|
55
|
+
configuration = {
|
56
|
+
:foreign_key => "parent_id",
|
57
|
+
:order => nil,
|
58
|
+
:counter_cache => nil,
|
59
|
+
:dependent => :destroy
|
60
|
+
}
|
61
|
+
|
62
|
+
configuration.update(options) if options.is_a?(Hash)
|
63
|
+
|
64
|
+
belongs_to :parent, :class_name => name,
|
65
|
+
:foreign_key => configuration[:foreign_key],
|
66
|
+
:counter_cache => configuration[:counter_cache],
|
67
|
+
:inverse_of => :children
|
68
|
+
|
69
|
+
has_many :children, :class_name => name,
|
70
|
+
:foreign_key => configuration[:foreign_key],
|
71
|
+
:order => configuration[:order],
|
72
|
+
:dependent => configuration[:dependent],
|
73
|
+
:inverse_of => :parent
|
74
|
+
|
75
|
+
class_eval <<-EOV
|
76
|
+
include ActiveRecord::Acts::Tree::InstanceMethods
|
77
|
+
|
78
|
+
after_update :update_parents_counter_cache
|
79
|
+
|
80
|
+
def self.roots
|
81
|
+
find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL",
|
82
|
+
:order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.root
|
86
|
+
find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL",
|
87
|
+
:order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
|
88
|
+
end
|
89
|
+
EOV
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
module InstanceMethods
|
94
|
+
# Returns list of ancestors, starting from parent until root.
|
95
|
+
#
|
96
|
+
# subchild1.ancestors # => [child1, root]
|
97
|
+
def ancestors
|
98
|
+
node, nodes = self, []
|
99
|
+
nodes << node = node.parent while node.parent
|
100
|
+
nodes
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns the root node of the tree.
|
104
|
+
def root
|
105
|
+
node = self
|
106
|
+
node = node.parent while node.parent
|
107
|
+
node
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns all siblings of the current node.
|
111
|
+
#
|
112
|
+
# subchild1.siblings # => [subchild2]
|
113
|
+
def siblings
|
114
|
+
self_and_siblings - [self]
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns all siblings and a reference to the current node.
|
118
|
+
#
|
119
|
+
# subchild1.self_and_siblings # => [subchild1, subchild2]
|
120
|
+
def self_and_siblings
|
121
|
+
parent ? parent.children : self.class.roots
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns children (without subchildren) and current node itself.
|
125
|
+
#
|
126
|
+
# root.self_and_children # => [root, child1]
|
127
|
+
def self_and_children
|
128
|
+
[self] + self.children
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def update_parents_counter_cache
|
134
|
+
if self.respond_to?(:children_count) && parent_id_changed?
|
135
|
+
self.class.decrement_counter(:children_count, parent_id_was)
|
136
|
+
self.class.increment_counter(:children_count, parent_id)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
data/lib/acts_as_tree.rb
CHANGED
@@ -1,96 +1,3 @@
|
|
1
|
-
require 'active_record/
|
2
|
-
|
3
|
-
|
4
|
-
def self.included(base)
|
5
|
-
base.extend(ClassMethods)
|
6
|
-
end
|
7
|
-
|
8
|
-
# Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children
|
9
|
-
# association. This requires that you have a foreign key column, which by default is called +parent_id+.
|
10
|
-
#
|
11
|
-
# class Category < ActiveRecord::Base
|
12
|
-
# acts_as_tree :order => "name"
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
# Example:
|
16
|
-
# root
|
17
|
-
# \_ child1
|
18
|
-
# \_ subchild1
|
19
|
-
# \_ subchild2
|
20
|
-
#
|
21
|
-
# root = Category.create("name" => "root")
|
22
|
-
# child1 = root.children.create("name" => "child1")
|
23
|
-
# subchild1 = child1.children.create("name" => "subchild1")
|
24
|
-
#
|
25
|
-
# root.parent # => nil
|
26
|
-
# child1.parent # => root
|
27
|
-
# root.children # => [child1]
|
28
|
-
# root.children.first.children.first # => subchild1
|
29
|
-
#
|
30
|
-
# In addition to the parent and children associations, the following instance methods are added to the class
|
31
|
-
# after calling <tt>acts_as_tree</tt>:
|
32
|
-
# * <tt>siblings</tt> - Returns all the children of the parent, excluding the current node (<tt>[subchild2]</tt> when called on <tt>subchild1</tt>)
|
33
|
-
# * <tt>self_and_siblings</tt> - Returns all the children of the parent, including the current node (<tt>[subchild1, subchild2]</tt> when called on <tt>subchild1</tt>)
|
34
|
-
# * <tt>ancestors</tt> - Returns all the ancestors of the current node (<tt>[child1, root]</tt> when called on <tt>subchild2</tt>)
|
35
|
-
# * <tt>root</tt> - Returns the root of the current node (<tt>root</tt> when called on <tt>subchild2</tt>)
|
36
|
-
module ClassMethods
|
37
|
-
# Configuration options are:
|
38
|
-
#
|
39
|
-
# * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
|
40
|
-
# * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
|
41
|
-
# * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
|
42
|
-
def acts_as_tree(options = {})
|
43
|
-
configuration = { :foreign_key => "parent_id", :order => nil, :counter_cache => nil }
|
44
|
-
configuration.update(options) if options.is_a?(Hash)
|
45
|
-
|
46
|
-
belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
|
47
|
-
has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => :destroy
|
48
|
-
|
49
|
-
class_eval <<-EOV
|
50
|
-
include ActsAsTree::InstanceMethods
|
51
|
-
|
52
|
-
def self.roots
|
53
|
-
find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.root
|
57
|
-
find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
|
58
|
-
end
|
59
|
-
EOV
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
module InstanceMethods
|
64
|
-
# Returns list of ancestors, starting from parent until root.
|
65
|
-
#
|
66
|
-
# subchild1.ancestors # => [child1, root]
|
67
|
-
def ancestors
|
68
|
-
node, nodes = self, []
|
69
|
-
nodes << node = node.parent while node.parent
|
70
|
-
nodes
|
71
|
-
end
|
72
|
-
|
73
|
-
# Returns the root node of the tree.
|
74
|
-
def root
|
75
|
-
node = self
|
76
|
-
node = node.parent while node.parent
|
77
|
-
node
|
78
|
-
end
|
79
|
-
|
80
|
-
# Returns all siblings of the current node.
|
81
|
-
#
|
82
|
-
# subchild1.siblings # => [subchild2]
|
83
|
-
def siblings
|
84
|
-
self_and_siblings - [self]
|
85
|
-
end
|
86
|
-
|
87
|
-
# Returns all siblings and a reference to the current node.
|
88
|
-
#
|
89
|
-
# subchild1.self_and_siblings # => [subchild1, subchild2]
|
90
|
-
def self_and_siblings
|
91
|
-
parent ? parent.children : self.class.roots
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
ActiveRecord::Base.class_eval { include ActsAsTree }
|
1
|
+
require 'acts_as_tree/active_record/acts/tree'
|
2
|
+
require 'acts_as_tree/version'
|
3
|
+
ActiveRecord::Base.class_eval { include ActiveRecord::Acts::Tree }
|
data/test/acts_as_tree_test.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
require 'test/unit'
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
2
|
require 'active_record'
|
5
|
-
|
6
|
-
require "#{File.dirname(__FILE__)}/../lib/acts_as_tree"
|
3
|
+
require "#{File.dirname(__FILE__)}/../init"
|
7
4
|
|
8
5
|
class Test::Unit::TestCase
|
9
6
|
def assert_queries(num = 1)
|
@@ -29,6 +26,7 @@ def setup_db
|
|
29
26
|
create_table :mixins do |t|
|
30
27
|
t.column :type, :string
|
31
28
|
t.column :parent_id, :integer
|
29
|
+
t.column :children_count, :integer, :default => 0
|
32
30
|
end
|
33
31
|
end
|
34
32
|
end
|
@@ -42,7 +40,7 @@ end
|
|
42
40
|
class Mixin < ActiveRecord::Base
|
43
41
|
end
|
44
42
|
|
45
|
-
class TreeMixin < Mixin
|
43
|
+
class TreeMixin < Mixin
|
46
44
|
acts_as_tree :foreign_key => "parent_id", :order => "id"
|
47
45
|
end
|
48
46
|
|
@@ -50,18 +48,27 @@ class TreeMixinWithoutOrder < Mixin
|
|
50
48
|
acts_as_tree :foreign_key => "parent_id"
|
51
49
|
end
|
52
50
|
|
51
|
+
class TreeMixinNullify < Mixin
|
52
|
+
acts_as_tree :foreign_key => "parent_id", :order => "id", :dependent => :nullify
|
53
|
+
end
|
54
|
+
|
55
|
+
class TreeMixinWithCounterCache < Mixin
|
56
|
+
acts_as_tree :foreign_key => "parent_id", :order => "id", :counter_cache => :children_count
|
57
|
+
end
|
58
|
+
|
53
59
|
class RecursivelyCascadedTreeMixin < Mixin
|
54
60
|
acts_as_tree :foreign_key => "parent_id"
|
55
61
|
has_one :first_child, :class_name => 'RecursivelyCascadedTreeMixin', :foreign_key => :parent_id
|
56
62
|
end
|
57
63
|
|
58
64
|
class TreeTest < Test::Unit::TestCase
|
59
|
-
|
65
|
+
|
60
66
|
def setup
|
61
67
|
setup_db
|
62
68
|
@root1 = TreeMixin.create!
|
63
69
|
@root_child1 = TreeMixin.create! :parent_id => @root1.id
|
64
70
|
@child1_child = TreeMixin.create! :parent_id => @root_child1.id
|
71
|
+
@child1_child_child = TreeMixin.create! :parent_id => @child1_child.id
|
65
72
|
@root_child2 = TreeMixin.create! :parent_id => @root1.id
|
66
73
|
@root2 = TreeMixin.create!
|
67
74
|
@root3 = TreeMixin.create!
|
@@ -74,7 +81,8 @@ class TreeTest < Test::Unit::TestCase
|
|
74
81
|
def test_children
|
75
82
|
assert_equal @root1.children, [@root_child1, @root_child2]
|
76
83
|
assert_equal @root_child1.children, [@child1_child]
|
77
|
-
assert_equal @child1_child.children, []
|
84
|
+
assert_equal @child1_child.children, [@child1_child_child]
|
85
|
+
assert_equal @child1_child_child.children, []
|
78
86
|
assert_equal @root_child2.children, []
|
79
87
|
end
|
80
88
|
|
@@ -85,7 +93,7 @@ class TreeTest < Test::Unit::TestCase
|
|
85
93
|
end
|
86
94
|
|
87
95
|
def test_delete
|
88
|
-
assert_equal
|
96
|
+
assert_equal 7, TreeMixin.count
|
89
97
|
@root1.destroy
|
90
98
|
assert_equal 2, TreeMixin.count
|
91
99
|
@root2.destroy
|
@@ -100,7 +108,7 @@ class TreeTest < Test::Unit::TestCase
|
|
100
108
|
|
101
109
|
assert_equal @extra.parent, @root1
|
102
110
|
|
103
|
-
assert_equal 3, @root1.children.
|
111
|
+
assert_equal 3, @root1.reload.children.count
|
104
112
|
assert @root1.children.include?(@extra)
|
105
113
|
assert @root1.children.include?(@root_child1)
|
106
114
|
assert @root1.children.include?(@root_child2)
|
@@ -145,12 +153,28 @@ class TreeTest < Test::Unit::TestCase
|
|
145
153
|
assert_equal [@root_child1, @root_child2], @root_child2.self_and_siblings
|
146
154
|
assert_equal [@root1, @root2, @root3], @root2.self_and_siblings
|
147
155
|
assert_equal [@root1, @root2, @root3], @root3.self_and_siblings
|
148
|
-
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_self_and_children
|
159
|
+
assert_equal [@root1, @root_child1, @root_child2], @root1.self_and_children
|
160
|
+
assert_equal [@root2], @root2.self_and_children
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_nullify
|
164
|
+
root4 = TreeMixinNullify.create!
|
165
|
+
root4_child = TreeMixinNullify.create! :parent_id => root4.id
|
166
|
+
assert_equal 2, TreeMixinNullify.count
|
167
|
+
assert_equal root4.id, root4_child.parent_id
|
168
|
+
root4.destroy
|
169
|
+
assert_equal 1, TreeMixinNullify.count
|
170
|
+
assert_nil root4_child.reload.parent_id
|
171
|
+
end
|
172
|
+
|
149
173
|
end
|
150
174
|
|
151
175
|
class TreeTestWithEagerLoading < Test::Unit::TestCase
|
152
|
-
|
153
|
-
def setup
|
176
|
+
|
177
|
+
def setup
|
154
178
|
teardown_db
|
155
179
|
setup_db
|
156
180
|
@root1 = TreeMixin.create!
|
@@ -159,9 +183,9 @@ class TreeTestWithEagerLoading < Test::Unit::TestCase
|
|
159
183
|
@root_child2 = TreeMixin.create! :parent_id => @root1.id
|
160
184
|
@root2 = TreeMixin.create!
|
161
185
|
@root3 = TreeMixin.create!
|
162
|
-
|
186
|
+
|
163
187
|
@rc1 = RecursivelyCascadedTreeMixin.create!
|
164
|
-
@rc2 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc1.id
|
188
|
+
@rc2 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc1.id
|
165
189
|
@rc3 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc2.id
|
166
190
|
@rc4 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc3.id
|
167
191
|
end
|
@@ -169,36 +193,36 @@ class TreeTestWithEagerLoading < Test::Unit::TestCase
|
|
169
193
|
def teardown
|
170
194
|
teardown_db
|
171
195
|
end
|
172
|
-
|
196
|
+
|
173
197
|
def test_eager_association_loading
|
174
198
|
roots = TreeMixin.find(:all, :include => :children, :conditions => "mixins.parent_id IS NULL", :order => "mixins.id")
|
175
|
-
assert_equal [@root1, @root2, @root3], roots
|
199
|
+
assert_equal [@root1, @root2, @root3], roots
|
176
200
|
assert_no_queries do
|
177
|
-
assert_equal 2, roots[0].children.
|
178
|
-
assert_equal 0, roots[1].children.
|
179
|
-
assert_equal 0, roots[2].children.
|
180
|
-
end
|
201
|
+
assert_equal 2, roots[0].children.count
|
202
|
+
assert_equal 0, roots[1].children.count
|
203
|
+
assert_equal 0, roots[2].children.count
|
204
|
+
end
|
181
205
|
end
|
182
|
-
|
206
|
+
|
183
207
|
def test_eager_association_loading_with_recursive_cascading_three_levels_has_many
|
184
208
|
root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :children => { :children => :children } }, :order => 'mixins.id')
|
185
209
|
assert_equal @rc4, assert_no_queries { root_node.children.first.children.first.children.first }
|
186
210
|
end
|
187
|
-
|
211
|
+
|
188
212
|
def test_eager_association_loading_with_recursive_cascading_three_levels_has_one
|
189
213
|
root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :first_child => { :first_child => :first_child } }, :order => 'mixins.id')
|
190
214
|
assert_equal @rc4, assert_no_queries { root_node.first_child.first_child.first_child }
|
191
215
|
end
|
192
|
-
|
216
|
+
|
193
217
|
def test_eager_association_loading_with_recursive_cascading_three_levels_belongs_to
|
194
218
|
leaf_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :parent => { :parent => :parent } }, :order => 'mixins.id DESC')
|
195
219
|
assert_equal @rc1, assert_no_queries { leaf_node.parent.parent.parent }
|
196
|
-
end
|
220
|
+
end
|
197
221
|
end
|
198
222
|
|
199
223
|
class TreeTestWithoutOrder < Test::Unit::TestCase
|
200
|
-
|
201
|
-
def setup
|
224
|
+
|
225
|
+
def setup
|
202
226
|
setup_db
|
203
227
|
@root1 = TreeMixinWithoutOrder.create!
|
204
228
|
@root2 = TreeMixinWithoutOrder.create!
|
@@ -211,8 +235,53 @@ class TreeTestWithoutOrder < Test::Unit::TestCase
|
|
211
235
|
def test_root
|
212
236
|
assert [@root1, @root2].include?(TreeMixinWithoutOrder.root)
|
213
237
|
end
|
214
|
-
|
238
|
+
|
215
239
|
def test_roots
|
216
240
|
assert_equal [], [@root1, @root2] - TreeMixinWithoutOrder.roots
|
217
241
|
end
|
218
|
-
end
|
242
|
+
end
|
243
|
+
|
244
|
+
class UnsavedTreeTest < Test::Unit::TestCase
|
245
|
+
def setup
|
246
|
+
setup_db
|
247
|
+
@root = TreeMixin.new
|
248
|
+
@root_child = @root.children.build
|
249
|
+
end
|
250
|
+
|
251
|
+
def teardown
|
252
|
+
teardown_db
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_inverse_of
|
256
|
+
# We want children to be aware of their parent before saving either
|
257
|
+
assert_equal @root, @root_child.parent
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
|
262
|
+
class TreeTestWithCounterCache < Test::Unit::TestCase
|
263
|
+
def setup
|
264
|
+
teardown_db
|
265
|
+
setup_db
|
266
|
+
@root = TreeMixinWithCounterCache.create!
|
267
|
+
@child1 = TreeMixinWithCounterCache.create! :parent_id => @root.id
|
268
|
+
@child1_child1 = TreeMixinWithCounterCache.create! :parent_id => @child1.id
|
269
|
+
@child2 = TreeMixinWithCounterCache.create! :parent_id => @root.id
|
270
|
+
end
|
271
|
+
|
272
|
+
def teardown
|
273
|
+
teardown_db
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_counter_cache
|
277
|
+
assert_equal 2, @root.reload.children_count
|
278
|
+
assert_equal 1, @child1.reload.children_count
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_update_parents_counter_cache
|
282
|
+
@child1_child1.update_attributes(:parent_id => @root.id)
|
283
|
+
assert_equal 3, @root.reload.children_count
|
284
|
+
assert_equal 0, @child1.reload.children_count
|
285
|
+
end
|
286
|
+
|
287
|
+
end
|
metadata
CHANGED
@@ -1,63 +1,109 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_tree
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
|
-
authors:
|
7
|
+
authors:
|
7
8
|
- Erik Dahlstrand
|
8
9
|
- Rails Core
|
10
|
+
- Mark Turner
|
11
|
+
- Swanand Pagnis
|
9
12
|
autorequire:
|
10
13
|
bindir: bin
|
11
14
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
date: 2012-04-09 00:00:00.000000000 Z
|
16
|
+
dependencies:
|
17
|
+
- !ruby/object:Gem::Dependency
|
18
|
+
name: bundler
|
19
|
+
requirement: &70099568607080 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ! '>='
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.0.0
|
25
|
+
type: :development
|
26
|
+
prerelease: false
|
27
|
+
version_requirements: *70099568607080
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: activerecord
|
30
|
+
requirement: &70099568606560 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.15.4.7794
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: *70099568606560
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
name: rdoc
|
41
|
+
requirement: &70099568606180 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
type: :development
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: *70099568606180
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: sqlite3
|
52
|
+
requirement: &70099568605720 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
type: :development
|
59
|
+
prerelease: false
|
60
|
+
version_requirements: *70099568605720
|
61
|
+
description: Specify this acts_as extension if you want to model a tree structure
|
62
|
+
by providing a parent association and a children association.
|
63
|
+
email:
|
64
|
+
- erik.dahlstrand@gmail.com
|
65
|
+
- mark@amerine.net
|
66
|
+
- swanand.pagnis@gmail.com
|
19
67
|
executables: []
|
20
|
-
|
21
68
|
extensions: []
|
22
|
-
|
23
|
-
|
24
|
-
- README.rdoc
|
25
|
-
files:
|
26
|
-
- .document
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
27
71
|
- .gitignore
|
28
|
-
-
|
72
|
+
- .travis.yml
|
73
|
+
- Gemfile
|
74
|
+
- README.md
|
29
75
|
- Rakefile
|
30
|
-
- VERSION
|
31
76
|
- acts_as_tree.gemspec
|
77
|
+
- init.rb
|
32
78
|
- lib/acts_as_tree.rb
|
79
|
+
- lib/acts_as_tree/active_record/acts/tree.rb
|
80
|
+
- lib/acts_as_tree/version.rb
|
33
81
|
- test/acts_as_tree_test.rb
|
34
|
-
|
35
|
-
homepage: http://github.com/erdah/acts_as_tree
|
82
|
+
homepage: https://github.com/amerine/acts_as_tree
|
36
83
|
licenses: []
|
37
|
-
|
38
84
|
post_install_message:
|
39
|
-
rdoc_options:
|
85
|
+
rdoc_options:
|
40
86
|
- --charset=UTF-8
|
41
|
-
require_paths:
|
87
|
+
require_paths:
|
42
88
|
- lib
|
43
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
55
101
|
requirements: []
|
56
|
-
|
57
|
-
|
58
|
-
rubygems_version: 1.3.5
|
102
|
+
rubyforge_project: acts_as_tree
|
103
|
+
rubygems_version: 1.8.11
|
59
104
|
signing_key:
|
60
105
|
specification_version: 3
|
61
|
-
summary:
|
62
|
-
test_files:
|
106
|
+
summary: Provides a simple tree behaviour to active_record mdoels.
|
107
|
+
test_files:
|
63
108
|
- test/acts_as_tree_test.rb
|
109
|
+
has_rdoc:
|
data/.document
DELETED
data/README.rdoc
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
= acts_as_tree
|
2
|
-
|
3
|
-
Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children
|
4
|
-
association. This requires that you have a foreign key column, which by default is called +parent_id+.
|
5
|
-
|
6
|
-
== Install
|
7
|
-
|
8
|
-
gem install acts_as_tree --source http://gemcutter.org
|
9
|
-
|
10
|
-
== Example
|
11
|
-
|
12
|
-
class Category < ActiveRecord::Base
|
13
|
-
acts_as_tree :order => "name"
|
14
|
-
end
|
15
|
-
|
16
|
-
Example:
|
17
|
-
root
|
18
|
-
\_ child1
|
19
|
-
\_ subchild1
|
20
|
-
\_ subchild2
|
21
|
-
|
22
|
-
root = Category.create("name" => "root")
|
23
|
-
child1 = root.children.create("name" => "child1")
|
24
|
-
subchild1 = child1.children.create("name" => "subchild1")
|
25
|
-
|
26
|
-
root.parent # => nil
|
27
|
-
child1.parent # => root
|
28
|
-
root.children # => [child1]
|
29
|
-
root.children.first.children.first # => subchild1
|
30
|
-
|
31
|
-
Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.1.1
|