From 03bde9fb42235af7147d6312e2cf6d928111dee1 Mon Sep 17 00:00:00 2001 From: hukl Date: Tue, 8 Sep 2009 11:30:11 +0200 Subject: updated awesome_nested_set plugin --- vendor/plugins/awesome_nested_set/.gitignore | 5 - vendor/plugins/awesome_nested_set/README.rdoc | 21 ++- vendor/plugins/awesome_nested_set/Rakefile | 32 ++-- vendor/plugins/awesome_nested_set/VERSION | 1 + .../awesome_nested_set/awesome_nested_set.gemspec | 84 ++++++++-- .../awesome_nested_set/lib/awesome_nested_set.rb | 173 ++++++++++++--------- .../lib/awesome_nested_set/compatability.rb | 29 ---- .../lib/awesome_nested_set/named_scope.rb | 140 ----------------- vendor/plugins/awesome_nested_set/rails/init.rb | 1 - .../plugins/awesome_nested_set/test/application.rb | 1 + .../test/awesome_nested_set/helper_test.rb | 6 +- .../test/awesome_nested_set_test.rb | 165 +++++++++++++++++--- .../plugins/awesome_nested_set/test/test_helper.rb | 14 +- 13 files changed, 363 insertions(+), 309 deletions(-) delete mode 100644 vendor/plugins/awesome_nested_set/.gitignore create mode 100644 vendor/plugins/awesome_nested_set/VERSION delete mode 100644 vendor/plugins/awesome_nested_set/lib/awesome_nested_set/compatability.rb delete mode 100644 vendor/plugins/awesome_nested_set/lib/awesome_nested_set/named_scope.rb create mode 100644 vendor/plugins/awesome_nested_set/test/application.rb (limited to 'vendor/plugins') diff --git a/vendor/plugins/awesome_nested_set/.gitignore b/vendor/plugins/awesome_nested_set/.gitignore deleted file mode 100644 index df112b0..0000000 --- a/vendor/plugins/awesome_nested_set/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -awesome_nested_set.sqlite3.db -test/debug.log -rdoc -coverage -pkg diff --git a/vendor/plugins/awesome_nested_set/README.rdoc b/vendor/plugins/awesome_nested_set/README.rdoc index c093f75..884016d 100644 --- a/vendor/plugins/awesome_nested_set/README.rdoc +++ b/vendor/plugins/awesome_nested_set/README.rdoc @@ -1,6 +1,6 @@ = AwesomeNestedSet -Awesome 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. +Awesome 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. == What makes this so awesome? @@ -8,7 +8,7 @@ This is a new implementation of nested set based off of BetterNestedSet that fix == Installation -If you are on Rails 2.1 or later: +Install as a plugin: script/plugin install git://github.com/collectiveidea/awesome_nested_set.git @@ -60,5 +60,20 @@ You can learn more about nested sets at: http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html http://opensource.symetrie.com/trac/better_nested_set/ +== How to contribute -Copyright (c) 2008 Collective Idea, released under the MIT license \ No newline at end of file +If you find what you might think is a bug: + +1. Check the GitHub issue tracker to see if anyone else has had the same issue. + http://github.com/collectiveidea/awesome_nested_set/issues/ +2. If you don't see anything, create an issue with information on how to reproduce it. + +If you want to contribute an enhancement or a fix: + +1. Fork the project on github. + http://github.com/collectiveidea/awesome_nested_set/ +2. Make your changes with tests. +3. Commit the changes without making changes to the Rakefile, VERSION, or any other files that aren't related to your enhancement or fix +4. Send a pull request. + +Copyright ©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 index 53906f6..ce70813 100644 --- a/vendor/plugins/awesome_nested_set/Rakefile +++ b/vendor/plugins/awesome_nested_set/Rakefile @@ -1,26 +1,34 @@ -require 'rake' +begin + require 'jeweler' +rescue LoadError + puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com" + exit 1 +end require 'rake/testtask' require 'rake/rdoctask' -require 'rake/gempackagetask' require 'rcov/rcovtask' require "load_multi_rails_rake_tasks" -spec = eval(File.read("#{File.dirname(__FILE__)}/awesome_nested_set.gemspec")) -PKG_NAME = spec.name -PKG_VERSION = spec.version - -Rake::GemPackageTask.new(spec) do |pkg| - pkg.need_zip = true - pkg.need_tar = true +Jeweler::Tasks.new do |s| + s.name = "awesome_nested_set" + s.summary = "An awesome nested set implementation for Active Record" + s.description = s.summary + s.email = "info@collectiveidea.com" + s.homepage = "http://github.com/collectiveidea/awesome_nested_set" + s.authors = ["Brandon Keepers", "Daniel Morrison"] + s.add_dependency "activerecord", ['>= 1.1'] + s.has_rdoc = true + s.extra_rdoc_files = [ "README.rdoc"] + s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"] + s.test_files = Dir['test/**/*.{yml,rb}'] end - desc 'Default: run unit tests.' task :default => :test desc 'Test the awesome_nested_set plugin.' Rake::TestTask.new(:test) do |t| - t.libs << 'lib' + t.libs += ['lib', 'test'] t.pattern = 'test/**/*_test.rb' t.verbose = true end @@ -37,7 +45,7 @@ end namespace :test do desc "just rcov minus html output" Rcov::RcovTask.new(:coverage) do |t| - # t.libs << 'test' + t.libs << 'test' t.test_files = FileList['test/**/*_test.rb'] t.output_dir = 'coverage' t.verbose = true diff --git a/vendor/plugins/awesome_nested_set/VERSION b/vendor/plugins/awesome_nested_set/VERSION new file mode 100644 index 0000000..347f583 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/VERSION @@ -0,0 +1 @@ +1.4.1 diff --git a/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec b/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec index c5a1d49..dbbca9e 100644 --- a/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec +++ b/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec @@ -1,20 +1,72 @@ +# Generated by jeweler +# DO NOT EDIT THIS FILE +# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec` +# -*- encoding: utf-8 -*- + Gem::Specification.new do |s| - s.name = "awesome_nested_set" - s.version = "1.1.1" - s.summary = "An awesome replacement for acts_as_nested_set and better_nested_set." - s.description = s.summary - - s.files = %w(init.rb MIT-LICENSE Rakefile README.rdoc lib/awesome_nested_set.rb lib/awesome_nested_set/compatability.rb lib/awesome_nested_set/helper.rb lib/awesome_nested_set/named_scope.rb rails/init.rb test/awesome_nested_set_test.rb test/test_helper.rb test/awesome_nested_set/helper_test.rb test/db/database.yml test/db/schema.rb test/fixtures/categories.yml test/fixtures/category.rb test/fixtures/departments.yml test/fixtures/notes.yml) - - s.add_dependency "activerecord", ['>= 1.1'] - + s.name = %q{awesome_nested_set} + s.version = "1.4.1" + + s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= + s.authors = ["Brandon Keepers", "Daniel Morrison"] + s.date = %q{2009-09-06} + s.description = %q{An awesome nested set implementation for Active Record} + s.email = %q{info@collectiveidea.com} + s.extra_rdoc_files = [ + "README.rdoc" + ] + s.files = [ + ".autotest", + ".gitignore", + "MIT-LICENSE", + "README.rdoc", + "Rakefile", + "VERSION", + "awesome_nested_set.gemspec", + "init.rb", + "lib/awesome_nested_set.rb", + "lib/awesome_nested_set/helper.rb", + "rails/init.rb", + "test/application.rb", + "test/awesome_nested_set/helper_test.rb", + "test/awesome_nested_set_test.rb", + "test/db/database.yml", + "test/db/schema.rb", + "test/fixtures/categories.yml", + "test/fixtures/category.rb", + "test/fixtures/departments.yml", + "test/fixtures/notes.yml", + "test/test_helper.rb" + ] s.has_rdoc = true - s.extra_rdoc_files = [ "README.rdoc"] + s.homepage = %q{http://github.com/collectiveidea/awesome_nested_set} s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"] - - s.test_files = %w(test/awesome_nested_set_test.rb test/test_helper.rb test/awesome_nested_set/helper_test.rb test/db/database.yml test/db/schema.rb test/fixtures/categories.yml test/fixtures/category.rb test/fixtures/departments.yml test/fixtures/notes.yml) - s.require_path = 'lib' - s.author = "Collective Idea" - s.email = "info@collectiveidea.com" - s.homepage = "http://collectiveidea.com" + s.require_paths = ["lib"] + s.rubygems_version = %q{1.3.1} + s.summary = %q{An awesome nested set implementation for Active Record} + s.test_files = [ + "test/db/database.yml", + "test/fixtures/categories.yml", + "test/fixtures/departments.yml", + "test/fixtures/notes.yml", + "test/application.rb", + "test/awesome_nested_set/helper_test.rb", + "test/awesome_nested_set_test.rb", + "test/db/schema.rb", + "test/fixtures/category.rb", + "test/test_helper.rb" + ] + + if s.respond_to? :specification_version then + current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION + s.specification_version = 2 + + if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then + s.add_runtime_dependency(%q, [">= 1.1"]) + else + s.add_dependency(%q, [">= 1.1"]) + end + else + s.add_dependency(%q, [">= 1.1"]) + end end diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb index 3e10891..bafdf4c 100644 --- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb @@ -15,24 +15,11 @@ module CollectiveIdea #:nodoc: # # == API # - # Methods names are aligned with acts_as_tree as much as possible, to make replacment from one - # by another easier, except for the creation: + # Methods names are aligned with acts_as_tree as much as possible to make replacment from one + # by another easier. # - # in acts_as_tree: # item.children.create(:name => "child1") # - # in acts_as_nested_set: - # # adds a new item at the "end" of the tree, i.e. with child.left = max(tree.right)+1 - # child = MyClass.new(:name => "child1") - # child.save - # # now move the item to its right place - # child.move_to_child_of my_item - # - # You can pass an id or an object to: - # * #move_to_child_of - # * #move_to_right_of - # * #move_to_left_of - # module SingletonMethods # Configuration options are: # @@ -66,35 +53,43 @@ module CollectiveIdea #:nodoc: write_inheritable_attribute :acts_as_nested_set_options, options class_inheritable_reader :acts_as_nested_set_options - include Comparable - include Columns - include InstanceMethods - extend Columns - extend ClassMethods + unless self.is_a?(ClassMethods) + include Comparable + include Columns + include InstanceMethods + extend Columns + extend ClassMethods + + belongs_to :parent, :class_name => self.base_class.class_name, + :foreign_key => parent_column_name + has_many :children, :class_name => self.base_class.class_name, + :foreign_key => parent_column_name - # no bulk assignment - attr_protected left_column_name.intern, - right_column_name.intern, - parent_column_name.intern + attr_accessor :skip_before_destroy + + # no bulk assignment + attr_protected left_column_name.intern, + right_column_name.intern - before_create :set_default_left_and_right - before_destroy :prune_from_tree + before_create :set_default_left_and_right + before_save :store_new_parent + after_save :move_to_new_parent + before_destroy :destroy_descendants - # no assignment to structure fields - [left_column_name, right_column_name, parent_column_name].each do |column| - module_eval <<-"end_eval", __FILE__, __LINE__ - def #{column}=(x) - raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." - end - end_eval - end + # no assignment to structure fields + [left_column_name, right_column_name].each do |column| + module_eval <<-"end_eval", __FILE__, __LINE__ + def #{column}=(x) + raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." + end + end_eval + end - named_scope :roots, :conditions => {parent_column_name => nil}, :order => quoted_left_column_name - named_scope :leaves, :conditions => "#{quoted_right_column_name} - #{quoted_left_column_name} = 1", :order => quoted_left_column_name - if self.respond_to?(:define_callbacks) - define_callbacks("before_move", "after_move") - end + named_scope :roots, :conditions => {parent_column_name => nil}, :order => quoted_left_column_name + named_scope :leaves, :conditions => "#{quoted_right_column_name} - #{quoted_left_column_name} = 1", :order => quoted_left_column_name + define_callbacks("before_move", "after_move") if self.respond_to?(:define_callbacks) + end end @@ -192,6 +187,30 @@ module CollectiveIdea #:nodoc: set_left_and_rights.call(root_node) end end + + # Iterates over tree elements and determines the current level in the tree. + # Only accepts default ordering, odering by an other column than lft + # does not work. This method is much more efficent than calling level + # because it doesn't require any additional database queries. + # + # Example: + # Category.each_with_level(Category.root.self_and_descendants) do |o, level| + # + def each_with_level(objects) + path = [nil] + objects.each do |o| + if o.parent_id != path.last + # we are on a new level, did we decent or ascent? + if path.include?(o.parent_id) + # remove wrong wrong tailing paths elements + path.pop while path.last != o.parent_id + else + path << o.parent_id + end + end + yield(o, path.length - 1) + end + end end # Mixed into both classes and instances to provide easy access to the column names @@ -255,7 +274,7 @@ module CollectiveIdea #:nodoc: end def leaf? - right - left == 1 + !new_record? && right - left == 1 end # Returns true is this is a child node @@ -281,15 +300,10 @@ module CollectiveIdea #:nodoc: self_and_ancestors.find(:first) end - # Returns the immediate parent - def parent - nested_set_scope.find_by_id(parent_id) if parent_id - end - # Returns the array of all parents and self def self_and_ancestors nested_set_scope.scoped :conditions => [ - "#{self.class.table_name}.#{quoted_left_column_name} <= ? AND #{self.class.table_name}.#{quoted_right_column_name} >= ?", left, right + "#{self.class.quoted_table_name}.#{quoted_left_column_name} <= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} >= ?", left, right ] end @@ -310,7 +324,7 @@ module CollectiveIdea #:nodoc: # Returns a set of all of its nested children which do not have children def leaves - descendants.scoped :conditions => "#{self.class.table_name}.#{quoted_right_column_name} - #{self.class.table_name}.#{quoted_left_column_name} = 1" + descendants.scoped :conditions => "#{self.class.quoted_table_name}.#{quoted_right_column_name} - #{self.class.quoted_table_name}.#{quoted_left_column_name} = 1" end # Returns the level of this object in the tree @@ -322,7 +336,7 @@ module CollectiveIdea #:nodoc: # Returns a set of itself and all of its nested children def self_and_descendants nested_set_scope.scoped :conditions => [ - "#{self.class.table_name}.#{quoted_left_column_name} >= ? AND #{self.class.table_name}.#{quoted_right_column_name} <= ?", left, right + "#{self.class.quoted_table_name}.#{quoted_left_column_name} >= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} <= ?", left, right ] end @@ -331,11 +345,6 @@ module CollectiveIdea #:nodoc: without_self self_and_descendants end - # Returns a set of only this entry's immediate children - def children - nested_set_scope.scoped :conditions => {parent_column_name => self} - end - def is_descendant_of?(other) other.left < self.left && self.left < other.right && same_scope?(other) end @@ -361,13 +370,13 @@ module CollectiveIdea #:nodoc: # Find the first sibling to the left def left_sibling - siblings.find(:first, :conditions => ["#{self.class.table_name}.#{quoted_left_column_name} < ?", left], - :order => "#{self.class.table_name}.#{quoted_left_column_name} DESC") + siblings.find(:first, :conditions => ["#{self.class.quoted_table_name}.#{quoted_left_column_name} < ?", left], + :order => "#{self.class.quoted_table_name}.#{quoted_left_column_name} DESC") end # Find the first sibling to the right def right_sibling - siblings.find(:first, :conditions => ["#{self.class.table_name}.#{quoted_left_column_name} > ?", left]) + siblings.find(:first, :conditions => ["#{self.class.quoted_table_name}.#{quoted_left_column_name} > ?", left]) end # Shorthand method for finding the left sibling and moving to the left of it. @@ -417,7 +426,7 @@ module CollectiveIdea #:nodoc: protected def without_self(scope) - scope.scoped :conditions => ["#{self.class.table_name}.#{self.class.primary_key} != ?", self] + scope.scoped :conditions => ["#{self.class.quoted_table_name}.#{self.class.primary_key} != ?", self] end # All nested set queries should use this nested_set_scope, which performs finds on @@ -432,6 +441,19 @@ module CollectiveIdea #:nodoc: self.class.base_class.scoped options end + def store_new_parent + @move_to_new_parent_id = parent_id_changed? ? parent_id : false + true # force callback to return true + end + + def move_to_new_parent + if @move_to_new_parent_id.nil? + move_to_root + elsif @move_to_new_parent_id + move_to_child_of(@move_to_new_parent_id) + end + end + # on creation, set automatically lft and rgt to the end of the tree def set_default_left_and_right maxright = nested_set_scope.maximum(right_column_name) || 0 @@ -442,29 +464,38 @@ module CollectiveIdea #:nodoc: # Prunes a branch off of the tree, shifting all of the elements on the right # back to the left so the counts still work. - def prune_from_tree - return if right.nil? || left.nil? - diff = right - left + 1 - - delete_method = acts_as_nested_set_options[:dependent] == :destroy ? - :destroy_all : :delete_all - + def destroy_descendants + return if right.nil? || left.nil? || skip_before_destroy + self.class.base_class.transaction do - nested_set_scope.send(delete_method, - ["#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?", - left, right] - ) + if acts_as_nested_set_options[:dependent] == :destroy + descendants.each do |model| + model.skip_before_destroy = true + model.destroy + end + else + nested_set_scope.delete_all( + ["#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?", + left, right] + ) + end + + # update lefts and rights for remaining nodes + diff = right - left + 1 nested_set_scope.update_all( ["#{quoted_left_column_name} = (#{quoted_left_column_name} - ?)", diff], - ["#{quoted_left_column_name} >= ?", right] + ["#{quoted_left_column_name} > ?", right] ) nested_set_scope.update_all( ["#{quoted_right_column_name} = (#{quoted_right_column_name} - ?)", diff], - ["#{quoted_right_column_name} >= ?", right] + ["#{quoted_right_column_name} > ?", right] ) + + # Don't allow multiple calls to destroy to corrupt the set + self.skip_before_destroy = true end end - + # reload left, right, and parent def reload_nested_set reload(:select => "#{quoted_left_column_name}, " + diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/compatability.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/compatability.rb deleted file mode 100644 index 2d11da3..0000000 --- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/compatability.rb +++ /dev/null @@ -1,29 +0,0 @@ -# Rails <2.x doesn't define #except -class Hash #:nodoc: - # Returns a new hash without the given keys. - def except(*keys) - clone.except!(*keys) - end unless method_defined?(:except) - - # Replaces the hash without the given keys. - def except!(*keys) - keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) - keys.each { |key| delete(key) } - self - end unless method_defined?(:except!) -end - -# NamedScope is new to Rails 2.1 -unless defined? ActiveRecord::NamedScope - require 'awesome_nested_set/named_scope' - ActiveRecord::Base.class_eval do - include CollectiveIdea::NamedScope - end -end - -# Rails 1.2.x doesn't define #quoted_table_name -class ActiveRecord::Base #:nodoc: - def self.quoted_table_name - self.connection.quote_column_name(self.table_name) - end unless methods.include?('quoted_table_name') -end \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/named_scope.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/named_scope.rb deleted file mode 100644 index 1836498..0000000 --- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/named_scope.rb +++ /dev/null @@ -1,140 +0,0 @@ -# Taken from Rails 2.1 -module CollectiveIdea #:nodoc: - module NamedScope #:nodoc: - # All subclasses of ActiveRecord::Base have two named_scopes: - # * all, which is similar to a find(:all) query, and - # * scoped, which allows for the creation of anonymous scopes, on the fly: - # - # Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) - # - # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing - # intermediate values (scopes) around as first-class objects is convenient. - def self.included(base) - base.class_eval do - extend ClassMethods - named_scope :scoped, lambda { |scope| scope } - end - end - - module ClassMethods #:nodoc: - def scopes - read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {}) - end - - # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query, - # such as :conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions. - # - # class Shirt < ActiveRecord::Base - # named_scope :red, :conditions => {:color => 'red'} - # named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true] - # end - # - # The above calls to named_scope define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red, - # in effect, represents the query Shirt.find(:all, :conditions => {:color => 'red'}). - # - # Unlike Shirt.find(...), however, the object returned by Shirt.red is not an Array; it resembles the association object - # constructed by a has_many declaration. For instance, you can invoke Shirt.red.find(:first), Shirt.red.count, - # Shirt.red.find(:all, :conditions => {:size => 'small'}). Also, just - # as with the association objects, name scopes acts like an Array, implementing Enumerable; Shirt.red.each(&block), - # Shirt.red.first, and Shirt.red.inject(memo, &block) all behave as if Shirt.red really were an Array. - # - # These named scopes are composable. For instance, Shirt.red.dry_clean_only will produce all shirts that are both red and dry clean only. - # Nested finds and calculations also work with these compositions: Shirt.red.dry_clean_only.count returns the number of garments - # for which these criteria obtain. Similarly with Shirt.red.dry_clean_only.average(:thread_count). - # - # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to - # has_many associations. If, - # - # class Person < ActiveRecord::Base - # has_many :shirts - # end - # - # then elton.shirts.red.dry_clean_only will return all of Elton's red, dry clean - # only shirts. - # - # Named scopes can also be procedural. - # - # class Shirt < ActiveRecord::Base - # named_scope :colored, lambda { |color| - # { :conditions => { :color => color } } - # } - # end - # - # In this example, Shirt.colored('puce') finds all puce shirts. - # - # Named scopes can also have extensions, just as with has_many declarations: - # - # class Shirt < ActiveRecord::Base - # named_scope :red, :conditions => {:color => 'red'} do - # def dom_id - # 'red_shirts' - # end - # end - # end - # - # - # For testing complex named scopes, you can examine the scoping options using the - # proxy_options method on the proxy itself. - # - # class Shirt < ActiveRecord::Base - # named_scope :colored, lambda { |color| - # { :conditions => { :color => color } } - # } - # end - # - # expected_options = { :conditions => { :colored => 'red' } } - # assert_equal expected_options, Shirt.colored('red').proxy_options - def named_scope(name, options = {}, &block) - scopes[name] = lambda do |parent_scope, *args| - Scope.new(parent_scope, case options - when Hash - options - when Proc - options.call(*args) - end, &block) - end - (class << self; self end).instance_eval do - define_method name do |*args| - scopes[name].call(self, *args) - end - end - end - end - - class Scope #:nodoc: - attr_reader :proxy_scope, :proxy_options - [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } - delegate :scopes, :with_scope, :to => :proxy_scope - - def initialize(proxy_scope, options, &block) - [options[:extend]].flatten.each { |extension| extend extension } if options[:extend] - extend Module.new(&block) if block_given? - @proxy_scope, @proxy_options = proxy_scope, options.except(:extend) - end - - def reload - load_found; self - end - - protected - def proxy_found - @found || load_found - end - - private - def method_missing(method, *args, &block) - if scopes.include?(method) - scopes[method].call(self, *args) - else - with_scope :find => proxy_options do - proxy_scope.send(method, *args, &block) - end - end - end - - def load_found - @found = find(:all) - end - end - end -end \ 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 index e0a4e8b..2ff1336 100644 --- a/vendor/plugins/awesome_nested_set/rails/init.rb +++ b/vendor/plugins/awesome_nested_set/rails/init.rb @@ -1,4 +1,3 @@ -require 'awesome_nested_set/compatability' require 'awesome_nested_set' ActiveRecord::Base.class_eval do diff --git a/vendor/plugins/awesome_nested_set/test/application.rb b/vendor/plugins/awesome_nested_set/test/application.rb new file mode 100644 index 0000000..0e6eacf --- /dev/null +++ b/vendor/plugins/awesome_nested_set/test/application.rb @@ -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 index 6122a0e..888323c 100644 --- 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 @@ -1,9 +1,9 @@ -require File.dirname(__FILE__) + '/../test_helper' +require 'test_helper' module CollectiveIdea module Acts #:nodoc: module NestedSet #:nodoc: - class AwesomeNestedSetTest < Test::Unit::TestCase + class AwesomeNestedSetTest < TestCaseClass include Helper fixtures :categories @@ -38,4 +38,4 @@ module CollectiveIdea end end end -end \ No newline at end of file +end 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 index 5252d80..7da4504 100644 --- a/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb +++ b/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb @@ -1,19 +1,18 @@ -require File.dirname(__FILE__) + '/test_helper' +require 'test_helper' class Note < ActiveRecord::Base acts_as_nested_set :scope => [:notable_id, :notable_type] end +class Default < ActiveRecord::Base + acts_as_nested_set + set_table_name 'categories' +end +class ScopedCategory < ActiveRecord::Base + acts_as_nested_set :scope => :organization + set_table_name 'categories' +end -class AwesomeNestedSetTest < Test::Unit::TestCase - - class Default < ActiveRecord::Base - acts_as_nested_set - set_table_name 'categories' - end - class Scoped < ActiveRecord::Base - acts_as_nested_set :scope => :organization - set_table_name 'categories' - end +class AwesomeNestedSetTest < TestCaseClass def test_left_column_default assert_equal 'lft', Default.acts_as_nested_set_options[:left_column] @@ -66,19 +65,14 @@ class AwesomeNestedSetTest < Test::Unit::TestCase assert_raises(ActiveRecord::ActiveRecordError) { Category.new.rgt = 1 } end - def test_parent_column_protected_from_assignment - assert_raises(ActiveRecord::ActiveRecordError) { Category.new.parent_id = 1 } - end - def test_colums_protected_on_initialize - c = Category.new(:lft => 1, :rgt => 2, :parent_id => 3) + c = Category.new(:lft => 1, :rgt => 2) assert_nil c.lft assert_nil c.rgt - assert_nil c.parent_id end def test_scoped_appends_id - assert_equal :organization_id, Scoped.acts_as_nested_set_options[:scope] + assert_equal :organization_id, ScopedCategory.acts_as_nested_set_options[:scope] end def test_roots_class_method @@ -115,7 +109,9 @@ class AwesomeNestedSetTest < Test::Unit::TestCase assert !categories(:top_level).leaf? assert !categories(:child_2).leaf? + assert !Category.new.leaf? end + def test_parent assert_equal categories(:child_2), categories(:child_2_1).parent @@ -218,7 +214,7 @@ class AwesomeNestedSetTest < Test::Unit::TestCase end def test_is_or_is_ancestor_of_with_scope - root = Scoped.root + root = ScopedCategory.root child = root.children.first assert root.is_or_is_ancestor_of?(child) child.update_attribute :organization_id, 'different' @@ -244,7 +240,7 @@ class AwesomeNestedSetTest < Test::Unit::TestCase end def test_is_or_is_descendant_of_with_scope - root = Scoped.root + root = ScopedCategory.root child = root.children.first assert child.is_or_is_descendant_of?(root) child.update_attribute :organization_id, 'different' @@ -252,7 +248,7 @@ class AwesomeNestedSetTest < Test::Unit::TestCase end def test_same_scope? - root = Scoped.root + root = ScopedCategory.root child = root.children.first assert child.same_scope?(root) child.update_attribute :organization_id, 'different' @@ -600,4 +596,131 @@ class AwesomeNestedSetTest < Test::Unit::TestCase assert_not_equal notes(:scope1), notes(:scope2) end + def test_delete_does_not_invalidate + Category.acts_as_nested_set_options[:dependent] = :delete + categories(:child_2).destroy + assert Category.valid? + end + + def test_destroy_does_not_invalidate + Category.acts_as_nested_set_options[:dependent] = :destroy + categories(:child_2).destroy + assert Category.valid? + end + + def test_destroy_multiple_times_does_not_invalidate + Category.acts_as_nested_set_options[:dependent] = :destroy + categories(:child_2).destroy + categories(:child_2).destroy + assert Category.valid? + end + + def test_assigning_parent_id_on_create + category = Category.create!(:name => "Child", :parent_id => categories(:child_2).id) + assert_equal categories(:child_2), category.parent + assert_equal categories(:child_2).id, category.parent_id + assert_not_nil category.left + assert_not_nil category.right + assert Category.valid? + end + + def test_assigning_parent_on_create + category = Category.create!(:name => "Child", :parent => categories(:child_2)) + assert_equal categories(:child_2), category.parent + assert_equal categories(:child_2).id, category.parent_id + assert_not_nil category.left + assert_not_nil category.right + assert Category.valid? + end + + def test_assigning_parent_id_to_nil_on_create + category = Category.create!(:name => "New Root", :parent_id => nil) + assert_nil category.parent + assert_nil category.parent_id + assert_not_nil category.left + assert_not_nil category.right + assert Category.valid? + end + + def test_assigning_parent_id_on_update + category = categories(:child_2_1) + category.parent_id = categories(:child_3).id + category.save + assert_equal categories(:child_3), category.parent + assert_equal categories(:child_3).id, category.parent_id + assert Category.valid? + end + + def test_assigning_parent_on_update + category = categories(:child_2_1) + category.parent = categories(:child_3) + category.save + assert_equal categories(:child_3), category.parent + assert_equal categories(:child_3).id, category.parent_id + assert Category.valid? + end + + def test_assigning_parent_id_to_nil_on_update + category = categories(:child_2_1) + category.parent_id = nil + category.save + assert_nil category.parent + assert_nil category.parent_id + assert Category.valid? + end + + def test_creating_child_from_parent + category = categories(:child_2).children.create!(:name => "Child") + assert_equal categories(:child_2), category.parent + assert_equal categories(:child_2).id, category.parent_id + assert_not_nil category.left + assert_not_nil category.right + assert Category.valid? + end + + def check_structure(entries, structure) + structure = structure.dup + Category.each_with_level(entries) do |category, level| + expected_level, expected_name = structure.shift + assert_equal expected_name, category.name, "wrong category" + assert_equal expected_level, level, "wrong level for #{category.name}" + end + end + + def test_each_with_level + levels = [ + [0, "Top Level"], + [1, "Child 1"], + [1, "Child 2"], + [2, "Child 2.1"], + [1, "Child 3" ]] + + check_structure(Category.root.self_and_descendants, levels) + + # test some deeper structures + category = Category.find_by_name("Child 1") + c1 = Category.new(:name => "Child 1.1") + c2 = Category.new(:name => "Child 1.1.1") + c3 = Category.new(:name => "Child 1.1.1.1") + c4 = Category.new(:name => "Child 1.2") + [c1, c2, c3, c4].each(&:save!) + + c1.move_to_child_of(category) + c2.move_to_child_of(c1) + c3.move_to_child_of(c2) + c4.move_to_child_of(category) + + levels = [ + [0, "Top Level"], + [1, "Child 1"], + [2, "Child 1.1"], + [3, "Child 1.1.1"], + [4, "Child 1.1.1.1"], + [2, "Child 1.2"], + [1, "Child 2"], + [2, "Child 2.1"], + [1, "Child 3" ]] + + check_structure(Category.root.self_and_descendants, levels) + end end diff --git a/vendor/plugins/awesome_nested_set/test/test_helper.rb b/vendor/plugins/awesome_nested_set/test/test_helper.rb index 6939822..05d8855 100644 --- a/vendor/plugins/awesome_nested_set/test/test_helper.rb +++ b/vendor/plugins/awesome_nested_set/test/test_helper.rb @@ -1,17 +1,16 @@ $:.unshift(File.dirname(__FILE__) + '/../lib') plugin_test_dir = File.dirname(__FILE__) +RAILS_ROOT = plugin_test_dir require 'rubygems' require 'test/unit' require 'multi_rails_init' -# gem 'activerecord', '>= 2.0' -require 'active_record' -require 'action_controller' -require 'action_view' -require 'active_record/fixtures' +require 'test_help' require plugin_test_dir + '/../init.rb' +TestCaseClass = ActiveSupport::TestCase rescue Test::Unit::TestCase + ActiveRecord::Base.logger = Logger.new(plugin_test_dir + "/debug.log") ActiveRecord::Base.configurations = YAML::load(IO.read(plugin_test_dir + "/db/database.yml")) @@ -21,11 +20,10 @@ load(File.join(plugin_test_dir, "db", "schema.rb")) Dir["#{plugin_test_dir}/fixtures/*.rb"].each {|file| require file } - -class Test::Unit::TestCase #:nodoc: +class TestCaseClass #:nodoc: self.fixture_path = File.dirname(__FILE__) + "/fixtures/" self.use_transactional_fixtures = true self.use_instantiated_fixtures = false fixtures :categories, :notes, :departments -end \ No newline at end of file +end -- cgit v1.3