acts_as_tree_rails3 0.1.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.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Permission is hereby granted, free of charge, to any person obtaining
2
+ a copy of this software and associated documentation files (the
3
+ "Software"), to deal in the Software without restriction, including
4
+ without limitation the rights to use, copy, modify, merge, publish,
5
+ distribute, sublicense, and/or sell copies of the Software, and to
6
+ permit persons to whom the Software is furnished to do so, subject to
7
+ the following conditions:
8
+
9
+ The above copyright notice and this permission notice shall be
10
+ included in all copies or substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,27 @@
1
+ # acts_as_tree for Rails 3 #
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
+ class Category < ActiveRecord::Base
7
+ acts_as_tree :order => "name"
8
+ end
9
+
10
+ Example:
11
+ root
12
+ \_ child1
13
+ \_ subchild1
14
+ \_ subchild2
15
+
16
+ root = Category.create("name" => "root")
17
+ child1 = root.children.create("name" => "child1")
18
+ subchild1 = child1.children.create("name" => "subchild1")
19
+
20
+ root.parent # => nil
21
+ child1.parent # => root
22
+ root.children # => [child1]
23
+ root.children.first.children.first # => subchild1
24
+
25
+ Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
26
+
27
+ Includes patch from http://dev.rubyonrails.org/ticket/1924
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "acts_as_tree_rails3"
8
+ gem.summary = %Q{Make your model act as a tree structure}
9
+ gem.description = %Q{Model gets: root, siblings, ancestors, descendants and other methods for tree navigation}
10
+ gem.email = "jim@saturnflyer.com"
11
+ gem.homepage = "http://github.com/saturnflyer/acts_as_tree"
12
+ gem.authors = ["David Heinemeier Hansson",'and others']
13
+ end
14
+ Jeweler::GemcutterTasks.new
15
+ rescue LoadError
16
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
17
+ end
18
+
19
+ require 'rake/testtask'
20
+ Rake::TestTask.new(:test) do |test|
21
+ test.libs << 'lib' << 'test'
22
+ test.pattern = 'test/**/*_test.rb'
23
+ test.verbose = true
24
+ end
25
+
26
+ begin
27
+ require 'rcov/rcovtask'
28
+ Rcov::RcovTask.new do |test|
29
+ test.libs << 'test'
30
+ test.pattern = 'test/**/*_test.rb'
31
+ test.verbose = true
32
+ end
33
+ rescue LoadError
34
+ task :rcov do
35
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
36
+ end
37
+ end
38
+
39
+ task :test => :check_dependencies
40
+
41
+ task :default => :test
42
+
43
+ require 'rake/rdoctask'
44
+ Rake::RDocTask.new do |rdoc|
45
+ if File.exist?('VERSION')
46
+ version = File.read('VERSION')
47
+ else
48
+ version = ""
49
+ end
50
+
51
+ rdoc.rdoc_dir = 'rdoc'
52
+ rdoc.title = "acts_as_tree #{version}"
53
+ rdoc.rdoc_files.include('README*')
54
+ rdoc.rdoc_files.include('lib/**/*.rb')
55
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init"
@@ -0,0 +1,186 @@
1
+ module ActiveRecord
2
+ module Acts
3
+ module Tree
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
+ # * <tt>descendants</tt> - Returns a flat list of the descendants of the current node (<tt>[child1, subchild1, subchild2]</tt> when called on <tt>root</tt>)
37
+ module ClassMethods
38
+ # Configuration options are:
39
+ #
40
+ # * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
41
+ # * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
42
+ # * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
43
+ def acts_as_tree(options = {})
44
+ configuration = {
45
+ :foreign_key => "parent_id",
46
+ :order => nil,
47
+ :counter_cache => nil,
48
+ :dependent => :destroy,
49
+ :touch => false
50
+ }
51
+ configuration.update(options) if options.is_a?(Hash)
52
+
53
+ # facebooker seems unhappy with :touch
54
+ if configuration[:touch]
55
+ belongs_to :parent,
56
+ :class_name => name,
57
+ :foreign_key => configuration[:foreign_key],
58
+ :counter_cache => configuration[:counter_cache],
59
+ :touch => configuration[:touch]
60
+ else
61
+ belongs_to :parent,
62
+ :class_name => name,
63
+ :foreign_key => configuration[:foreign_key],
64
+ :counter_cache => configuration[:counter_cache]
65
+ end
66
+
67
+ has_many :children,
68
+ :class_name => name,
69
+ :foreign_key => configuration[:foreign_key],
70
+ :order => configuration[:order],
71
+ :dependent => configuration[:dependent]
72
+
73
+ class_eval <<-EOV
74
+ include ActiveRecord::Acts::Tree::InstanceMethods
75
+
76
+ scope :roots,
77
+ :conditions => "#{configuration[:foreign_key]} IS NULL",
78
+ :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}}
79
+
80
+ after_save :update_level_cache
81
+ after_update :update_parents_counter_cache
82
+
83
+ def self.root
84
+ roots.first
85
+ end
86
+
87
+ def self.childless
88
+ nodes = []
89
+
90
+ find(:all).each do |node|
91
+ nodes << node if node.children.empty?
92
+ end
93
+
94
+ nodes
95
+ end
96
+
97
+ validates_each "#{configuration[:foreign_key]}" do |record, attr, value|
98
+ if value
99
+ if record.id == value
100
+ record.errors.add attr, "cannot be it's own id"
101
+ elsif record.descendants.map {|c| c.id}.include?(value)
102
+ record.errors.add attr, "cannot be a descendant's id"
103
+ end
104
+ end
105
+ end
106
+ EOV
107
+ end
108
+ end
109
+
110
+ module InstanceMethods
111
+ # Returns list of ancestors, starting from parent until root.
112
+ #
113
+ # subchild1.ancestors # => [child1, root]
114
+ def ancestors
115
+ node, nodes = self, []
116
+ nodes << node = node.parent until node.parent.nil? and return nodes
117
+ end
118
+
119
+ def root?
120
+ parent == nil
121
+ end
122
+
123
+ def leaf?
124
+ children.length == 0
125
+ end
126
+
127
+ # Returns the root node of the tree.
128
+ def root
129
+ node = self
130
+ node = node.parent until node.parent.nil? and return node
131
+ end
132
+
133
+ # Returns all siblings of the current node.
134
+ #
135
+ # subchild1.siblings # => [subchild2]
136
+ def siblings
137
+ self_and_siblings - [self]
138
+ end
139
+
140
+ # Returns all siblings and a reference to the current node.
141
+ #
142
+ # subchild1.self_and_siblings # => [subchild1, subchild2]
143
+ def self_and_siblings
144
+ parent ? parent.children : self.class.roots
145
+ end
146
+
147
+ # Returns a flat list of the descendants of the current node.
148
+ #
149
+ # root.descendants # => [child1, subchild1, subchild2]
150
+ def descendants(node=self)
151
+ nodes = []
152
+ nodes << node unless node == self
153
+
154
+ node.children.each do |child|
155
+ nodes += descendants(child)
156
+ end
157
+
158
+ nodes.compact
159
+ end
160
+
161
+ def childless
162
+ self.descendants.collect{|d| d.children.empty? ? d : nil}.compact
163
+ end
164
+
165
+ private
166
+
167
+ def update_parents_counter_cache
168
+ if self.respond_to?(:children_count) && parent_id_changed?
169
+ self.class.decrement_counter(:children_count, parent_id_was)
170
+ self.class.increment_counter(:children_count, parent_id)
171
+ end
172
+ end
173
+
174
+ def update_level_cache
175
+ if respond_to?(:level_cache) && parent_id_changed?
176
+ _level_cache = ancestors.length
177
+
178
+ if level_cache != _level_cache
179
+ self.class.update_all("level_cache = #{_level_cache}", ['id = ?', id])
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,2 @@
1
+ require 'active_record/acts/tree'
2
+ ActiveRecord::Base.send :include, ActiveRecord::Acts::Tree
@@ -0,0 +1 @@
1
+ require 'acts_as_tree_rails3'
@@ -0,0 +1,311 @@
1
+ require 'test/unit'
2
+
3
+ require 'rubygems'
4
+ require 'active_record'
5
+
6
+ $:.unshift File.dirname(__FILE__) + '/../lib'
7
+ require File.dirname(__FILE__) + '/../init'
8
+
9
+ class Test::Unit::TestCase
10
+ def assert_queries(num = 1)
11
+ $query_count = 0
12
+ yield
13
+ ensure
14
+ assert_equal num, $query_count, "#{$query_count} instead of #{num} queries were executed."
15
+ end
16
+
17
+ def assert_no_queries(&block)
18
+ assert_queries(0, &block)
19
+ end
20
+ end
21
+
22
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
23
+
24
+ # AR keeps printing annoying schema statements
25
+ $stdout_orig = $stdout
26
+ $stdout = StringIO.new
27
+
28
+ def setup_db
29
+ ActiveRecord::Base.logger
30
+ ActiveRecord::Schema.define(:version => 1) do
31
+ create_table :mixins do |t|
32
+ t.column :type, :string
33
+ t.column :parent_id, :integer
34
+ t.column :children_count, :integer, :default => 0
35
+ t.column :level_cache, :integer, :default => 0
36
+ end
37
+ end
38
+ end
39
+
40
+ def teardown_db
41
+ ActiveRecord::Base.connection.tables.each do |table|
42
+ ActiveRecord::Base.connection.drop_table(table)
43
+ end
44
+ end
45
+
46
+ class Mixin < ActiveRecord::Base
47
+ end
48
+
49
+ class TreeMixin < Mixin
50
+ acts_as_tree :foreign_key => "parent_id", :order => "id"
51
+ end
52
+
53
+ class TreeMixinWithCounterCache < Mixin
54
+ acts_as_tree :foreign_key => "parent_id", :order => "id", :counter_cache => :children_count
55
+ end
56
+
57
+ class TreeMixinWithoutOrder < Mixin
58
+ acts_as_tree :foreign_key => "parent_id"
59
+ end
60
+
61
+ class RecursivelyCascadedTreeMixin < Mixin
62
+ acts_as_tree :foreign_key => "parent_id"
63
+ has_one :first_child, :class_name => 'RecursivelyCascadedTreeMixin', :foreign_key => :parent_id
64
+ end
65
+
66
+ class TreeMixinNullify < Mixin
67
+ acts_as_tree :foreign_key => "parent_id", :order => "id", :dependent => :nullify
68
+ end
69
+
70
+ class TreeTest < Test::Unit::TestCase
71
+ def setup
72
+ setup_db
73
+ @root1 = TreeMixin.create!
74
+ @root_child1 = TreeMixin.create! :parent_id => @root1.id
75
+ @child1_child = TreeMixin.create! :parent_id => @root_child1.id
76
+ @root_child2 = TreeMixin.create! :parent_id => @root1.id
77
+ @root2 = TreeMixin.create!
78
+ @root3 = TreeMixin.create!
79
+ end
80
+
81
+ def teardown
82
+ teardown_db
83
+ end
84
+
85
+ def test_children
86
+ assert_equal @root1.reload.children, [@root_child1, @root_child2]
87
+ assert_equal @root_child1.reload.children, [@child1_child]
88
+ assert_equal @child1_child.reload.children, []
89
+ assert_equal @root_child2.reload.children, []
90
+ end
91
+
92
+ def test_parent
93
+ assert_equal @root_child1.parent, @root1
94
+ assert_equal @root_child1.parent, @root_child2.parent
95
+ assert_nil @root1.parent
96
+ end
97
+
98
+ def test_nullify
99
+ root4 = TreeMixinNullify.create!
100
+ root4_child = TreeMixinNullify.create! :parent_id => root4.id
101
+ assert_equal 2, TreeMixinNullify.count
102
+ assert_equal root4.id, root4_child.parent_id
103
+ root4.destroy
104
+ assert_equal 1, TreeMixinNullify.count
105
+ assert_nil root4_child.reload.parent_id
106
+ end
107
+
108
+ def test_delete
109
+ assert_equal 6, TreeMixin.count
110
+ @root1.destroy
111
+ assert_equal 2, TreeMixin.count
112
+ @root2.destroy
113
+ @root3.destroy
114
+ assert_equal 0, TreeMixin.count
115
+ end
116
+
117
+ def test_insert
118
+ @extra = @root1.children.create
119
+
120
+ assert @extra
121
+
122
+ assert_equal @extra.parent, @root1
123
+
124
+ assert_equal 3, @root1.reload.children.count
125
+ assert @root1.children.include?(@extra)
126
+ assert @root1.children.include?(@root_child1)
127
+ assert @root1.children.include?(@root_child2)
128
+ end
129
+
130
+ def test_ancestors
131
+ assert_equal [], @root1.ancestors
132
+ assert_equal [@root1], @root_child1.ancestors
133
+ assert_equal [@root_child1, @root1], @child1_child.ancestors
134
+ assert_equal [@root1], @root_child2.ancestors
135
+ assert_equal [], @root2.ancestors
136
+ assert_equal [], @root3.ancestors
137
+ end
138
+
139
+ def test_root
140
+ assert_equal @root1, TreeMixin.root
141
+ assert_equal @root1, @root1.root
142
+ assert_equal @root1, @root_child1.root
143
+ assert_equal @root1, @child1_child.root
144
+ assert_equal @root1, @root_child2.root
145
+ assert_equal @root2, @root2.root
146
+ assert_equal @root3, @root3.root
147
+ end
148
+
149
+ def test_roots
150
+ assert_equal [@root1, @root2, @root3], TreeMixin.roots
151
+ end
152
+
153
+ def test_siblings
154
+ assert_equal [@root2, @root3], @root1.siblings
155
+ assert_equal [@root_child2], @root_child1.siblings
156
+ assert_equal [], @child1_child.siblings
157
+ assert_equal [@root_child1], @root_child2.siblings
158
+ assert_equal [@root1, @root3], @root2.siblings
159
+ assert_equal [@root1, @root2], @root3.siblings
160
+ end
161
+
162
+ def test_self_and_siblings
163
+ assert_equal [@root1, @root2, @root3], @root1.self_and_siblings
164
+ assert_equal [@root_child1, @root_child2], @root_child1.self_and_siblings
165
+ assert_equal [@child1_child], @child1_child.self_and_siblings
166
+ assert_equal [@root_child1, @root_child2], @root_child2.self_and_siblings
167
+ assert_equal [@root1, @root2, @root3], @root2.self_and_siblings
168
+ assert_equal [@root1, @root2, @root3], @root3.self_and_siblings
169
+ end
170
+
171
+ def test_root
172
+ assert_equal true, @root1.root?
173
+ assert_equal false, @child1_child.root?
174
+ end
175
+
176
+ def test_leaf
177
+ assert_equal false, @root1.leaf?
178
+ assert_equal true, @child1_child.leaf?
179
+ end
180
+ end
181
+
182
+ class TreeTestWithCounterCache < Test::Unit::TestCase
183
+ def setup
184
+ teardown_db
185
+ setup_db
186
+ @root = TreeMixinWithCounterCache.create!
187
+ @child1 = TreeMixinWithCounterCache.create! :parent_id => @root.id
188
+ @child1_child1 = TreeMixinWithCounterCache.create! :parent_id => @child1.id
189
+ @child2 = TreeMixinWithCounterCache.create! :parent_id => @root.id
190
+ end
191
+
192
+ def teardown
193
+ teardown_db
194
+ end
195
+
196
+ def test_counter_cache
197
+ assert_equal 2, @root.reload.children_count
198
+ assert_equal 1, @child1.reload.children_count
199
+ end
200
+
201
+ def test_update_parents_counter_cache
202
+ @child1_child1.update_attributes(:parent_id => @root.id)
203
+ assert_equal 3, @root.reload.children_count
204
+ assert_equal 0, @child1.reload.children_count
205
+ end
206
+
207
+ end
208
+
209
+ class TreeTestWithLevelCache < Test::Unit::TestCase
210
+ def setup
211
+ teardown_db
212
+ setup_db
213
+ @root1 = TreeMixin.create!
214
+ @root_child1 = TreeMixin.create! :parent_id => @root1.id
215
+ @child1_child = TreeMixin.create! :parent_id => @root_child1.id
216
+ @root_child2 = TreeMixin.create! :parent_id => @root1.id
217
+ @root2 = TreeMixin.create!
218
+ end
219
+
220
+ def teardown
221
+ teardown_db
222
+ end
223
+
224
+ def test_level_cache
225
+ assert_equal 0, @root1.reload.level_cache
226
+ assert_equal 1, @root_child1.reload.level_cache
227
+ assert_equal 2, @child1_child.reload.level_cache
228
+ assert_equal 0, @root2.reload.level_cache
229
+ end
230
+
231
+ def test_level_cache_are_updated
232
+ @child1_child.reload.parent_id = nil
233
+ @child1_child.save
234
+
235
+ @root2.reload.parent_id = @root_child2.reload.id
236
+ @root2.save
237
+
238
+ assert_equal 0, @root1.reload.level_cache
239
+ assert_equal 1, @root_child1.reload.level_cache
240
+ assert_equal 0, @child1_child.reload.level_cache
241
+ assert_equal 2, @root2.reload.level_cache
242
+ end
243
+ end
244
+
245
+ class TreeTestWithEagerLoading < Test::Unit::TestCase
246
+
247
+ def setup
248
+ teardown_db
249
+ setup_db
250
+ @root1 = TreeMixin.create!
251
+ @root_child1 = TreeMixin.create! :parent_id => @root1.id
252
+ @child1_child = TreeMixin.create! :parent_id => @root_child1.id
253
+ @root_child2 = TreeMixin.create! :parent_id => @root1.id
254
+ @root2 = TreeMixin.create!
255
+ @root3 = TreeMixin.create!
256
+
257
+ @rc1 = RecursivelyCascadedTreeMixin.create!
258
+ @rc2 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc1.id
259
+ @rc3 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc2.id
260
+ @rc4 = RecursivelyCascadedTreeMixin.create! :parent_id => @rc3.id
261
+ end
262
+
263
+ def teardown
264
+ teardown_db
265
+ end
266
+
267
+ def test_eager_association_loading
268
+ roots = TreeMixin.find(:all, :include => :children, :conditions => "mixins.parent_id IS NULL", :order => "mixins.id")
269
+ assert_equal [@root1, @root2, @root3], roots
270
+ assert_no_queries do
271
+ assert_equal 2, roots[0].children.count
272
+ assert_equal 0, roots[1].children.count
273
+ assert_equal 0, roots[2].children.count
274
+ end
275
+ end
276
+
277
+ def test_eager_association_loading_with_recursive_cascading_three_levels_has_many
278
+ root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :children => { :children => :children } }, :order => 'mixins.id')
279
+ assert_equal @rc4, assert_no_queries { root_node.children.first.children.first.children.first }
280
+ end
281
+
282
+ def test_eager_association_loading_with_recursive_cascading_three_levels_has_one
283
+ root_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :first_child => { :first_child => :first_child } }, :order => 'mixins.id')
284
+ assert_equal @rc4, assert_no_queries { root_node.first_child.first_child.first_child }
285
+ end
286
+
287
+ def test_eager_association_loading_with_recursive_cascading_three_levels_belongs_to
288
+ leaf_node = RecursivelyCascadedTreeMixin.find(:first, :include => { :parent => { :parent => :parent } }, :order => 'mixins.id DESC')
289
+ assert_equal @rc1, assert_no_queries { leaf_node.parent.parent.parent }
290
+ end
291
+ end
292
+
293
+ class TreeTestWithoutOrder < Test::Unit::TestCase
294
+ def setup
295
+ setup_db
296
+ @root1 = TreeMixinWithoutOrder.create!
297
+ @root2 = TreeMixinWithoutOrder.create!
298
+ end
299
+
300
+ def teardown
301
+ teardown_db
302
+ end
303
+
304
+ def test_root
305
+ assert [@root1, @root2].include?(TreeMixinWithoutOrder.root)
306
+ end
307
+
308
+ def test_roots
309
+ assert_equal [], [@root1, @root2] - TreeMixinWithoutOrder.roots
310
+ end
311
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_tree_rails3
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - David Heinemeier Hansson
13
+ - and others
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-19 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: "Model gets: root, siblings, ancestors, descendants and other methods for tree navigation"
23
+ email: jim@saturnflyer.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - LICENSE
30
+ - README.markdown
31
+ files:
32
+ - .document
33
+ - .gitignore
34
+ - LICENSE
35
+ - README.markdown
36
+ - Rakefile
37
+ - VERSION
38
+ - init.rb
39
+ - lib/active_record/acts/tree.rb
40
+ - lib/acts_as_tree_rails3.rb
41
+ - rails/init.rb
42
+ - test/acts_as_tree_test.rb
43
+ has_rdoc: true
44
+ homepage: http://github.com/saturnflyer/acts_as_tree
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --charset=UTF-8
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.3.7
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Make your model act as a tree structure
75
+ test_files:
76
+ - test/acts_as_tree_test.rb