summaryrefslogtreecommitdiff
path: root/vendor/plugins/awesome_nested_set
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-06-27 22:52:50 +0200
committererdgeist <erdgeist@erdgeist.org>2026-06-27 22:52:50 +0200
commit9a19a0494ef51cdac9a78e24d517ca48ba44c453 (patch)
tree8eaae12d8047a40e29d3ea7ff3116b5c869e04bd /vendor/plugins/awesome_nested_set
parent85a01e35274b8d4d4165a7b26bd7986e211246bb (diff)
parent1853082fcd8c067390c246f9daa01a9b47387497 (diff)
Migration from Rails 2.3.5 to Rails 8.1 successful.
Merging dev branch.
Diffstat (limited to 'vendor/plugins/awesome_nested_set')
-rw-r--r--vendor/plugins/awesome_nested_set/.autotest13
-rw-r--r--vendor/plugins/awesome_nested_set/MIT-LICENSE20
-rw-r--r--vendor/plugins/awesome_nested_set/README.rdoc79
-rw-r--r--vendor/plugins/awesome_nested_set/Rakefile54
-rw-r--r--vendor/plugins/awesome_nested_set/VERSION1
-rw-r--r--vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec68
-rw-r--r--vendor/plugins/awesome_nested_set/init.rb1
-rw-r--r--vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb577
-rw-r--r--vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb40
-rw-r--r--vendor/plugins/awesome_nested_set/rails/init.rb12
-rw-r--r--vendor/plugins/awesome_nested_set/test/application.rb1
-rw-r--r--vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb41
-rw-r--r--vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb748
-rw-r--r--vendor/plugins/awesome_nested_set/test/fixtures/categories.yml34
-rw-r--r--vendor/plugins/awesome_nested_set/test/fixtures/category.rb15
-rw-r--r--vendor/plugins/awesome_nested_set/test/fixtures/departments.yml3
-rw-r--r--vendor/plugins/awesome_nested_set/test/fixtures/notes.yml38
-rw-r--r--vendor/plugins/awesome_nested_set/test/test_helper.rb29
18 files changed, 0 insertions, 1774 deletions
diff --git a/vendor/plugins/awesome_nested_set/.autotest b/vendor/plugins/awesome_nested_set/.autotest
deleted file mode 100644
index 54518a4..0000000
--- a/vendor/plugins/awesome_nested_set/.autotest
+++ /dev/null
@@ -1,13 +0,0 @@
1Autotest.add_hook :initialize do |at|
2 at.clear_mappings
3
4 at.add_mapping %r%^lib/(.*)\.rb$% do |_, m|
5 at.files_matching %r%^test/#{m[1]}_test.rb$%
6 end
7
8 at.add_mapping(%r%^test/.*\.rb$%) {|filename, _| filename }
9
10 at.add_mapping %r%^test/fixtures/(.*)s.yml% do |_, _|
11 at.files_matching %r%^test/.*\.rb$%
12 end
13end \ No newline at end of file
diff --git a/vendor/plugins/awesome_nested_set/MIT-LICENSE b/vendor/plugins/awesome_nested_set/MIT-LICENSE
deleted file mode 100644
index 570ecf8..0000000
--- a/vendor/plugins/awesome_nested_set/MIT-LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
1Copyright (c) 2007 [name of plugin creator]
2
3Permission is hereby granted, free of charge, to any person obtaining
4a copy of this software and associated documentation files (the
5"Software"), to deal in the Software without restriction, including
6without limitation the rights to use, copy, modify, merge, publish,
7distribute, sublicense, and/or sell copies of the Software, and to
8permit persons to whom the Software is furnished to do so, subject to
9the following conditions:
10
11The above copyright notice and this permission notice shall be
12included in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/plugins/awesome_nested_set/README.rdoc b/vendor/plugins/awesome_nested_set/README.rdoc
deleted file mode 100644
index 884016d..0000000
--- a/vendor/plugins/awesome_nested_set/README.rdoc
+++ /dev/null
@@ -1,79 +0,0 @@
1= AwesomeNestedSet
2
3Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is replacement for acts_as_nested_set and BetterNestedSet, but awesomer. It supports Rails 2.1 and later.
4
5== What makes this so awesome?
6
7This is a new implementation of nested set based off of BetterNestedSet that fixes some bugs, removes tons of duplication, adds a few useful methods, and adds STI support.
8
9== Installation
10
11Install as a plugin:
12
13 script/plugin install git://github.com/collectiveidea/awesome_nested_set.git
14
15== Usage
16
17To make use of awesome_nested_set, your model needs to have 3 fields: lft, rgt, and parent_id:
18
19 class CreateCategories < ActiveRecord::Migration
20 def self.up
21 create_table :categories do |t|
22 t.string :name
23 t.integer :parent_id
24 t.integer :lft
25 t.integer :rgt
26 end
27 end
28
29 def self.down
30 drop_table :categories
31 end
32 end
33
34Enable the nested set functionality by declaring acts_as_nested_set on your model
35
36 class Category < ActiveRecord::Base
37 acts_as_nested_set
38 end
39
40Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::SingletonMethods for more info.
41
42== View Helper
43
44The view helper is called #nested_set_options.
45
46Example usage:
47
48 <%= f.select :parent_id, nested_set_options(Category, @category) {|i| "#{'-' * i.level} #{i.name}" } %>
49
50 <%= select_tag 'parent_id', options_for_select(nested_set_options(Category) {|i| "#{'-' * i.level} #{i.name}" } ) %>
51
52See CollectiveIdea::Acts::NestedSet::Helper for more information about the helpers.
53
54== References
55
56You can learn more about nested sets at:
57
58 http://www.dbmsmag.com/9603d06.html
59 http://threebit.net/tutorials/nestedset/tutorial1.html
60 http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html
61 http://opensource.symetrie.com/trac/better_nested_set/
62
63== How to contribute
64
65If you find what you might think is a bug:
66
671. Check the GitHub issue tracker to see if anyone else has had the same issue.
68 http://github.com/collectiveidea/awesome_nested_set/issues/
692. If you don't see anything, create an issue with information on how to reproduce it.
70
71If you want to contribute an enhancement or a fix:
72
731. Fork the project on github.
74 http://github.com/collectiveidea/awesome_nested_set/
752. Make your changes with tests.
763. Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix
774. Send a pull request.
78
79Copyright ©2008 Collective Idea, released under the MIT license \ No newline at end of file
diff --git a/vendor/plugins/awesome_nested_set/Rakefile b/vendor/plugins/awesome_nested_set/Rakefile
deleted file mode 100644
index ce70813..0000000
--- a/vendor/plugins/awesome_nested_set/Rakefile
+++ /dev/null
@@ -1,54 +0,0 @@
1begin
2 require 'jeweler'
3rescue LoadError
4 puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
5 exit 1
6end
7require 'rake/testtask'
8require 'rake/rdoctask'
9require 'rcov/rcovtask'
10require "load_multi_rails_rake_tasks"
11
12Jeweler::Tasks.new do |s|
13 s.name = "awesome_nested_set"
14 s.summary = "An awesome nested set implementation for Active Record"
15 s.description = s.summary
16 s.email = "info@collectiveidea.com"
17 s.homepage = "http://github.com/collectiveidea/awesome_nested_set"
18 s.authors = ["Brandon Keepers", "Daniel Morrison"]
19 s.add_dependency "activerecord", ['>= 1.1']
20 s.has_rdoc = true
21 s.extra_rdoc_files = [ "README.rdoc"]
22 s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"]
23 s.test_files = Dir['test/**/*.{yml,rb}']
24end
25
26desc 'Default: run unit tests.'
27task :default => :test
28
29desc 'Test the awesome_nested_set plugin.'
30Rake::TestTask.new(:test) do |t|
31 t.libs += ['lib', 'test']
32 t.pattern = 'test/**/*_test.rb'
33 t.verbose = true
34end
35
36desc 'Generate documentation for the awesome_nested_set plugin.'
37Rake::RDocTask.new(:rdoc) do |rdoc|
38 rdoc.rdoc_dir = 'rdoc'
39 rdoc.title = 'AwesomeNestedSet'
40 rdoc.options << '--line-numbers' << '--inline-source'
41 rdoc.rdoc_files.include('README.rdoc')
42 rdoc.rdoc_files.include('lib/**/*.rb')
43end
44
45namespace :test do
46 desc "just rcov minus html output"
47 Rcov::RcovTask.new(:coverage) do |t|
48 t.libs << 'test'
49 t.test_files = FileList['test/**/*_test.rb']
50 t.output_dir = 'coverage'
51 t.verbose = true
52 t.rcov_opts = %w(--exclude test,/usr/lib/ruby,/Library/Ruby,lib/awesome_nested_set/named_scope.rb --sort coverage)
53 end
54end \ No newline at end of file
diff --git a/vendor/plugins/awesome_nested_set/VERSION b/vendor/plugins/awesome_nested_set/VERSION
deleted file mode 100644
index 9df886c..0000000
--- a/vendor/plugins/awesome_nested_set/VERSION
+++ /dev/null
@@ -1 +0,0 @@
11.4.2
diff --git a/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec b/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec
deleted file mode 100644
index 81108c5..0000000
--- a/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec
+++ /dev/null
@@ -1,68 +0,0 @@
1# -*- encoding: utf-8 -*-
2
3Gem::Specification.new do |s|
4 s.name = %q{awesome_nested_set}
5 s.version = "1.4.2"
6
7 s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8 s.authors = ["Brandon Keepers", "Daniel Morrison"]
9 s.date = %q{2009-09-08}
10 s.description = %q{An awesome nested set implementation for Active Record}
11 s.email = %q{info@collectiveidea.com}
12 s.extra_rdoc_files = [
13 "README.rdoc"
14 ]
15 s.files = [
16 ".autotest",
17 ".gitignore",
18 "MIT-LICENSE",
19 "README.rdoc",
20 "Rakefile",
21 "VERSION",
22 "awesome_nested_set.gemspec",
23 "init.rb",
24 "lib/awesome_nested_set.rb",
25 "lib/awesome_nested_set/helper.rb",
26 "rails/init.rb",
27 "test/application.rb",
28 "test/awesome_nested_set/helper_test.rb",
29 "test/awesome_nested_set_test.rb",
30 "test/db/database.yml",
31 "test/db/schema.rb",
32 "test/fixtures/categories.yml",
33 "test/fixtures/category.rb",
34 "test/fixtures/departments.yml",
35 "test/fixtures/notes.yml",
36 "test/test_helper.rb"
37 ]
38 s.homepage = %q{http://github.com/collectiveidea/awesome_nested_set}
39 s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"]
40 s.require_paths = ["lib"]
41 s.rubygems_version = %q{1.3.3}
42 s.summary = %q{An awesome nested set implementation for Active Record}
43 s.test_files = [
44 "test/db/database.yml",
45 "test/fixtures/categories.yml",
46 "test/fixtures/departments.yml",
47 "test/fixtures/notes.yml",
48 "test/application.rb",
49 "test/awesome_nested_set/helper_test.rb",
50 "test/awesome_nested_set_test.rb",
51 "test/db/schema.rb",
52 "test/fixtures/category.rb",
53 "test/test_helper.rb"
54 ]
55
56 if s.respond_to? :specification_version then
57 current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
58 s.specification_version = 3
59
60 if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
61 s.add_runtime_dependency(%q<activerecord>, [">= 1.1"])
62 else
63 s.add_dependency(%q<activerecord>, [">= 1.1"])
64 end
65 else
66 s.add_dependency(%q<activerecord>, [">= 1.1"])
67 end
68end
diff --git a/vendor/plugins/awesome_nested_set/init.rb b/vendor/plugins/awesome_nested_set/init.rb
deleted file mode 100644
index 43dc7c2..0000000
--- a/vendor/plugins/awesome_nested_set/init.rb
+++ /dev/null
@@ -1 +0,0 @@
1require File.dirname(__FILE__) + "/rails/init"
diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb
deleted file mode 100644
index 015aa0f..0000000
--- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb
+++ /dev/null
@@ -1,577 +0,0 @@
1module CollectiveIdea #:nodoc:
2 module Acts #:nodoc:
3 module NestedSet #:nodoc:
4 def self.included(base)
5 base.extend(SingletonMethods)
6 end
7
8 # This acts provides Nested Set functionality. Nested Set is a smart way to implement
9 # an _ordered_ tree, with the added feature that you can select the children and all of their
10 # descendants with a single query. The drawback is that insertion or move need some complex
11 # sql queries. But everything is done here by this module!
12 #
13 # Nested sets are appropriate each time you want either an orderd tree (menus,
14 # commercial categories) or an efficient way of querying big trees (threaded posts).
15 #
16 # == API
17 #
18 # Methods names are aligned with acts_as_tree as much as possible to make replacment from one
19 # by another easier.
20 #
21 # item.children.create(:name => "child1")
22 #
23 module SingletonMethods
24 # Configuration options are:
25 #
26 # * +:parent_column+ - specifies the column name to use for keeping the position integer (default: parent_id)
27 # * +:left_column+ - column name for left boundry data, default "lft"
28 # * +:right_column+ - column name for right boundry data, default "rgt"
29 # * +:scope+ - restricts what is to be considered a list. Given a symbol, it'll attach "_id"
30 # (if it hasn't been already) and use that as the foreign key restriction. You
31 # can also pass an array to scope by multiple attributes.
32 # Example: <tt>acts_as_nested_set :scope => [:notable_id, :notable_type]</tt>
33 # * +:dependent+ - behavior for cascading destroy. If set to :destroy, all the
34 # child objects are destroyed alongside this object by calling their destroy
35 # method. If set to :delete_all (default), all the child objects are deleted
36 # without calling their destroy method.
37 #
38 # See CollectiveIdea::Acts::NestedSet::ClassMethods for a list of class methods and
39 # CollectiveIdea::Acts::NestedSet::InstanceMethods for a list of instance methods added
40 # to acts_as_nested_set models
41 def acts_as_nested_set(options = {})
42 options = {
43 :parent_column => 'parent_id',
44 :left_column => 'lft',
45 :right_column => 'rgt',
46 :dependent => :delete_all, # or :destroy
47 }.merge(options)
48
49 if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/
50 options[:scope] = "#{options[:scope]}_id".intern
51 end
52
53 write_inheritable_attribute :acts_as_nested_set_options, options
54 class_inheritable_reader :acts_as_nested_set_options
55
56 unless self.is_a?(ClassMethods)
57 include Comparable
58 include Columns
59 include InstanceMethods
60 extend Columns
61 extend ClassMethods
62
63 belongs_to :parent, :class_name => self.base_class.class_name,
64 :foreign_key => parent_column_name
65 has_many :children, :class_name => self.base_class.class_name,
66 :foreign_key => parent_column_name, :order => quoted_left_column_name
67
68 attr_accessor :skip_before_destroy
69
70 # no bulk assignment
71 attr_protected left_column_name.intern,
72 right_column_name.intern
73
74 before_create :set_default_left_and_right
75 before_save :store_new_parent
76 after_save :move_to_new_parent
77 before_destroy :destroy_descendants
78
79 # no assignment to structure fields
80 [left_column_name, right_column_name].each do |column|
81 module_eval <<-"end_eval", __FILE__, __LINE__
82 def #{column}=(x)
83 raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
84 end
85 end_eval
86 end
87
88 named_scope :roots, :conditions => {parent_column_name => nil}, :order => quoted_left_column_name
89 named_scope :leaves, :conditions => "#{quoted_right_column_name} - #{quoted_left_column_name} = 1", :order => quoted_left_column_name
90
91 define_callbacks("before_move", "after_move") if self.respond_to?(:define_callbacks)
92 end
93
94 end
95
96 end
97
98 module ClassMethods
99
100 # Returns the first root
101 def root
102 roots.find(:first)
103 end
104
105 def valid?
106 left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid?
107 end
108
109 def left_and_rights_valid?
110 count(
111 :joins => "LEFT OUTER JOIN #{quoted_table_name} AS parent ON " +
112 "#{quoted_table_name}.#{quoted_parent_column_name} = parent.#{primary_key}",
113 :conditions =>
114 "#{quoted_table_name}.#{quoted_left_column_name} IS NULL OR " +
115 "#{quoted_table_name}.#{quoted_right_column_name} IS NULL OR " +
116 "#{quoted_table_name}.#{quoted_left_column_name} >= " +
117 "#{quoted_table_name}.#{quoted_right_column_name} OR " +
118 "(#{quoted_table_name}.#{quoted_parent_column_name} IS NOT NULL AND " +
119 "(#{quoted_table_name}.#{quoted_left_column_name} <= parent.#{quoted_left_column_name} OR " +
120 "#{quoted_table_name}.#{quoted_right_column_name} >= parent.#{quoted_right_column_name}))"
121 ) == 0
122 end
123
124 def no_duplicates_for_columns?
125 scope_string = Array(acts_as_nested_set_options[:scope]).map do |c|
126 connection.quote_column_name(c)
127 end.push(nil).join(", ")
128 [quoted_left_column_name, quoted_right_column_name].all? do |column|
129 # No duplicates
130 find(:first,
131 :select => "#{scope_string}#{column}, COUNT(#{column})",
132 :group => "#{scope_string}#{column}
133 HAVING COUNT(#{column}) > 1").nil?
134 end
135 end
136
137 # Wrapper for each_root_valid? that can deal with scope.
138 def all_roots_valid?
139 if acts_as_nested_set_options[:scope]
140 roots(:group => scope_column_names).group_by{|record| scope_column_names.collect{|col| record.send(col.to_sym)}}.all? do |scope, grouped_roots|
141 each_root_valid?(grouped_roots)
142 end
143 else
144 each_root_valid?(roots)
145 end
146 end
147
148 def each_root_valid?(roots_to_validate)
149 left = right = 0
150 roots_to_validate.all? do |root|
151 returning(root.left > left && root.right > right) do
152 left = root.left
153 right = root.right
154 end
155 end
156 end
157
158 # Rebuilds the left & rights if unset or invalid. Also very useful for converting from acts_as_tree.
159 def rebuild!
160 # Don't rebuild a valid tree.
161 return true if valid?
162
163 scope = lambda{|node|}
164 if acts_as_nested_set_options[:scope]
165 scope = lambda{|node|
166 scope_column_names.inject(""){|str, column_name|
167 str << "AND #{connection.quote_column_name(column_name)} = #{connection.quote(node.send(column_name.to_sym))} "
168 }
169 }
170 end
171 indices = {}
172
173 set_left_and_rights = lambda do |node|
174 # set left
175 node[left_column_name] = indices[scope.call(node)] += 1
176 # find
177 find(:all, :conditions => ["#{quoted_parent_column_name} = ? #{scope.call(node)}", node], :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, id").each{|n| set_left_and_rights.call(n) }
178 # set right
179 node[right_column_name] = indices[scope.call(node)] += 1
180 node.save!
181 end
182
183 # Find root node(s)
184 root_nodes = find(:all, :conditions => "#{quoted_parent_column_name} IS NULL", :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, id").each do |root_node|
185 # setup index for this scope
186 indices[scope.call(root_node)] ||= 0
187 set_left_and_rights.call(root_node)
188 end
189 end
190
191 # Iterates over tree elements and determines the current level in the tree.
192 # Only accepts default ordering, odering by an other column than lft
193 # does not work. This method is much more efficent than calling level
194 # because it doesn't require any additional database queries.
195 #
196 # Example:
197 # Category.each_with_level(Category.root.self_and_descendants) do |o, level|
198 #
199 def each_with_level(objects)
200 path = [nil]
201 objects.each do |o|
202 if o.parent_id != path.last
203 # we are on a new level, did we decent or ascent?
204 if path.include?(o.parent_id)
205 # remove wrong wrong tailing paths elements
206 path.pop while path.last != o.parent_id
207 else
208 path << o.parent_id
209 end
210 end
211 yield(o, path.length - 1)
212 end
213 end
214 end
215
216 # Mixed into both classes and instances to provide easy access to the column names
217 module Columns
218 def left_column_name
219 acts_as_nested_set_options[:left_column]
220 end
221
222 def right_column_name
223 acts_as_nested_set_options[:right_column]
224 end
225
226 def parent_column_name
227 acts_as_nested_set_options[:parent_column]
228 end
229
230 def scope_column_names
231 Array(acts_as_nested_set_options[:scope])
232 end
233
234 def quoted_left_column_name
235 connection.quote_column_name(left_column_name)
236 end
237
238 def quoted_right_column_name
239 connection.quote_column_name(right_column_name)
240 end
241
242 def quoted_parent_column_name
243 connection.quote_column_name(parent_column_name)
244 end
245
246 def quoted_scope_column_names
247 scope_column_names.collect {|column_name| connection.quote_column_name(column_name) }
248 end
249 end
250
251 # Any instance method that returns a collection makes use of Rails 2.1's named_scope (which is bundled for Rails 2.0), so it can be treated as a finder.
252 #
253 # category.self_and_descendants.count
254 # category.ancestors.find(:all, :conditions => "name like '%foo%'")
255 module InstanceMethods
256 # Value of the parent column
257 def parent_id
258 self[parent_column_name]
259 end
260
261 # Value of the left column
262 def left
263 self[left_column_name]
264 end
265
266 # Value of the right column
267 def right
268 self[right_column_name]
269 end
270
271 # Returns true if this is a root node.
272 def root?
273 parent_id.nil?
274 end
275
276 def leaf?
277 !new_record? && right - left == 1
278 end
279
280 # Returns true is this is a child node
281 def child?
282 !parent_id.nil?
283 end
284
285 # order by left column
286 def <=>(x)
287 left <=> x.left
288 end
289
290 # Redefine to act like active record
291 def ==(comparison_object)
292 comparison_object.equal?(self) ||
293 (comparison_object.instance_of?(self.class) &&
294 comparison_object.id == id &&
295 !comparison_object.new_record?)
296 end
297
298 # Returns root
299 def root
300 self_and_ancestors.find(:first)
301 end
302
303 # Returns the array of all parents and self
304 def self_and_ancestors
305 nested_set_scope.scoped :conditions => [
306 "#{self.class.quoted_table_name}.#{quoted_left_column_name} <= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} >= ?", left, right
307 ]
308 end
309
310 # Returns an array of all parents
311 def ancestors
312 without_self self_and_ancestors
313 end
314
315 # Returns the array of all children of the parent, including self
316 def self_and_siblings
317 nested_set_scope.scoped :conditions => {parent_column_name => parent_id}
318 end
319
320 # Returns the array of all children of the parent, except self
321 def siblings
322 without_self self_and_siblings
323 end
324
325 # Returns a set of all of its nested children which do not have children
326 def leaves
327 descendants.scoped :conditions => "#{self.class.quoted_table_name}.#{quoted_right_column_name} - #{self.class.quoted_table_name}.#{quoted_left_column_name} = 1"
328 end
329
330 # Returns the level of this object in the tree
331 # root level is 0
332 def level
333 parent_id.nil? ? 0 : ancestors.count
334 end
335
336 # Returns a set of itself and all of its nested children
337 def self_and_descendants
338 nested_set_scope.scoped :conditions => [
339 "#{self.class.quoted_table_name}.#{quoted_left_column_name} >= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} <= ?", left, right
340 ]
341 end
342
343 # Returns a set of all of its children and nested children
344 def descendants
345 without_self self_and_descendants
346 end
347
348 def is_descendant_of?(other)
349 other.left < self.left && self.left < other.right && same_scope?(other)
350 end
351
352 def is_or_is_descendant_of?(other)
353 other.left <= self.left && self.left < other.right && same_scope?(other)
354 end
355
356 def is_ancestor_of?(other)
357 self.left < other.left && other.left < self.right && same_scope?(other)
358 end
359
360 def is_or_is_ancestor_of?(other)
361 self.left <= other.left && other.left < self.right && same_scope?(other)
362 end
363
364 # Check if other model is in the same scope
365 def same_scope?(other)
366 Array(acts_as_nested_set_options[:scope]).all? do |attr|
367 self.send(attr) == other.send(attr)
368 end
369 end
370
371 # Find the first sibling to the left
372 def left_sibling
373 siblings.find(:first, :conditions => ["#{self.class.quoted_table_name}.#{quoted_left_column_name} < ?", left],
374 :order => "#{self.class.quoted_table_name}.#{quoted_left_column_name} DESC")
375 end
376
377 # Find the first sibling to the right
378 def right_sibling
379 siblings.find(:first, :conditions => ["#{self.class.quoted_table_name}.#{quoted_left_column_name} > ?", left])
380 end
381
382 # Shorthand method for finding the left sibling and moving to the left of it.
383 def move_left
384 move_to_left_of left_sibling
385 end
386
387 # Shorthand method for finding the right sibling and moving to the right of it.
388 def move_right
389 move_to_right_of right_sibling
390 end
391
392 # Move the node to the left of another node (you can pass id only)
393 def move_to_left_of(node)
394 move_to node, :left
395 end
396
397 # Move the node to the left of another node (you can pass id only)
398 def move_to_right_of(node)
399 move_to node, :right
400 end
401
402 # Move the node to the child of another node (you can pass id only)
403 def move_to_child_of(node)
404 move_to node, :child
405 end
406
407 # Move the node to root nodes
408 def move_to_root
409 move_to nil, :root
410 end
411
412 def move_possible?(target)
413 self != target && # Can't target self
414 same_scope?(target) && # can't be in different scopes
415 # !(left..right).include?(target.left..target.right) # this needs tested more
416 # detect impossible move
417 !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right))
418 end
419
420 def to_text
421 self_and_descendants.map do |node|
422 "#{'*'*(node.level+1)} #{node.id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})"
423 end.join("\n")
424 end
425
426 protected
427
428 def without_self(scope)
429 scope.scoped :conditions => ["#{self.class.quoted_table_name}.#{self.class.primary_key} != ?", self]
430 end
431
432 # All nested set queries should use this nested_set_scope, which performs finds on
433 # the base ActiveRecord class, using the :scope declared in the acts_as_nested_set
434 # declaration.
435 def nested_set_scope
436 options = {:order => quoted_left_column_name}
437 scopes = Array(acts_as_nested_set_options[:scope])
438 options[:conditions] = scopes.inject({}) do |conditions,attr|
439 conditions.merge attr => self[attr]
440 end unless scopes.empty?
441 self.class.base_class.scoped options
442 end
443
444 def store_new_parent
445 @move_to_new_parent_id = send("#{parent_column_name}_changed?") ? parent_id : false
446 true # force callback to return true
447 end
448
449 def move_to_new_parent
450 if @move_to_new_parent_id.nil?
451 move_to_root
452 elsif @move_to_new_parent_id
453 move_to_child_of(@move_to_new_parent_id)
454 end
455 end
456
457 # on creation, set automatically lft and rgt to the end of the tree
458 def set_default_left_and_right
459 maxright = nested_set_scope.maximum(right_column_name) || 0
460 # adds the new node to the right of all existing nodes
461 self[left_column_name] = maxright + 1
462 self[right_column_name] = maxright + 2
463 end
464
465 # Prunes a branch off of the tree, shifting all of the elements on the right
466 # back to the left so the counts still work.
467 def destroy_descendants
468 return if right.nil? || left.nil? || skip_before_destroy
469
470 self.class.base_class.transaction do
471 if acts_as_nested_set_options[:dependent] == :destroy
472 descendants.each do |model|
473 model.skip_before_destroy = true
474 model.destroy
475 end
476 else
477 nested_set_scope.delete_all(
478 ["#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?",
479 left, right]
480 )
481 end
482
483 # update lefts and rights for remaining nodes
484 diff = right - left + 1
485 nested_set_scope.update_all(
486 ["#{quoted_left_column_name} = (#{quoted_left_column_name} - ?)", diff],
487 ["#{quoted_left_column_name} > ?", right]
488 )
489 nested_set_scope.update_all(
490 ["#{quoted_right_column_name} = (#{quoted_right_column_name} - ?)", diff],
491 ["#{quoted_right_column_name} > ?", right]
492 )
493
494 # Don't allow multiple calls to destroy to corrupt the set
495 self.skip_before_destroy = true
496 end
497 end
498
499 # reload left, right, and parent
500 def reload_nested_set
501 reload(:select => "#{quoted_left_column_name}, " +
502 "#{quoted_right_column_name}, #{quoted_parent_column_name}")
503 end
504
505 def move_to(target, position)
506 raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if self.new_record?
507 return if callback(:before_move) == false
508 transaction do
509 if target.is_a? self.class.base_class
510 target.reload_nested_set
511 elsif position != :root
512 # load object if node is not an object
513 target = nested_set_scope.find(target)
514 end
515 self.reload_nested_set
516
517 unless position == :root || move_possible?(target)
518 raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree."
519 end
520
521 bound = case position
522 when :child; target[right_column_name]
523 when :left; target[left_column_name]
524 when :right; target[right_column_name] + 1
525 when :root; 1
526 else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left, :right or :root ('#{position}' received)."
527 end
528
529 if bound > self[right_column_name]
530 bound = bound - 1
531 other_bound = self[right_column_name] + 1
532 else
533 other_bound = self[left_column_name] - 1
534 end
535
536 # there would be no change
537 return if bound == self[right_column_name] || bound == self[left_column_name]
538
539 # we have defined the boundaries of two non-overlapping intervals,
540 # so sorting puts both the intervals and their boundaries in order
541 a, b, c, d = [self[left_column_name], self[right_column_name], bound, other_bound].sort
542
543 new_parent = case position
544 when :child; target.id
545 when :root; nil
546 else target[parent_column_name]
547 end
548
549 self.class.base_class.update_all([
550 "#{quoted_left_column_name} = CASE " +
551 "WHEN #{quoted_left_column_name} BETWEEN :a AND :b " +
552 "THEN #{quoted_left_column_name} + :d - :b " +
553 "WHEN #{quoted_left_column_name} BETWEEN :c AND :d " +
554 "THEN #{quoted_left_column_name} + :a - :c " +
555 "ELSE #{quoted_left_column_name} END, " +
556 "#{quoted_right_column_name} = CASE " +
557 "WHEN #{quoted_right_column_name} BETWEEN :a AND :b " +
558 "THEN #{quoted_right_column_name} + :d - :b " +
559 "WHEN #{quoted_right_column_name} BETWEEN :c AND :d " +
560 "THEN #{quoted_right_column_name} + :a - :c " +
561 "ELSE #{quoted_right_column_name} END, " +
562 "#{quoted_parent_column_name} = CASE " +
563 "WHEN #{self.class.base_class.primary_key} = :id THEN :new_parent " +
564 "ELSE #{quoted_parent_column_name} END",
565 {:a => a, :b => b, :c => c, :d => d, :id => self.id, :new_parent => new_parent}
566 ], nested_set_scope.proxy_options[:conditions])
567 end
568 target.reload_nested_set if target
569 self.reload_nested_set
570 callback(:after_move)
571 end
572
573 end
574
575 end
576 end
577end
diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb
deleted file mode 100644
index 09c803f..0000000
--- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb
+++ /dev/null
@@ -1,40 +0,0 @@
1module CollectiveIdea #:nodoc:
2 module Acts #:nodoc:
3 module NestedSet #:nodoc:
4 # This module provides some helpers for the model classes using acts_as_nested_set.
5 # It is included by default in all views.
6 #
7 module Helper
8 # Returns options for select.
9 # You can exclude some items from the tree.
10 # You can pass a block receiving an item and returning the string displayed in the select.
11 #
12 # == Params
13 # * +class_or_item+ - Class name or top level times
14 # * +mover+ - The item that is being move, used to exlude impossible moves
15 # * +&block+ - a block that will be used to display: { |item| ... item.name }
16 #
17 # == Usage
18 #
19 # <%= f.select :parent_id, nested_set_options(Category, @category) {|i|
20 # "#{'–' * i.level} #{i.name}"
21 # }) %>
22 #
23 def nested_set_options(class_or_item, mover = nil)
24 class_or_item = class_or_item.roots if class_or_item.is_a?(Class)
25 items = Array(class_or_item)
26 result = []
27 items.each do |root|
28 result += root.self_and_descendants.map do |i|
29 if mover.nil? || mover.new_record? || mover.move_possible?(i)
30 [yield(i), i.id]
31 end
32 end.compact
33 end
34 result
35 end
36
37 end
38 end
39 end
40end \ No newline at end of file
diff --git a/vendor/plugins/awesome_nested_set/rails/init.rb b/vendor/plugins/awesome_nested_set/rails/init.rb
deleted file mode 100644
index 2ff1336..0000000
--- a/vendor/plugins/awesome_nested_set/rails/init.rb
+++ /dev/null
@@ -1,12 +0,0 @@
1require 'awesome_nested_set'
2
3ActiveRecord::Base.class_eval do
4 include CollectiveIdea::Acts::NestedSet
5end
6
7if defined?(ActionView)
8 require 'awesome_nested_set/helper'
9 ActionView::Base.class_eval do
10 include CollectiveIdea::Acts::NestedSet::Helper
11 end
12end \ No newline at end of file
diff --git a/vendor/plugins/awesome_nested_set/test/application.rb b/vendor/plugins/awesome_nested_set/test/application.rb
deleted file mode 100644
index 0e6eacf..0000000
--- a/vendor/plugins/awesome_nested_set/test/application.rb
+++ /dev/null
@@ -1 +0,0 @@
1# This file is here to satisfy test_help from Rails < 2.3 \ No newline at end of file
diff --git a/vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb b/vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb
deleted file mode 100644
index 888323c..0000000
--- a/vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb
+++ /dev/null
@@ -1,41 +0,0 @@
1require 'test_helper'
2
3module CollectiveIdea
4 module Acts #:nodoc:
5 module NestedSet #:nodoc:
6 class AwesomeNestedSetTest < TestCaseClass
7 include Helper
8 fixtures :categories
9
10 def test_nested_set_options
11 expected = [
12 [" Top Level", 1],
13 ["- Child 1", 2],
14 ['- Child 2', 3],
15 ['-- Child 2.1', 4],
16 ['- Child 3', 5],
17 [" Top Level 2", 6]
18 ]
19 actual = nested_set_options(Category) do |c|
20 "#{'-' * c.level} #{c.name}"
21 end
22 assert_equal expected, actual
23 end
24
25 def test_nested_set_options_with_mover
26 expected = [
27 [" Top Level", 1],
28 ["- Child 1", 2],
29 ['- Child 3', 5],
30 [" Top Level 2", 6]
31 ]
32 actual = nested_set_options(Category, categories(:child_2)) do |c|
33 "#{'-' * c.level} #{c.name}"
34 end
35 assert_equal expected, actual
36 end
37
38 end
39 end
40 end
41end
diff --git a/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb b/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb
deleted file mode 100644
index 7b587de..0000000
--- a/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb
+++ /dev/null
@@ -1,748 +0,0 @@
1require 'test_helper'
2
3class Note < ActiveRecord::Base
4 acts_as_nested_set :scope => [:notable_id, :notable_type]
5end
6class Default < ActiveRecord::Base
7 acts_as_nested_set
8 set_table_name 'categories'
9end
10class ScopedCategory < ActiveRecord::Base
11 acts_as_nested_set :scope => :organization
12 set_table_name 'categories'
13end
14class RenamedColumns < ActiveRecord::Base
15 acts_as_nested_set :parent_column => 'mother_id', :left_column => 'red', :right_column => 'black'
16end
17
18class AwesomeNestedSetTest < TestCaseClass
19
20 def test_left_column_default
21 assert_equal 'lft', Default.acts_as_nested_set_options[:left_column]
22 end
23
24 def test_right_column_default
25 assert_equal 'rgt', Default.acts_as_nested_set_options[:right_column]
26 end
27
28 def test_parent_column_default
29 assert_equal 'parent_id', Default.acts_as_nested_set_options[:parent_column]
30 end
31
32 def test_scope_default
33 assert_nil Default.acts_as_nested_set_options[:scope]
34 end
35
36 def test_left_column_name
37 assert_equal 'lft', Default.left_column_name
38 assert_equal 'lft', Default.new.left_column_name
39 assert_equal 'red', RenamedColumns.left_column_name
40 assert_equal 'red', RenamedColumns.new.left_column_name
41 end
42
43 def test_right_column_name
44 assert_equal 'rgt', Default.right_column_name
45 assert_equal 'rgt', Default.new.right_column_name
46 assert_equal 'black', RenamedColumns.right_column_name
47 assert_equal 'black', RenamedColumns.new.right_column_name
48 end
49
50 def test_parent_column_name
51 assert_equal 'parent_id', Default.parent_column_name
52 assert_equal 'parent_id', Default.new.parent_column_name
53 assert_equal 'mother_id', RenamedColumns.parent_column_name
54 assert_equal 'mother_id', RenamedColumns.new.parent_column_name
55 end
56
57 def test_creation_with_altered_column_names
58 assert_nothing_raised do
59 RenamedColumns.create!()
60 end
61 end
62
63 def test_quoted_left_column_name
64 quoted = Default.connection.quote_column_name('lft')
65 assert_equal quoted, Default.quoted_left_column_name
66 assert_equal quoted, Default.new.quoted_left_column_name
67 end
68
69 def test_quoted_right_column_name
70 quoted = Default.connection.quote_column_name('rgt')
71 assert_equal quoted, Default.quoted_right_column_name
72 assert_equal quoted, Default.new.quoted_right_column_name
73 end
74
75 def test_left_column_protected_from_assignment
76 assert_raises(ActiveRecord::ActiveRecordError) { Category.new.lft = 1 }
77 end
78
79 def test_right_column_protected_from_assignment
80 assert_raises(ActiveRecord::ActiveRecordError) { Category.new.rgt = 1 }
81 end
82
83 def test_colums_protected_on_initialize
84 c = Category.new(:lft => 1, :rgt => 2)
85 assert_nil c.lft
86 assert_nil c.rgt
87 end
88
89 def test_scoped_appends_id
90 assert_equal :organization_id, ScopedCategory.acts_as_nested_set_options[:scope]
91 end
92
93 def test_roots_class_method
94 assert_equal Category.find_all_by_parent_id(nil), Category.roots
95 end
96
97 def test_root_class_method
98 assert_equal categories(:top_level), Category.root
99 end
100
101 def test_root
102 assert_equal categories(:top_level), categories(:child_3).root
103 end
104
105 def test_root?
106 assert categories(:top_level).root?
107 assert categories(:top_level_2).root?
108 end
109
110 def test_leaves_class_method
111 assert_equal Category.find(:all, :conditions => "#{Category.right_column_name} - #{Category.left_column_name} = 1"), Category.leaves
112 assert_equal Category.leaves.count, 4
113 assert (Category.leaves.include? categories(:child_1))
114 assert (Category.leaves.include? categories(:child_2_1))
115 assert (Category.leaves.include? categories(:child_3))
116 assert (Category.leaves.include? categories(:top_level_2))
117 end
118
119 def test_leaf
120 assert categories(:child_1).leaf?
121 assert categories(:child_2_1).leaf?
122 assert categories(:child_3).leaf?
123 assert categories(:top_level_2).leaf?
124
125 assert !categories(:top_level).leaf?
126 assert !categories(:child_2).leaf?
127 assert !Category.new.leaf?
128 end
129
130
131 def test_parent
132 assert_equal categories(:child_2), categories(:child_2_1).parent
133 end
134
135 def test_self_and_ancestors
136 child = categories(:child_2_1)
137 self_and_ancestors = [categories(:top_level), categories(:child_2), child]
138 assert_equal self_and_ancestors, child.self_and_ancestors
139 end
140
141 def test_ancestors
142 child = categories(:child_2_1)
143 ancestors = [categories(:top_level), categories(:child_2)]
144 assert_equal ancestors, child.ancestors
145 end
146
147 def test_self_and_siblings
148 child = categories(:child_2)
149 self_and_siblings = [categories(:child_1), child, categories(:child_3)]
150 assert_equal self_and_siblings, child.self_and_siblings
151 assert_nothing_raised do
152 tops = [categories(:top_level), categories(:top_level_2)]
153 assert_equal tops, categories(:top_level).self_and_siblings
154 end
155 end
156
157 def test_siblings
158 child = categories(:child_2)
159 siblings = [categories(:child_1), categories(:child_3)]
160 assert_equal siblings, child.siblings
161 end
162
163 def test_leaves
164 leaves = [categories(:child_1), categories(:child_2_1), categories(:child_3), categories(:top_level_2)]
165 assert categories(:top_level).leaves, leaves
166 end
167
168 def test_level
169 assert_equal 0, categories(:top_level).level
170 assert_equal 1, categories(:child_1).level
171 assert_equal 2, categories(:child_2_1).level
172 end
173
174 def test_has_children?
175 assert categories(:child_2_1).children.empty?
176 assert !categories(:child_2).children.empty?
177 assert !categories(:top_level).children.empty?
178 end
179
180 def test_self_and_descendents
181 parent = categories(:top_level)
182 self_and_descendants = [parent, categories(:child_1), categories(:child_2),
183 categories(:child_2_1), categories(:child_3)]
184 assert_equal self_and_descendants, parent.self_and_descendants
185 assert_equal self_and_descendants, parent.self_and_descendants.count
186 end
187
188 def test_descendents
189 lawyers = Category.create!(:name => "lawyers")
190 us = Category.create!(:name => "United States")
191 us.move_to_child_of(lawyers)
192 patent = Category.create!(:name => "Patent Law")
193 patent.move_to_child_of(us)
194 lawyers.reload
195
196 assert_equal 1, lawyers.children.size
197 assert_equal 1, us.children.size
198 assert_equal 2, lawyers.descendants.size
199 end
200
201 def test_self_and_descendents
202 parent = categories(:top_level)
203 descendants = [categories(:child_1), categories(:child_2),
204 categories(:child_2_1), categories(:child_3)]
205 assert_equal descendants, parent.descendants
206 end
207
208 def test_children
209 category = categories(:top_level)
210 category.children.each {|c| assert_equal category.id, c.parent_id }
211 end
212
213 def test_order_of_children
214 categories(:child_2).move_left
215 assert_equal categories(:child_2), categories(:top_level).children[0]
216 assert_equal categories(:child_1), categories(:top_level).children[1]
217 assert_equal categories(:child_3), categories(:top_level).children[2]
218 end
219
220 def test_is_or_is_ancestor_of?
221 assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_1))
222 assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_2_1))
223 assert categories(:child_2).is_or_is_ancestor_of?(categories(:child_2_1))
224 assert !categories(:child_2_1).is_or_is_ancestor_of?(categories(:child_2))
225 assert !categories(:child_1).is_or_is_ancestor_of?(categories(:child_2))
226 assert categories(:child_1).is_or_is_ancestor_of?(categories(:child_1))
227 end
228
229 def test_is_ancestor_of?
230 assert categories(:top_level).is_ancestor_of?(categories(:child_1))
231 assert categories(:top_level).is_ancestor_of?(categories(:child_2_1))
232 assert categories(:child_2).is_ancestor_of?(categories(:child_2_1))
233 assert !categories(:child_2_1).is_ancestor_of?(categories(:child_2))
234 assert !categories(:child_1).is_ancestor_of?(categories(:child_2))
235 assert !categories(:child_1).is_ancestor_of?(categories(:child_1))
236 end
237
238 def test_is_or_is_ancestor_of_with_scope
239 root = ScopedCategory.root
240 child = root.children.first
241 assert root.is_or_is_ancestor_of?(child)
242 child.update_attribute :organization_id, 'different'
243 assert !root.is_or_is_ancestor_of?(child)
244 end
245
246 def test_is_or_is_descendant_of?
247 assert categories(:child_1).is_or_is_descendant_of?(categories(:top_level))
248 assert categories(:child_2_1).is_or_is_descendant_of?(categories(:top_level))
249 assert categories(:child_2_1).is_or_is_descendant_of?(categories(:child_2))
250 assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_2_1))
251 assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_1))
252 assert categories(:child_1).is_or_is_descendant_of?(categories(:child_1))
253 end
254
255 def test_is_descendant_of?
256 assert categories(:child_1).is_descendant_of?(categories(:top_level))
257 assert categories(:child_2_1).is_descendant_of?(categories(:top_level))
258 assert categories(:child_2_1).is_descendant_of?(categories(:child_2))
259 assert !categories(:child_2).is_descendant_of?(categories(:child_2_1))
260 assert !categories(:child_2).is_descendant_of?(categories(:child_1))
261 assert !categories(:child_1).is_descendant_of?(categories(:child_1))
262 end
263
264 def test_is_or_is_descendant_of_with_scope
265 root = ScopedCategory.root
266 child = root.children.first
267 assert child.is_or_is_descendant_of?(root)
268 child.update_attribute :organization_id, 'different'
269 assert !child.is_or_is_descendant_of?(root)
270 end
271
272 def test_same_scope?
273 root = ScopedCategory.root
274 child = root.children.first
275 assert child.same_scope?(root)
276 child.update_attribute :organization_id, 'different'
277 assert !child.same_scope?(root)
278 end
279
280 def test_left_sibling
281 assert_equal categories(:child_1), categories(:child_2).left_sibling
282 assert_equal categories(:child_2), categories(:child_3).left_sibling
283 end
284
285 def test_left_sibling_of_root
286 assert_nil categories(:top_level).left_sibling
287 end
288
289 def test_left_sibling_without_siblings
290 assert_nil categories(:child_2_1).left_sibling
291 end
292
293 def test_left_sibling_of_leftmost_node
294 assert_nil categories(:child_1).left_sibling
295 end
296
297 def test_right_sibling
298 assert_equal categories(:child_3), categories(:child_2).right_sibling
299 assert_equal categories(:child_2), categories(:child_1).right_sibling
300 end
301
302 def test_right_sibling_of_root
303 assert_equal categories(:top_level_2), categories(:top_level).right_sibling
304 assert_nil categories(:top_level_2).right_sibling
305 end
306
307 def test_right_sibling_without_siblings
308 assert_nil categories(:child_2_1).right_sibling
309 end
310
311 def test_right_sibling_of_rightmost_node
312 assert_nil categories(:child_3).right_sibling
313 end
314
315 def test_move_left
316 categories(:child_2).move_left
317 assert_nil categories(:child_2).left_sibling
318 assert_equal categories(:child_1), categories(:child_2).right_sibling
319 assert Category.valid?
320 end
321
322 def test_move_right
323 categories(:child_2).move_right
324 assert_nil categories(:child_2).right_sibling
325 assert_equal categories(:child_3), categories(:child_2).left_sibling
326 assert Category.valid?
327 end
328
329 def test_move_to_left_of
330 categories(:child_3).move_to_left_of(categories(:child_1))
331 assert_nil categories(:child_3).left_sibling
332 assert_equal categories(:child_1), categories(:child_3).right_sibling
333 assert Category.valid?
334 end
335
336 def test_move_to_right_of
337 categories(:child_1).move_to_right_of(categories(:child_3))
338 assert_nil categories(:child_1).right_sibling
339 assert_equal categories(:child_3), categories(:child_1).left_sibling
340 assert Category.valid?
341 end
342
343 def test_move_to_root
344 categories(:child_2).move_to_root
345 assert_nil categories(:child_2).parent
346 assert_equal 0, categories(:child_2).level
347 assert_equal 1, categories(:child_2_1).level
348 assert_equal 1, categories(:child_2).left
349 assert_equal 4, categories(:child_2).right
350 assert Category.valid?
351 end
352
353 def test_move_to_child_of
354 categories(:child_1).move_to_child_of(categories(:child_3))
355 assert_equal categories(:child_3).id, categories(:child_1).parent_id
356 assert Category.valid?
357 end
358
359 def test_move_to_child_of_appends_to_end
360 child = Category.create! :name => 'New Child'
361 child.move_to_child_of categories(:top_level)
362 assert_equal child, categories(:top_level).children.last
363 end
364
365 def test_subtree_move_to_child_of
366 assert_equal 4, categories(:child_2).left
367 assert_equal 7, categories(:child_2).right
368
369 assert_equal 2, categories(:child_1).left
370 assert_equal 3, categories(:child_1).right
371
372 categories(:child_2).move_to_child_of(categories(:child_1))
373 assert Category.valid?
374 assert_equal categories(:child_1).id, categories(:child_2).parent_id
375
376 assert_equal 3, categories(:child_2).left
377 assert_equal 6, categories(:child_2).right
378 assert_equal 2, categories(:child_1).left
379 assert_equal 7, categories(:child_1).right
380 end
381
382 def test_slightly_difficult_move_to_child_of
383 assert_equal 11, categories(:top_level_2).left
384 assert_equal 12, categories(:top_level_2).right
385
386 # create a new top-level node and move single-node top-level tree inside it.
387 new_top = Category.create(:name => 'New Top')
388 assert_equal 13, new_top.left
389 assert_equal 14, new_top.right
390
391 categories(:top_level_2).move_to_child_of(new_top)
392
393 assert Category.valid?
394 assert_equal new_top.id, categories(:top_level_2).parent_id
395
396 assert_equal 12, categories(:top_level_2).left
397 assert_equal 13, categories(:top_level_2).right
398 assert_equal 11, new_top.left
399 assert_equal 14, new_top.right
400 end
401
402 def test_difficult_move_to_child_of
403 assert_equal 1, categories(:top_level).left
404 assert_equal 10, categories(:top_level).right
405 assert_equal 5, categories(:child_2_1).left
406 assert_equal 6, categories(:child_2_1).right
407
408 # create a new top-level node and move an entire top-level tree inside it.
409 new_top = Category.create(:name => 'New Top')
410 categories(:top_level).move_to_child_of(new_top)
411 categories(:child_2_1).reload
412 assert Category.valid?
413 assert_equal new_top.id, categories(:top_level).parent_id
414
415 assert_equal 4, categories(:top_level).left
416 assert_equal 13, categories(:top_level).right
417 assert_equal 8, categories(:child_2_1).left
418 assert_equal 9, categories(:child_2_1).right
419 end
420
421 #rebuild swaps the position of the 2 children when added using move_to_child twice onto same parent
422 def test_move_to_child_more_than_once_per_parent_rebuild
423 root1 = Category.create(:name => 'Root1')
424 root2 = Category.create(:name => 'Root2')
425 root3 = Category.create(:name => 'Root3')
426
427 root2.move_to_child_of root1
428 root3.move_to_child_of root1
429
430 output = Category.roots.last.to_text
431 Category.update_all('lft = null, rgt = null')
432 Category.rebuild!
433
434 assert_equal Category.roots.last.to_text, output
435 end
436
437 # doing move_to_child twice onto same parent from the furthest right first
438 def test_move_to_child_more_than_once_per_parent_outside_in
439 node1 = Category.create(:name => 'Node-1')
440 node2 = Category.create(:name => 'Node-2')
441 node3 = Category.create(:name => 'Node-3')
442
443 node2.move_to_child_of node1
444 node3.move_to_child_of node1
445
446 output = Category.roots.last.to_text
447 Category.update_all('lft = null, rgt = null')
448 Category.rebuild!
449
450 assert_equal Category.roots.last.to_text, output
451 end
452
453
454 def test_valid_with_null_lefts
455 assert Category.valid?
456 Category.update_all('lft = null')
457 assert !Category.valid?
458 end
459
460 def test_valid_with_null_rights
461 assert Category.valid?
462 Category.update_all('rgt = null')
463 assert !Category.valid?
464 end
465
466 def test_valid_with_missing_intermediate_node
467 # Even though child_2_1 will still exist, it is a sign of a sloppy delete, not an invalid tree.
468 assert Category.valid?
469 Category.delete(categories(:child_2).id)
470 assert Category.valid?
471 end
472
473 def test_valid_with_overlapping_and_rights
474 assert Category.valid?
475 categories(:top_level_2)['lft'] = 0
476 categories(:top_level_2).save
477 assert !Category.valid?
478 end
479
480 def test_rebuild
481 assert Category.valid?
482 before_text = Category.root.to_text
483 Category.update_all('lft = null, rgt = null')
484 Category.rebuild!
485 assert Category.valid?
486 assert_equal before_text, Category.root.to_text
487 end
488
489 def test_move_possible_for_sibling
490 assert categories(:child_2).move_possible?(categories(:child_1))
491 end
492
493 def test_move_not_possible_to_self
494 assert !categories(:top_level).move_possible?(categories(:top_level))
495 end
496
497 def test_move_not_possible_to_parent
498 categories(:top_level).descendants.each do |descendant|
499 assert !categories(:top_level).move_possible?(descendant)
500 assert descendant.move_possible?(categories(:top_level))
501 end
502 end
503
504 def test_is_or_is_ancestor_of?
505 [:child_1, :child_2, :child_2_1, :child_3].each do |c|
506 assert categories(:top_level).is_or_is_ancestor_of?(categories(c))
507 end
508 assert !categories(:top_level).is_or_is_ancestor_of?(categories(:top_level_2))
509 end
510
511 def test_left_and_rights_valid_with_blank_left
512 assert Category.left_and_rights_valid?
513 categories(:child_2)[:lft] = nil
514 categories(:child_2).save(false)
515 assert !Category.left_and_rights_valid?
516 end
517
518 def test_left_and_rights_valid_with_blank_right
519 assert Category.left_and_rights_valid?
520 categories(:child_2)[:rgt] = nil
521 categories(:child_2).save(false)
522 assert !Category.left_and_rights_valid?
523 end
524
525 def test_left_and_rights_valid_with_equal
526 assert Category.left_and_rights_valid?
527 categories(:top_level_2)[:lft] = categories(:top_level_2)[:rgt]
528 categories(:top_level_2).save(false)
529 assert !Category.left_and_rights_valid?
530 end
531
532 def test_left_and_rights_valid_with_left_equal_to_parent
533 assert Category.left_and_rights_valid?
534 categories(:child_2)[:lft] = categories(:top_level)[:lft]
535 categories(:child_2).save(false)
536 assert !Category.left_and_rights_valid?
537 end
538
539 def test_left_and_rights_valid_with_right_equal_to_parent
540 assert Category.left_and_rights_valid?
541 categories(:child_2)[:rgt] = categories(:top_level)[:rgt]
542 categories(:child_2).save(false)
543 assert !Category.left_and_rights_valid?
544 end
545
546 def test_moving_dirty_objects_doesnt_invalidate_tree
547 r1 = Category.create
548 r2 = Category.create
549 r3 = Category.create
550 r4 = Category.create
551 nodes = [r1, r2, r3, r4]
552
553 r2.move_to_child_of(r1)
554 assert Category.valid?
555
556 r3.move_to_child_of(r1)
557 assert Category.valid?
558
559 r4.move_to_child_of(r2)
560 assert Category.valid?
561 end
562
563 def test_multi_scoped_no_duplicates_for_columns?
564 assert_nothing_raised do
565 Note.no_duplicates_for_columns?
566 end
567 end
568
569 def test_multi_scoped_all_roots_valid?
570 assert_nothing_raised do
571 Note.all_roots_valid?
572 end
573 end
574
575 def test_multi_scoped
576 note1 = Note.create!(:body => "A", :notable_id => 2, :notable_type => 'Category')
577 note2 = Note.create!(:body => "B", :notable_id => 2, :notable_type => 'Category')
578 note3 = Note.create!(:body => "C", :notable_id => 2, :notable_type => 'Default')
579
580 assert_equal [note1, note2], note1.self_and_siblings
581 assert_equal [note3], note3.self_and_siblings
582 end
583
584 def test_multi_scoped_rebuild
585 root = Note.create!(:body => "A", :notable_id => 3, :notable_type => 'Category')
586 child1 = Note.create!(:body => "B", :notable_id => 3, :notable_type => 'Category')
587 child2 = Note.create!(:body => "C", :notable_id => 3, :notable_type => 'Category')
588
589 child1.move_to_child_of root
590 child2.move_to_child_of root
591
592 Note.update_all('lft = null, rgt = null')
593 Note.rebuild!
594
595 assert_equal Note.roots.find_by_body('A'), root
596 assert_equal [child1, child2], Note.roots.find_by_body('A').children
597 end
598
599 def test_same_scope_with_multi_scopes
600 assert_nothing_raised do
601 notes(:scope1).same_scope?(notes(:child_1))
602 end
603 assert notes(:scope1).same_scope?(notes(:child_1))
604 assert notes(:child_1).same_scope?(notes(:scope1))
605 assert !notes(:scope1).same_scope?(notes(:scope2))
606 end
607
608 def test_quoting_of_multi_scope_column_names
609 assert_equal ["\"notable_id\"", "\"notable_type\""], Note.quoted_scope_column_names
610 end
611
612 def test_equal_in_same_scope
613 assert_equal notes(:scope1), notes(:scope1)
614 assert_not_equal notes(:scope1), notes(:child_1)
615 end
616
617 def test_equal_in_different_scopes
618 assert_not_equal notes(:scope1), notes(:scope2)
619 end
620
621 def test_delete_does_not_invalidate
622 Category.acts_as_nested_set_options[:dependent] = :delete
623 categories(:child_2).destroy
624 assert Category.valid?
625 end
626
627 def test_destroy_does_not_invalidate
628 Category.acts_as_nested_set_options[:dependent] = :destroy
629 categories(:child_2).destroy
630 assert Category.valid?
631 end
632
633 def test_destroy_multiple_times_does_not_invalidate
634 Category.acts_as_nested_set_options[:dependent] = :destroy
635 categories(:child_2).destroy
636 categories(:child_2).destroy
637 assert Category.valid?
638 end
639
640 def test_assigning_parent_id_on_create
641 category = Category.create!(:name => "Child", :parent_id => categories(:child_2).id)
642 assert_equal categories(:child_2), category.parent
643 assert_equal categories(:child_2).id, category.parent_id
644 assert_not_nil category.left
645 assert_not_nil category.right
646 assert Category.valid?
647 end
648
649 def test_assigning_parent_on_create
650 category = Category.create!(:name => "Child", :parent => categories(:child_2))
651 assert_equal categories(:child_2), category.parent
652 assert_equal categories(:child_2).id, category.parent_id
653 assert_not_nil category.left
654 assert_not_nil category.right
655 assert Category.valid?
656 end
657
658 def test_assigning_parent_id_to_nil_on_create
659 category = Category.create!(:name => "New Root", :parent_id => nil)
660 assert_nil category.parent
661 assert_nil category.parent_id
662 assert_not_nil category.left
663 assert_not_nil category.right
664 assert Category.valid?
665 end
666
667 def test_assigning_parent_id_on_update
668 category = categories(:child_2_1)
669 category.parent_id = categories(:child_3).id
670 category.save
671 assert_equal categories(:child_3), category.parent
672 assert_equal categories(:child_3).id, category.parent_id
673 assert Category.valid?
674 end
675
676 def test_assigning_parent_on_update
677 category = categories(:child_2_1)
678 category.parent = categories(:child_3)
679 category.save
680 assert_equal categories(:child_3), category.parent
681 assert_equal categories(:child_3).id, category.parent_id
682 assert Category.valid?
683 end
684
685 def test_assigning_parent_id_to_nil_on_update
686 category = categories(:child_2_1)
687 category.parent_id = nil
688 category.save
689 assert_nil category.parent
690 assert_nil category.parent_id
691 assert Category.valid?
692 end
693
694 def test_creating_child_from_parent
695 category = categories(:child_2).children.create!(:name => "Child")
696 assert_equal categories(:child_2), category.parent
697 assert_equal categories(:child_2).id, category.parent_id
698 assert_not_nil category.left
699 assert_not_nil category.right
700 assert Category.valid?
701 end
702
703 def check_structure(entries, structure)
704 structure = structure.dup
705 Category.each_with_level(entries) do |category, level|
706 expected_level, expected_name = structure.shift
707 assert_equal expected_name, category.name, "wrong category"
708 assert_equal expected_level, level, "wrong level for #{category.name}"
709 end
710 end
711
712 def test_each_with_level
713 levels = [
714 [0, "Top Level"],
715 [1, "Child 1"],
716 [1, "Child 2"],
717 [2, "Child 2.1"],
718 [1, "Child 3" ]]
719
720 check_structure(Category.root.self_and_descendants, levels)
721
722 # test some deeper structures
723 category = Category.find_by_name("Child 1")
724 c1 = Category.new(:name => "Child 1.1")
725 c2 = Category.new(:name => "Child 1.1.1")
726 c3 = Category.new(:name => "Child 1.1.1.1")
727 c4 = Category.new(:name => "Child 1.2")
728 [c1, c2, c3, c4].each(&:save!)
729
730 c1.move_to_child_of(category)
731 c2.move_to_child_of(c1)
732 c3.move_to_child_of(c2)
733 c4.move_to_child_of(category)
734
735 levels = [
736 [0, "Top Level"],
737 [1, "Child 1"],
738 [2, "Child 1.1"],
739 [3, "Child 1.1.1"],
740 [4, "Child 1.1.1.1"],
741 [2, "Child 1.2"],
742 [1, "Child 2"],
743 [2, "Child 2.1"],
744 [1, "Child 3" ]]
745
746 check_structure(Category.root.self_and_descendants, levels)
747 end
748end
diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/categories.yml b/vendor/plugins/awesome_nested_set/test/fixtures/categories.yml
deleted file mode 100644
index bc8e078..0000000
--- a/vendor/plugins/awesome_nested_set/test/fixtures/categories.yml
+++ /dev/null
@@ -1,34 +0,0 @@
1top_level:
2 id: 1
3 name: Top Level
4 lft: 1
5 rgt: 10
6child_1:
7 id: 2
8 name: Child 1
9 parent_id: 1
10 lft: 2
11 rgt: 3
12child_2:
13 id: 3
14 name: Child 2
15 parent_id: 1
16 lft: 4
17 rgt: 7
18child_2_1:
19 id: 4
20 name: Child 2.1
21 parent_id: 3
22 lft: 5
23 rgt: 6
24child_3:
25 id: 5
26 name: Child 3
27 parent_id: 1
28 lft: 8
29 rgt: 9
30top_level_2:
31 id: 6
32 name: Top Level 2
33 lft: 11
34 rgt: 12
diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/category.rb b/vendor/plugins/awesome_nested_set/test/fixtures/category.rb
deleted file mode 100644
index 506b0da..0000000
--- a/vendor/plugins/awesome_nested_set/test/fixtures/category.rb
+++ /dev/null
@@ -1,15 +0,0 @@
1class Category < ActiveRecord::Base
2 acts_as_nested_set
3
4 def to_s
5 name
6 end
7
8 def recurse &block
9 block.call self, lambda{
10 self.children.each do |child|
11 child.recurse &block
12 end
13 }
14 end
15end \ No newline at end of file
diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/departments.yml b/vendor/plugins/awesome_nested_set/test/fixtures/departments.yml
deleted file mode 100644
index e50a944..0000000
--- a/vendor/plugins/awesome_nested_set/test/fixtures/departments.yml
+++ /dev/null
@@ -1,3 +0,0 @@
1top:
2 id: 1
3 name: Top \ No newline at end of file
diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/notes.yml b/vendor/plugins/awesome_nested_set/test/fixtures/notes.yml
deleted file mode 100644
index 004a533..0000000
--- a/vendor/plugins/awesome_nested_set/test/fixtures/notes.yml
+++ /dev/null
@@ -1,38 +0,0 @@
1scope1:
2 id: 1
3 body: Top Level
4 lft: 1
5 rgt: 10
6 notable_id: 1
7 notable_type: Category
8child_1:
9 id: 2
10 body: Child 1
11 parent_id: 1
12 lft: 2
13 rgt: 3
14 notable_id: 1
15 notable_type: Category
16child_2:
17 id: 3
18 body: Child 2
19 parent_id: 1
20 lft: 4
21 rgt: 7
22 notable_id: 1
23 notable_type: Category
24child_3:
25 id: 4
26 body: Child 3
27 parent_id: 1
28 lft: 8
29 rgt: 9
30 notable_id: 1
31 notable_type: Category
32scope2:
33 id: 5
34 body: Top Level 2
35 lft: 1
36 rgt: 2
37 notable_id: 1
38 notable_type: Departments
diff --git a/vendor/plugins/awesome_nested_set/test/test_helper.rb b/vendor/plugins/awesome_nested_set/test/test_helper.rb
deleted file mode 100644
index 05d8855..0000000
--- a/vendor/plugins/awesome_nested_set/test/test_helper.rb
+++ /dev/null
@@ -1,29 +0,0 @@
1$:.unshift(File.dirname(__FILE__) + '/../lib')
2plugin_test_dir = File.dirname(__FILE__)
3RAILS_ROOT = plugin_test_dir
4
5require 'rubygems'
6require 'test/unit'
7require 'multi_rails_init'
8require 'test_help'
9
10require plugin_test_dir + '/../init.rb'
11
12TestCaseClass = ActiveSupport::TestCase rescue Test::Unit::TestCase
13
14ActiveRecord::Base.logger = Logger.new(plugin_test_dir + "/debug.log")
15
16ActiveRecord::Base.configurations = YAML::load(IO.read(plugin_test_dir + "/db/database.yml"))
17ActiveRecord::Base.establish_connection(ENV["DB"] || "sqlite3mem")
18ActiveRecord::Migration.verbose = false
19load(File.join(plugin_test_dir, "db", "schema.rb"))
20
21Dir["#{plugin_test_dir}/fixtures/*.rb"].each {|file| require file }
22
23class TestCaseClass #:nodoc:
24 self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
25 self.use_transactional_fixtures = true
26 self.use_instantiated_fixtures = false
27
28 fixtures :categories, :notes, :departments
29end