diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2012-04-25 17:17:49 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2012-04-25 17:17:49 +0000 |
commit | 5e57a1a9d9478162ac4f27ae96b2ccaf55a1aba7 (patch) | |
tree | 93e57765139714bd82dede475725516c448c0d55 /vendor/plugins | |
parent | 34e20c4373b7f5a20ab3a132feae3f70f21ec477 (diff) | |
download | redmine-5e57a1a9d9478162ac4f27ae96b2ccaf55a1aba7.tar.gz redmine-5e57a1a9d9478162ac4f27ae96b2ccaf55a1aba7.zip |
Merged rails-3.2 branch.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@9528 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'vendor/plugins')
155 files changed, 2753 insertions, 3891 deletions
diff --git a/vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb b/vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb index bba10c437..36442b2ad 100644 --- a/vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb +++ b/vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb @@ -377,10 +377,12 @@ module ActiveRecord #:nodoc: new_model.send("#{key}=", orig_model.send(key)) if orig_model.has_attribute?(key) end - if orig_model.is_a?(self.class.versioned_class) - new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column] - elsif new_model.is_a?(self.class.versioned_class) - new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column] + if self.class.columns_hash.include?(self.class.inheritance_column) + if orig_model.is_a?(self.class.versioned_class) + new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column] + elsif new_model.is_a?(self.class.versioned_class) + new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column] + end end end diff --git a/vendor/plugins/awesome_nested_set/.autotest b/vendor/plugins/awesome_nested_set/.autotest new file mode 100644 index 000000000..8614a6657 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/.autotest @@ -0,0 +1,13 @@ +Autotest.add_hook :initialize do |at|
+ at.clear_mappings
+
+ at.add_mapping %r%^lib/(.*)\.rb$% do |_, m|
+ at.files_matching %r%^test/#{m[1]}_test.rb$%
+ end
+
+ at.add_mapping(%r%^test/.*\.rb$%) {|filename, _| filename }
+
+ at.add_mapping %r%^test/fixtures/(.*)s.yml% do |_, _|
+ at.files_matching %r%^test/.*\.rb$%
+ end
+end
\ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/.travis.yml b/vendor/plugins/awesome_nested_set/.travis.yml new file mode 100644 index 000000000..8b9a87628 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/.travis.yml @@ -0,0 +1,14 @@ +notifications:
+ email:
+ - parndt@gmail.com
+env:
+ - DB=sqlite3
+ - DB=sqlite3mem
+ - DB=postgresql
+ - DB=mysql
+rvm:
+ - 1.8.7
+ - 1.9.2
+ - 1.9.3
+ - rbx-2.0
+ - jruby
\ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/CHANGELOG b/vendor/plugins/awesome_nested_set/CHANGELOG new file mode 100644 index 000000000..140164fcf --- /dev/null +++ b/vendor/plugins/awesome_nested_set/CHANGELOG @@ -0,0 +1,14 @@ +2.0.2 +* Fixed deprecation warning under Rails 3.1 [Philip Arndt] +* Converted Test::Unit matchers to RSpec. [UÄ£is Ozols] +* Added inverse_of to associations to improve performance rendering trees. [Sergio Cambra] +* Added row locking and fixed some race conditions. [Markus J. Q. Roberts] + +2.0.1 +* Fixed a bug with move_to not using nested_set_scope [Andreas Sekine] + +2.0.0.pre +* Expect Rails 3 +* Changed how callbacks work. Returning false in a before_move action does not block save operations. Use a validation or exception in the callback if you need that. +* Switched to RSpec +* Remove use of Comparable diff --git a/vendor/plugins/awesome_nested_set/MIT-LICENSE b/vendor/plugins/awesome_nested_set/MIT-LICENSE index 570ecf870..7cdb82927 100644 --- a/vendor/plugins/awesome_nested_set/MIT-LICENSE +++ b/vendor/plugins/awesome_nested_set/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2007 [name of plugin creator] +Copyright (c) 2007-2011 Collective Idea Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/vendor/plugins/awesome_nested_set/README.rdoc b/vendor/plugins/awesome_nested_set/README.rdoc index c093f751d..6a7380b60 100644 --- a/vendor/plugins/awesome_nested_set/README.rdoc +++ b/vendor/plugins/awesome_nested_set/README.rdoc @@ -1,6 +1,8 @@ = 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 more awesome. + +Version 2 supports Rails 3. Gem versions prior to 2.0 support Rails 2. == What makes this so awesome? @@ -8,10 +10,10 @@ This is a new implementation of nested set based off of BetterNestedSet that fix == Installation -If you are on Rails 2.1 or later: + Add to your Gemfile: + + gem 'awesome_nested_set' - script/plugin install git://github.com/collectiveidea/awesome_nested_set.git - == Usage To make use of awesome_nested_set, your model needs to have 3 fields: lft, rgt, and parent_id: @@ -36,12 +38,36 @@ Enable the nested set functionality by declaring acts_as_nested_set on your mode class Category < ActiveRecord::Base acts_as_nested_set end - -Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::SingletonMethods for more info. + +Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet for more info. + +== Protecting attributes from mass assignment + +It's generally best to "white list" the attributes that can be used in mass assignment: + + class Category < ActiveRecord::Base + acts_as_nested_set + attr_accessible :name, :parent_id + end + +If for some reason that is not possible, you will probably want to protect the lft and rgt attributes: + + class Category < ActiveRecord::Base + acts_as_nested_set + attr_protected :lft, :rgt + end + +== Conversion from other trees + +Coming from acts_as_tree or another system where you only have a parent_id? No problem. Simply add the lft & rgt fields as above, and then run + + Category.rebuild! + +Your tree will be converted to a valid nested set. Awesome! == View Helper -The view helper is called #nested_set_options. +The view helper is called #nested_set_options. Example usage: @@ -53,12 +79,22 @@ See CollectiveIdea::Acts::NestedSet::Helper for more information about the helpe == References -You can learn more about nested sets at: +You can learn more about nested sets at: http://threebit.net/tutorials/nestedset/tutorial1.html + +== How to contribute + +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. - http://www.dbmsmag.com/9603d06.html - http://threebit.net/tutorials/nestedset/tutorial1.html - http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html - http://opensource.symetrie.com/trac/better_nested_set/ +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 (c) 2008 Collective Idea, released under the MIT license
\ No newline at end of file +Copyright ©2008 Collective Idea, released under the MIT license diff --git a/vendor/plugins/awesome_nested_set/Rakefile b/vendor/plugins/awesome_nested_set/Rakefile index 53906f68b..b913bc5e2 100644 --- a/vendor/plugins/awesome_nested_set/Rakefile +++ b/vendor/plugins/awesome_nested_set/Rakefile @@ -1,30 +1,23 @@ -require 'rake' -require 'rake/testtask' -require 'rake/rdoctask' -require 'rake/gempackagetask' -require 'rcov/rcovtask' -require "load_multi_rails_rake_tasks" +# -*- encoding: utf-8 -*- +$LOAD_PATH.unshift File.expand_path("../lib", __FILE__) +require 'rubygems' +require 'bundler/setup' +require 'awesome_nested_set/version' -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 -end +require "rspec/core/rake_task" +RSpec::Core::RakeTask.new(:spec) +task :default => :spec -desc 'Default: run unit tests.' -task :default => :test +task :build do + system "gem build awesome_nested_set.gemspec" +end -desc 'Test the awesome_nested_set plugin.' -Rake::TestTask.new(:test) do |t| - t.libs << 'lib' - t.pattern = 'test/**/*_test.rb' - t.verbose = true +task :release => :build do + system "gem push awesome_nested_set-#{ActsAsGeocodable::VERSION}.gem" end +require 'rdoc/task' desc 'Generate documentation for the awesome_nested_set plugin.' Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.rdoc_dir = 'rdoc' @@ -33,14 +26,3 @@ Rake::RDocTask.new(:rdoc) do |rdoc| rdoc.rdoc_files.include('README.rdoc') rdoc.rdoc_files.include('lib/**/*.rb') end - -namespace :test do - desc "just rcov minus html output" - Rcov::RcovTask.new(:coverage) do |t| - # t.libs << 'test' - t.test_files = FileList['test/**/*_test.rb'] - t.output_dir = 'coverage' - t.verbose = true - t.rcov_opts = %w(--exclude test,/usr/lib/ruby,/Library/Ruby,lib/awesome_nested_set/named_scope.rb --sort coverage) - end -end
\ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec b/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec index c5a1d49e5..8e85d6733 100644 --- a/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec +++ b/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec @@ -1,20 +1,22 @@ +# -*- encoding: utf-8 -*- +lib = File.expand_path('../lib/', __FILE__) +$:.unshift lib unless $:.include?(lib) +require 'awesome_nested_set/version' + 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.has_rdoc = true - s.extra_rdoc_files = [ "README.rdoc"] + s.name = %q{awesome_nested_set} + s.version = ::AwesomeNestedSet::VERSION + s.authors = ["Brandon Keepers", "Daniel Morrison", "Philip Arndt"] + 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 = Dir.glob("lib/**/*") + %w(MIT-LICENSE README.rdoc CHANGELOG) + 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.6} + s.summary = %q{An awesome nested set implementation for Active Record} + s.add_runtime_dependency 'activerecord', '>= 3.0.0' end diff --git a/vendor/plugins/awesome_nested_set/init.rb b/vendor/plugins/awesome_nested_set/init.rb index 43dc7c274..a505b6acf 100644 --- a/vendor/plugins/awesome_nested_set/init.rb +++ b/vendor/plugins/awesome_nested_set/init.rb @@ -1 +1 @@ -require File.dirname(__FILE__) + "/rails/init" +require File.dirname(__FILE__) + '/lib/awesome_nested_set'
\ No newline at end of file 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 e14b9d75f..022044275 100644 --- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb @@ -1,554 +1,7 @@ -module CollectiveIdea #:nodoc: - module Acts #:nodoc: - module NestedSet #:nodoc: - def self.included(base) - base.extend(SingletonMethods) - end +require 'awesome_nested_set/awesome_nested_set' +ActiveRecord::Base.send :extend, CollectiveIdea::Acts::NestedSet - # This acts provides Nested Set functionality. Nested Set is a smart way to implement - # an _ordered_ tree, with the added feature that you can select the children and all of their - # descendants with a single query. The drawback is that insertion or move need some complex - # sql queries. But everything is done here by this module! - # - # Nested sets are appropriate each time you want either an orderd tree (menus, - # commercial categories) or an efficient way of querying big trees (threaded posts). - # - # == 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: - # - # 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: - # * <tt>#move_to_child_of</tt> - # * <tt>#move_to_right_of</tt> - # * <tt>#move_to_left_of</tt> - # - module SingletonMethods - # Configuration options are: - # - # * +:parent_column+ - specifies the column name to use for keeping the position integer (default: parent_id) - # * +:left_column+ - column name for left boundry data, default "lft" - # * +:right_column+ - column name for right boundry data, default "rgt" - # * +:scope+ - restricts what is to be considered a list. Given a symbol, it'll attach "_id" - # (if it hasn't been already) and use that as the foreign key restriction. You - # can also pass an array to scope by multiple attributes. - # Example: <tt>acts_as_nested_set :scope => [:notable_id, :notable_type]</tt> - # * +:dependent+ - behavior for cascading destroy. If set to :destroy, all the - # child objects are destroyed alongside this object by calling their destroy - # method. If set to :delete_all (default), all the child objects are deleted - # without calling their destroy method. - # - # See CollectiveIdea::Acts::NestedSet::ClassMethods for a list of class methods and - # CollectiveIdea::Acts::NestedSet::InstanceMethods for a list of instance methods added - # to acts_as_nested_set models - def acts_as_nested_set(options = {}) - options = { - :parent_column => 'parent_id', - :left_column => 'lft', - :right_column => 'rgt', - :order => 'id', - :dependent => :delete_all, # or :destroy - }.merge(options) - - if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/ - options[:scope] = "#{options[:scope]}_id".intern - end - - 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 - - # no bulk assignment - attr_protected left_column_name.intern, - right_column_name.intern, - parent_column_name.intern - - before_create :set_default_left_and_right - before_destroy :prune_from_tree - - # 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 - - 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 - - - end - - end - - module ClassMethods - - # Returns the first root - def root - roots.find(:first) - end - - def valid? - left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid? - end - - def left_and_rights_valid? - count( - :joins => "LEFT OUTER JOIN #{quoted_table_name} AS parent ON " + - "#{quoted_table_name}.#{quoted_parent_column_name} = parent.#{primary_key}", - :conditions => - "#{quoted_table_name}.#{quoted_left_column_name} IS NULL OR " + - "#{quoted_table_name}.#{quoted_right_column_name} IS NULL OR " + - "#{quoted_table_name}.#{quoted_left_column_name} >= " + - "#{quoted_table_name}.#{quoted_right_column_name} OR " + - "(#{quoted_table_name}.#{quoted_parent_column_name} IS NOT NULL AND " + - "(#{quoted_table_name}.#{quoted_left_column_name} <= parent.#{quoted_left_column_name} OR " + - "#{quoted_table_name}.#{quoted_right_column_name} >= parent.#{quoted_right_column_name}))" - ) == 0 - end - - def no_duplicates_for_columns? - scope_string = Array(acts_as_nested_set_options[:scope]).map do |c| - connection.quote_column_name(c) - end.push(nil).join(", ") - [quoted_left_column_name, quoted_right_column_name].all? do |column| - # No duplicates - find(:first, - :select => "#{scope_string}#{column}, COUNT(#{column})", - :group => "#{scope_string}#{column} - HAVING COUNT(#{column}) > 1").nil? - end - end - - # Wrapper for each_root_valid? that can deal with scope. - def all_roots_valid? - if acts_as_nested_set_options[:scope] - roots(:group => scope_column_names).group_by{|record| scope_column_names.collect{|col| record.send(col.to_sym)}}.all? do |scope, grouped_roots| - each_root_valid?(grouped_roots) - end - else - each_root_valid?(roots) - end - end - - def each_root_valid?(roots_to_validate) - left = right = 0 - roots_to_validate.all? do |root| - (root.left > left && root.right > right).tap do - left = root.left - right = root.right - end - end - end - - # Rebuilds the left & rights if unset or invalid. Also very useful for converting from acts_as_tree. - def rebuild!(force=false) - # Don't rebuild a valid tree. - # valid? doesn't strictly validate the tree - return true if !force && valid? - - scope = lambda{|node|} - if acts_as_nested_set_options[:scope] - scope = lambda{|node| - scope_column_names.inject(""){|str, column_name| - str << "AND #{connection.quote_column_name(column_name)} = #{connection.quote(node.send(column_name.to_sym))} " - } - } - end - indices = {} - - set_left_and_rights = lambda do |node| - # set left - node[left_column_name] = indices[scope.call(node)] += 1 - # find - find(:all, :conditions => ["#{quoted_parent_column_name} = ? #{scope.call(node)}", node], :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, #{acts_as_nested_set_options[:order]}").each{|n| set_left_and_rights.call(n) } - # set right - node[right_column_name] = indices[scope.call(node)] += 1 - node.save! - end - - # Find root node(s) - root_nodes = find(:all, :conditions => "#{quoted_parent_column_name} IS NULL", :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, #{acts_as_nested_set_options[:order]}").each do |root_node| - # setup index for this scope - indices[scope.call(root_node)] ||= 0 - set_left_and_rights.call(root_node) - end - end - end - - # Mixed into both classes and instances to provide easy access to the column names - module Columns - def left_column_name - acts_as_nested_set_options[:left_column] - end - - def right_column_name - acts_as_nested_set_options[:right_column] - end - - def parent_column_name - acts_as_nested_set_options[:parent_column] - end - - def scope_column_names - Array(acts_as_nested_set_options[:scope]) - end - - def quoted_left_column_name - connection.quote_column_name(left_column_name) - end - - def quoted_right_column_name - connection.quote_column_name(right_column_name) - end - - def quoted_parent_column_name - connection.quote_column_name(parent_column_name) - end - - def quoted_scope_column_names - scope_column_names.collect {|column_name| connection.quote_column_name(column_name) } - end - end - - # 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. - # - # category.self_and_descendants.count - # category.ancestors.find(:all, :conditions => "name like '%foo%'") - module InstanceMethods - # Value of the parent column - def parent_id - self[parent_column_name] - end - - # Value of the left column - def left - self[left_column_name] - end - - # Value of the right column - def right - self[right_column_name] - end - - # Returns true if this is a root node. - def root? - parent_id.nil? - end - - def leaf? - new_record? || (right - left == 1) - end - - # Returns true is this is a child node - def child? - !parent_id.nil? - end - - # order by left column - def <=>(x) - left <=> x.left - end - - # Redefine to act like active record - def ==(comparison_object) - comparison_object.equal?(self) || - (comparison_object.instance_of?(self.class) && - comparison_object.id == id && - !comparison_object.new_record?) - end - - # Returns root - def root - 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 - ] - end - - # Returns an array of all parents - def ancestors - without_self self_and_ancestors - end - - # Returns the array of all children of the parent, including self - def self_and_siblings - nested_set_scope.scoped :conditions => {parent_column_name => parent_id} - end - - # Returns the array of all children of the parent, except self - def siblings - without_self self_and_siblings - end - - # 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" - end - - # Returns the level of this object in the tree - # root level is 0 - def level - parent_id.nil? ? 0 : ancestors.count - end - - # 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 - ] - end - - # Returns a set of all of its children and nested children - def descendants - 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 - - def is_or_is_descendant_of?(other) - other.left <= self.left && self.left < other.right && same_scope?(other) - end - - def is_ancestor_of?(other) - self.left < other.left && other.left < self.right && same_scope?(other) - end - - def is_or_is_ancestor_of?(other) - self.left <= other.left && other.left < self.right && same_scope?(other) - end - - # Check if other model is in the same scope - def same_scope?(other) - Array(acts_as_nested_set_options[:scope]).all? do |attr| - self.send(attr) == other.send(attr) - end - end - - # 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") - end - - # Find the first sibling to the right - def right_sibling - siblings.find(:first, :conditions => ["#{self.class.table_name}.#{quoted_left_column_name} > ?", left]) - end - - # Shorthand method for finding the left sibling and moving to the left of it. - def move_left - move_to_left_of left_sibling - end - - # Shorthand method for finding the right sibling and moving to the right of it. - def move_right - move_to_right_of right_sibling - end - - # Move the node to the left of another node (you can pass id only) - def move_to_left_of(node) - move_to node, :left - end - - # Move the node to the left of another node (you can pass id only) - def move_to_right_of(node) - move_to node, :right - end - - # Move the node to the child of another node (you can pass id only) - def move_to_child_of(node) - move_to node, :child - end - - # Move the node to root nodes - def move_to_root - move_to nil, :root - end - - def move_possible?(target) - self != target && # Can't target self - same_scope?(target) && # can't be in different scopes - # !(left..right).include?(target.left..target.right) # this needs tested more - # detect impossible move - !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right)) - end - - def to_text - self_and_descendants.map do |node| - "#{'*'*(node.level+1)} #{node.id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})" - end.join("\n") - end - - protected - - def without_self(scope) - scope.scoped :conditions => ["#{self.class.table_name}.#{self.class.primary_key} != ?", self] - end - - # All nested set queries should use this nested_set_scope, which performs finds on - # the base ActiveRecord class, using the :scope declared in the acts_as_nested_set - # declaration. - def nested_set_scope - options = {:order => "#{self.class.table_name}.#{quoted_left_column_name}"} - scopes = Array(acts_as_nested_set_options[:scope]) - options[:conditions] = scopes.inject({}) do |conditions,attr| - conditions.merge attr => self[attr] - end unless scopes.empty? - self.class.base_class.scoped options - 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 - # adds the new node to the right of all existing nodes - self[left_column_name] = maxright + 1 - self[right_column_name] = maxright + 2 - end - - # 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? || !self.class.exists?(id) - - self.class.base_class.transaction do - reload_nested_set - if acts_as_nested_set_options[:dependent] == :destroy - children.each(&:destroy) - else - nested_set_scope.send(:delete_all, - ["#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?", - left, right] - ) - end - reload_nested_set - diff = right - left + 1 - nested_set_scope.update_all( - ["#{quoted_left_column_name} = (#{quoted_left_column_name} - ?)", diff], - ["#{quoted_left_column_name} >= ?", right] - ) - nested_set_scope.update_all( - ["#{quoted_right_column_name} = (#{quoted_right_column_name} - ?)", diff], - ["#{quoted_right_column_name} >= ?", right] - ) - end - - # Reload is needed because children may have updated their parent (self) during deletion. - reload - end - - # reload left, right, and parent - def reload_nested_set - reload(:select => "#{quoted_left_column_name}, " + - "#{quoted_right_column_name}, #{quoted_parent_column_name}") - end - - def move_to(target, position) - raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if self.new_record? - return if callback(:before_move) == false - transaction do - if target.is_a? self.class.base_class - target.reload_nested_set - elsif position != :root - # load object if node is not an object - target = nested_set_scope.find(target) - end - self.reload_nested_set - - unless position == :root || move_possible?(target) - raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree." - end - - bound = case position - when :child; target[right_column_name] - when :left; target[left_column_name] - when :right; target[right_column_name] + 1 - when :root; 1 - else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left, :right or :root ('#{position}' received)." - end - - if bound > self[right_column_name] - bound = bound - 1 - other_bound = self[right_column_name] + 1 - else - other_bound = self[left_column_name] - 1 - end - - # there would be no change - return if bound == self[right_column_name] || bound == self[left_column_name] - - # we have defined the boundaries of two non-overlapping intervals, - # so sorting puts both the intervals and their boundaries in order - a, b, c, d = [self[left_column_name], self[right_column_name], bound, other_bound].sort - - new_parent = case position - when :child; target.id - when :root; nil - else target[parent_column_name] - end - - self.class.base_class.update_all([ - "#{quoted_left_column_name} = CASE " + - "WHEN #{quoted_left_column_name} BETWEEN :a AND :b " + - "THEN #{quoted_left_column_name} + :d - :b " + - "WHEN #{quoted_left_column_name} BETWEEN :c AND :d " + - "THEN #{quoted_left_column_name} + :a - :c " + - "ELSE #{quoted_left_column_name} END, " + - "#{quoted_right_column_name} = CASE " + - "WHEN #{quoted_right_column_name} BETWEEN :a AND :b " + - "THEN #{quoted_right_column_name} + :d - :b " + - "WHEN #{quoted_right_column_name} BETWEEN :c AND :d " + - "THEN #{quoted_right_column_name} + :a - :c " + - "ELSE #{quoted_right_column_name} END, " + - "#{quoted_parent_column_name} = CASE " + - "WHEN #{self.class.base_class.primary_key} = :id THEN :new_parent " + - "ELSE #{quoted_parent_column_name} END", - {:a => a, :b => b, :c => c, :d => d, :id => self.id, :new_parent => new_parent} - ], nested_set_scope.proxy_options[:conditions]) - end - target.reload_nested_set if target - self.reload_nested_set - callback(:after_move) - end - - end - - end - end -end +if defined?(ActionView) + require 'awesome_nested_set/helper' + ActionView::Base.send :include, CollectiveIdea::Acts::NestedSet::Helper +end
\ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/awesome_nested_set.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/awesome_nested_set.rb new file mode 100644 index 000000000..9608806c6 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/awesome_nested_set.rb @@ -0,0 +1,603 @@ +module CollectiveIdea #:nodoc: + module Acts #:nodoc: + module NestedSet #:nodoc: + + # This acts provides Nested Set functionality. Nested Set is a smart way to implement + # an _ordered_ tree, with the added feature that you can select the children and all of their + # descendants with a single query. The drawback is that insertion or move need some complex + # sql queries. But everything is done here by this module! + # + # Nested sets are appropriate each time you want either an orderd tree (menus, + # commercial categories) or an efficient way of querying big trees (threaded posts). + # + # == API + # + # Methods names are aligned with acts_as_tree as much as possible to make replacment from one + # by another easier. + # + # item.children.create(:name => "child1") + # + + # Configuration options are: + # + # * +:parent_column+ - specifies the column name to use for keeping the position integer (default: parent_id) + # * +:left_column+ - column name for left boundry data, default "lft" + # * +:right_column+ - column name for right boundry data, default "rgt" + # * +:scope+ - restricts what is to be considered a list. Given a symbol, it'll attach "_id" + # (if it hasn't been already) and use that as the foreign key restriction. You + # can also pass an array to scope by multiple attributes. + # Example: <tt>acts_as_nested_set :scope => [:notable_id, :notable_type]</tt> + # * +:dependent+ - behavior for cascading destroy. If set to :destroy, all the + # child objects are destroyed alongside this object by calling their destroy + # method. If set to :delete_all (default), all the child objects are deleted + # without calling their destroy method. + # * +:counter_cache+ adds a counter cache for the number of children. + # defaults to false. + # Example: <tt>acts_as_nested_set :counter_cache => :children_count</tt> + # + # See CollectiveIdea::Acts::NestedSet::Model::ClassMethods for a list of class methods and + # CollectiveIdea::Acts::NestedSet::Model::InstanceMethods for a list of instance methods added + # to acts_as_nested_set models + def acts_as_nested_set(options = {}) + options = { + :parent_column => 'parent_id', + :left_column => 'lft', + :right_column => 'rgt', + :dependent => :delete_all, # or :destroy + :counter_cache => false, + :order => 'id' + }.merge(options) + + if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/ + options[:scope] = "#{options[:scope]}_id".intern + end + + class_attribute :acts_as_nested_set_options + self.acts_as_nested_set_options = options + + include CollectiveIdea::Acts::NestedSet::Model + include Columns + extend Columns + + belongs_to :parent, :class_name => self.base_class.to_s, + :foreign_key => parent_column_name, + :counter_cache => options[:counter_cache], + :inverse_of => :children + has_many :children, :class_name => self.base_class.to_s, + :foreign_key => parent_column_name, :order => left_column_name, + :inverse_of => :parent, + :before_add => options[:before_add], + :after_add => options[:after_add], + :before_remove => options[:before_remove], + :after_remove => options[:after_remove] + + attr_accessor :skip_before_destroy + + 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].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 + + define_model_callbacks :move + end + + module Model + extend ActiveSupport::Concern + + module ClassMethods + # Returns the first root + def root + roots.first + end + + def roots + where(parent_column_name => nil).order(quoted_left_column_name) + end + + def leaves + where("#{quoted_right_column_name} - #{quoted_left_column_name} = 1").order(quoted_left_column_name) + end + + def valid? + left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid? + end + + def left_and_rights_valid? + joins("LEFT OUTER JOIN #{quoted_table_name} AS parent ON " + + "#{quoted_table_name}.#{quoted_parent_column_name} = parent.#{primary_key}"). + where( + "#{quoted_table_name}.#{quoted_left_column_name} IS NULL OR " + + "#{quoted_table_name}.#{quoted_right_column_name} IS NULL OR " + + "#{quoted_table_name}.#{quoted_left_column_name} >= " + + "#{quoted_table_name}.#{quoted_right_column_name} OR " + + "(#{quoted_table_name}.#{quoted_parent_column_name} IS NOT NULL AND " + + "(#{quoted_table_name}.#{quoted_left_column_name} <= parent.#{quoted_left_column_name} OR " + + "#{quoted_table_name}.#{quoted_right_column_name} >= parent.#{quoted_right_column_name}))" + ).count == 0 + end + + def no_duplicates_for_columns? + scope_string = Array(acts_as_nested_set_options[:scope]).map do |c| + connection.quote_column_name(c) + end.push(nil).join(", ") + [quoted_left_column_name, quoted_right_column_name].all? do |column| + # No duplicates + select("#{scope_string}#{column}, COUNT(#{column})"). + group("#{scope_string}#{column}"). + having("COUNT(#{column}) > 1"). + first.nil? + end + end + + # Wrapper for each_root_valid? that can deal with scope. + def all_roots_valid? + if acts_as_nested_set_options[:scope] + roots.group(scope_column_names).group_by{|record| scope_column_names.collect{|col| record.send(col.to_sym)}}.all? do |scope, grouped_roots| + each_root_valid?(grouped_roots) + end + else + each_root_valid?(roots) + end + end + + def each_root_valid?(roots_to_validate) + left = right = 0 + roots_to_validate.all? do |root| + (root.left > left && root.right > right).tap do + left = root.left + right = root.right + end + end + end + + # Rebuilds the left & rights if unset or invalid. + # Also very useful for converting from acts_as_tree. + def rebuild!(validate_nodes = true) + # Don't rebuild a valid tree. + return true if valid? + + scope = lambda{|node|} + if acts_as_nested_set_options[:scope] + scope = lambda{|node| + scope_column_names.inject(""){|str, column_name| + str << "AND #{connection.quote_column_name(column_name)} = #{connection.quote(node.send(column_name.to_sym))} " + } + } + end + indices = {} + + set_left_and_rights = lambda do |node| + # set left + node[left_column_name] = indices[scope.call(node)] += 1 + # find + where(["#{quoted_parent_column_name} = ? #{scope.call(node)}", node]).order(acts_as_nested_set_options[:order]).each{|n| set_left_and_rights.call(n) } + # set right + node[right_column_name] = indices[scope.call(node)] += 1 + node.save!(:validate => validate_nodes) + end + + # Find root node(s) + root_nodes = where("#{quoted_parent_column_name} IS NULL").order("#{quoted_left_column_name}, #{quoted_right_column_name}, id").each do |root_node| + # setup index for this scope + indices[scope.call(root_node)] ||= 0 + 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 + + # 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. + # + # category.self_and_descendants.count + # category.ancestors.find(:all, :conditions => "name like '%foo%'") + module InstanceMethods + # Value of the parent column + def parent_id + self[parent_column_name] + end + + # Value of the left column + def left + self[left_column_name] + end + + # Value of the right column + def right + self[right_column_name] + end + + # Returns true if this is a root node. + def root? + parent_id.nil? + end + + def leaf? + new_record? || (right - left == 1) + end + + # Returns true is this is a child node + def child? + !parent_id.nil? + end + + # Returns root + def root + self_and_ancestors.where(parent_column_name => nil).first + end + + # Returns the array of all parents and self + def self_and_ancestors + nested_set_scope.where([ + "#{self.class.quoted_table_name}.#{quoted_left_column_name} <= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} >= ?", left, right + ]) + end + + # Returns an array of all parents + def ancestors + without_self self_and_ancestors + end + + # Returns the array of all children of the parent, including self + def self_and_siblings + nested_set_scope.where(parent_column_name => parent_id) + end + + # Returns the array of all children of the parent, except self + def siblings + without_self self_and_siblings + end + + # Returns a set of all of its nested children which do not have children + def leaves + descendants.where("#{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 + # root level is 0 + def level + parent_id.nil? ? 0 : ancestors.count + end + + # Returns a set of itself and all of its nested children + def self_and_descendants + nested_set_scope.where([ + "#{self.class.quoted_table_name}.#{quoted_left_column_name} >= ? AND #{self.class.quoted_table_name}.#{quoted_right_column_name} <= ?", left, right + ]) + end + + # Returns a set of all of its children and nested children + def descendants + without_self self_and_descendants + end + + def is_descendant_of?(other) + other.left < self.left && self.left < other.right && same_scope?(other) + end + + def is_or_is_descendant_of?(other) + other.left <= self.left && self.left < other.right && same_scope?(other) + end + + def is_ancestor_of?(other) + self.left < other.left && other.left < self.right && same_scope?(other) + end + + def is_or_is_ancestor_of?(other) + self.left <= other.left && other.left < self.right && same_scope?(other) + end + + # Check if other model is in the same scope + def same_scope?(other) + Array(acts_as_nested_set_options[:scope]).all? do |attr| + self.send(attr) == other.send(attr) + end + end + + # Find the first sibling to the left + def left_sibling + siblings.where(["#{self.class.quoted_table_name}.#{quoted_left_column_name} < ?", left]). + order("#{self.class.quoted_table_name}.#{quoted_left_column_name} DESC").last + end + + # Find the first sibling to the right + def right_sibling + siblings.where(["#{self.class.quoted_table_name}.#{quoted_left_column_name} > ?", left]).first + end + + # Shorthand method for finding the left sibling and moving to the left of it. + def move_left + move_to_left_of left_sibling + end + + # Shorthand method for finding the right sibling and moving to the right of it. + def move_right + move_to_right_of right_sibling + end + + # Move the node to the left of another node (you can pass id only) + def move_to_left_of(node) + move_to node, :left + end + + # Move the node to the left of another node (you can pass id only) + def move_to_right_of(node) + move_to node, :right + end + + # Move the node to the child of another node (you can pass id only) + def move_to_child_of(node) + move_to node, :child + end + + # Move the node to root nodes + def move_to_root + move_to nil, :root + end + + def move_possible?(target) + self != target && # Can't target self + same_scope?(target) && # can't be in different scopes + # !(left..right).include?(target.left..target.right) # this needs tested more + # detect impossible move + !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right)) + end + + def to_text + self_and_descendants.map do |node| + "#{'*'*(node.level+1)} #{node.id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})" + end.join("\n") + end + + protected + + def without_self(scope) + scope.where(["#{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 + # the base ActiveRecord class, using the :scope declared in the acts_as_nested_set + # declaration. + def nested_set_scope(options = {}) + options = {:order => "#{self.class.quoted_table_name}.#{quoted_left_column_name}"}.merge(options) + scopes = Array(acts_as_nested_set_options[:scope]) + options[:conditions] = scopes.inject({}) do |conditions,attr| + conditions.merge attr => self[attr] + end unless scopes.empty? + self.class.base_class.scoped options + end + + def store_new_parent + @move_to_new_parent_id = send("#{parent_column_name}_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 + highest_right_row = nested_set_scope(:order => "#{quoted_right_column_name} desc").find(:first, :limit => 1,:lock => true ) + maxright = highest_right_row ? (highest_right_row[right_column_name] || 0) : 0 + # adds the new node to the right of all existing nodes + self[left_column_name] = maxright + 1 + self[right_column_name] = maxright + 2 + end + + def in_tenacious_transaction(&block) + retry_count = 0 + begin + transaction(&block) + rescue ActiveRecord::StatementInvalid => error + raise unless connection.open_transactions.zero? + raise unless error.message =~ /Deadlock found when trying to get lock|Lock wait timeout exceeded/ + raise unless retry_count < 10 + retry_count += 1 + logger.info "Deadlock detected on retry #{retry_count}, restarting transaction" + sleep(rand(retry_count)*0.1) # Aloha protocol + retry + end + end + + # 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 destroy_descendants + return if right.nil? || left.nil? || skip_before_destroy + + in_tenacious_transaction do + reload_nested_set + # select the rows in the model that extend past the deletion point and apply a lock + self.class.base_class.find(:all, + :select => "id", + :conditions => ["#{quoted_left_column_name} >= ?", left], + :lock => true + ) + + 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] + ) + nested_set_scope.update_all( + ["#{quoted_right_column_name} = (#{quoted_right_column_name} - ?)", diff], + ["#{quoted_right_column_name} > ?", right] + ) + +reload + # 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}, #{quoted_right_column_name}, #{quoted_parent_column_name}", + :lock => true + ) + end + + def move_to(target, position) + raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if self.new_record? + run_callbacks :move do + in_tenacious_transaction do + if target.is_a? self.class.base_class + target.reload_nested_set + elsif position != :root + # load object if node is not an object + target = nested_set_scope.find(target) + end + self.reload_nested_set + + unless position == :root || move_possible?(target) + raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree." + end + + bound = case position + when :child; target[right_column_name] + when :left; target[left_column_name] + when :right; target[right_column_name] + 1 + when :root; 1 + else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left, :right or :root ('#{position}' received)." + end + + if bound > self[right_column_name] + bound = bound - 1 + other_bound = self[right_column_name] + 1 + else + other_bound = self[left_column_name] - 1 + end + + # there would be no change + return if bound == self[right_column_name] || bound == self[left_column_name] + + # we have defined the boundaries of two non-overlapping intervals, + # so sorting puts both the intervals and their boundaries in order + a, b, c, d = [self[left_column_name], self[right_column_name], bound, other_bound].sort + + # select the rows in the model between a and d, and apply a lock + self.class.base_class.select('id').lock(true).where( + ["#{quoted_left_column_name} >= :a and #{quoted_right_column_name} <= :d", {:a => a, :d => d}] + ) + + new_parent = case position + when :child; target.id + when :root; nil + else target[parent_column_name] + end + + self.nested_set_scope.update_all([ + "#{quoted_left_column_name} = CASE " + + "WHEN #{quoted_left_column_name} BETWEEN :a AND :b " + + "THEN #{quoted_left_column_name} + :d - :b " + + "WHEN #{quoted_left_column_name} BETWEEN :c AND :d " + + "THEN #{quoted_left_column_name} + :a - :c " + + "ELSE #{quoted_left_column_name} END, " + + "#{quoted_right_column_name} = CASE " + + "WHEN #{quoted_right_column_name} BETWEEN :a AND :b " + + "THEN #{quoted_right_column_name} + :d - :b " + + "WHEN #{quoted_right_column_name} BETWEEN :c AND :d " + + "THEN #{quoted_right_column_name} + :a - :c " + + "ELSE #{quoted_right_column_name} END, " + + "#{quoted_parent_column_name} = CASE " + + "WHEN #{self.class.base_class.primary_key} = :id THEN :new_parent " + + "ELSE #{quoted_parent_column_name} END", + {:a => a, :b => b, :c => c, :d => d, :id => self.id, :new_parent => new_parent} + ]) + end + target.reload_nested_set if target + self.reload_nested_set + end + end + + end + + end + + # Mixed into both classes and instances to provide easy access to the column names + module Columns + def left_column_name + acts_as_nested_set_options[:left_column] + end + + def right_column_name + acts_as_nested_set_options[:right_column] + end + + def parent_column_name + acts_as_nested_set_options[:parent_column] + end + + def scope_column_names + Array(acts_as_nested_set_options[:scope]) + end + + def quoted_left_column_name + connection.quote_column_name(left_column_name) + end + + def quoted_right_column_name + connection.quote_column_name(right_column_name) + end + + def quoted_parent_column_name + connection.quote_column_name(parent_column_name) + end + + def quoted_scope_column_names + scope_column_names.collect {|column_name| connection.quote_column_name(column_name) } + end + end + + end + end +end 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 2d11da330..000000000 --- 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/helper.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb index 09c803fd0..bfeb18ce4 100644 --- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb @@ -21,8 +21,12 @@ module CollectiveIdea #:nodoc: # }) %> # def nested_set_options(class_or_item, mover = nil) - class_or_item = class_or_item.roots if class_or_item.is_a?(Class) - items = Array(class_or_item) + if class_or_item.is_a? Array + items = class_or_item.reject { |e| !e.root? } + else + class_or_item = class_or_item.roots if class_or_item.is_a?(Class) + items = Array(class_or_item) + end result = [] items.each do |root| result += root.self_and_descendants.map do |i| @@ -32,9 +36,9 @@ module CollectiveIdea #:nodoc: end.compact end result - end - + end + end - end + end end -end
\ No newline at end of file +end 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 1836498bd..000000000 --- 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: - # * <tt>all</tt>, which is similar to a <tt>find(:all)</tt> query, and - # * <tt>scoped</tt>, 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 <tt>:conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions</tt>. - # - # 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 <tt>named_scope</tt> define class methods <tt>Shirt.red</tt> and <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.red</tt>, - # in effect, represents the query <tt>Shirt.find(:all, :conditions => {:color => 'red'})</tt>. - # - # Unlike Shirt.find(...), however, the object returned by <tt>Shirt.red</tt> is not an Array; it resembles the association object - # constructed by a <tt>has_many</tt> declaration. For instance, you can invoke <tt>Shirt.red.find(:first)</tt>, <tt>Shirt.red.count</tt>, - # <tt>Shirt.red.find(:all, :conditions => {:size => 'small'})</tt>. Also, just - # as with the association objects, name scopes acts like an Array, implementing Enumerable; <tt>Shirt.red.each(&block)</tt>, - # <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if Shirt.red really were an Array. - # - # These named scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are both red and dry clean only. - # Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt> returns the number of garments - # for which these criteria obtain. Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>. - # - # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to - # <tt>has_many</tt> associations. If, - # - # class Person < ActiveRecord::Base - # has_many :shirts - # end - # - # then <tt>elton.shirts.red.dry_clean_only</tt> 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, <tt>Shirt.colored('puce')</tt> finds all puce shirts. - # - # Named scopes can also have extensions, just as with <tt>has_many</tt> 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 - # <tt>proxy_options</tt> 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/lib/awesome_nested_set/version.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/version.rb new file mode 100644 index 000000000..755256ab4 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/version.rb @@ -0,0 +1,3 @@ +module AwesomeNestedSet + VERSION = '2.1.0' unless defined?(::AwesomeNestedSet::VERSION) +end diff --git a/vendor/plugins/awesome_nested_set/spec/awesome_nested_set/helper_spec.rb b/vendor/plugins/awesome_nested_set/spec/awesome_nested_set/helper_spec.rb new file mode 100644 index 000000000..cc32a0d0a --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/awesome_nested_set/helper_spec.rb @@ -0,0 +1,67 @@ +require 'spec_helper'
+
+describe "Helper" do
+ include CollectiveIdea::Acts::NestedSet::Helper
+
+ before(:all) do
+ self.class.fixtures :categories
+ end
+
+ describe "nested_set_options" do
+ it "test_nested_set_options" do
+ expected = [
+ [" Top Level", 1],
+ ["- Child 1", 2],
+ ['- Child 2', 3],
+ ['-- Child 2.1', 4],
+ ['- Child 3', 5],
+ [" Top Level 2", 6]
+ ]
+ actual = nested_set_options(Category) do |c|
+ "#{'-' * c.level} #{c.name}"
+ end
+ actual.should == expected
+ end
+
+ it "test_nested_set_options_with_mover" do
+ expected = [
+ [" Top Level", 1],
+ ["- Child 1", 2],
+ ['- Child 3', 5],
+ [" Top Level 2", 6]
+ ]
+ actual = nested_set_options(Category, categories(:child_2)) do |c|
+ "#{'-' * c.level} #{c.name}"
+ end
+ actual.should == expected
+ end
+
+ it "test_nested_set_options_with_array_as_argument_without_mover" do
+ expected = [
+ [" Top Level", 1],
+ ["- Child 1", 2],
+ ['- Child 2', 3],
+ ['-- Child 2.1', 4],
+ ['- Child 3', 5],
+ [" Top Level 2", 6]
+ ]
+ actual = nested_set_options(Category.all) do |c|
+ "#{'-' * c.level} #{c.name}"
+ end
+ actual.should == expected
+ end
+
+ it "test_nested_set_options_with_array_as_argument_with_mover" do
+ expected = [
+ [" Top Level", 1],
+ ["- Child 1", 2],
+ ['- Child 3', 5],
+ [" Top Level 2", 6]
+ ]
+ actual = nested_set_options(Category.all, categories(:child_2)) do |c|
+ "#{'-' * c.level} #{c.name}"
+ end
+ actual.should == expected
+ end
+ end
+end
diff --git a/vendor/plugins/awesome_nested_set/spec/awesome_nested_set_spec.rb b/vendor/plugins/awesome_nested_set/spec/awesome_nested_set_spec.rb new file mode 100644 index 000000000..1060bba4a --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/awesome_nested_set_spec.rb @@ -0,0 +1,841 @@ +require 'spec_helper'
+
+describe "AwesomeNestedSet" do
+ before(:all) do
+ self.class.fixtures :categories, :departments, :notes, :things, :brokens
+ end
+
+ describe "defaults" do
+ it "should have left_column_default" do
+ Default.acts_as_nested_set_options[:left_column].should == 'lft'
+ end
+
+ it "should have right_column_default" do
+ Default.acts_as_nested_set_options[:right_column].should == 'rgt'
+ end
+
+ it "should have parent_column_default" do
+ Default.acts_as_nested_set_options[:parent_column].should == 'parent_id'
+ end
+
+ it "should have scope_default" do
+ Default.acts_as_nested_set_options[:scope].should be_nil
+ end
+
+ it "should have left_column_name" do
+ Default.left_column_name.should == 'lft'
+ Default.new.left_column_name.should == 'lft'
+ RenamedColumns.left_column_name.should == 'red'
+ RenamedColumns.new.left_column_name.should == 'red'
+ end
+
+ it "should have right_column_name" do
+ Default.right_column_name.should == 'rgt'
+ Default.new.right_column_name.should == 'rgt'
+ RenamedColumns.right_column_name.should == 'black'
+ RenamedColumns.new.right_column_name.should == 'black'
+ end
+
+ it "should have parent_column_name" do
+ Default.parent_column_name.should == 'parent_id'
+ Default.new.parent_column_name.should == 'parent_id'
+ RenamedColumns.parent_column_name.should == 'mother_id'
+ RenamedColumns.new.parent_column_name.should == 'mother_id'
+ end
+ end
+
+ it "creation_with_altered_column_names" do
+ lambda {
+ RenamedColumns.create!()
+ }.should_not raise_exception
+ end
+
+ it "creation when existing record has nil left column" do
+ assert_nothing_raised do
+ Broken.create!
+ end
+ end
+
+ it "quoted_left_column_name" do
+ quoted = Default.connection.quote_column_name('lft')
+ Default.quoted_left_column_name.should == quoted
+ Default.new.quoted_left_column_name.should == quoted
+ end
+
+ it "quoted_right_column_name" do
+ quoted = Default.connection.quote_column_name('rgt')
+ Default.quoted_right_column_name.should == quoted
+ Default.new.quoted_right_column_name.should == quoted
+ end
+
+ it "left_column_protected_from_assignment" do
+ lambda {
+ Category.new.lft = 1
+ }.should raise_exception(ActiveRecord::ActiveRecordError)
+ end
+
+ it "right_column_protected_from_assignment" do
+ lambda {
+ Category.new.rgt = 1
+ }.should raise_exception(ActiveRecord::ActiveRecordError)
+ end
+
+ it "scoped_appends_id" do
+ ScopedCategory.acts_as_nested_set_options[:scope].should == :organization_id
+ end
+
+ it "roots_class_method" do
+ Category.roots.should == Category.find_all_by_parent_id(nil)
+ end
+
+ it "root_class_method" do
+ Category.root.should == categories(:top_level)
+ end
+
+ it "root" do
+ categories(:child_3).root.should == categories(:top_level)
+ end
+
+ it "root?" do
+ categories(:top_level).root?.should be_true
+ categories(:top_level_2).root?.should be_true
+ end
+
+ it "leaves_class_method" do
+ Category.find(:all, :conditions => "#{Category.right_column_name} - #{Category.left_column_name} = 1").should == Category.leaves
+ Category.leaves.count.should == 4
+ Category.leaves.should include(categories(:child_1))
+ Category.leaves.should include(categories(:child_2_1))
+ Category.leaves.should include(categories(:child_3))
+ Category.leaves.should include(categories(:top_level_2))
+ end
+
+ it "leaf" do
+ categories(:child_1).leaf?.should be_true
+ categories(:child_2_1).leaf?.should be_true
+ categories(:child_3).leaf?.should be_true
+ categories(:top_level_2).leaf?.should be_true
+
+ categories(:top_level).leaf?.should be_false
+ categories(:child_2).leaf?.should be_false
+ Category.new.leaf?.should be_false
+ end
+
+
+ it "parent" do
+ categories(:child_2_1).parent.should == categories(:child_2)
+ end
+
+ it "self_and_ancestors" do
+ child = categories(:child_2_1)
+ self_and_ancestors = [categories(:top_level), categories(:child_2), child]
+ self_and_ancestors.should == child.self_and_ancestors
+ end
+
+ it "ancestors" do
+ child = categories(:child_2_1)
+ ancestors = [categories(:top_level), categories(:child_2)]
+ ancestors.should == child.ancestors
+ end
+
+ it "self_and_siblings" do
+ child = categories(:child_2)
+ self_and_siblings = [categories(:child_1), child, categories(:child_3)]
+ self_and_siblings.should == child.self_and_siblings
+ lambda do
+ tops = [categories(:top_level), categories(:top_level_2)]
+ assert_equal tops, categories(:top_level).self_and_siblings
+ end.should_not raise_exception
+ end
+
+ it "siblings" do
+ child = categories(:child_2)
+ siblings = [categories(:child_1), categories(:child_3)]
+ siblings.should == child.siblings
+ end
+
+ it "leaves" do
+ leaves = [categories(:child_1), categories(:child_2_1), categories(:child_3)]
+ categories(:top_level).leaves.should == leaves
+ end
+
+ it "level" do
+ categories(:top_level).level.should == 0
+ categories(:child_1).level.should == 1
+ categories(:child_2_1).level.should == 2
+ end
+
+ it "has_children?" do
+ categories(:child_2_1).children.empty?.should be_true
+ categories(:child_2).children.empty?.should be_false
+ categories(:top_level).children.empty?.should be_false
+ end
+
+ it "self_and_descendents" do
+ parent = categories(:top_level)
+ self_and_descendants = [parent, categories(:child_1), categories(:child_2),
+ categories(:child_2_1), categories(:child_3)]
+ self_and_descendants.should == parent.self_and_descendants
+ self_and_descendants.count.should == parent.self_and_descendants.count
+ end
+
+ it "descendents" do
+ lawyers = Category.create!(:name => "lawyers")
+ us = Category.create!(:name => "United States")
+ us.move_to_child_of(lawyers)
+ patent = Category.create!(:name => "Patent Law")
+ patent.move_to_child_of(us)
+ lawyers.reload
+
+ lawyers.children.size.should == 1
+ us.children.size.should == 1
+ lawyers.descendants.size.should == 2
+ end
+
+ it "self_and_descendents" do
+ parent = categories(:top_level)
+ descendants = [categories(:child_1), categories(:child_2),
+ categories(:child_2_1), categories(:child_3)]
+ descendants.should == parent.descendants
+ end
+
+ it "children" do
+ category = categories(:top_level)
+ category.children.each {|c| category.id.should == c.parent_id }
+ end
+
+ it "order_of_children" do
+ categories(:child_2).move_left
+ categories(:child_2).should == categories(:top_level).children[0]
+ categories(:child_1).should == categories(:top_level).children[1]
+ categories(:child_3).should == categories(:top_level).children[2]
+ end
+
+ it "is_or_is_ancestor_of?" do
+ categories(:top_level).is_or_is_ancestor_of?(categories(:child_1)).should be_true
+ categories(:top_level).is_or_is_ancestor_of?(categories(:child_2_1)).should be_true
+ categories(:child_2).is_or_is_ancestor_of?(categories(:child_2_1)).should be_true
+ categories(:child_2_1).is_or_is_ancestor_of?(categories(:child_2)).should be_false
+ categories(:child_1).is_or_is_ancestor_of?(categories(:child_2)).should be_false
+ categories(:child_1).is_or_is_ancestor_of?(categories(:child_1)).should be_true
+ end
+
+ it "is_ancestor_of?" do
+ categories(:top_level).is_ancestor_of?(categories(:child_1)).should be_true
+ categories(:top_level).is_ancestor_of?(categories(:child_2_1)).should be_true
+ categories(:child_2).is_ancestor_of?(categories(:child_2_1)).should be_true
+ categories(:child_2_1).is_ancestor_of?(categories(:child_2)).should be_false
+ categories(:child_1).is_ancestor_of?(categories(:child_2)).should be_false
+ categories(:child_1).is_ancestor_of?(categories(:child_1)).should be_false
+ end
+
+ it "is_or_is_ancestor_of_with_scope" do
+ root = ScopedCategory.root
+ child = root.children.first
+ root.is_or_is_ancestor_of?(child).should be_true
+ child.update_attribute :organization_id, 'different'
+ root.is_or_is_ancestor_of?(child).should be_false
+ end
+
+ it "is_or_is_descendant_of?" do
+ categories(:child_1).is_or_is_descendant_of?(categories(:top_level)).should be_true
+ categories(:child_2_1).is_or_is_descendant_of?(categories(:top_level)).should be_true
+ categories(:child_2_1).is_or_is_descendant_of?(categories(:child_2)).should be_true
+ categories(:child_2).is_or_is_descendant_of?(categories(:child_2_1)).should be_false
+ categories(:child_2).is_or_is_descendant_of?(categories(:child_1)).should be_false
+ categories(:child_1).is_or_is_descendant_of?(categories(:child_1)).should be_true
+ end
+
+ it "is_descendant_of?" do
+ categories(:child_1).is_descendant_of?(categories(:top_level)).should be_true
+ categories(:child_2_1).is_descendant_of?(categories(:top_level)).should be_true
+ categories(:child_2_1).is_descendant_of?(categories(:child_2)).should be_true
+ categories(:child_2).is_descendant_of?(categories(:child_2_1)).should be_false
+ categories(:child_2).is_descendant_of?(categories(:child_1)).should be_false
+ categories(:child_1).is_descendant_of?(categories(:child_1)).should be_false
+ end
+
+ it "is_or_is_descendant_of_with_scope" do
+ root = ScopedCategory.root
+ child = root.children.first
+ child.is_or_is_descendant_of?(root).should be_true
+ child.update_attribute :organization_id, 'different'
+ child.is_or_is_descendant_of?(root).should be_false
+ end
+
+ it "same_scope?" do
+ root = ScopedCategory.root
+ child = root.children.first
+ child.same_scope?(root).should be_true
+ child.update_attribute :organization_id, 'different'
+ child.same_scope?(root).should be_false
+ end
+
+ it "left_sibling" do
+ categories(:child_1).should == categories(:child_2).left_sibling
+ categories(:child_2).should == categories(:child_3).left_sibling
+ end
+
+ it "left_sibling_of_root" do
+ categories(:top_level).left_sibling.should be_nil
+ end
+
+ it "left_sibling_without_siblings" do
+ categories(:child_2_1).left_sibling.should be_nil
+ end
+
+ it "left_sibling_of_leftmost_node" do
+ categories(:child_1).left_sibling.should be_nil
+ end
+
+ it "right_sibling" do
+ categories(:child_3).should == categories(:child_2).right_sibling
+ categories(:child_2).should == categories(:child_1).right_sibling
+ end
+
+ it "right_sibling_of_root" do
+ categories(:top_level_2).should == categories(:top_level).right_sibling
+ categories(:top_level_2).right_sibling.should be_nil
+ end
+
+ it "right_sibling_without_siblings" do
+ categories(:child_2_1).right_sibling.should be_nil
+ end
+
+ it "right_sibling_of_rightmost_node" do
+ categories(:child_3).right_sibling.should be_nil
+ end
+
+ it "move_left" do
+ categories(:child_2).move_left
+ categories(:child_2).left_sibling.should be_nil
+ categories(:child_1).should == categories(:child_2).right_sibling
+ Category.valid?.should be_true
+ end
+
+ it "move_right" do
+ categories(:child_2).move_right
+ categories(:child_2).right_sibling.should be_nil
+ categories(:child_3).should == categories(:child_2).left_sibling
+ Category.valid?.should be_true
+ end
+
+ it "move_to_left_of" do
+ categories(:child_3).move_to_left_of(categories(:child_1))
+ categories(:child_3).left_sibling.should be_nil
+ categories(:child_1).should == categories(:child_3).right_sibling
+ Category.valid?.should be_true
+ end
+
+ it "move_to_right_of" do
+ categories(:child_1).move_to_right_of(categories(:child_3))
+ categories(:child_1).right_sibling.should be_nil
+ categories(:child_3).should == categories(:child_1).left_sibling
+ Category.valid?.should be_true
+ end
+
+ it "move_to_root" do
+ categories(:child_2).move_to_root
+ categories(:child_2).parent.should be_nil
+ categories(:child_2).level.should == 0
+ categories(:child_2_1).level.should == 1
+ categories(:child_2).left.should == 1
+ categories(:child_2).right.should == 4
+ Category.valid?.should be_true
+ end
+
+ it "move_to_child_of" do
+ categories(:child_1).move_to_child_of(categories(:child_3))
+ categories(:child_3).id.should == categories(:child_1).parent_id
+ Category.valid?.should be_true
+ end
+
+ it "move_to_child_of_appends_to_end" do
+ child = Category.create! :name => 'New Child'
+ child.move_to_child_of categories(:top_level)
+ child.should == categories(:top_level).children.last
+ end
+
+ it "subtree_move_to_child_of" do
+ categories(:child_2).left.should == 4
+ categories(:child_2).right.should == 7
+
+ categories(:child_1).left.should == 2
+ categories(:child_1).right.should == 3
+
+ categories(:child_2).move_to_child_of(categories(:child_1))
+ Category.valid?.should be_true
+ categories(:child_1).id.should == categories(:child_2).parent_id
+
+ categories(:child_2).left.should == 3
+ categories(:child_2).right.should == 6
+ categories(:child_1).left.should == 2
+ categories(:child_1).right.should == 7
+ end
+
+ it "slightly_difficult_move_to_child_of" do
+ categories(:top_level_2).left.should == 11
+ categories(:top_level_2).right.should == 12
+
+ # create a new top-level node and move single-node top-level tree inside it.
+ new_top = Category.create(:name => 'New Top')
+ new_top.left.should == 13
+ new_top.right.should == 14
+
+ categories(:top_level_2).move_to_child_of(new_top)
+
+ Category.valid?.should be_true
+ new_top.id.should == categories(:top_level_2).parent_id
+
+ categories(:top_level_2).left.should == 12
+ categories(:top_level_2).right.should == 13
+ new_top.left.should == 11
+ new_top.right.should == 14
+ end
+
+ it "difficult_move_to_child_of" do
+ categories(:top_level).left.should == 1
+ categories(:top_level).right.should == 10
+ categories(:child_2_1).left.should == 5
+ categories(:child_2_1).right.should == 6
+
+ # create a new top-level node and move an entire top-level tree inside it.
+ new_top = Category.create(:name => 'New Top')
+ categories(:top_level).move_to_child_of(new_top)
+ categories(:child_2_1).reload
+ Category.valid?.should be_true
+ new_top.id.should == categories(:top_level).parent_id
+
+ categories(:top_level).left.should == 4
+ categories(:top_level).right.should == 13
+ categories(:child_2_1).left.should == 8
+ categories(:child_2_1).right.should == 9
+ end
+
+ #rebuild swaps the position of the 2 children when added using move_to_child twice onto same parent
+ it "move_to_child_more_than_once_per_parent_rebuild" do
+ root1 = Category.create(:name => 'Root1')
+ root2 = Category.create(:name => 'Root2')
+ root3 = Category.create(:name => 'Root3')
+
+ root2.move_to_child_of root1
+ root3.move_to_child_of root1
+
+ output = Category.roots.last.to_text
+ Category.update_all('lft = null, rgt = null')
+ Category.rebuild!
+
+ Category.roots.last.to_text.should == output
+ end
+
+ # doing move_to_child twice onto same parent from the furthest right first
+ it "move_to_child_more_than_once_per_parent_outside_in" do
+ node1 = Category.create(:name => 'Node-1')
+ node2 = Category.create(:name => 'Node-2')
+ node3 = Category.create(:name => 'Node-3')
+
+ node2.move_to_child_of node1
+ node3.move_to_child_of node1
+
+ output = Category.roots.last.to_text
+ Category.update_all('lft = null, rgt = null')
+ Category.rebuild!
+
+ Category.roots.last.to_text.should == output
+ end
+
+ it "should be able to rebuild without validating each record" do
+ root1 = Category.create(:name => 'Root1')
+ root2 = Category.create(:name => 'Root2')
+ root3 = Category.create(:name => 'Root3')
+
+ root2.move_to_child_of root1
+ root3.move_to_child_of root1
+
+ root2.name = nil
+ root2.save!(:validate => false)
+
+ output = Category.roots.last.to_text
+ Category.update_all('lft = null, rgt = null')
+ Category.rebuild!(false)
+
+ Category.roots.last.to_text.should == output
+ end
+
+ it "valid_with_null_lefts" do
+ Category.valid?.should be_true
+ Category.update_all('lft = null')
+ Category.valid?.should be_false
+ end
+
+ it "valid_with_null_rights" do
+ Category.valid?.should be_true
+ Category.update_all('rgt = null')
+ Category.valid?.should be_false
+ end
+
+ it "valid_with_missing_intermediate_node" do
+ # Even though child_2_1 will still exist, it is a sign of a sloppy delete, not an invalid tree.
+ Category.valid?.should be_true
+ Category.delete(categories(:child_2).id)
+ Category.valid?.should be_true
+ end
+
+ it "valid_with_overlapping_and_rights" do
+ Category.valid?.should be_true
+ categories(:top_level_2)['lft'] = 0
+ categories(:top_level_2).save
+ Category.valid?.should be_false
+ end
+
+ it "rebuild" do
+ Category.valid?.should be_true
+ before_text = Category.root.to_text
+ Category.update_all('lft = null, rgt = null')
+ Category.rebuild!
+ Category.valid?.should be_true
+ before_text.should == Category.root.to_text
+ end
+
+ it "move_possible_for_sibling" do
+ categories(:child_2).move_possible?(categories(:child_1)).should be_true
+ end
+
+ it "move_not_possible_to_self" do
+ categories(:top_level).move_possible?(categories(:top_level)).should be_false
+ end
+
+ it "move_not_possible_to_parent" do
+ categories(:top_level).descendants.each do |descendant|
+ categories(:top_level).move_possible?(descendant).should be_false
+ descendant.move_possible?(categories(:top_level)).should be_true
+ end
+ end
+
+ it "is_or_is_ancestor_of?" do
+ [:child_1, :child_2, :child_2_1, :child_3].each do |c|
+ categories(:top_level).is_or_is_ancestor_of?(categories(c)).should be_true
+ end
+ categories(:top_level).is_or_is_ancestor_of?(categories(:top_level_2)).should be_false
+ end
+
+ it "left_and_rights_valid_with_blank_left" do
+ Category.left_and_rights_valid?.should be_true
+ categories(:child_2)[:lft] = nil
+ categories(:child_2).save(:validate => false)
+ Category.left_and_rights_valid?.should be_false
+ end
+
+ it "left_and_rights_valid_with_blank_right" do
+ Category.left_and_rights_valid?.should be_true
+ categories(:child_2)[:rgt] = nil
+ categories(:child_2).save(:validate => false)
+ Category.left_and_rights_valid?.should be_false
+ end
+
+ it "left_and_rights_valid_with_equal" do
+ Category.left_and_rights_valid?.should be_true
+ categories(:top_level_2)[:lft] = categories(:top_level_2)[:rgt]
+ categories(:top_level_2).save(:validate => false)
+ Category.left_and_rights_valid?.should be_false
+ end
+
+ it "left_and_rights_valid_with_left_equal_to_parent" do
+ Category.left_and_rights_valid?.should be_true
+ categories(:child_2)[:lft] = categories(:top_level)[:lft]
+ categories(:child_2).save(:validate => false)
+ Category.left_and_rights_valid?.should be_false
+ end
+
+ it "left_and_rights_valid_with_right_equal_to_parent" do
+ Category.left_and_rights_valid?.should be_true
+ categories(:child_2)[:rgt] = categories(:top_level)[:rgt]
+ categories(:child_2).save(:validate => false)
+ Category.left_and_rights_valid?.should be_false
+ end
+
+ it "moving_dirty_objects_doesnt_invalidate_tree" do
+ r1 = Category.create :name => "Test 1"
+ r2 = Category.create :name => "Test 2"
+ r3 = Category.create :name => "Test 3"
+ r4 = Category.create :name => "Test 4"
+ nodes = [r1, r2, r3, r4]
+
+ r2.move_to_child_of(r1)
+ Category.valid?.should be_true
+
+ r3.move_to_child_of(r1)
+ Category.valid?.should be_true
+
+ r4.move_to_child_of(r2)
+ Category.valid?.should be_true
+ end
+
+ it "multi_scoped_no_duplicates_for_columns?" do
+ lambda {
+ Note.no_duplicates_for_columns?
+ }.should_not raise_exception
+ end
+
+ it "multi_scoped_all_roots_valid?" do
+ lambda {
+ Note.all_roots_valid?
+ }.should_not raise_exception
+ end
+
+ it "multi_scoped" do
+ note1 = Note.create!(:body => "A", :notable_id => 2, :notable_type => 'Category')
+ note2 = Note.create!(:body => "B", :notable_id => 2, :notable_type => 'Category')
+ note3 = Note.create!(:body => "C", :notable_id => 2, :notable_type => 'Default')
+
+ [note1, note2].should == note1.self_and_siblings
+ [note3].should == note3.self_and_siblings
+ end
+
+ it "multi_scoped_rebuild" do
+ root = Note.create!(:body => "A", :notable_id => 3, :notable_type => 'Category')
+ child1 = Note.create!(:body => "B", :notable_id => 3, :notable_type => 'Category')
+ child2 = Note.create!(:body => "C", :notable_id => 3, :notable_type => 'Category')
+
+ child1.move_to_child_of root
+ child2.move_to_child_of root
+
+ Note.update_all('lft = null, rgt = null')
+ Note.rebuild!
+
+ Note.roots.find_by_body('A').should == root
+ [child1, child2].should == Note.roots.find_by_body('A').children
+ end
+
+ it "same_scope_with_multi_scopes" do
+ lambda {
+ notes(:scope1).same_scope?(notes(:child_1))
+ }.should_not raise_exception
+ notes(:scope1).same_scope?(notes(:child_1)).should be_true
+ notes(:child_1).same_scope?(notes(:scope1)).should be_true
+ notes(:scope1).same_scope?(notes(:scope2)).should be_false
+ end
+
+ it "quoting_of_multi_scope_column_names" do
+ ["\"notable_id\"", "\"notable_type\""].should == Note.quoted_scope_column_names
+ end
+
+ it "equal_in_same_scope" do
+ notes(:scope1).should == notes(:scope1)
+ notes(:scope1).should_not == notes(:child_1)
+ end
+
+ it "equal_in_different_scopes" do
+ notes(:scope1).should_not == notes(:scope2)
+ end
+
+ it "delete_does_not_invalidate" do
+ Category.acts_as_nested_set_options[:dependent] = :delete
+ categories(:child_2).destroy
+ Category.valid?.should be_true
+ end
+
+ it "destroy_does_not_invalidate" do
+ Category.acts_as_nested_set_options[:dependent] = :destroy
+ categories(:child_2).destroy
+ Category.valid?.should be_true
+ end
+
+ it "destroy_multiple_times_does_not_invalidate" do
+ Category.acts_as_nested_set_options[:dependent] = :destroy
+ categories(:child_2).destroy
+ categories(:child_2).destroy
+ Category.valid?.should be_true
+ end
+
+ it "assigning_parent_id_on_create" do
+ category = Category.create!(:name => "Child", :parent_id => categories(:child_2).id)
+ categories(:child_2).should == category.parent
+ categories(:child_2).id.should == category.parent_id
+ category.left.should_not be_nil
+ category.right.should_not be_nil
+ Category.valid?.should be_true
+ end
+
+ it "assigning_parent_on_create" do
+ category = Category.create!(:name => "Child", :parent => categories(:child_2))
+ categories(:child_2).should == category.parent
+ categories(:child_2).id.should == category.parent_id
+ category.left.should_not be_nil
+ category.right.should_not be_nil
+ Category.valid?.should be_true
+ end
+
+ it "assigning_parent_id_to_nil_on_create" do
+ category = Category.create!(:name => "New Root", :parent_id => nil)
+ category.parent.should be_nil
+ category.parent_id.should be_nil
+ category.left.should_not be_nil
+ category.right.should_not be_nil
+ Category.valid?.should be_true
+ end
+
+ it "assigning_parent_id_on_update" do
+ category = categories(:child_2_1)
+ category.parent_id = categories(:child_3).id
+ category.save
+ category.reload
+ categories(:child_3).reload
+ categories(:child_3).should == category.parent
+ categories(:child_3).id.should == category.parent_id
+ Category.valid?.should be_true
+ end
+
+ it "assigning_parent_on_update" do
+ category = categories(:child_2_1)
+ category.parent = categories(:child_3)
+ category.save
+ category.reload
+ categories(:child_3).reload
+ categories(:child_3).should == category.parent
+ categories(:child_3).id.should == category.parent_id
+ Category.valid?.should be_true
+ end
+
+ it "assigning_parent_id_to_nil_on_update" do
+ category = categories(:child_2_1)
+ category.parent_id = nil
+ category.save
+ category.parent.should be_nil
+ category.parent_id.should be_nil
+ Category.valid?.should be_true
+ end
+
+ it "creating_child_from_parent" do
+ category = categories(:child_2).children.create!(:name => "Child")
+ categories(:child_2).should == category.parent
+ categories(:child_2).id.should == category.parent_id
+ category.left.should_not be_nil
+ category.right.should_not be_nil
+ Category.valid?.should be_true
+ end
+
+ def check_structure(entries, structure)
+ structure = structure.dup
+ Category.each_with_level(entries) do |category, level|
+ expected_level, expected_name = structure.shift
+ expected_name.should == category.name
+ expected_level.should == level
+ end
+ end
+
+ it "each_with_level" do
+ 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
+
+ it "should not error on a model with attr_accessible" do
+ model = Class.new(ActiveRecord::Base)
+ model.set_table_name 'categories'
+ model.attr_accessible :name
+ lambda {
+ model.acts_as_nested_set
+ model.new(:name => 'foo')
+ }.should_not raise_exception
+ end
+
+ describe "before_move_callback" do
+ it "should fire the callback" do
+ categories(:child_2).should_receive(:custom_before_move)
+ categories(:child_2).move_to_root
+ end
+
+ it "should stop move when callback returns false" do
+ Category.test_allows_move = false
+ categories(:child_3).move_to_root.should be_false
+ categories(:child_3).root?.should be_false
+ end
+
+ it "should not halt save actions" do
+ Category.test_allows_move = false
+ categories(:child_3).parent_id = nil
+ categories(:child_3).save.should be_true
+ end
+ end
+
+ describe "counter_cache" do
+
+ it "should allow use of a counter cache for children" do
+ note1 = things(:parent1)
+ note1.children.count.should == 2
+ end
+
+ it "should increment the counter cache on create" do
+ note1 = things(:parent1)
+ note1.children.count.should == 2
+ note1[:children_count].should == 2
+ note1.children.create :body => 'Child 3'
+ note1.children.count.should == 3
+ note1.reload
+ note1[:children_count].should == 3
+ end
+
+ it "should decrement the counter cache on destroy" do
+ note1 = things(:parent1)
+ note1.children.count.should == 2
+ note1[:children_count].should == 2
+ note1.children.last.destroy
+ note1.children.count.should == 1
+ note1.reload
+ note1[:children_count].should == 1
+ end
+ end
+
+ describe "association callbacks on children" do
+ it "should call the appropriate callbacks on the children :has_many association " do
+ root = DefaultWithCallbacks.create
+ root.should_not be_new_record
+
+ child = root.children.build
+
+ root.before_add.should == child
+ root.after_add.should == child
+
+ root.before_remove.should_not == child
+ root.after_remove.should_not == child
+
+ child.save.should be_true
+ root.children.delete(child).should be_true
+
+ root.before_remove.should == child
+ root.after_remove.should == child
+ end
+ end
+end
diff --git a/vendor/plugins/awesome_nested_set/spec/db/database.yml b/vendor/plugins/awesome_nested_set/spec/db/database.yml new file mode 100644 index 000000000..c8c0aeeac --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/db/database.yml @@ -0,0 +1,18 @@ +sqlite3:
+ adapter: <%= "jdbc" if defined? JRUBY_VERSION %>sqlite3
+ database: awesome_nested_set.sqlite3.db
+sqlite3mem:
+ adapter: <%= "jdbc" if defined? JRUBY_VERSION %>sqlite3
+ database: ":memory:"
+postgresql:
+ adapter: postgresql
+ username: postgres
+ password: postgres
+ database: awesome_nested_set_plugin_test
+ min_messages: ERROR
+mysql:
+ adapter: mysql2
+ host: localhost
+ username: root
+ password:
+ database: awesome_nested_set_plugin_test
\ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/spec/db/schema.rb b/vendor/plugins/awesome_nested_set/spec/db/schema.rb new file mode 100644 index 000000000..d3625fa3a --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/db/schema.rb @@ -0,0 +1,45 @@ +ActiveRecord::Schema.define(:version => 0) do
+
+ create_table :categories, :force => true do |t|
+ t.column :name, :string
+ t.column :parent_id, :integer
+ t.column :lft, :integer
+ t.column :rgt, :integer
+ t.column :organization_id, :integer
+ end
+
+ create_table :departments, :force => true do |t|
+ t.column :name, :string
+ end
+
+ create_table :notes, :force => true do |t|
+ t.column :body, :text
+ t.column :parent_id, :integer
+ t.column :lft, :integer
+ t.column :rgt, :integer
+ t.column :notable_id, :integer
+ t.column :notable_type, :string
+ end
+
+ create_table :renamed_columns, :force => true do |t|
+ t.column :name, :string
+ t.column :mother_id, :integer
+ t.column :red, :integer
+ t.column :black, :integer
+ end
+
+ create_table :things, :force => true do |t|
+ t.column :body, :text
+ t.column :parent_id, :integer
+ t.column :lft, :integer
+ t.column :rgt, :integer
+ t.column :children_count, :integer
+ end
+
+ create_table :brokens, :force => true do |t|
+ t.column :name, :string
+ t.column :parent_id, :integer
+ t.column :lft, :integer
+ t.column :rgt, :integer
+ end
+end
diff --git a/vendor/plugins/awesome_nested_set/spec/fixtures/brokens.yml b/vendor/plugins/awesome_nested_set/spec/fixtures/brokens.yml new file mode 100644 index 000000000..45a8c0981 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/fixtures/brokens.yml @@ -0,0 +1,3 @@ +one:
+ id: 1
+ name: One
\ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/spec/fixtures/categories.yml b/vendor/plugins/awesome_nested_set/spec/fixtures/categories.yml new file mode 100644 index 000000000..6cf7f3f41 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/fixtures/categories.yml @@ -0,0 +1,34 @@ +top_level:
+ id: 1
+ name: Top Level
+ lft: 1
+ rgt: 10
+child_1:
+ id: 2
+ name: Child 1
+ parent_id: 1
+ lft: 2
+ rgt: 3
+child_2:
+ id: 3
+ name: Child 2
+ parent_id: 1
+ lft: 4
+ rgt: 7
+child_2_1:
+ id: 4
+ name: Child 2.1
+ parent_id: 3
+ lft: 5
+ rgt: 6
+child_3:
+ id: 5
+ name: Child 3
+ parent_id: 1
+ lft: 8
+ rgt: 9
+top_level_2:
+ id: 6
+ name: Top Level 2
+ lft: 11
+ rgt: 12
diff --git a/vendor/plugins/awesome_nested_set/spec/fixtures/departments.yml b/vendor/plugins/awesome_nested_set/spec/fixtures/departments.yml new file mode 100644 index 000000000..31d65624a --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/fixtures/departments.yml @@ -0,0 +1,3 @@ +top:
+ id: 1
+ name: Top
\ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/spec/fixtures/notes.yml b/vendor/plugins/awesome_nested_set/spec/fixtures/notes.yml new file mode 100644 index 000000000..cb7a48faf --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/fixtures/notes.yml @@ -0,0 +1,38 @@ +scope1:
+ id: 1
+ body: Top Level
+ lft: 1
+ rgt: 10
+ notable_id: 1
+ notable_type: Category
+child_1:
+ id: 2
+ body: Child 1
+ parent_id: 1
+ lft: 2
+ rgt: 3
+ notable_id: 1
+ notable_type: Category
+child_2:
+ id: 3
+ body: Child 2
+ parent_id: 1
+ lft: 4
+ rgt: 7
+ notable_id: 1
+ notable_type: Category
+child_3:
+ id: 4
+ body: Child 3
+ parent_id: 1
+ lft: 8
+ rgt: 9
+ notable_id: 1
+ notable_type: Category
+scope2:
+ id: 5
+ body: Top Level 2
+ lft: 1
+ rgt: 2
+ notable_id: 1
+ notable_type: Departments
diff --git a/vendor/plugins/awesome_nested_set/spec/fixtures/things.yml b/vendor/plugins/awesome_nested_set/spec/fixtures/things.yml new file mode 100644 index 000000000..b9c868831 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/fixtures/things.yml @@ -0,0 +1,27 @@ +parent1:
+ id: 1
+ body: Top Level
+ lft: 1
+ rgt: 10
+ children_count: 2
+child_1:
+ id: 2
+ body: Child 1
+ parent_id: 1
+ lft: 2
+ rgt: 3
+ children_count: 0
+child_2:
+ id: 3
+ body: Child 2
+ parent_id: 1
+ lft: 4
+ rgt: 7
+ children_count: 0
+child_2_1:
+ id: 4
+ body: Child 2.1
+ parent_id: 3
+ lft: 8
+ rgt: 9
+ children_count: 0
diff --git a/vendor/plugins/awesome_nested_set/spec/spec_helper.rb b/vendor/plugins/awesome_nested_set/spec/spec_helper.rb new file mode 100644 index 000000000..3fa1ba3ad --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/spec_helper.rb @@ -0,0 +1,32 @@ +$:.unshift(File.dirname(__FILE__) + '/../lib')
+plugin_test_dir = File.dirname(__FILE__)
+
+require 'rubygems'
+require 'bundler/setup'
+
+require 'rspec'
+require 'logger'
+
+require 'active_support'
+require 'active_model'
+require 'active_record'
+require 'action_controller'
+
+require 'awesome_nested_set'
+
+ActiveRecord::Base.logger = Logger.new(plugin_test_dir + "/debug.log")
+
+require 'yaml'
+require 'erb'
+ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(plugin_test_dir + "/db/database.yml")).result)
+ActiveRecord::Base.establish_connection(ENV["DB"] || "sqlite3mem")
+ActiveRecord::Migration.verbose = false
+load(File.join(plugin_test_dir, "db", "schema.rb"))
+
+require 'support/models'
+
+require 'rspec/rails'
+RSpec.configure do |config|
+ config.fixture_path = "#{plugin_test_dir}/fixtures"
+ config.use_transactional_fixtures = true
+end
diff --git a/vendor/plugins/awesome_nested_set/spec/support/models.rb b/vendor/plugins/awesome_nested_set/spec/support/models.rb new file mode 100644 index 000000000..816b682c1 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/spec/support/models.rb @@ -0,0 +1,72 @@ +class Note < ActiveRecord::Base
+ acts_as_nested_set :scope => [:notable_id, :notable_type]
+end
+
+class Default < ActiveRecord::Base
+ set_table_name 'categories'
+ acts_as_nested_set
+end
+
+class ScopedCategory < ActiveRecord::Base
+ set_table_name 'categories'
+ acts_as_nested_set :scope => :organization
+end
+
+class RenamedColumns < ActiveRecord::Base
+ acts_as_nested_set :parent_column => 'mother_id', :left_column => 'red', :right_column => 'black'
+end
+
+class Category < ActiveRecord::Base
+ acts_as_nested_set
+
+ validates_presence_of :name
+
+ # Setup a callback that we can switch to true or false per-test
+ set_callback :move, :before, :custom_before_move
+ cattr_accessor :test_allows_move
+ @@test_allows_move = true
+ def custom_before_move
+ @@test_allows_move
+ end
+
+ def to_s
+ name
+ end
+
+ def recurse &block
+ block.call self, lambda{
+ self.children.each do |child|
+ child.recurse &block
+ end
+ }
+ end
+end
+
+class Thing < ActiveRecord::Base
+ acts_as_nested_set :counter_cache => 'children_count'
+end
+
+class DefaultWithCallbacks < ActiveRecord::Base
+
+ set_table_name 'categories'
+
+ attr_accessor :before_add, :after_add, :before_remove, :after_remove
+
+ acts_as_nested_set :before_add => :do_before_add_stuff,
+ :after_add => :do_after_add_stuff,
+ :before_remove => :do_before_remove_stuff,
+ :after_remove => :do_after_remove_stuff
+
+ private
+
+ [ :before_add, :after_add, :before_remove, :after_remove ].each do |hook_name|
+ define_method "do_#{hook_name}_stuff" do |child_node|
+ self.send("#{hook_name}=", child_node)
+ end
+ end
+
+end
+
+class Broken < ActiveRecord::Base
+ acts_as_nested_set
+end
\ No newline at end of file diff --git a/vendor/plugins/engines/.gitignore b/vendor/plugins/engines/.gitignore deleted file mode 100644 index 721bd7dee..000000000 --- a/vendor/plugins/engines/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.DS_Store -test_app -doc
\ No newline at end of file diff --git a/vendor/plugins/engines/CHANGELOG b/vendor/plugins/engines/CHANGELOG deleted file mode 100644 index 20e9b34d5..000000000 --- a/vendor/plugins/engines/CHANGELOG +++ /dev/null @@ -1,274 +0,0 @@ -= EDGE - -* Samuel Williams (http://www.oriontransfer.co.nz/): - Thanks to Tekin for his patches. - Updated migrations system to tie in more closely with the current rails mechanism. - Rake task for updating database schema info - rake db:migrate:upgrade_plugin_migrations - Please see http://engines.lighthouseapp.com/projects/10178-engines-plugin/tickets/17 for more information. - -* Refactored the view loading to work with changes in Edge Rails - -* Fixed integration of plugin migrations with the new, default timestamped migrations in Edge Rails - -* Refactored tests into the plugin itself - the plugin can now generate its own test_app harness and run tests within it. - - -= 2.0.0 - (ANOTHER) MASSIVE INTERNAL REFACTORING - -* Engines now conforms to the new plugin loading mechanism, delegating plugin load order and lots of other things to Rails itself. - - - -= 1.2.2 - -* Added the ability to code mix different types of files, cleaning up the existing code-mixing implementation slightly (Ticket #271) - - -= 1.2.1 - -* Added documentation to clarify some of the issues with Rails unloading classes that aren't required using "require_dependency" (Ticket #266) - -* Fixed a bug where test_help was being loaded when it wasn't needed, and was actually causing problems (Ticket #265) - - -= 1.2.0 - MASSIVE INTERNAL REFACTORING - -* !!!Support for Rails < 1.2 has been dropped!!!; if you are using Rails =< 1.1.6, please use Engines 1.1.6, available from http://svn.rails-engines.org/engines/tags/rel_1.1.6 - -* Engines are dead! Long live plugins! There is now no meaningful notion of an engine - all plugins can take advantage of the more powerful features that the engines plugin provides by including app directories, etc. - -* Init_engine.rb is no longer used; please use the plugin-standard init.rb instead. - -* Engines.start is no longer required; please use the config.plugins array provided by Rails instead - -* To get the most benefit from Engines, set config.plugins to ["engines", "*"] to load the engines plugin first, and then all other plugins in their normal order after. - -* Access all loaded plugins via the new Rails.plugins array, and by name using Rails.plugins[:plugin_name]. - -* Access plugin metadata loaded automatically from about.yml: Rails.plugins[:name].about. Plugin#version is provided directly, for easy access. - -* Module.config is has been removed - use mattr_accessor instead, and initialize your default values via the init.rb mechanism. - -* Public asset helpers have been rewritten; instead of engine_stylesheet, now use stylesheet_link_tag :name, :plugin => "plugin_name" - -* Plugin migrations have been reworked to integrate into the main migration stream. Please run script/generate plugin_migration to create plugin migrations in your main application. - -* The fixture method for loading fixtures against any class has been removed; instead, engines will now provide a mechanism for loading fixtures from all plugins, by mirroring fixtures into a common location. - -* All references to engines have been removed; For example, any rake tasks which applied to engines now apply to all plugins. The default Rails rake tasks for plugins are overridden where necessary. - -* Layouts can now be shared via plugins - inspiration gratefully taken from PluginAWeek's plugin_routing :) - -* Actual routing from plugins is now possible, by including routes.rb in your plugin directory and using the from_plugin method in config/routes.rb (Ticket #182) - -* Controllers are no longer loaded twice if they're not present in the normal app/ directory (Ticket #177) - -* The preferred location for javascripts/stylesheets/etc is now 'assets' rather than 'public' - -* Ensure that plugins started before routing have their controllers appropriately added to config.controller_paths (Ticket #258) - -* Removed Engines.version - it's not longer relevant, now we're loading version information from about.yml files. - -* Added a huge amount of documentation to all new modules. - -* Added new warning message if installation of engines 1.2.x is attempted in a Rails 1.1.x application - -* Added details of the removal of the config method to UPGRADING - -* Removed the plugins:info rake task in favour of adding information to script/about via the Rails::Info module (Ticket #261) - -* Improved handling of testing and documentation tasks for plugins - - - -= 1.1.4 - -* Fixed creation of multipart emails (Ticket #190) - -* Added a temporary fix to the code-mixing issue. In your engine's test/test_helper.rb, please add the following lines: - - # Ensure that the code mixing and view loading from the application is disabled - Engines.disable_app_views_loading = true - Engines.disable_app_code_mixing = true - - which will prevent code mixing for controllers and helpers, and loading views from the application. One thing to remember is to load any controllers/helpers using 'require_or_load' in your tests, to ensure that the engine behaviour is respected (Ticket #135) - -* Added tasks to easily test engines individually (Ticket #120) - -* Fixture extensions will now fail with an exception if the corresponding class cannot be loaded (Ticket #138) - -* Patch for new routing/controller loading in Rails 1.1.6. The routing code is now replaced with the contents of config.controller_paths, along with controller paths from any started engines (Ticket #196) - -* Rails' Configuration instance is now stored, and available from all engines and plugins. - - - -= 1.1.3 - -* Fixed README to show 'models' rather than 'model' class (Ticket #167) -* Fixed dependency loading to work with Rails 1.1.4 (Ticket #180) - - - -= 1.1.2 - -* Added better fix to version checking (Ticket #130, jdell@gbdev.com). - -* Fixed generated init_engine.rb so that VERSION module doesn't cause probems (Ticket #131, japgolly@gmail.com) - -* Fixed error with Rails 1.0 when trying to ignore the engine_schema_info table (Ticket #132, snowblink@gmail.com) - -* Re-added old style rake tasks (Ticket #133) - -* No longer adding all subdirectories of <engine>/app or <engine>/lib, as this can cause issues when files are grouped in modules (Ticket #149, kasatani@gmail.com) - -* Fixed engine precidence ordering for Rails 1.1 (Ticket #146) - -* Added new Engines.each method to assist in processing the engines in the desired order (Ticket #146) - -* Fixed annoying error message at appears when starting the console in development mode (Ticket #134) - -* Engines is now super-careful about loading the correct version of Rails from vendor (Ticket #154) - - - -= 1.1.1 - -* Fixed migration rake task failing when given a specific version (Ticket #115) - -* Added new rake task "test:engines" which will test engines (and other plugins) but ensure that the test database is cloned from development beforehand (Ticket #125) - -* Fixed issue where 'engine_schema_info' table was included in schema dumps (Ticket #87) - -* Fixed multi-part emails (Ticket #121) - -* Added an 'install.rb' file to new engines created by the bundled generator, which installs the engines plugin automatically if it doesn't already exist (Ticket #122) - -* Added a default VERSION module to generated engines (Ticket #123) - -* Refactored copying of engine's public files to a method of an Engine instance. You can now call Engines.get(:engine_name).copy_public_files (Ticket #108) - -* Changed engine generator templates from .rb files to .erb files (Ticket #106) - -* Fixed the test_helper.erb file to use the correct testing extensions and not load any schema - the schema will be cloned automatically via rake test:engines - -* Fixed problem when running with Rails 1.1.1 where version wasn't determined correctly (Ticket #129) - -* Fixed bug preventing engines from loading when both Rails 1.1.0 and 1.1.1 gems are installed and in use. - -* Updated version (d'oh!) - - - -= 1.1.0 - -* Improved regexp matching for Rails 1.0 engines with peculiar paths - -* Engine instance objects can be accessed via Engines[:name], an alias for Engines.get(:name) (Ticket #99) - -* init_engine.rb is now processed as the final step in the Engine.start process, so it can access files within the lib directory, which is now in the $LOAD_PATH at that point. (Ticket #99) - -* Clarified MIT license (Ticket #98) - -* Updated Rake tasks to integrate smoothly with Rails 1.1 namespaces - -* Changed the version to "1.1.0 (svn)" - -* Added more information about using the plugin with Edge Rails to the README - -* moved extensions into lib/engines/ directory to enable use of Engines module in extension code. - -* Added conditional require_or_load method which attempts to detect the current Rails version. To use the Edge Rails version of the loading mechanism, add the line: - -* Engines.config :edge, true - -* to your environment.rb file. - -* Merged changes from /branches/edge and /branches/rb_1.0 into /trunk - -* engine_schema_info now respects the prefix/suffixes set for ActiveRecord::Base (Ticket #67) - -* added ActiveRecord::Base.wrapped_table_name(name) method to assist in determining the correct table name - - - -= 1.0.6 - -* Added ability to determine version information for engines: rake engine_info - -* Added a custom logger for the Engines module, to stop pollution of the Rails logs. - -* Added some more tests (in particular, see rails_engines/applications/engines_test). - -* Another attempt at solving Ticket #53 - controllers and helpers should now be loadable from modules, and if a full path (including RAILS_ROOT/ENGINES_ROOT) is given, it should be safely stripped from the require filename such that corresponding files can be located in any active engines. In other words, controller/helper overloading should now completely work, even if the controllers/helpers are in modules. - -* Added (finally) patch from Ticket #22 - ActionMailer helpers should now load - -* Removed support for Engines.start :engine, :engine_name => 'whatever'. It was pointless. - -* Fixed engine name referencing; engine_stylesheet/engine_javascript can now happily use shorthand engine names (i.e. :test == :test_engine) (Ticket #45) - -* Fixed minor documentation error ('Engine.start' ==> 'Engines.start') (Ticket #57) - -* Fixed double inclusion of RAILS_ROOT in engine_migrate rake task (Ticket #61) - -* Added ability to force config values even if given as a hash (Ticket #62) - - - -= 1.0.5 - -* Fixed bug stopping fixtures from loading with PostgreSQL - - - -= 1.0.4 - -* Another attempt at loading controllers within modules (Ticket #56) - - - -= 1.0.3 - -* Fixed serious dependency bug stopping controllers being loaded (Ticket #56) - - - -= 1.0.2 - -* Fixed bug with overloading controllers in modules from /app directory - -* Fixed exception thrown when public files couldn't be created; exception is now logged (Ticket #52) - -* Fixed problem with generated test_helper.rb file via File.expand_path (Ticket #50) - - - -= 1.0.1 - -* Added engine generator for creation of new engines - -* Fixed 'Engine' typo in README - -* Fixed bug in fixtures extensions - -* Fixed /lib path management bug - -* Added method to determine public directory location from Engine object - -* Fixed bug in the error message in get_engine_dir() - -* Added proper component loading - -* Added preliminary tests for the config() methods module - - - -= pre-v170 - -* Fixed copyright notices to point to DHH, rather than me. - -* Moved extension require statements into lib/engines.rb, so the will be loaded if another module/file calls require 'engines - -* Added a CHANGELOG file (this file) diff --git a/vendor/plugins/engines/MIT-LICENSE b/vendor/plugins/engines/MIT-LICENSE deleted file mode 100644 index 2718d6d4b..000000000 --- a/vendor/plugins/engines/MIT-LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -Copyright (c) 2008 James Adam - -The MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE.
\ No newline at end of file diff --git a/vendor/plugins/engines/README b/vendor/plugins/engines/README deleted file mode 100644 index e26101344..000000000 --- a/vendor/plugins/engines/README +++ /dev/null @@ -1,83 +0,0 @@ -The engines plugin enhances Rails' own plugin framework, making it simple to share controllers, helpers, models, public assets, routes and migrations in plugins. - -For more information, see http://rails-engines.org - -= Using the plugin - -Once you've installed the engines plugin, you'll need to add a single line to the top of config/environment.rb: - - require File.join(File.dirname(__FILE__), '../vendor/plugins/engines/boot') - -You should add this line just below the require for Rails' own boot.rb file. This will enabled the enhanced plugin loading mechanism automatically for you (i.e. you don't need to set config.plugin_loader manually). - -With that aside, you're now ready to start using more powerful plugins in your application. Read on to find out more about what the engines plugin enables. - - -== Better plugins - -In addition to the regular set of plugin-supported files (lib, init.rb, tasks, generators, tests), plugins can carry the following when the engines plugin is also installed. - - -=== Controllers, Helpers, and Views - -Include these files in an <tt>app</tt> directory just like you would in a normal Rails application. If you need to override a method, view or partial, create the corresponding file in your main <tt>app</tt> directory and it will be used instead. - -* Controllers & Helpers: See Engines::RailsExtensions::Dependencies for more information. -* Views: now handled almost entirely by ActionView itself (see Engines::Plugin#add_plugin_view_paths for more information) - -=== Models - -Model code can similarly be placed in an <tt>app/models/</tt> directory. Unfortunately, it's not possible to automatically override methods within a model; if your application needs to change the way a model behaves, consider creating a subclass, or replacing the model entirely within your application's <tt>app/models/</tt> directory. See Engines::RailsExtensions::Dependencies for more information. - -IMPORTANT NOTE: when you load code from within plugins, it is typically not handled well by Rails in terms of unloading and reloading changes. Look here for more information - http://rails-engines.org/development/common-issues-when-overloading-code-from-plugins/ - -=== Routes - -Include your route declarations in a <tt>routes.rb</tt> file at the root of your plugins, e.g.: - - connect "/my/url", :controller => "some_controller" - my_named_route "do_stuff", :controller => "blah", :action => "stuff" - # etc. - -You can then load these files into your application by declaring their inclusion in the application's <tt>config/routes.rb</tt>: - - map.from_plugin :plugin_name - -See Engines::RailsExtensions::Routing for more information. - -=== Migrations - -Migrations record the changes in your database as your application evolves. With engines 1.2, migrations from plugins can also join in this evolution as first-class entities. To add migrations to a plugin, include a <tt>db/migrate/</tt> folder and add migrations there as normal. These migrations can then be integrated into the main flow of database evolution by running the plugin_migration generator: - - script/generate plugin_migration - -This will produce a migration in your application. Running this migration (via <tt>rake db:migrate</tt>, as normal) will migrate the database according to the latest migrations in each plugin. See Engines::RailsExtensions::Migrations for more information. - - -=== More powerful Rake tasks - -The engines plugin enhances and adds to the suite of default rake tasks for working with plugins. The <tt>doc:plugins</tt> task now includes controllers, helpers and models under <tt>app</tt>, and anything other code found under the plugin's <tt>code_paths</tt> attribute. New testing tasks have been added to run unit, functional and integration tests from plugins, whilst making it easier to load fixtures from plugins. See Engines::Testing for more details about testing, and run - - rake -T - -to see the set of rake tasks available. - -= Testing the engines plugin itself - -Because of the way the engines plugin modifies Rails, the simplest way to consistently test it against multiple versions is by generating a test harness application - a full Rails application that includes tests to verify the engines plugin behaviour in a real, running environment. - -Run the tests like this: - - $ cd engines - $ rake test - -This will generate a test_app directory within the engines plugin (using the default 'rails' command), import tests and code into that application and then run the test suite. - -If you wish to test against a specific version of Rails, run the tests with the RAILS environment variable set to the local directory containing your Rails checkout - - $ rake test RAILS=/Users/james/Code/rails_edge_checkout - -Alternatively, you can clone the latest version of Rails ('edge rails') from github like so: - - $ rake test RAILS=edge - diff --git a/vendor/plugins/engines/Rakefile b/vendor/plugins/engines/Rakefile deleted file mode 100644 index 6c621deeb..000000000 --- a/vendor/plugins/engines/Rakefile +++ /dev/null @@ -1,226 +0,0 @@ -require 'rake' -require 'rake/rdoctask' -require 'tmpdir' - -task :default => :doc - -desc 'Generate documentation for the engines plugin.' -Rake::RDocTask.new(:doc) do |doc| - doc.rdoc_dir = 'doc' - doc.title = 'Engines' - doc.main = "README" - doc.rdoc_files.include("README", "CHANGELOG", "MIT-LICENSE") - doc.rdoc_files.include('lib/**/*.rb') - doc.options << '--line-numbers' << '--inline-source' -end - -desc 'Run the engine plugin tests within their test harness' -task :cruise do - # checkout the project into a temporary directory - version = "rails_2.0" - test_dir = "#{Dir.tmpdir}/engines_plugin_#{version}_test" - puts "Checking out test harness for #{version} into #{test_dir}" - `svn co http://svn.rails-engines.org/test/engines/#{version} #{test_dir}` - - # run all the tests in this project - Dir.chdir(test_dir) - load 'Rakefile' - puts "Running all tests in test harness" - ['db:migrate', 'test', 'test:plugins'].each do |t| - Rake::Task[t].invoke - end -end - -task :clean => [:clobber_doc, "test:clean"] - -namespace :test do - - # Yields a block with STDOUT and STDERR silenced. If you *really* want - # to output something, the block is yielded with the original output - # streams, i.e. - # - # silence do |o, e| - # puts 'hello!' # no output produced - # o.puts 'hello!' # output on STDOUT - # end - # - # (based on silence_stream in ActiveSupport.) - def silence - yield(STDOUT, STDERR) if ENV['VERBOSE'] - streams = [STDOUT, STDERR] - actual_stdout = STDOUT.dup - actual_stderr = STDERR.dup - streams.each do |s| - s.reopen(RUBY_PLATFORM =~ /mswin/ ? 'NUL:' : '/dev/null') - s.sync = true - end - yield actual_stdout, actual_stderr - ensure - STDOUT.reopen(actual_stdout) - STDERR.reopen(actual_stderr) - end - - def test_app_dir - File.join(File.dirname(__FILE__), 'test_app') - end - - def run(cmd) - cmd = cmd.join(" && ") if cmd.is_a?(Array) - system(cmd) || raise("failed running '#{cmd}'") - end - - desc 'Remove the test application' - task :clean do - FileUtils.rm_r(test_app_dir) if File.exist?(test_app_dir) - end - - desc 'Build the test rails application (use RAILS=[edge,<directory>] to test against specific version)' - task :generate_app do - silence do |out, err| - out.puts "> Creating test application at #{test_app_dir}" - - if ENV['RAILS'] - vendor_dir = File.join(test_app_dir, 'vendor') - FileUtils.mkdir_p vendor_dir - - if ENV['RAILS'] == 'edge' - out.puts " Cloning Edge Rails from GitHub" - run "cd #{vendor_dir} && git clone --depth 1 git://github.com/rails/rails.git" - elsif ENV['RAILS'] =~ /\d\.\d\.\d/ - if ENV['CURL'] - out.puts " Cloning Rails Tag #{ENV['RAILS']} from GitHub using curl and tar" - run ["cd #{vendor_dir}", - "mkdir rails", - "cd rails", - "curl -s -L http://github.com/rails/rails/tarball/#{ENV['RAILS']} | tar xzv --strip-components 1"] - else - out.puts " Cloning Rails Tag #{ENV['RAILS']} from GitHub (can be slow - set CURL=true to use curl)" - run ["cd #{vendor_dir}", - "git clone git://github.com/rails/rails.git", - "cd rails", - "git pull", - "git checkout v#{ENV['RAILS']}"] - end - elsif File.exist?(ENV['RAILS']) - out.puts " Linking rails from #{ENV['RAILS']}" - run "cd #{vendor_dir} && ln -s #{ENV['RAILS']} rails" - else - raise "Couldn't build test application from '#{ENV['RAILS']}'" - end - - out.puts " generating rails default directory structure" - run "ruby #{File.join(vendor_dir, 'rails', 'railties', 'bin', 'rails')} #{test_app_dir}" - else - version = `rails --version`.chomp.split.last - out.puts " building rails using the 'rails' command (rails version: #{version})" - run "rails #{test_app_dir}" - end - - # get the database config and schema in place - out.puts " writing database.yml" - require 'yaml' - File.open(File.join(test_app_dir, 'config', 'database.yml'), 'w') do |f| - f.write(%w(development test).inject({}) do |h, env| - h[env] = {"adapter" => "sqlite3", "database" => "engines_#{env}.sqlite3"} ; h - end.to_yaml) - end - out.puts " installing exception_notification plugin" - run "cd #{test_app_dir} && ./script/plugin install git://github.com/rails/exception_notification.git" - end - end - - # We can't link the plugin, as it needs to be present for script/generate to find - # the plugin generator. - # TODO: find and +1/create issue for loading generators from symlinked plugins - desc 'Mirror the engines plugin into the test application' - task :copy_engines_plugin do - puts "> Copying engines plugin into test application" - engines_plugin = File.join(test_app_dir, "vendor", "plugins", "engines") - FileUtils.rm_r(engines_plugin) if File.exist?(engines_plugin) - FileUtils.mkdir_p(engines_plugin) - FileList["*"].exclude("test_app").each do |file| - FileUtils.cp_r(file, engines_plugin) - end - end - - def insert_line(line, options) - line = line + "\n" - target_file = File.join(test_app_dir, options[:into]) - lines = File.readlines(target_file) - return if lines.include?(line) - - if options[:after] - if options[:after].is_a?(String) - after_line = options[:after] + "\n" - else - after_line = lines.find { |l| l =~ options[:after] } - raise "couldn't find a line matching #{options[:after].inspect} in #{target_file}" unless after_line - end - index = lines.index(after_line) - raise "couldn't find line '#{after_line}' in #{target_file}" unless index - lines.insert(index + 1, line) - else - lines << line - end - File.open(target_file, 'w') { |f| f.write lines.join } - end - - def mirror_test_files(src, dest=nil) - destination_dir = File.join(*([test_app_dir, dest].compact)) - FileUtils.cp_r(File.join(File.dirname(__FILE__), 'test', src), destination_dir) - end - - desc 'Update the plugin and tests files in the test application from the plugin' - task :mirror_engine_files => [:test_app, :copy_engines_plugin] do - puts "> Tweaking generated application to be suitable for testing" - - # Replace the Rails plugin loader with the engines one. - insert_line("require File.join(File.dirname(__FILE__), '../vendor/plugins/engines/boot')", - :into => 'config/environment.rb', - :after => "require File.join(File.dirname(__FILE__), 'boot')") - - # Add the engines test helper to handle fixtures & stuff. - insert_line("require 'engines_test_helper'", :into => 'test/test_helper.rb') - - # Run engine plugin tests when running the application - insert_line("task :test => ['test:engines:all']", :into => 'Rakefile') - - # We want exceptions to be raised - insert_line("def rescue_action(e) raise e end;", - :into => "app/controllers/application_controller.rb", - :after => "class ApplicationController < ActionController::Base") - - # We need this method to test where actions are being rendered from. - insert_line("include RenderInformation", - :into => "app/controllers/application_controller.rb", - :after => "class ApplicationController < ActionController::Base") - - puts "> Mirroring test application files into #{test_app_dir}" - mirror_test_files('app') - mirror_test_files('lib') - mirror_test_files('plugins', 'vendor') - mirror_test_files('unit', 'test') - mirror_test_files('functional', 'test') - end - - desc 'Prepare the engines test environment' - task :test_app do - version_tag = File.join(test_app_dir, 'RAILS_VERSION') - existing_version = File.read(version_tag).chomp rescue 'unknown' - if existing_version == ENV['RAILS'] - puts "> Reusing existing test application (#{ENV['RAILS']})" - else - puts "> Recreating test application" - Rake::Task["test:clean"].invoke - Rake::Task["test:generate_app"].invoke - - File.open(version_tag, "w") { |f| f.write ENV['RAILS'] } - end - end -end - -task :test => "test:mirror_engine_files" do - puts "> Loading the test application environment and running tests" - # We use exec here to replace the current running rake process - exec("cd #{test_app_dir} && rake db:migrate && rake") -end diff --git a/vendor/plugins/engines/about.yml b/vendor/plugins/engines/about.yml deleted file mode 100644 index 13f55ec97..000000000 --- a/vendor/plugins/engines/about.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: James Adam -email: james.adam@gmail.com -homepage: http://www.rails-engines.org -summary: Enhances the plugin mechanism to perform more flexible sharing -description: The Rails Engines plugin allows the sharing of almost any type of code or asset that you could use in a Rails application, including controllers, models, stylesheets, and views. -license: MIT -version: 2.3.2
\ No newline at end of file diff --git a/vendor/plugins/engines/boot.rb b/vendor/plugins/engines/boot.rb deleted file mode 100644 index 7dd90d17a..000000000 --- a/vendor/plugins/engines/boot.rb +++ /dev/null @@ -1,17 +0,0 @@ -begin - require 'rails/version' - unless Rails::VERSION::MAJOR >= 2 && Rails::VERSION::MINOR >= 3 && Rails::VERSION::TINY >= 2 - raise "This version of the engines plugin requires Rails 2.3.2 or later!" - end -end - -require File.join(File.dirname(__FILE__), 'lib/engines') - -# initialize Rails::Configuration with our own default values to spare users -# some hassle with the installation and keep the environment cleaner - -{ :default_plugin_locators => (defined?(Gem) ? [Rails::Plugin::GemLocator] : []).push(Engines::Plugin::FileSystemLocator), - :default_plugin_loader => Engines::Plugin::Loader, - :default_plugins => [:engines, :all] }.each do |name, default| - Rails::Configuration.send(:define_method, name) { default } -end
\ No newline at end of file diff --git a/vendor/plugins/engines/generators/plugin_migration/USAGE b/vendor/plugins/engines/generators/plugin_migration/USAGE deleted file mode 100644 index ae05db767..000000000 --- a/vendor/plugins/engines/generators/plugin_migration/USAGE +++ /dev/null @@ -1,45 +0,0 @@ -Description: - The plugin migration generator assists in working with schema additions - required by plugins. Instead of running migrations from plugins directly, - the generator creates a regular Rails migration which will be responsible - for migrating the plugins from their current version to the latest version - installed. - - This is important because the set of application migrations remains an - accurate record of the state of the database, even as plugins are installed - and removed during the development process. - -Example: - ./script/generate plugin_migration [<plugin_name> <another_plugin_name> ...] - - This will generate: - - RAILS_ROOT - |- db - |-migrate - |- xxx_plugin_migrations.rb - - which contains the migrations for the given plugin(s). - - -Advanced Usage: - -There may be situations where you need *complete* control over the migrations -of plugins in your application, migrating a certainly plugin down to X, and -another plugin up to Y, where neither X or Y are the latest migrations for those -plugins. - -For those unfortunate few, I have two pieces of advice: - - 1. Why? This is a code smell [http://c2.com/xp/CodeSmell.html]. - - 2. Well, OK. Don't panic. You can completely control plugin migrations by - creating your own migrations. To manually migrate a plugin to a specific - version, simply use - - Engines.plugins[:your_plugin_name].migrate(version) - - where version is the integer of the migration this plugin should end - up at. - -With great power comes great responsibility. Use this wisely.
\ No newline at end of file diff --git a/vendor/plugins/engines/generators/plugin_migration/plugin_migration_generator.rb b/vendor/plugins/engines/generators/plugin_migration/plugin_migration_generator.rb deleted file mode 100644 index 900dc056b..000000000 --- a/vendor/plugins/engines/generators/plugin_migration/plugin_migration_generator.rb +++ /dev/null @@ -1,98 +0,0 @@ -# Generates a migration which migrates all plugins to their latest versions -# within the database. -class PluginMigrationGenerator < Rails::Generator::Base - - # 255 characters max for Windows NTFS (http://en.wikipedia.org/wiki/Filename) - # minus 14 for timestamp, minus some extra chars for dot, underscore, file - # extension. So let's have 230. - MAX_FILENAME_LENGTH = 230 - - def initialize(runtime_args, runtime_options={}) - super - @options = {:assigns => {}} - ensure_schema_table_exists - get_plugins_to_migrate(runtime_args) - - if @plugins_to_migrate.empty? - puts "All plugins are migrated to their latest versions" - exit(0) - end - - @options[:migration_file_name] = build_migration_name - @options[:assigns][:class_name] = build_migration_name.classify - end - - def manifest - record do |m| - m.migration_template 'plugin_migration.erb', 'db/migrate', @options - end - end - - protected - - # Create the schema table if it doesn't already exist. - def ensure_schema_table_exists - ActiveRecord::Base.connection.initialize_schema_migrations_table - end - - # Determine all the plugins which have migrations that aren't present - # according to the plugin schema information from the database. - def get_plugins_to_migrate(plugin_names) - - # First, grab all the plugins which exist and have migrations - @plugins_to_migrate = if plugin_names.empty? - Engines.plugins - else - plugin_names.map do |name| - Engines.plugins[name] ? Engines.plugins[name] : raise("Cannot find the plugin '#{name}'") - end - end - - @plugins_to_migrate.reject! { |p| !p.respond_to?(:latest_migration) || p.latest_migration.nil? } - - # Then find the current versions from the database - @current_versions = {} - @plugins_to_migrate.each do |plugin| - @current_versions[plugin.name] = Engines::Plugin::Migrator.current_version(plugin) - end - - # Then find the latest versions from their migration directories - @new_versions = {} - @plugins_to_migrate.each do |plugin| - @new_versions[plugin.name] = plugin.latest_migration - end - - # Remove any plugins that don't need migration - @plugins_to_migrate.map { |p| p.name }.each do |name| - @plugins_to_migrate.delete(Engines.plugins[name]) if @current_versions[name] == @new_versions[name] - end - - @options[:assigns][:plugins] = @plugins_to_migrate - @options[:assigns][:new_versions] = @new_versions - @options[:assigns][:current_versions] = @current_versions - end - - # Returns a migration name. If the descriptive migration name based on the - # plugin names involved is shorter than 230 characters that one will be - # used. Otherwise a shorter name will be returned. - def build_migration_name - descriptive_migration_name.tap do |name| - name.replace short_migration_name if name.length > MAX_FILENAME_LENGTH - end - end - - # Construct a unique migration name based on the plugins involved and the - # versions they should reach after this migration is run. The name constructed - # needs to be lowercase - def descriptive_migration_name - @plugins_to_migrate.map do |plugin| - "#{plugin.name}_to_version_#{@new_versions[plugin.name]}" - end.join("_and_").downcase - end - - # Short migration name that will be used if the descriptive_migration_name - # exceeds 230 characters - def short_migration_name - 'plugin_migrations' - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/generators/plugin_migration/templates/plugin_migration.erb b/vendor/plugins/engines/generators/plugin_migration/templates/plugin_migration.erb deleted file mode 100644 index 044f62384..000000000 --- a/vendor/plugins/engines/generators/plugin_migration/templates/plugin_migration.erb +++ /dev/null @@ -1,13 +0,0 @@ -class <%= class_name %> < ActiveRecord::Migration - def self.up - <%- plugins.each do |plugin| -%> - Engines.plugins["<%= plugin.name %>"].migrate(<%= new_versions[plugin.name] %>) - <%- end -%> - end - - def self.down - <%- plugins.each do |plugin| -%> - Engines.plugins["<%= plugin.name %>"].migrate(<%= current_versions[plugin.name] %>) - <%- end -%> - end -end diff --git a/vendor/plugins/engines/init.rb b/vendor/plugins/engines/init.rb deleted file mode 100644 index 28418166a..000000000 --- a/vendor/plugins/engines/init.rb +++ /dev/null @@ -1,5 +0,0 @@ -# Only call Engines.init once, in the after_initialize block so that Rails -# plugin reloading works when turned on -config.after_initialize do - Engines.init(initializer) if defined? :Engines -end
\ No newline at end of file diff --git a/vendor/plugins/engines/lib/engines.rb b/vendor/plugins/engines/lib/engines.rb deleted file mode 100644 index d601710b0..000000000 --- a/vendor/plugins/engines/lib/engines.rb +++ /dev/null @@ -1,174 +0,0 @@ -require 'active_support' -require File.join(File.dirname(__FILE__), 'engines/plugin') -require File.join(File.dirname(__FILE__), 'engines/plugin/list') -require File.join(File.dirname(__FILE__), 'engines/plugin/loader') -require File.join(File.dirname(__FILE__), 'engines/plugin/locator') -require File.join(File.dirname(__FILE__), 'engines/assets') -require File.join(File.dirname(__FILE__), 'engines/rails_extensions/rails') - -# == Parameters -# -# The Engines module has a number of public configuration parameters: -# -# [+public_directory+] The directory into which plugin assets should be -# mirrored. Defaults to <tt>RAILS_ROOT/public/plugin_assets</tt>. -# [+schema_info_table+] The table to use when storing plugin migration -# version information. Defaults to +plugin_schema_info+. -# -# Additionally, there are a few flags which control the behaviour of -# some of the features the engines plugin adds to Rails: -# -# [+disable_application_view_loading+] A boolean flag determining whether -# or not views should be loaded from -# the main <tt>app/views</tt> directory. -# Defaults to false; probably only -# useful when testing your plugin. -# [+disable_application_code_loading+] A boolean flag determining whether -# or not to load controllers/helpers -# from the main +app+ directory, -# if corresponding code exists within -# a plugin. Defaults to false; again, -# probably only useful when testing -# your plugin. -# [+disable_code_mixing+] A boolean flag indicating whether all plugin -# copies of a particular controller/helper should -# be loaded and allowed to override each other, -# or if the first matching file should be loaded -# instead. Defaults to false. -# -module Engines - # The set of all loaded plugins - mattr_accessor :plugins - self.plugins = Engines::Plugin::List.new - - # List of extensions to load, can be changed in init.rb before calling Engines.init - mattr_accessor :rails_extensions - self.rails_extensions = %w(asset_helpers form_tag_helpers migrations dependencies) - - # The name of the public directory to mirror public engine assets into. - # Defaults to <tt>RAILS_ROOT/public/plugin_assets</tt>. - mattr_accessor :public_directory - self.public_directory = File.join(RAILS_ROOT, 'public', 'plugin_assets') - - # The table in which to store plugin schema information. Defaults to - # "plugin_schema_info". - mattr_accessor :schema_info_table - self.schema_info_table = "plugin_schema_info" - - #-- - # These attributes control the behaviour of the engines extensions - #++ - - # Set this to true if views should *only* be loaded from plugins - mattr_accessor :disable_application_view_loading - self.disable_application_view_loading = false - - # Set this to true if controller/helper code shouldn't be loaded - # from the application - mattr_accessor :disable_application_code_loading - self.disable_application_code_loading = false - - # Set this to true if code should not be mixed (i.e. it will be loaded - # from the first valid path on $LOAD_PATH) - mattr_accessor :disable_code_mixing - self.disable_code_mixing = false - - # This is used to determine which files are candidates for the "code - # mixing" feature that the engines plugin provides, where classes from - # plugins can be loaded, and then code from the application loaded - # on top of that code to override certain methods. - mattr_accessor :code_mixing_file_types - self.code_mixing_file_types = %w(controller helper) - - class << self - def init(initializer) - load_extensions - Engines::Assets.initialize_base_public_directory - end - - def logger - RAILS_DEFAULT_LOGGER - end - - def load_extensions - rails_extensions.each { |name| require "engines/rails_extensions/#{name}" } - # load the testing extensions, if we are in the test environment. - require "engines/testing" if RAILS_ENV == "test" - end - - def select_existing_paths(paths) - paths.select { |path| File.directory?(path) } - end - - # The engines plugin will, by default, mix code from controllers and helpers, - # allowing application code to override specific methods in the corresponding - # controller or helper classes and modules. However, if other file types should - # also be mixed like this, they can be added by calling this method. For example, - # if you want to include "things" within your plugin and override them from - # your applications, you should use the following layout: - # - # app/ - # +-- things/ - # | +-- one_thing.rb - # | +-- another_thing.rb - # ... - # vendor/ - # +-- plugins/ - # +-- my_plugin/ - # +-- app/ - # +-- things/ - # +-- one_thing.rb - # +-- another_thing.rb - # - # The important point here is that your "things" are named <whatever>_thing.rb, - # and that they are placed within plugin/app/things (the pluralized form of 'thing'). - # - # It's important to note that you'll also want to ensure that the "things" are - # on your load path by including them in Rails load path mechanism, e.g. in init.rb: - # - # ActiveSupport::Dependencies.load_paths << File.join(File.dirname(__FILE__), 'app', 'things')) - # - def mix_code_from(*types) - self.code_mixing_file_types += types.map { |x| x.to_s.singularize } - end - - # A general purpose method to mirror a directory (+source+) into a destination - # directory, including all files and subdirectories. Files will not be mirrored - # if they are identical already (checked via FileUtils#identical?). - def mirror_files_from(source, destination) - return unless File.directory?(source) - - # TODO: use Rake::FileList#pathmap? - source_files = Dir[source + "/**/*"] - source_dirs = source_files.select { |d| File.directory?(d) } - source_files -= source_dirs - - unless source_files.empty? - base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, '')) - FileUtils.mkdir_p(base_target_dir) - end - - source_dirs.each do |dir| - # strip down these paths so we have simple, relative paths we can - # add to the destination - target_dir = File.join(destination, dir.gsub(source, '')) - begin - FileUtils.mkdir_p(target_dir) - rescue Exception => e - raise "Could not create directory #{target_dir}: \n" + e - end - end - - source_files.each do |file| - begin - target = File.join(destination, file.gsub(source, '')) - unless File.exist?(target) && FileUtils.identical?(file, target) - FileUtils.cp(file, target) - end - rescue Exception => e - raise "Could not copy #{file} to #{target}: \n" + e - end - end - end - end -end diff --git a/vendor/plugins/engines/lib/engines/assets.rb b/vendor/plugins/engines/lib/engines/assets.rb deleted file mode 100644 index e6435bb1d..000000000 --- a/vendor/plugins/engines/lib/engines/assets.rb +++ /dev/null @@ -1,36 +0,0 @@ -module Engines - module Assets - class << self - @@readme = %{Files in this directory are automatically generated from your plugins. -They are copied from the 'assets' directories of each plugin into this directory -each time Rails starts (script/server, script/console... and so on). -Any edits you make will NOT persist across the next server restart; instead you -should edit the files within the <plugin_name>/assets/ directory itself.} - - # Ensure that the plugin asset subdirectory of RAILS_ROOT/public exists, and - # that we've added a little warning message to instruct developers not to mess with - # the files inside, since they're automatically generated. - def initialize_base_public_directory - dir = Engines.public_directory - unless File.exist?(dir) - FileUtils.mkdir_p(dir) - end - readme = File.join(dir, "README") - File.open(readme, 'w') { |f| f.puts @@readme } unless File.exist?(readme) - end - - # Replicates the subdirectories under the plugins's +assets+ (or +public+) - # directory into the corresponding public directory. See also - # Plugin#public_directory for more. - def mirror_files_for(plugin) - return if plugin.public_directory.nil? - begin - Engines.mirror_files_from(plugin.public_directory, File.join(Engines.public_directory, plugin.name)) - rescue Exception => e - Engines.logger.warn "WARNING: Couldn't create the public file structure for plugin '#{plugin.name}'; Error follows:" - Engines.logger.warn e - end - end - end - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/lib/engines/plugin.rb b/vendor/plugins/engines/lib/engines/plugin.rb deleted file mode 100644 index c52bbb0ce..000000000 --- a/vendor/plugins/engines/lib/engines/plugin.rb +++ /dev/null @@ -1,97 +0,0 @@ -# An instance of Plugin is created for each plugin loaded by Rails, and -# stored in the <tt>Engines.plugins</tt> PluginList -# (see Engines::RailsExtensions::RailsInitializer for more details). -# -# Engines.plugins[:plugin_name] -# -# Other properties of the Plugin instance can also be set. -module Engines - class Plugin < Rails::Plugin - # Plugins can add paths to this attribute in init.rb if they need - # controllers loaded from additional locations. - attr_accessor :controller_paths - - # The directory in this plugin to mirror into the shared directory - # under +public+. - # - # Defaults to "assets" (see default_public_directory). - attr_accessor :public_directory - - protected - # The default set of code paths which will be added to the routing system - def default_controller_paths - %w(app/controllers components) - end - - # Attempts to detect the directory to use for public files. - # If +assets+ exists in the plugin, this will be used. If +assets+ is missing - # but +public+ is found, +public+ will be used. - def default_public_directory - Engines.select_existing_paths(%w(assets public).map { |p| File.join(directory, p) }).first - end - - public - - def initialize(directory) - super directory - @controller_paths = default_controller_paths - @public_directory = default_public_directory - end - - # Extends the superclass' load method to additionally mirror public assets - def load(initializer) - return if loaded? - super initializer - add_plugin_locale_paths - Assets.mirror_files_for(self) - end - - # select those paths that actually exist in the plugin's directory - def select_existing_paths(name) - Engines.select_existing_paths(self.send(name).map { |p| File.join(directory, p) }) - end - - def add_plugin_locale_paths - locale_path = File.join(directory, 'locales') - return unless File.exists?(locale_path) - - locale_files = Dir[File.join(locale_path, '*.{rb,yml}')] - return if locale_files.blank? - - first_app_element = - I18n.load_path.select{ |e| e =~ /^#{ RAILS_ROOT }/ }.reject{ |e| e =~ /^#{ RAILS_ROOT }\/vendor\/plugins/ }.first - app_index = I18n.load_path.index(first_app_element) || - 1 - - I18n.load_path.insert(app_index, *locale_files) - end - - # The path to this plugin's public files - def public_asset_directory - "#{File.basename(Engines.public_directory)}/#{name}" - end - - # The directory containing this plugin's migrations (<tt>plugin/db/migrate</tt>) - def migration_directory - File.join(self.directory, 'db', 'migrate') - end - - # Returns the version number of the latest migration for this plugin. Returns - # nil if this plugin has no migrations. - def latest_migration - migrations.last - end - - # Returns the version numbers of all migrations for this plugin. - def migrations - migrations = Dir[migration_directory+"/*.rb"] - migrations.map { |p| File.basename(p).match(/0*(\d+)\_/)[1].to_i }.sort - end - - # Migrate this plugin to the given version. See Engines::Plugin::Migrator for more - # information. - def migrate(version = nil) - Engines::Plugin::Migrator.migrate_plugin(self, version) - end - end -end - diff --git a/vendor/plugins/engines/lib/engines/plugin/list.rb b/vendor/plugins/engines/lib/engines/plugin/list.rb deleted file mode 100644 index 316fa575f..000000000 --- a/vendor/plugins/engines/lib/engines/plugin/list.rb +++ /dev/null @@ -1,30 +0,0 @@ -# The PluginList class is an array, enhanced to allow access to loaded plugins -# by name, and iteration over loaded plugins in order of priority. This array is used -# by Engines::RailsExtensions::RailsInitializer to create the Engines.plugins array. -# -# Each loaded plugin has a corresponding Plugin instance within this array, and -# the order the plugins were loaded is reflected in the entries in this array. -# -# For more information, see the Rails module. -module Engines - class Plugin - class List < Array - # Finds plugins with the set with the given name (accepts Strings or Symbols), or - # index. So, Engines.plugins[0] returns the first-loaded Plugin, and Engines.plugins[:engines] - # returns the Plugin instance for the engines plugin itself. - def [](name_or_index) - if name_or_index.is_a?(Fixnum) - super - else - self.find { |plugin| plugin.name.to_s == name_or_index.to_s } - end - end - - # Go through each plugin, highest priority first (last loaded first). Effectively, - # this is like <tt>Engines.plugins.reverse</tt> - def by_precedence - reverse - end - end - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/lib/engines/plugin/loader.rb b/vendor/plugins/engines/lib/engines/plugin/loader.rb deleted file mode 100644 index e316e4750..000000000 --- a/vendor/plugins/engines/lib/engines/plugin/loader.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Engines - class Plugin - class Loader < Rails::Plugin::Loader - protected - def register_plugin_as_loaded(plugin) - super plugin - Engines.plugins << plugin - end - end - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/lib/engines/plugin/locator.rb b/vendor/plugins/engines/lib/engines/plugin/locator.rb deleted file mode 100644 index 1ff5c7626..000000000 --- a/vendor/plugins/engines/lib/engines/plugin/locator.rb +++ /dev/null @@ -1,11 +0,0 @@ -module Engines - class Plugin - class FileSystemLocator < Rails::Plugin::FileSystemLocator - def create_plugin(path) - plugin = Engines::Plugin.new(path) - plugin.valid? ? plugin : nil - end - end - end -end - diff --git a/vendor/plugins/engines/lib/engines/plugin/migrator.rb b/vendor/plugins/engines/lib/engines/plugin/migrator.rb deleted file mode 100644 index 05379d992..000000000 --- a/vendor/plugins/engines/lib/engines/plugin/migrator.rb +++ /dev/null @@ -1,41 +0,0 @@ -# The Plugin::Migrator class contains the logic to run migrations from -# within plugin directories. The directory in which a plugin's migrations -# should be is determined by the Plugin#migration_directory method. -# -# To migrate a plugin, you can simple call the migrate method (Plugin#migrate) -# with the version number that plugin should be at. The plugin's migrations -# will then be used to migrate up (or down) to the given version. -# -# For more information, see Engines::RailsExtensions::Migrations -class Engines::Plugin::Migrator < ActiveRecord::Migrator - - # We need to be able to set the 'current' engine being migrated. - cattr_accessor :current_plugin - - class << self - # Runs the migrations from a plugin, up (or down) to the version given - def migrate_plugin(plugin, version) - self.current_plugin = plugin - return if current_version(plugin) == version - migrate(plugin.migration_directory, version) - end - - def current_version(plugin=current_plugin) - # Delete migrations that don't match .. to_i will work because the number comes first - ::ActiveRecord::Base.connection.select_values( - "SELECT version FROM #{schema_migrations_table_name}" - ).delete_if{ |v| v.match(/-#{plugin.name}/) == nil }.map(&:to_i).max || 0 - end - end - - def migrated - sm_table = self.class.schema_migrations_table_name - ::ActiveRecord::Base.connection.select_values( - "SELECT version FROM #{sm_table}" - ).delete_if{ |v| v.match(/-#{current_plugin.name}/) == nil }.map(&:to_i).sort - end - - def record_version_state_after_migrating(version) - super(version.to_s + "-" + current_plugin.name) - end -end diff --git a/vendor/plugins/engines/lib/engines/rails_extensions/asset_helpers.rb b/vendor/plugins/engines/lib/engines/rails_extensions/asset_helpers.rb deleted file mode 100644 index a4a9266f2..000000000 --- a/vendor/plugins/engines/lib/engines/rails_extensions/asset_helpers.rb +++ /dev/null @@ -1,119 +0,0 @@ -# The engines plugin makes it trivial to share public assets using plugins. -# To do this, include an <tt>assets</tt> directory within your plugin, and put -# your javascripts, stylesheets and images in subdirectories of that folder: -# -# my_plugin -# |- init.rb -# |- lib/ -# |- assets/ -# |- javascripts/ -# | |- my_functions.js -# | -# |- stylesheets/ -# | |- my_styles.css -# | -# |- images/ -# |- my_face.jpg -# -# Files within the <tt>asset</tt> structure are automatically mirrored into -# a publicly-accessible folder each time your application starts (see -# Engines::Assets#mirror_assets). -# -# -# == Using plugin assets in views -# -# It's also simple to use Rails' helpers in your views to use plugin assets. -# The default helper methods have been enhanced by the engines plugin to accept -# a <tt>:plugin</tt> option, indicating the plugin containing the desired asset. -# -# For example, it's easy to use plugin assets in your layouts: -# -# <%= stylesheet_link_tag "my_styles", :plugin => "my_plugin", :media => "screen" %> -# <%= javascript_include_tag "my_functions", :plugin => "my_plugin" %> -# -# ... and similarly in views and partials, it's easy to use plugin images: -# -# <%= image_tag "my_face", :plugin => "my_plugin" %> -# <!-- or --> -# <%= image_path "my_face", :plugin => "my_plugin" %> -# -# Where the default helpers allow the specification of more than one file (i.e. the -# javascript and stylesheet helpers), you can do similarly for multiple assets from -# within a single plugin. -# -# --- -# -# This module enhances four of the methods from ActionView::Helpers::AssetTagHelper: -# -# * stylesheet_link_tag -# * javascript_include_tag -# * image_path -# * image_tag -# -# Each one of these methods now accepts the key/value pair <tt>:plugin => "plugin_name"</tt>, -# which can be used to specify the originating plugin for any assets. -# -module Engines::RailsExtensions::AssetHelpers - def self.included(base) #:nodoc: - base.class_eval do - [:stylesheet_link_tag, :javascript_include_tag, :image_path, :image_tag].each do |m| - alias_method_chain m, :engine_additions - end - end - end - - # Adds plugin functionality to Rails' default stylesheet_link_tag method. - def stylesheet_link_tag_with_engine_additions(*sources) - stylesheet_link_tag_without_engine_additions(*Engines::RailsExtensions::AssetHelpers.pluginify_sources("stylesheets", *sources)) - end - - # Adds plugin functionality to Rails' default javascript_include_tag method. - def javascript_include_tag_with_engine_additions(*sources) - javascript_include_tag_without_engine_additions(*Engines::RailsExtensions::AssetHelpers.pluginify_sources("javascripts", *sources)) - end - - #-- - # Our modified image_path now takes a 'plugin' option, though it doesn't require it - #++ - - # Adds plugin functionality to Rails' default image_path method. - def image_path_with_engine_additions(source, options={}) - options.stringify_keys! - source = Engines::RailsExtensions::AssetHelpers.plugin_asset_path(options["plugin"], "images", source) if options["plugin"] - image_path_without_engine_additions(source) - end - - # Adds plugin functionality to Rails' default image_tag method. - def image_tag_with_engine_additions(source, options={}) - options.stringify_keys! - if options["plugin"] - source = Engines::RailsExtensions::AssetHelpers.plugin_asset_path(options["plugin"], "images", source) - options.delete("plugin") - end - image_tag_without_engine_additions(source, options) - end - - #-- - # The following are methods on this module directly because of the weird-freaky way - # Rails creates the helper instance that views actually get - #++ - - # Convert sources to the paths for the given plugin, if any plugin option is given - def self.pluginify_sources(type, *sources) - options = sources.last.is_a?(Hash) ? sources.pop.stringify_keys : { } - sources.map! { |s| plugin_asset_path(options["plugin"], type, s) } if options["plugin"] - options.delete("plugin") # we don't want it appearing in the HTML - sources << options # re-add options - end - - # Returns the publicly-addressable relative URI for the given asset, type and plugin - def self.plugin_asset_path(plugin_name, type, asset) - raise "No plugin called '#{plugin_name}' - please use the full name of a loaded plugin." if Engines.plugins[plugin_name].nil? - "#{ActionController::Base.relative_url_root}/#{Engines.plugins[plugin_name].public_asset_directory}/#{type}/#{asset}" - end - -end - -module ::ActionView::Helpers::AssetTagHelper #:nodoc: - include Engines::RailsExtensions::AssetHelpers -end diff --git a/vendor/plugins/engines/lib/engines/rails_extensions/dependencies.rb b/vendor/plugins/engines/lib/engines/rails_extensions/dependencies.rb deleted file mode 100644 index f18b19a4a..000000000 --- a/vendor/plugins/engines/lib/engines/rails_extensions/dependencies.rb +++ /dev/null @@ -1,138 +0,0 @@ -# One of the magic features that that engines plugin provides is the ability to -# override selected methods in controllers and helpers from your application. -# This is achieved by trapping requests to load those files, and then mixing in -# code from plugins (in the order the plugins were loaded) before finally loading -# any versions from the main +app+ directory. -# -# The behaviour of this extension is output to the log file for help when -# debugging. -# -# == Example -# -# A plugin contains the following controller in <tt>plugin/app/controllers/my_controller.rb</tt>: -# -# class MyController < ApplicationController -# def index -# @name = "HAL 9000" -# end -# def list -# @robots = Robot.find(:all) -# end -# end -# -# In one application that uses this plugin, we decide that the name used in the -# index action should be "Robbie", not "HAL 9000". To override this single method, -# we create the corresponding controller in our application -# (<tt>RAILS_ROOT/app/controllers/my_controller.rb</tt>), and redefine the method: -# -# class MyController < ApplicationController -# def index -# @name = "Robbie" -# end -# end -# -# The list method remains as it was defined in the plugin controller. -# -# The same basic principle applies to helpers, and also views and partials (although -# view overriding is performed in Engines::RailsExtensions::Templates; see that -# module for more information). -# -# === What about models? -# -# Unfortunately, it's not possible to provide this kind of magic for models. -# The only reason why it's possible for controllers and helpers is because -# they can be recognised by their filenames ("whatever_controller", "jazz_helper"), -# whereas models appear the same as any other typical Ruby library ("node", -# "user", "image", etc.). -# -# If mixing were allowed in models, it would mean code mixing for *every* -# file that was loaded via +require_or_load+, and this could result in -# problems where, for example, a Node model might start to include -# functionality from another file called "node" somewhere else in the -# <tt>$LOAD_PATH</tt>. -# -# One way to overcome this is to provide model functionality as a module in -# a plugin, which developers can then include into their own model -# implementations. -# -# Another option is to provide an abstract model (see the ActiveRecord::Base -# documentation) and have developers subclass this model in their own -# application if they must. -# -# --- -# -# The Engines::RailsExtensions::Dependencies module includes a method to -# override Dependencies.require_or_load, which is called to load code needed -# by Rails as it encounters constants that aren't defined. -# -# This method is enhanced with the code-mixing features described above. -# -module Engines::RailsExtensions::Dependencies - def self.included(base) #:nodoc: - base.class_eval { alias_method_chain :require_or_load, :engine_additions } - end - - # Attempt to load the given file from any plugins, as well as the application. - # This performs the 'code mixing' magic, allowing application controllers and - # helpers to override single methods from those in plugins. - # If the file can be found in any plugins, it will be loaded first from those - # locations. Finally, the application version is loaded, using Ruby's behaviour - # to replace existing methods with their new definitions. - # - # If <tt>Engines.disable_code_mixing == true</tt>, the first controller/helper on the - # <tt>$LOAD_PATH</tt> will be used (plugins' +app+ directories are always lower on the - # <tt>$LOAD_PATH</tt> than the main +app+ directory). - # - # If <tt>Engines.disable_application_code_loading == true</tt>, controllers will - # not be loaded from the main +app+ directory *if* they are present in any - # plugins. - # - # Returns true if the file could be loaded (from anywhere); false otherwise - - # mirroring the behaviour of +require_or_load+ from Rails (which mirrors - # that of Ruby's own +require+, I believe). - def require_or_load_with_engine_additions(file_name, const_path=nil) - return require_or_load_without_engine_additions(file_name, const_path) if Engines.disable_code_mixing - - file_loaded = false - - # try and load the plugin code first - # can't use model, as there's nothing in the name to indicate that the file is a 'model' file - # rather than a library or anything else. - Engines.code_mixing_file_types.each do |file_type| - # if we recognise this type - # (this regexp splits out the module/filename from any instances of app/#{type}, so that - # modules are still respected.) - if file_name =~ /^(.*app\/#{file_type}s\/)+(.*_#{file_type})(\.rb)?$/ - base_name = $2 - # ... go through the plugins from first started to last, so that - # code with a high precedence (started later) will override lower precedence - # implementations - Engines.plugins.each do |plugin| - plugin_file_name = File.expand_path(File.join(plugin.directory, 'app', "#{file_type}s", base_name)) - if File.file?("#{plugin_file_name}.rb") - file_loaded = true if require_or_load_without_engine_additions(plugin_file_name, const_path) - end - end - - # finally, load any application-specific controller classes using the 'proper' - # rails load mechanism, EXCEPT when we're testing engines and could load this file - # from an engine - unless Engines.disable_application_code_loading - # Ensure we are only loading from the /app directory at this point - app_file_name = File.join(RAILS_ROOT, 'app', "#{file_type}s", "#{base_name}") - if File.file?("#{app_file_name}.rb") - file_loaded = true if require_or_load_without_engine_additions(app_file_name, const_path) - end - end - end - end - - # if we managed to load a file, return true. If not, default to the original method. - # Note that this relies on the RHS of a boolean || not to be evaluated if the LHS is true. - file_loaded || require_or_load_without_engine_additions(file_name, const_path) - end -end - -module ActiveSupport::Dependencies #:nodoc: - include Engines::RailsExtensions::Dependencies -end diff --git a/vendor/plugins/engines/lib/engines/rails_extensions/form_tag_helpers.rb b/vendor/plugins/engines/lib/engines/rails_extensions/form_tag_helpers.rb deleted file mode 100644 index c4dab3cf7..000000000 --- a/vendor/plugins/engines/lib/engines/rails_extensions/form_tag_helpers.rb +++ /dev/null @@ -1,37 +0,0 @@ -# == Using plugin assets for form tag helpers -# -# It's as easy to use plugin images for image_submit_tag using Engines as it is for image_tag: -# -# <%= image_submit_tag "my_face", :plugin => "my_plugin" %> -# -# --- -# -# This module enhances one of the methods from ActionView::Helpers::FormTagHelper: -# -# * image_submit_tag -# -# This method now accepts the key/value pair <tt>:plugin => "plugin_name"</tt>, -# which can be used to specify the originating plugin for any assets. -# -module Engines::RailsExtensions::FormTagHelpers - def self.included(base) - base.class_eval do - alias_method_chain :image_submit_tag, :engine_additions - end - end - - # Adds plugin functionality to Rails' default image_submit_tag method. - def image_submit_tag_with_engine_additions(source, options={}) - options.stringify_keys! - if options["plugin"] - source = Engines::RailsExtensions::AssetHelpers.plugin_asset_path(options["plugin"], "images", source) - options.delete("plugin") - end - image_submit_tag_without_engine_additions(source, options) - end -end - -module ::ActionView::Helpers::FormTagHelper #:nodoc: - include Engines::RailsExtensions::FormTagHelpers -end - diff --git a/vendor/plugins/engines/lib/engines/rails_extensions/migrations.rb b/vendor/plugins/engines/lib/engines/rails_extensions/migrations.rb deleted file mode 100644 index 7f51cb844..000000000 --- a/vendor/plugins/engines/lib/engines/rails_extensions/migrations.rb +++ /dev/null @@ -1,133 +0,0 @@ -# Contains the enhancements to Rails' migrations system to support the -# Engines::Plugin::Migrator. See Engines::RailsExtensions::Migrations for more -# information. - -require "engines/plugin/migrator" - -# = Plugins and Migrations: Background -# -# Rails uses migrations to describe changes to the databases as your application -# evolves. Each change to your application - adding and removing models, most -# commonly - might require tweaks to your schema in the form of new tables, or new -# columns on existing tables, or possibly the removal of tables or columns. Migrations -# can even include arbitrary code to *transform* data as the underlying schema -# changes. -# -# The point is that at any particular stage in your application's development, -# migrations serve to transform the database into a state where it is compatible -# and appropriate at that time. -# -# == What about plugins? -# -# If you want to share models using plugins, chances are that you might also -# want to include the corresponding migrations to create tables for those models. -# With the engines plugin installed, plugins can carry migration data easily: -# -# vendor/ -# | -# plugins/ -# | -# my_plugin/ -# |- init.rb -# |- lib/ -# |- db/ -# |-migrate/ -# |- 20081105123419_add_some_new_feature.rb -# |- 20081107144959_and_something_else.rb -# |- ... -# -# When you install a plugin which contains migrations, you are undertaking a -# further step in the development of your application, the same as the addition -# of any other code. With this in mind, you may want to 'roll back' the -# installation of this plugin at some point, and the database should be able -# to migrate back to the point without this plugin in it too. -# -# == An example -# -# For example, our current application is at version 20081106164503 (according to the -# +schema_migrations+ table), when we decide that we want to add a tagging plugin. The -# tagging plugin chosen includes migrations to create the tables it requires -# (say, _tags_ and _taggings_, for instance), along with the models and helpers -# one might expect. -# -# After installing this plugin, these tables should be created in our database. -# Rather than running the migrations directly from the plugin, they should be -# integrated into our main migration stream in order to accurately reflect the -# state of our application's database *at this moment in time*. -# -# $ script/generate plugin_migration -# exists db/migrate -# create db/migrate/20081108120415_my_plugin_to_version_20081107144959.rb -# -# This migration will take our application to version 20081108120415, and contains the -# following, typical migration code: -# -# class TaggingToVersion20081107144959 < ActiveRecord::Migration -# def self.up -# Engines.plugins[:tagging].migrate(20081107144959) -# end -# def self.down -# Engines.plugins[:tagging].migrate(0) -# end -# end -# -# When we migrate our application up, using <tt>rake db:migrate</tt> as normal, -# the plugin will be migrated up to its latest version (20081108120415 in this example). If we -# ever decide to migrate the application back to the state it was in at version 20081106164503, -# the plugin migrations will be taken back down to version 0 (which, typically, -# would remove all tables the plugin migrations define). -# -# == Upgrading plugins -# -# It might happen that later in an application's life, we update to a new version of -# the tagging plugin which requires some changes to our database. The tagging plugin -# provides these changes in the form of its own migrations. -# -# In this case, we just need to re-run the plugin_migration generator to create a -# new migration from the current revision to the newest one: -# -# $ script/generate plugin_migration -# exists db/migrate -# create db/migrate/20081210131437_tagging_to_version_20081201172034.rb -# -# The contents of this migration are: -# -# class TaggingToVersion20081108120415 < ActiveRecord::Migration -# def self.up -# Engines.plugins[:tagging].migrate(20081201172034) -# end -# def self.down -# Engines.plugins[:tagging].migrate(20081107144959) -# end -# end -# -# Notice that if we were to migrate down to revision 20081108120415 or lower, the tagging plugin -# will be migrated back down to version 20081107144959 - the version we were previously at. -# -# -# = Creating migrations in plugins -# -# In order to use the plugin migration functionality that engines provides, a plugin -# only needs to provide regular migrations in a <tt>db/migrate</tt> folder within it. -# -# = Explicitly migrating plugins -# -# It's possible to migrate plugins within your own migrations, or any other code. -# Simply get the Plugin instance, and its Plugin#migrate method with the version -# you wish to end up at: -# -# Engines.plugins[:whatever].migrate(version) -# -# -# = Upgrading from previous versions of the engines plugin -# -# Thanks to the tireless work of the plugin developer community, we can now relying on the migration -# mechanism in Rails 2.1+ to do much of the plugin migration work for us. This also means that we -# don't need a seperate schema_info table for plugins. -# -# To update your application, run -# -# rake db:migrate:upgrade_plugin_migrations -# -# This will ensure that migration information is carried over into the main schema_migrations table. -#
\ No newline at end of file diff --git a/vendor/plugins/engines/lib/engines/rails_extensions/rails.rb b/vendor/plugins/engines/lib/engines/rails_extensions/rails.rb deleted file mode 100644 index 3692d0d0e..000000000 --- a/vendor/plugins/engines/lib/engines/rails_extensions/rails.rb +++ /dev/null @@ -1,11 +0,0 @@ -# This is only here to allow for backwards compability with Engines that -# have been implemented based on Engines for Rails 1.2. It is preferred that -# the plugin list be accessed via Engines.plugins. - -module Rails - # Returns the Engines::Plugin::List from Engines.plugins. It is preferable to - # access Engines.plugins directly. - def self.plugins - Engines.plugins - end -end diff --git a/vendor/plugins/engines/lib/engines/testing.rb b/vendor/plugins/engines/lib/engines/testing.rb deleted file mode 100644 index c411f8335..000000000 --- a/vendor/plugins/engines/lib/engines/testing.rb +++ /dev/null @@ -1,101 +0,0 @@ -# Contains the enhancements to assist in testing plugins. See Engines::Testing -# for more details. - -require 'test/unit' - -require 'tmpdir' -require 'fileutils' - -# In most cases, Rails' own plugin testing mechanisms are sufficient. However, there -# are cases where plugins can be given a helping hand in the testing arena. This module -# contains some methods to assist when testing plugins that contain fixtures. -# -# == Fixtures and plugins -# -# Since Rails' own fixtures method is fairly strict about where files can be loaded from, -# the simplest approach when running plugin tests with fixtures is to simply copy all -# fixtures into a single temporary location and inform the standard Rails mechanism to -# use this directory, rather than RAILS_ROOT/test/fixtures. -# -# The Engines::Testing#setup_plugin_fixtures method does this, copying all plugin fixtures -# into the temporary location before and tests are performed. This behaviour is invoked -# the the rake tasks provided by the Engines plugin, in the "test:plugins" namespace. If -# necessary, you can invoke the task manually. -# -# If you wish to take advantage of this, add a call to the Engines::Testing.set_fixture_path -# method somewhere before your tests (in a test_helper file, or above the TestCase itself). -# -# = Testing plugins -# -# Normally testing a plugin will require that Rails is loaded, unless you are including -# a skeleton Rails environment or set of mocks within your plugin tests. If you require -# the Rails environment to be started, you must ensure that this actually happens; while -# it's not obvious, your tests do not automatically run with Rails loaded. -# -# The simplest way to setup plugin tests is to include a test helper with the following -# contents: -# -# # Load the normal Rails helper. This ensures the environment is loaded -# require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper') -# # Ensure that we are using the temporary fixture path -# Engines::Testing.set_fixture_path -# -# Then run tests using the provided tasks (<tt>test:plugins</tt>, or the tasks that the engines -# plugin provides - <tt>test:plugins:units</tt>, etc.). -# -# Alternatively, you can explicitly load the environment by adpating the contents of the -# default <tt>test_helper</tt>: -# -# ENV["RAILS_ENV"] = "test" -# # Note that we are requiring config/environment from the root of the enclosing application. -# require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment") -# require 'test_help' -# -module Engines::Testing - mattr_accessor :temporary_fixtures_directory - self.temporary_fixtures_directory = FileUtils.mkdir_p(File.join(Dir.tmpdir, "rails_fixtures")) - - # Copies fixtures from plugins and the application into a temporary directory - # (Engines::Testing.temporary_fixtures_directory). - # - # If a set of plugins is not given, fixtures are copied from all plugins in order - # of precedence, meaning that plugins can 'overwrite' the fixtures of others if they are - # loaded later; the application's fixtures are copied last, allowing any custom fixtures - # to override those in the plugins. If no argument is given, plugins are loaded via - # PluginList#by_precedence. - # - # This method is called by the engines-supplied plugin testing rake tasks - def self.setup_plugin_fixtures(plugins = Engines.plugins.by_precedence) - - # First, clear the directory - Dir.glob("#{self.temporary_fixtures_directory}/*.yml").each{|fixture| File.delete(fixture)} - - # Copy all plugin fixtures, and then the application fixtures, into this directory - plugins.each do |plugin| - plugin_fixtures_directory = File.join(plugin.directory, "test", "fixtures") - plugin_app_directory = File.join(plugin.directory, "app") - if File.directory?(plugin_app_directory) && File.directory?(plugin_fixtures_directory) - Engines.mirror_files_from(plugin_fixtures_directory, self.temporary_fixtures_directory) - end - end - Engines.mirror_files_from(File.join(RAILS_ROOT, "test", "fixtures"), - self.temporary_fixtures_directory) - end - - # Sets the fixture path used by Test::Unit::TestCase to the temporary - # directory which contains all plugin fixtures. - def self.set_fixture_path - ActiveSupport::TestCase.fixture_path = self.temporary_fixtures_directory - $LOAD_PATH.unshift self.temporary_fixtures_directory - end - - # overridden test should be in test/{unit,functional,integration}/{plugin_name}/{test_name} - def self.override_tests_from_app - filename = caller.first.split(":").first - plugin_name = filename.split("/")[-4] - test_kind = filename.split("/")[-2] - override_file = File.expand_path(File.join(File.dirname(filename), "..", "..", "..", "..", "..", "test", - test_kind, plugin_name, File.basename(filename))) - load(override_file) if File.exist?(override_file) - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/lib/tasks/engines.rake b/vendor/plugins/engines/lib/tasks/engines.rake deleted file mode 100644 index 231cd025a..000000000 --- a/vendor/plugins/engines/lib/tasks/engines.rake +++ /dev/null @@ -1,281 +0,0 @@ -# This code lets us redefine existing Rake tasks, which is extremely -# handy for modifying existing Rails rake tasks. -# Credit for the original snippet of code goes to Jeremy Kemper -# http://pastie.caboo.se/9620 -unless Rake::TaskManager.methods.include?('redefine_task') - module Rake - module TaskManager - def redefine_task(task_class, args, &block) - task_name, arg_names, deps = resolve_args([args]) - task_name = task_class.scope_name(@scope, task_name) - deps = [deps] unless deps.respond_to?(:to_ary) - deps = deps.collect {|d| d.to_s } - task = @tasks[task_name.to_s] = task_class.new(task_name, self) - task.application = self - task.add_description(@last_description) - @last_description = nil - task.enhance(deps, &block) - task - end - - end - class Task - class << self - def redefine_task(args, &block) - Rake.application.redefine_task(self, [args], &block) - end - end - end - end -end - -namespace :db do - namespace :migrate do - desc 'Migrate database and plugins to current status.' - task :all => [ 'db:migrate', 'db:migrate:plugins' ] - - desc 'Migrate plugins to current status.' - task :plugins => :environment do - Engines.plugins.each do |plugin| - next unless plugin.respond_to?(:migration_directory) - next unless File.exists? plugin.migration_directory - puts "Migrating plugin #{plugin.name} ..." - plugin.migrate - end - end - - desc 'For engines coming from Rails version < 2.0 or for those previously updated to work with Sven Fuch\'s fork of engines, you need to upgrade the schema info table' - task :upgrade_plugin_migrations => :environment do - svens_fork_table_name = 'plugin_schema_migrations' - - # Check if app was previously using Sven's fork - if ActiveRecord::Base.connection.table_exists?(svens_fork_table_name) - old_sm_table = svens_fork_table_name - else - old_sm_table = ActiveRecord::Migrator.proper_table_name(Engines.schema_info_table) - end - - unless ActiveRecord::Base.connection.table_exists?(old_sm_table) - abort "Cannot find old migration table - assuming nothing needs to be done" - end - - # There are two forms of the engines schema info - pre-fix_plugin_migrations and post - # We need to figure this out before we continue. - - results = ActiveRecord::Base.connection.select_rows( - "SELECT version, plugin_name FROM #{old_sm_table}" - ).uniq - - def insert_new_version(plugin_name, version) - version_string = "#{version}-#{plugin_name}" - new_sm_table = ActiveRecord::Migrator.schema_migrations_table_name - - # Check if the row already exists for some reason - maybe run this task more than once. - return if ActiveRecord::Base.connection.select_rows("SELECT * FROM #{new_sm_table} WHERE version = #{version_string.dump.gsub("\"", "'")}").size > 0 - - puts "Inserting new version #{version} for plugin #{plugin_name}.." - ActiveRecord::Base.connection.insert("INSERT INTO #{new_sm_table} (version) VALUES (#{version_string.dump.gsub("\"", "'")})") - end - - # We need to figure out if they already used "fix_plugin_migrations" - versions = {} - results.each do |r| - versions[r[1]] ||= [] - versions[r[1]] << r[0].to_i - end - - if versions.values.find{ |v| v.size > 1 } == nil - puts "Fixing migration info" - # We only have one listed migration per plugin - this is pre-fix_plugin_migrations, - # so we build all versions required. In this case, all migrations should - versions.each do |plugin_name, version| - version = version[0] # There is only one version - - # We have to make an assumption that numeric migrations won't get this long.. - # I'm not sure if there is a better assumption, it should work in all - # current cases.. (touch wood..) - if version.to_s.size < "YYYYMMDDHHMMSS".size - # Insert version records for each migration - (1..version).each do |v| - insert_new_version(plugin_name, v) - end - else - # If the plugin is new-format "YYYYMMDDHHMMSS", we just copy it across... - # The case in which this occurs is very rare.. - insert_new_version(plugin_name, version) - end - end - else - puts "Moving migration info" - # We have multiple migrations listed per plugin - thus we can assume they have - # already applied fix_plugin_migrations - we just copy it across verbatim - versions.each do |plugin_name, version| - version.each { |v| insert_new_version(plugin_name, v) } - end - end - - puts "Migration info successfully migrated - removing old schema info table" - ActiveRecord::Base.connection.drop_table(old_sm_table) - end - - desc 'Migrate a specified plugin.' - task(:plugin => :environment) do - name = ENV['NAME'] - if plugin = Engines.plugins[name] - version = ENV['VERSION'] - puts "Migrating #{plugin.name} to " + (version ? "version #{version}" : 'latest version') + " ..." - plugin.migrate(version ? version.to_i : nil) - else - puts "Plugin #{name} does not exist." - end - end - end -end - - -namespace :db do - namespace :fixtures do - namespace :plugins do - - desc "Load plugin fixtures into the current environment's database." - task :load => :environment do - require 'active_record/fixtures' - ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym) - Dir.glob(File.join(RAILS_ROOT, 'vendor', 'plugins', ENV['PLUGIN'] || '**', - 'test', 'fixtures', '*.yml')).each do |fixture_file| - Fixtures.create_fixtures(File.dirname(fixture_file), File.basename(fixture_file, '.*')) - end - end - - end - end -end - -# this is just a modification of the original task in railties/lib/tasks/documentation.rake, -# because the default task doesn't support subdirectories like <plugin>/app or -# <plugin>/component. These tasks now include every file under a plugin's load paths (see -# Plugin#load_paths). -namespace :doc do - - plugins = FileList['vendor/plugins/**'].collect { |plugin| File.basename(plugin) } - - namespace :plugins do - - # Define doc tasks for each plugin - plugins.each do |plugin| - desc "Create plugin documentation for '#{plugin}'" - Rake::Task.redefine_task(plugin => :environment) do - plugin_base = RAILS_ROOT + "/vendor/plugins/#{plugin}" - options = [] - files = Rake::FileList.new - options << "-o doc/plugins/#{plugin}" - options << "--title '#{plugin.titlecase} Plugin Documentation'" - options << '--line-numbers' << '--inline-source' - options << '-T html' - - # Include every file in the plugin's load_paths (see Plugin#load_paths) - if Engines.plugins[plugin] - files.include("#{plugin_base}/{#{Engines.plugins[plugin].load_paths.join(",")}}/**/*.rb") - end - if File.exists?("#{plugin_base}/README") - files.include("#{plugin_base}/README") - options << "--main '#{plugin_base}/README'" - end - files.include("#{plugin_base}/CHANGELOG") if File.exists?("#{plugin_base}/CHANGELOG") - - if files.empty? - puts "No source files found in #{plugin_base}. No documentation will be generated." - else - options << files.to_s - sh %(rdoc #{options * ' '}) - end - end - end - end -end - - - -namespace :test do - task :warn_about_multiple_plugin_testing_with_engines do - puts %{-~============== A Moste Polite Warninge ===========================~- - -You may experience issues testing multiple plugins at once when using -the code-mixing features that the engines plugin provides. If you do -experience any problems, please test plugins individually, i.e. - - $ rake test:plugins PLUGIN=my_plugin - -or use the per-type plugin test tasks: - - $ rake test:plugins:units - $ rake test:plugins:functionals - $ rake test:plugins:integration - $ rake test:plugins:all - -Report any issues on http://dev.rails-engines.org. Thanks! - --~===============( ... as you were ... )============================~-} - end - - namespace :engines do - - def engine_plugins - Dir["vendor/plugins/*"].select { |f| File.directory?(File.join(f, "app")) }.map { |f| File.basename(f) }.join(",") - end - - desc "Run tests from within engines plugins (plugins with an 'app' directory)" - task :all => [:units, :functionals, :integration] - - desc "Run unit tests from within engines plugins (plugins with an 'app' directory)" - Rake::TestTask.new(:units => "test:plugins:setup_plugin_fixtures") do |t| - t.pattern = "vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/unit/**/*_test.rb" - t.verbose = true - end - - desc "Run functional tests from within engines plugins (plugins with an 'app' directory)" - Rake::TestTask.new(:functionals => "test:plugins:setup_plugin_fixtures") do |t| - t.pattern = "vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/functional/**/*_test.rb" - t.verbose = true - end - - desc "Run integration tests from within engines plugins (plugins with an 'app' directory)" - Rake::TestTask.new(:integration => "test:plugins:setup_plugin_fixtures") do |t| - t.pattern = "vendor/plugins/{#{ENV['PLUGIN'] || engine_plugins}}/test/integration/**/*_test.rb" - t.verbose = true - end - end - - namespace :plugins do - - desc "Run the plugin tests in vendor/plugins/**/test (or specify with PLUGIN=name)" - task :all => [:warn_about_multiple_plugin_testing_with_engines, - :units, :functionals, :integration] - - desc "Run all plugin unit tests" - Rake::TestTask.new(:units => :setup_plugin_fixtures) do |t| - t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/unit/**/*_test.rb" - t.verbose = true - end - - desc "Run all plugin functional tests" - Rake::TestTask.new(:functionals => :setup_plugin_fixtures) do |t| - t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/functional/**/*_test.rb" - t.verbose = true - end - - desc "Integration test engines" - Rake::TestTask.new(:integration => :setup_plugin_fixtures) do |t| - t.pattern = "vendor/plugins/#{ENV['PLUGIN'] || "**"}/test/integration/**/*_test.rb" - t.verbose = true - end - - desc "Mirrors plugin fixtures into a single location to help plugin tests" - task :setup_plugin_fixtures => :environment do - Engines::Testing.setup_plugin_fixtures - end - - # Patch the default plugin testing task to have setup_plugin_fixtures as a prerequisite - Rake::Task["test:plugins"].prerequisites << "test:plugins:setup_plugin_fixtures" - end -end diff --git a/vendor/plugins/engines/test/app/controllers/app_and_plugin_controller.rb b/vendor/plugins/engines/test/app/controllers/app_and_plugin_controller.rb deleted file mode 100644 index 90b13ff1f..000000000 --- a/vendor/plugins/engines/test/app/controllers/app_and_plugin_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AppAndPluginController < ApplicationController - def an_action - render_class_and_action 'from app' - end -end diff --git a/vendor/plugins/engines/test/app/controllers/namespace/app_and_plugin_controller.rb b/vendor/plugins/engines/test/app/controllers/namespace/app_and_plugin_controller.rb deleted file mode 100644 index 05f9049e9..000000000 --- a/vendor/plugins/engines/test/app/controllers/namespace/app_and_plugin_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Namespace::AppAndPluginController < ApplicationController - def an_action - render_class_and_action 'from app' - end -end diff --git a/vendor/plugins/engines/test/app/helpers/mail_helper.rb b/vendor/plugins/engines/test/app/helpers/mail_helper.rb deleted file mode 100644 index 9e081e75f..000000000 --- a/vendor/plugins/engines/test/app/helpers/mail_helper.rb +++ /dev/null @@ -1,5 +0,0 @@ -module MailHelper - def do_something_helpful(var) - var.to_s.reverse - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/models/app_and_plugin_model.rb b/vendor/plugins/engines/test/app/models/app_and_plugin_model.rb deleted file mode 100644 index f0fe903c4..000000000 --- a/vendor/plugins/engines/test/app/models/app_and_plugin_model.rb +++ /dev/null @@ -1,3 +0,0 @@ -class AppAndPluginModel < ActiveRecord::Base - def self.report_location; TestHelper::report_location(__FILE__); end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/models/notify_mail.rb b/vendor/plugins/engines/test/app/models/notify_mail.rb deleted file mode 100644 index 899fc1a40..000000000 --- a/vendor/plugins/engines/test/app/models/notify_mail.rb +++ /dev/null @@ -1,26 +0,0 @@ -class NotifyMail < ActionMailer::Base - - helper :mail - - def signup(txt) - body(:name => txt) - end - - def multipart - recipients 'some_address@email.com' - subject 'multi part email' - from "another_user@email.com" - content_type 'multipart/alternative' - - part :content_type => "text/html", :body => render_message("multipart_html", {}) - part "text/plain" do |p| - p.body = render_message("multipart_plain", {}) - end - end - - def implicit_multipart - recipients 'some_address@email.com' - subject 'multi part email' - from "another_user@email.com" - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/things/thing.rb b/vendor/plugins/engines/test/app/things/thing.rb deleted file mode 100644 index ae6fbbf30..000000000 --- a/vendor/plugins/engines/test/app/things/thing.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Thing - def self.from_app; TestHelper::report_location(__FILE__); end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/views/app_and_plugin/a_view.html.erb b/vendor/plugins/engines/test/app/views/app_and_plugin/a_view.html.erb deleted file mode 100644 index 03e2bf81d..000000000 --- a/vendor/plugins/engines/test/app/views/app_and_plugin/a_view.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= TestHelper.view_path_for __FILE__ %> (from app)
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/views/namespace/app_and_plugin/a_view.html.erb b/vendor/plugins/engines/test/app/views/namespace/app_and_plugin/a_view.html.erb deleted file mode 100644 index 03e2bf81d..000000000 --- a/vendor/plugins/engines/test/app/views/namespace/app_and_plugin/a_view.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= TestHelper.view_path_for __FILE__ %> (from app)
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/views/notify_mail/implicit_multipart.text.html.erb b/vendor/plugins/engines/test/app/views/notify_mail/implicit_multipart.text.html.erb deleted file mode 100644 index 042b5c4ef..000000000 --- a/vendor/plugins/engines/test/app/views/notify_mail/implicit_multipart.text.html.erb +++ /dev/null @@ -1 +0,0 @@ -the implicit html part of the email <%= do_something_helpful("semaj") %>
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/views/notify_mail/implicit_multipart.text.plain.erb b/vendor/plugins/engines/test/app/views/notify_mail/implicit_multipart.text.plain.erb deleted file mode 100644 index 552acc1ea..000000000 --- a/vendor/plugins/engines/test/app/views/notify_mail/implicit_multipart.text.plain.erb +++ /dev/null @@ -1 +0,0 @@ -the implicit plaintext part of the email
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/views/notify_mail/multipart_html.html.erb b/vendor/plugins/engines/test/app/views/notify_mail/multipart_html.html.erb deleted file mode 100644 index 135488b17..000000000 --- a/vendor/plugins/engines/test/app/views/notify_mail/multipart_html.html.erb +++ /dev/null @@ -1 +0,0 @@ -the html part of the email <%= do_something_helpful("semaj") %>
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/views/notify_mail/multipart_plain.html.erb b/vendor/plugins/engines/test/app/views/notify_mail/multipart_plain.html.erb deleted file mode 100644 index e0050461c..000000000 --- a/vendor/plugins/engines/test/app/views/notify_mail/multipart_plain.html.erb +++ /dev/null @@ -1 +0,0 @@ -the plaintext part of the email
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/views/notify_mail/signup.text.plain.erb b/vendor/plugins/engines/test/app/views/notify_mail/signup.text.plain.erb deleted file mode 100644 index 5aaf46e97..000000000 --- a/vendor/plugins/engines/test/app/views/notify_mail/signup.text.plain.erb +++ /dev/null @@ -1,5 +0,0 @@ -Signup template from application - -Here's a local variable set in the Mail object: <%= @name %>. - -And here's a method called in a mail helper: <%= do_something_helpful(@name) %> diff --git a/vendor/plugins/engines/test/app/views/plugin_mail/mail_from_plugin_with_application_template.text.plain.erb b/vendor/plugins/engines/test/app/views/plugin_mail/mail_from_plugin_with_application_template.text.plain.erb deleted file mode 100644 index 67a6b8fa2..000000000 --- a/vendor/plugins/engines/test/app/views/plugin_mail/mail_from_plugin_with_application_template.text.plain.erb +++ /dev/null @@ -1 +0,0 @@ -<%= @note %> (from application)
\ No newline at end of file diff --git a/vendor/plugins/engines/test/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb b/vendor/plugins/engines/test/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb deleted file mode 100644 index 284e450f6..000000000 --- a/vendor/plugins/engines/test/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb +++ /dev/null @@ -1 +0,0 @@ -plugin mail template loaded from application
\ No newline at end of file diff --git a/vendor/plugins/engines/test/functional/controller_loading_test.rb b/vendor/plugins/engines/test/functional/controller_loading_test.rb deleted file mode 100644 index d51bc0007..000000000 --- a/vendor/plugins/engines/test/functional/controller_loading_test.rb +++ /dev/null @@ -1,51 +0,0 @@ -# Tests in this file ensure that: -# -# * plugin controller actions are found -# * actions defined in application controllers take precedence over those in plugins -# * actions in controllers in subsequently loaded plugins take precendence over those in previously loaded plugins -# * this works for actions in namespaced controllers accordingly - -require File.dirname(__FILE__) + '/../test_helper' - -class ControllerLoadingTest < ActionController::TestCase - def setup - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - # plugin controller actions should be found - - def test_WITH_an_action_defined_only_in_a_plugin_IT_should_use_this_action - get_action_on_controller :an_action, :alpha_plugin - assert_response_body 'rendered in AlphaPluginController#an_action' - end - - def test_WITH_an_action_defined_only_in_a_namespaced_plugin_controller_IT_should_use_this_action - get_action_on_controller :an_action, :alpha_plugin, :namespace - assert_response_body 'rendered in Namespace::AlphaPluginController#an_action' - end - - # app takes precedence over plugins - - def test_WITH_an_action_defined_in_both_app_and_plugin_IT_should_use_the_one_in_app - get_action_on_controller :an_action, :app_and_plugin - assert_response_body 'rendered in AppAndPluginController#an_action (from app)' - end - - def test_WITH_an_action_defined_in_namespaced_controllers_in_both_app_and_plugin_IT_should_use_the_one_in_app - get_action_on_controller :an_action, :app_and_plugin, :namespace - assert_response_body 'rendered in Namespace::AppAndPluginController#an_action (from app)' - end - - # subsequently loaded plugins take precendence over previously loaded plugins - - def test_WITH_an_action_defined_in_two_plugin_controllers_IT_should_use_the_latter_of_both - get_action_on_controller :an_action, :shared_plugin - assert_response_body 'rendered in SharedPluginController#an_action (from beta_plugin)' - end - - def test_WITH_an_action_defined_in_two_namespaced_plugin_controllers_IT_should_use_the_latter_of_both - get_action_on_controller :an_action, :shared_plugin, :namespace - assert_response_body 'rendered in Namespace::SharedPluginController#an_action (from beta_plugin)' - end -end diff --git a/vendor/plugins/engines/test/functional/exception_notification_compatibility_test.rb b/vendor/plugins/engines/test/functional/exception_notification_compatibility_test.rb deleted file mode 100644 index 309330659..000000000 --- a/vendor/plugins/engines/test/functional/exception_notification_compatibility_test.rb +++ /dev/null @@ -1,29 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class ExceptionNotificationCompatibilityTest < ActionController::TestCase - ExceptionNotifier.exception_recipients = %w(joe@schmoe.com bill@schmoe.com) - class SimpleController < ApplicationController - include ExceptionNotifiable - local_addresses.clear - consider_all_requests_local = false - def index - begin - raise "Fail!" - rescue Exception => e - rescue_action_in_public(e) - end - end - end - - def setup - @controller = SimpleController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - def test_should_work - assert_nothing_raised do - get :index - end - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/functional/locale_loading_test.rb b/vendor/plugins/engines/test/functional/locale_loading_test.rb deleted file mode 100644 index 21c8c7f94..000000000 --- a/vendor/plugins/engines/test/functional/locale_loading_test.rb +++ /dev/null @@ -1,26 +0,0 @@ -# Tests in this file ensure that: -# -# * translations in the application take precedence over those in plugins -# * translations in subsequently loaded plugins take precendence over those in previously loaded plugins - -require File.dirname(__FILE__) + '/../test_helper' - -class LocaleLoadingTest < ActionController::TestCase - def setup - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - # app takes precedence over plugins - - def test_WITH_a_translation_defined_in_both_app_and_plugin_IT_should_find_the_one_in_app - assert_equal I18n.t('hello'), 'Hello world' - end - - # subsequently loaded plugins take precendence over previously loaded plugins - - def test_WITH_a_translation_defined_in_two_plugins_IT_should_find_the_latter_of_both - assert_equal I18n.t('plugin'), 'beta' - end -end - diff --git a/vendor/plugins/engines/test/functional/routes_test.rb b/vendor/plugins/engines/test/functional/routes_test.rb deleted file mode 100644 index 733dd39f5..000000000 --- a/vendor/plugins/engines/test/functional/routes_test.rb +++ /dev/null @@ -1,29 +0,0 @@ -# Tests in this file ensure that: -# -# * Routes from plugins can be routed to -# * Named routes can be defined within a plugin - -require File.dirname(__FILE__) + '/../test_helper' - -class RoutesTest < ActionController::TestCase - tests TestRoutingController - - def test_WITH_a_route_defined_in_a_plugin_IT_should_route_it - path = '/routes/an_action' - opts = {:controller => 'test_routing', :action => 'an_action'} - assert_routing path, opts - assert_recognizes opts, path # not sure what exactly the difference is, but it won't hurt either - end - - def test_WITH_a_route_for_a_namespaced_controller_defined_in_a_plugin_IT_should_route_it - path = 'somespace/routes/an_action' - opts = {:controller => 'namespace/test_routing', :action => 'an_action'} - assert_routing path, opts - assert_recognizes opts, path - end - - def test_should_properly_generate_named_routes - get :test_named_routes_from_plugin - assert_response_body '/somespace/routes' - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/functional/view_helpers_test.rb b/vendor/plugins/engines/test/functional/view_helpers_test.rb deleted file mode 100644 index 5448ffeb7..000000000 --- a/vendor/plugins/engines/test/functional/view_helpers_test.rb +++ /dev/null @@ -1,37 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class ViewHelpersTest < ActionController::TestCase - tests AssetsController - - def setup - get :index - end - - def test_plugin_javascript_helpers - base_selector = "script[type='text/javascript']" - js_dir = "/plugin_assets/test_assets/javascripts" - assert_select "#{base_selector}[src='#{js_dir}/file.1.js']" - assert_select "#{base_selector}[src='#{js_dir}/file2.js']" - end - - def test_plugin_stylesheet_helpers - base_selector = "link[media='screen'][rel='stylesheet'][type='text/css']" - css_dir = "/plugin_assets/test_assets/stylesheets" - assert_select "#{base_selector}[href='#{css_dir}/file.1.css']" - assert_select "#{base_selector}[href='#{css_dir}/file2.css']" - end - - def test_plugin_image_helpers - assert_select "img[src='/plugin_assets/test_assets/images/image.png'][alt='Image']" - end - - def test_plugin_layouts - get :index - assert_select "div[id='assets_layout']" - end - - def test_plugin_image_submit_helpers - assert_select "input[src='/plugin_assets/test_assets/images/image.png'][type='image']" - end - -end diff --git a/vendor/plugins/engines/test/functional/view_loading_test.rb b/vendor/plugins/engines/test/functional/view_loading_test.rb deleted file mode 100644 index 28d47546a..000000000 --- a/vendor/plugins/engines/test/functional/view_loading_test.rb +++ /dev/null @@ -1,60 +0,0 @@ -# Tests in this file ensure that: -# -# * plugin views are found -# * views in the application take precedence over those in plugins -# * views in subsequently loaded plugins take precendence over those in previously loaded plugins -# * this works for namespaced views accordingly - -require File.dirname(__FILE__) + '/../test_helper' - -class ViewLoadingTest < ActionController::TestCase - def setup - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - # plugin views should be found - - def test_WITH_a_view_defined_only_in_a_plugin_IT_should_find_the_view - get_action_on_controller :a_view, :alpha_plugin - assert_response_body 'alpha_plugin/a_view' - end - - def test_WITH_a_namespaced_view_defined_only_in_a_plugin_IT_should_find_the_view - get_action_on_controller :a_view, :alpha_plugin, :namespace - assert_response_body 'namespace/alpha_plugin/a_view' - end - - # app takes precedence over plugins - - def test_WITH_a_view_defined_in_both_app_and_plugin_IT_should_find_the_one_in_app - get_action_on_controller :a_view, :app_and_plugin - assert_response_body 'app_and_plugin/a_view (from app)' - end - - def test_WITH_a_namespaced_view_defined_in_both_app_and_plugin_IT_should_find_the_one_in_app - get_action_on_controller :a_view, :app_and_plugin, :namespace - assert_response_body 'namespace/app_and_plugin/a_view (from app)' - end - - # subsequently loaded plugins take precendence over previously loaded plugins - - def test_WITH_a_view_defined_in_two_plugins_IT_should_find_the_latter_of_both - get_action_on_controller :a_view, :shared_plugin - assert_response_body 'shared_plugin/a_view (from beta_plugin)' - end - - def test_WITH_a_namespaced_view_defined_in_two_plugins_IT_should_find_the_latter_of_both - get_action_on_controller :a_view, :shared_plugin, :namespace - assert_response_body 'namespace/shared_plugin/a_view (from beta_plugin)' - end - - # layouts loaded from plugins - - def test_should_be_able_to_load_a_layout_from_a_plugin - get_action_on_controller :action_with_layout, :alpha_plugin - assert_response_body 'rendered in AlphaPluginController#action_with_layout (with plugin layout)' - end - -end -
\ No newline at end of file diff --git a/vendor/plugins/engines/test/lib/app_and_plugin_lib_model.rb b/vendor/plugins/engines/test/lib/app_and_plugin_lib_model.rb deleted file mode 100644 index 6ffe178a7..000000000 --- a/vendor/plugins/engines/test/lib/app_and_plugin_lib_model.rb +++ /dev/null @@ -1,3 +0,0 @@ -class AppAndPluginLibModel < ActiveRecord::Base - def self.report_location; TestHelper::report_location(__FILE__); end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/lib/engines_test_helper.rb b/vendor/plugins/engines/test/lib/engines_test_helper.rb deleted file mode 100644 index 47bd2bbfd..000000000 --- a/vendor/plugins/engines/test/lib/engines_test_helper.rb +++ /dev/null @@ -1,42 +0,0 @@ -module TestHelper - def self.report_location(path) - [RAILS_ROOT + '/', 'vendor/plugins/'].each { |part| path.sub! part, ''} - path = path.split('/') - location, subject = path.first, path.last - if subject.sub! '.rb', '' - subject = subject.classify - else - subject.sub! '.html.erb', '' - end - "#{subject} (from #{location})" - end - - def self.view_path_for path - [RAILS_ROOT + '/', 'vendor/plugins/', '.html.erb'].each { |part| path.sub! part, ''} - parts = path.split('/') - parts[(parts.index('views')+1)..-1].join('/') - end -end - -class Test::Unit::TestCase - # Add more helper methods to be used by all tests here... - def get_action_on_controller(*args) - action = args.shift - with_controller *args - get action - end - - def with_controller(controller, namespace = nil) - classname = controller.to_s.classify + 'Controller' - classname = namespace.to_s.classify + '::' + classname unless namespace.nil? - @controller = classname.constantize.new - end - - def assert_response_body(expected) - assert_equal expected, @response.body - end -end - -# Because we're testing this behaviour, we actually want these features on! -Engines.disable_application_view_loading = false -Engines.disable_application_code_loading = false diff --git a/vendor/plugins/engines/test/lib/render_information.rb b/vendor/plugins/engines/test/lib/render_information.rb deleted file mode 100644 index 0deb5d9d3..000000000 --- a/vendor/plugins/engines/test/lib/render_information.rb +++ /dev/null @@ -1,7 +0,0 @@ -module RenderInformation - def render_class_and_action(note = nil, options={}) - text = "rendered in #{self.class.name}##{params[:action]}" - text += " (#{note})" unless note.nil? - render options.update(:text => text) - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/alpha_plugin_controller.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/alpha_plugin_controller.rb deleted file mode 100644 index 736d59b83..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/alpha_plugin_controller.rb +++ /dev/null @@ -1,8 +0,0 @@ -class AlphaPluginController < ApplicationController - def an_action - render_class_and_action - end - def action_with_layout - render_class_and_action(nil, :layout => "plugin_layout") - end -end diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/app_and_plugin_controller.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/app_and_plugin_controller.rb deleted file mode 100644 index c41d6edd1..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/app_and_plugin_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AppAndPluginController < ApplicationController - def an_action - render_class_and_action 'from alpha_plugin' - end -end diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/alpha_plugin_controller.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/alpha_plugin_controller.rb deleted file mode 100644 index 5edf81b53..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/alpha_plugin_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Namespace::AlphaPluginController < ApplicationController - def an_action - render_class_and_action - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/app_and_plugin_controller.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/app_and_plugin_controller.rb deleted file mode 100644 index 7431a36b6..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/app_and_plugin_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Namespace::AppAndPluginController < ApplicationController - def an_action - render_class_and_action 'from alpha_plugin' - end -end diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/shared_plugin_controller.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/shared_plugin_controller.rb deleted file mode 100644 index fb162bcf6..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/namespace/shared_plugin_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Namespace::SharedPluginController < ApplicationController - def an_action - render_class_and_action 'from alpha_plugin' - end -end diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/shared_plugin_controller.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/shared_plugin_controller.rb deleted file mode 100644 index 00539bb8c..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/controllers/shared_plugin_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class SharedEngineController < ApplicationController - def an_action - render_class_and_action 'from alpha_engine' - end -end diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/models/alpha_plugin_model.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/models/alpha_plugin_model.rb deleted file mode 100644 index cde71b8d0..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/models/alpha_plugin_model.rb +++ /dev/null @@ -1,3 +0,0 @@ -class AlphaPluginModel < ActiveRecord::Base - def self.report_location; TestHelper::report_location(__FILE__); end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/models/app_and_plugin_model.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/models/app_and_plugin_model.rb deleted file mode 100644 index 92e6e625f..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/models/app_and_plugin_model.rb +++ /dev/null @@ -1,7 +0,0 @@ -class AppAndPluginModel < ActiveRecord::Base - def self.report_location; TestHelper::report_location(__FILE__); end - - def defined_only_in_alpha_plugin_version - # should not be defined as the model in app/models takes precedence - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/models/shared_plugin_model.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/models/shared_plugin_model.rb deleted file mode 100644 index e2ef43db7..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/models/shared_plugin_model.rb +++ /dev/null @@ -1,3 +0,0 @@ -class SharedPluginModel < ActiveRecord::Base - def self.report_location; TestHelper::report_location(__FILE__); end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/alpha_plugin/a_view.html.erb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/alpha_plugin/a_view.html.erb deleted file mode 100644 index 1ad694584..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/alpha_plugin/a_view.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= TestHelper.view_path_for __FILE__ %>
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/app_and_plugin/a_view.html.erb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/app_and_plugin/a_view.html.erb deleted file mode 100644 index 791a6fab4..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/app_and_plugin/a_view.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= TestHelper.view_path_for __FILE__ %> (from a_view)
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/layouts/plugin_layout.erb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/layouts/plugin_layout.erb deleted file mode 100644 index 878e07c2c..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/layouts/plugin_layout.erb +++ /dev/null @@ -1 +0,0 @@ -<%= yield %> (with plugin layout)
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/alpha_plugin/a_view.html.erb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/alpha_plugin/a_view.html.erb deleted file mode 100644 index 1ad694584..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/alpha_plugin/a_view.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= TestHelper.view_path_for __FILE__ %>
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/app_and_plugin/a_view.html.erb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/app_and_plugin/a_view.html.erb deleted file mode 100644 index 1ad694584..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/app_and_plugin/a_view.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= TestHelper.view_path_for __FILE__ %>
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/shared_plugin/a_view.html.erb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/shared_plugin/a_view.html.erb deleted file mode 100644 index f144ab394..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/namespace/shared_plugin/a_view.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= TestHelper.view_path_for __FILE__ %> (from alpha_plugin)
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/shared_plugin/a_view.html.erb b/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/shared_plugin/a_view.html.erb deleted file mode 100644 index f144ab394..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/app/views/shared_plugin/a_view.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= TestHelper.view_path_for __FILE__ %> (from alpha_plugin)
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/lib/alpha_plugin_lib_model.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/lib/alpha_plugin_lib_model.rb deleted file mode 100644 index 0ce4f91bb..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/lib/alpha_plugin_lib_model.rb +++ /dev/null @@ -1,3 +0,0 @@ -class AlphaPluginLibModel < ActiveRecord::Base - def self.report_location; TestHelper::report_location(__FILE__); end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/lib/app_and_plugin_lib_model.rb b/vendor/plugins/engines/test/plugins/alpha_plugin/lib/app_and_plugin_lib_model.rb deleted file mode 100644 index 645a70c83..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/lib/app_and_plugin_lib_model.rb +++ /dev/null @@ -1,7 +0,0 @@ -class AppAndPluginLibModel < ActiveRecord::Base - def self.report_location; TestHelper::report_location(__FILE__); end - - def defined_only_in_alpha_plugin_version - # should not be defined - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/alpha_plugin/locales/en.yml b/vendor/plugins/engines/test/plugins/alpha_plugin/locales/en.yml deleted file mode 100644 index 76d39d315..000000000 --- a/vendor/plugins/engines/test/plugins/alpha_plugin/locales/en.yml +++ /dev/null @@ -1,3 +0,0 @@ -en: - hello: "Hello from alfa" - plugin: "alfa" diff --git a/vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/app_and_plugin_controller.rb b/vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/app_and_plugin_controller.rb deleted file mode 100644 index 2e7798976..000000000 --- a/vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/app_and_plugin_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AppAndPluginController < ApplicationController - def an_action - render_class_and_action 'from beta_plugin' - end -end diff --git a/vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/namespace/shared_plugin_controller.rb b/vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/namespace/shared_plugin_controller.rb deleted file mode 100644 index 971c7d563..000000000 --- a/vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/namespace/shared_plugin_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Namespace::SharedPluginController < ApplicationController - def an_action - render_class_and_action 'from beta_plugin' - end -end diff --git a/vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/shared_plugin_controller.rb b/vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/shared_plugin_controller.rb deleted file mode 100644 index ddd9dbede..000000000 --- a/vendor/plugins/engines/test/plugins/beta_plugin/app/controllers/shared_plugin_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class SharedPluginController < ApplicationController - def an_action - render_class_and_action 'from beta_plugin' - end -end diff --git a/vendor/plugins/engines/test/plugins/beta_plugin/app/models/shared_plugin_model.rb b/vendor/plugins/engines/test/plugins/beta_plugin/app/models/shared_plugin_model.rb deleted file mode 100644 index bfde227d1..000000000 --- a/vendor/plugins/engines/test/plugins/beta_plugin/app/models/shared_plugin_model.rb +++ /dev/null @@ -1,3 +0,0 @@ -class SharedPluginModel < ActiveRecord::Base - def self.report_location; TestHelper::report_location(__FILE__); end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/beta_plugin/app/views/namespace/shared_plugin/a_view.html.erb b/vendor/plugins/engines/test/plugins/beta_plugin/app/views/namespace/shared_plugin/a_view.html.erb deleted file mode 100644 index 77b5a1538..000000000 --- a/vendor/plugins/engines/test/plugins/beta_plugin/app/views/namespace/shared_plugin/a_view.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= TestHelper.view_path_for __FILE__ %> (from beta_plugin)
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/beta_plugin/app/views/shared_plugin/a_view.html.erb b/vendor/plugins/engines/test/plugins/beta_plugin/app/views/shared_plugin/a_view.html.erb deleted file mode 100644 index 77b5a1538..000000000 --- a/vendor/plugins/engines/test/plugins/beta_plugin/app/views/shared_plugin/a_view.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= TestHelper.view_path_for __FILE__ %> (from beta_plugin)
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/beta_plugin/init.rb b/vendor/plugins/engines/test/plugins/beta_plugin/init.rb deleted file mode 100644 index b4c4b0e1d..000000000 --- a/vendor/plugins/engines/test/plugins/beta_plugin/init.rb +++ /dev/null @@ -1 +0,0 @@ -# just here so that Rails recognizes this as a plugin
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/beta_plugin/locales/en.yml b/vendor/plugins/engines/test/plugins/beta_plugin/locales/en.yml deleted file mode 100644 index f49279cca..000000000 --- a/vendor/plugins/engines/test/plugins/beta_plugin/locales/en.yml +++ /dev/null @@ -1,3 +0,0 @@ -en: - hello: "Hello from beta" - plugin: "beta" diff --git a/vendor/plugins/engines/test/plugins/not_a_plugin/public/should_not_be_copied.txt b/vendor/plugins/engines/test/plugins/not_a_plugin/public/should_not_be_copied.txt deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/not_a_plugin/public/should_not_be_copied.txt +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_assets/app/controllers/assets_controller.rb b/vendor/plugins/engines/test/plugins/test_assets/app/controllers/assets_controller.rb deleted file mode 100644 index db5de2e6a..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets/app/controllers/assets_controller.rb +++ /dev/null @@ -1,2 +0,0 @@ -class AssetsController < ApplicationController -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_assets/app/views/assets/index.html.erb b/vendor/plugins/engines/test/plugins/test_assets/app/views/assets/index.html.erb deleted file mode 100644 index 8340f76d1..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets/app/views/assets/index.html.erb +++ /dev/null @@ -1,4 +0,0 @@ -<%= image_tag 'image.png', :plugin => 'test_assets' %> -<%= javascript_include_tag 'file.1.js', 'file2', :plugin => "test_assets" %> -<%= stylesheet_link_tag 'file.1.css', 'file2', :plugin => "test_assets" %> -<%= image_submit_tag 'image.png', :plugin => "test_assets" %> diff --git a/vendor/plugins/engines/test/plugins/test_assets/app/views/layouts/assets.html.erb b/vendor/plugins/engines/test/plugins/test_assets/app/views/layouts/assets.html.erb deleted file mode 100644 index b7da375e9..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets/app/views/layouts/assets.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -<div id="assets_layout"> - <%= yield %> -</div>
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_assets/init.rb b/vendor/plugins/engines/test/plugins/test_assets/init.rb deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets/init.rb +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_assets/public/file.txt b/vendor/plugins/engines/test/plugins/test_assets/public/file.txt deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets/public/file.txt +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_assets/public/subfolder/file_in_subfolder.txt b/vendor/plugins/engines/test/plugins/test_assets/public/subfolder/file_in_subfolder.txt deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets/public/subfolder/file_in_subfolder.txt +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/assets/file.txt b/vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/assets/file.txt deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/assets/file.txt +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/assets/subfolder/file_in_subfolder.txt b/vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/assets/subfolder/file_in_subfolder.txt deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/assets/subfolder/file_in_subfolder.txt +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/init.rb b/vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/init.rb deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets_with_assets_directory/init.rb +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_assets_with_no_subdirectory/assets/file.txt b/vendor/plugins/engines/test/plugins/test_assets_with_no_subdirectory/assets/file.txt deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets_with_no_subdirectory/assets/file.txt +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_assets_with_no_subdirectory/init.rb b/vendor/plugins/engines/test/plugins/test_assets_with_no_subdirectory/init.rb deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_assets_with_no_subdirectory/init.rb +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_code_mixing/app/things/thing.rb b/vendor/plugins/engines/test/plugins/test_code_mixing/app/things/thing.rb deleted file mode 100644 index 535d988e6..000000000 --- a/vendor/plugins/engines/test/plugins/test_code_mixing/app/things/thing.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Thing - def self.from_plugin; TestHelper::report_location(__FILE__); end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_code_mixing/init.rb b/vendor/plugins/engines/test/plugins/test_code_mixing/init.rb deleted file mode 100644 index b4c4b0e1d..000000000 --- a/vendor/plugins/engines/test/plugins/test_code_mixing/init.rb +++ /dev/null @@ -1 +0,0 @@ -# just here so that Rails recognizes this as a plugin
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_load_path/init.rb b/vendor/plugins/engines/test/plugins/test_load_path/init.rb deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_load_path/init.rb +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_migration/db/migrate/001_create_tests.rb b/vendor/plugins/engines/test/plugins/test_migration/db/migrate/001_create_tests.rb deleted file mode 100644 index 804a0cd2d..000000000 --- a/vendor/plugins/engines/test/plugins/test_migration/db/migrate/001_create_tests.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateTests < ActiveRecord::Migration - def self.up - create_table 'tests' do |t| - t.column 'name', :string - end - end - - def self.down - drop_table 'tests' - end -end diff --git a/vendor/plugins/engines/test/plugins/test_migration/db/migrate/002_create_others.rb b/vendor/plugins/engines/test/plugins/test_migration/db/migrate/002_create_others.rb deleted file mode 100644 index 756aca653..000000000 --- a/vendor/plugins/engines/test/plugins/test_migration/db/migrate/002_create_others.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateOthers < ActiveRecord::Migration - def self.up - create_table 'others' do |t| - t.column 'name', :string - end - end - - def self.down - drop_table 'others' - end -end diff --git a/vendor/plugins/engines/test/plugins/test_migration/db/migrate/003_create_extras.rb b/vendor/plugins/engines/test/plugins/test_migration/db/migrate/003_create_extras.rb deleted file mode 100644 index fb5b6c205..000000000 --- a/vendor/plugins/engines/test/plugins/test_migration/db/migrate/003_create_extras.rb +++ /dev/null @@ -1,11 +0,0 @@ -class CreateExtras < ActiveRecord::Migration - def self.up - create_table 'extras' do |t| - t.column 'name', :string - end - end - - def self.down - drop_table 'extras' - end -end diff --git a/vendor/plugins/engines/test/plugins/test_migration/init.rb b/vendor/plugins/engines/test/plugins/test_migration/init.rb deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_migration/init.rb +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/models/plugin_mail.rb b/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/models/plugin_mail.rb deleted file mode 100644 index 4f3661639..000000000 --- a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/models/plugin_mail.rb +++ /dev/null @@ -1,26 +0,0 @@ -class PluginMail < ActionMailer::Base - def mail_from_plugin(note=nil) - body(:note => note) - end - - def mail_from_plugin_with_application_template(note=nil) - body(:note => note) - end - - def multipart_from_plugin - content_type 'multipart/alternative' - part :content_type => "text/html", :body => render_message("multipart_from_plugin_html", {}) - part "text/plain" do |p| - p.body = render_message("multipart_from_plugin_plain", {}) - end - end - - def multipart_from_plugin_with_application_template - content_type 'multipart/alternative' - part :content_type => "text/html", :body => render_message("multipart_from_plugin_with_application_template_html", {}) - part "text/plain" do |p| - p.body = render_message("multipart_from_plugin_with_application_template_plain", {}) - end - end - -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/mail_from_plugin.erb b/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/mail_from_plugin.erb deleted file mode 100644 index 2b4960625..000000000 --- a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/mail_from_plugin.erb +++ /dev/null @@ -1 +0,0 @@ -<%= @note %>
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_html.html.erb b/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_html.html.erb deleted file mode 100644 index 46291d8f0..000000000 --- a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_html.html.erb +++ /dev/null @@ -1 +0,0 @@ -html template
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_plain.html.erb b/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_plain.html.erb deleted file mode 100644 index f690dbaac..000000000 --- a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_plain.html.erb +++ /dev/null @@ -1 +0,0 @@ -plain template
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_html.html.erb b/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_html.html.erb deleted file mode 100644 index 795f0d508..000000000 --- a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_html.html.erb +++ /dev/null @@ -1 +0,0 @@ -template from plugin
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb b/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb deleted file mode 100644 index 795f0d508..000000000 --- a/vendor/plugins/engines/test/plugins/test_plugin_mailing/app/views/plugin_mail/multipart_from_plugin_with_application_template_plain.html.erb +++ /dev/null @@ -1 +0,0 @@ -template from plugin
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_plugin_mailing/init.rb b/vendor/plugins/engines/test/plugins/test_plugin_mailing/init.rb deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_plugin_mailing/init.rb +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_routing/app/controllers/namespace/test_routing_controller.rb b/vendor/plugins/engines/test/plugins/test_routing/app/controllers/namespace/test_routing_controller.rb deleted file mode 100644 index 29d7bdbd4..000000000 --- a/vendor/plugins/engines/test/plugins/test_routing/app/controllers/namespace/test_routing_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Namespace::TestRoutingController < ApplicationController - def routed_action - render_class_and_action - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_routing/app/controllers/test_routing_controller.rb b/vendor/plugins/engines/test/plugins/test_routing/app/controllers/test_routing_controller.rb deleted file mode 100644 index ac3164a4f..000000000 --- a/vendor/plugins/engines/test/plugins/test_routing/app/controllers/test_routing_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -class TestRoutingController < ApplicationController - def routed_action - render_class_and_action - end - - def test_named_routes_from_plugin - render :text => plugin_route_path(:action => "index") - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_routing/config/routes.rb b/vendor/plugins/engines/test/plugins/test_routing/config/routes.rb deleted file mode 100644 index dbc49f960..000000000 --- a/vendor/plugins/engines/test/plugins/test_routing/config/routes.rb +++ /dev/null @@ -1,4 +0,0 @@ -ActionController::Routing::Routes.draw do |map| - map.connect 'routes/:action', :controller => "test_routing" - map.plugin_route 'somespace/routes/:action', :controller => "namespace/test_routing" -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_routing/init.rb b/vendor/plugins/engines/test/plugins/test_routing/init.rb deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_routing/init.rb +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_testing/app/README.txt b/vendor/plugins/engines/test/plugins/test_testing/app/README.txt deleted file mode 100644 index 784e4fe28..000000000 --- a/vendor/plugins/engines/test/plugins/test_testing/app/README.txt +++ /dev/null @@ -1 +0,0 @@ -Fixtures are only copied from plugins with an +app+ directory, but git needs this directory to be non-empty
\ No newline at end of file diff --git a/vendor/plugins/engines/test/plugins/test_testing/init.rb b/vendor/plugins/engines/test/plugins/test_testing/init.rb deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_testing/init.rb +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_testing/test/fixtures/testing_fixtures.yml b/vendor/plugins/engines/test/plugins/test_testing/test/fixtures/testing_fixtures.yml deleted file mode 100644 index e69de29bb..000000000 --- a/vendor/plugins/engines/test/plugins/test_testing/test/fixtures/testing_fixtures.yml +++ /dev/null diff --git a/vendor/plugins/engines/test/plugins/test_testing/test/unit/override_test.rb b/vendor/plugins/engines/test/plugins/test_testing/test/unit/override_test.rb deleted file mode 100644 index 4c4c42a2c..000000000 --- a/vendor/plugins/engines/test/plugins/test_testing/test/unit/override_test.rb +++ /dev/null @@ -1,13 +0,0 @@ -require File.expand_path(File.join(File.dirname(__FILE__), *%w[.. .. .. .. .. test test_helper])) - -class OverrideTest < ActiveSupport::TestCase - def test_overrides_from_the_application_should_work - flunk "this test should be overridden by the app" - end - - def test_tests_within_the_plugin_should_still_run - assert true, "non-overridden plugin tests should still run" - end -end - -Engines::Testing.override_tests_from_app
\ No newline at end of file diff --git a/vendor/plugins/engines/test/unit/action_mailer_test.rb b/vendor/plugins/engines/test/unit/action_mailer_test.rb deleted file mode 100644 index fc3e75661..000000000 --- a/vendor/plugins/engines/test/unit/action_mailer_test.rb +++ /dev/null @@ -1,54 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class ActionMailerWithinApplicationTest < Test::Unit::TestCase - - def test_normal_implicit_template - m = NotifyMail.create_signup("hello") - assert m.body =~ /^Signup template from application/ - end - - def test_action_mailer_can_get_helper - m = NotifyMail.create_signup('James') - assert m.body =~ /James/ - assert m.body =~ /semaJ/ # from the helper - end - - def test_multipart_mails_with_explicit_templates - m = NotifyMail.create_multipart - assert_equal 2, m.parts.length - assert_equal 'the html part of the email james', m.parts[0].body - assert_equal 'the plaintext part of the email', m.parts[1].body - end - - def test_multipart_mails_with_implicit_templates - m = NotifyMail.create_implicit_multipart - assert_equal 2, m.parts.length - assert_equal 'the implicit plaintext part of the email', m.parts[0].body - assert_equal 'the implicit html part of the email james', m.parts[1].body - end -end - - -class ActionMailerWithinPluginsTest < Test::Unit::TestCase - def test_should_be_able_to_create_mails_from_plugin - m = PluginMail.create_mail_from_plugin("from_plugin") - assert_equal "from_plugin", m.body - end - - def test_should_be_able_to_overload_views_within_the_application - m = PluginMail.create_mail_from_plugin_with_application_template("from_plugin") - assert_equal "from_plugin (from application)", m.body - end - - def test_should_be_able_to_create_a_multipart_mail_from_within_plugin - m = PluginMail.create_multipart_from_plugin - assert_equal 2, m.parts.length - assert_equal 'html template', m.parts[0].body - assert_equal 'plain template', m.parts[1].body - end - - def test_plugin_mailer_template_overriding - m = PluginMail.create_multipart_from_plugin_with_application_template - assert_equal 'plugin mail template loaded from application', m.parts[1].body - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/unit/arbitrary_code_mixing_test.rb b/vendor/plugins/engines/test/unit/arbitrary_code_mixing_test.rb deleted file mode 100644 index 4b862f35b..000000000 --- a/vendor/plugins/engines/test/unit/arbitrary_code_mixing_test.rb +++ /dev/null @@ -1,41 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class ArbitraryCodeMixingTest < Test::Unit::TestCase - def setup - Engines.code_mixing_file_types = %w(controller helper) - end - - def test_should_allow_setting_of_different_code_mixing_file_types - assert_nothing_raised { - Engines.mix_code_from :things - } - end - - def test_should_add_new_types_to_existing_code_mixing_file_types - Engines.mix_code_from :things - assert_equal ["controller", "helper", "thing"], Engines.code_mixing_file_types - Engines.mix_code_from :other - assert_equal ["controller", "helper", "thing", "other"], Engines.code_mixing_file_types - end - - def test_should_allow_setting_of_multiple_types_at_once - Engines.mix_code_from :things, :other - assert_equal ["controller", "helper", "thing", "other"], Engines.code_mixing_file_types - end - - def test_should_singularize_elements_to_be_mixed - # this is the only test using mocha, so let's try to work around it - # also, this seems to be already tested with the :things in the tests above - # arg = stub(:to_s => stub(:singularize => "element")) - Engines.mix_code_from :elements - assert Engines.code_mixing_file_types.include?("element") - end - - # TODO doesn't seem to work as expected? - - # def test_should_successfully_mix_custom_types - # Engines.mix_code_from :things - # assert_equal 'Thing (from app)', Thing.from_app - # assert_equal 'Thing (from test_code_mixing)', Thing.from_plugin - # end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/unit/assets_test.rb b/vendor/plugins/engines/test/unit/assets_test.rb deleted file mode 100644 index 3332c533e..000000000 --- a/vendor/plugins/engines/test/unit/assets_test.rb +++ /dev/null @@ -1,52 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class AssetsTest < Test::Unit::TestCase - def setup - Engines::Assets.mirror_files_for Engines.plugins[:test_assets] - end - - def teardown - FileUtils.rm_r(Engines.public_directory) if File.exist?(Engines.public_directory) - end - - def test_engines_has_created_base_public_file - assert File.exist?(Engines.public_directory) - end - - def test_engines_has_created_README_in_public_directory - assert File.exist?(File.join(Engines.public_directory, 'README')) - end - - def test_public_files_have_been_copied_from_test_assets_plugin - assert File.exist?(File.join(Engines.public_directory, 'test_assets')) - assert File.exist?(File.join(Engines.public_directory, 'test_assets', 'file.txt')) - assert File.exist?(File.join(Engines.public_directory, 'test_assets', 'subfolder')) - assert File.exist?(File.join(Engines.public_directory, 'test_assets', 'subfolder', 'file_in_subfolder.txt')) - end - - def test_engines_has_not_created_duplicated_file_structure - assert !File.exists?(File.join(Engines.public_directory, "test_assets", RAILS_ROOT)) - end - - def test_public_files_have_been_copied_from_test_assets_with_assets_dir_plugin - Engines::Assets.mirror_files_for Engines.plugins[:test_assets_with_assets_directory] - - assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_assets_directory')) - assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_assets_directory', 'file.txt')) - assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_assets_directory', 'subfolder')) - assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_assets_directory', 'subfolder', 'file_in_subfolder.txt')) - end - - def test_public_files_have_been_copied_from_test_assets_with_no_subdirectory_plugin - Engines::Assets.mirror_files_for Engines.plugins[:test_assets_with_no_subdirectory] - - assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_no_subdirectory')) - assert File.exist?(File.join(Engines.public_directory, 'test_assets_with_no_subdirectory', 'file.txt')) - end - - def test_public_files_have_NOT_been_copied_from_plugins_without_public_or_asset_directories - Engines::Assets.mirror_files_for Engines.plugins[:alpha_plugin] - - assert !File.exist?(File.join(Engines.public_directory, 'alpha_plugin')) - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/unit/backwards_compat_test.rb b/vendor/plugins/engines/test/unit/backwards_compat_test.rb deleted file mode 100644 index 4fa3698f2..000000000 --- a/vendor/plugins/engines/test/unit/backwards_compat_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class BackwardsCompatibilityTest < Test::Unit::TestCase - def test_rails_module_plugin_method_should_delegate_to_engines_plugins - assert_nothing_raised { Rails.plugins } - assert_equal Engines.plugins, Rails.plugins - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/unit/load_path_test.rb b/vendor/plugins/engines/test/unit/load_path_test.rb deleted file mode 100644 index c26d331c3..000000000 --- a/vendor/plugins/engines/test/unit/load_path_test.rb +++ /dev/null @@ -1,58 +0,0 @@ -# Tests in this file ensure that: -# -# * the application /app/[controllers|helpers|models] and /lib -# paths preceed the corresponding plugin paths -# * the plugin paths are added to $LOAD_PATH in the order in which plugins are -# loaded - -require File.dirname(__FILE__) + '/../test_helper' - -class LoadPathTest < Test::Unit::TestCase - def setup - @load_path = expand_paths($LOAD_PATH) - end - - # Not sure if these test actually make sense as this now essentially tests - # Rails core functionality. On the other hand Engines relies on this to some - # extend so this will choke if something important changes in Rails. - - # the application app/... and lib/ directories should appear - # before any plugin directories - - def test_application_app_libs_should_precede_all_plugin_app_libs - types = %w(app/controllers app/helpers app/models lib) - types.each do |t| - app_index = load_path_index(File.join(RAILS_ROOT, t)) - assert_not_nil app_index, "#{t} is missing in $LOAD_PATH" - Engines.plugins.each do |plugin| - first_plugin_index = load_path_index(File.join(plugin.directory, t)) - assert(app_index < first_plugin_index) unless first_plugin_index.nil? - end - end - end - - # the engine directories should appear in the proper order based on - # the order they were started - - def test_plugin_dirs_should_appear_in_reverse_plugin_loading_order - app_paths = %w(app/controllers/ app app/models app/helpers lib) - app_paths.map { |p| File.join(RAILS_ROOT, p)} - plugin_paths = Engines.plugins.reverse.collect { |plugin| plugin.load_paths.reverse }.flatten - - expected_paths = expand_paths(app_paths + plugin_paths) - # only look at those paths that are also present in expected_paths so - # the only difference would be in the order of the paths - actual_paths = @load_path & expected_paths - - assert_equal expected_paths, actual_paths - end - - protected - def expand_paths(paths) - paths.collect { |p| File.expand_path(p) } - end - - def load_path_index(dir) - @load_path.index(File.expand_path(dir)) - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/unit/migration_test.rb b/vendor/plugins/engines/test/unit/migration_test.rb deleted file mode 100644 index eae7fe7d4..000000000 --- a/vendor/plugins/engines/test/unit/migration_test.rb +++ /dev/null @@ -1,63 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -require 'rails_generator' -require 'rails_generator/scripts/generate' - -class MigrationsTest < Test::Unit::TestCase - - @@migration_dir = "#{RAILS_ROOT}/db/migrate" - - def setup - ActiveRecord::Migration.verbose = false - Engines.plugins[:test_migration].migrate(0) - end - - def teardown - FileUtils.rm_r(@@migration_dir) if File.exist?(@@migration_dir) - end - - def test_engine_migrations_can_run_down - assert !table_exists?('tests'), ActiveRecord::Base.connection.tables.inspect - assert !table_exists?('others'), ActiveRecord::Base.connection.tables.inspect - assert !table_exists?('extras'), ActiveRecord::Base.connection.tables.inspect - end - - def test_engine_migrations_can_run_up - Engines.plugins[:test_migration].migrate(3) - assert table_exists?('tests') - assert table_exists?('others') - assert table_exists?('extras') - end - - def test_engine_migrations_can_upgrade_incrementally - Engines.plugins[:test_migration].migrate(1) - assert table_exists?('tests') - assert !table_exists?('others') - assert !table_exists?('extras') - assert_equal 1, Engines::Plugin::Migrator.current_version(Engines.plugins[:test_migration]) - - - Engines.plugins[:test_migration].migrate(2) - assert table_exists?('others') - assert_equal 2, Engines::Plugin::Migrator.current_version(Engines.plugins[:test_migration]) - - - Engines.plugins[:test_migration].migrate(3) - assert table_exists?('extras') - assert_equal 3, Engines::Plugin::Migrator.current_version(Engines.plugins[:test_migration]) - end - - def test_generator_creates_plugin_migration_file - Rails::Generator::Scripts::Generate.new.run(['plugin_migration', 'test_migration'], :quiet => true) - assert migration_file, "migration file is missing" - end - - private - - def table_exists?(table) - ActiveRecord::Base.connection.tables.include?(table) - end - - def migration_file - Dir["#{@@migration_dir}/*test_migration_to_version_3.rb"][0] - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/unit/model_and_lib_test.rb b/vendor/plugins/engines/test/unit/model_and_lib_test.rb deleted file mode 100644 index e5aa773ba..000000000 --- a/vendor/plugins/engines/test/unit/model_and_lib_test.rb +++ /dev/null @@ -1,37 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class ModelAndLibTest < Test::Unit::TestCase - - def test_WITH_a_model_defined_only_in_a_plugin_IT_should_load_the_model - assert_equal 'AlphaPluginModel (from alpha_plugin)', AlphaPluginModel.report_location - end - - def test_WITH_a_model_defined_only_in_a_plugin_lib_dir_IT_should_load_the_model - assert_equal 'AlphaPluginLibModel (from alpha_plugin)', AlphaPluginLibModel.report_location - end - - # app takes precedence over plugins - - def test_WITH_a_model_defined_in_both_app_and_plugin_IT_should_load_the_one_in_app - assert_equal 'AppAndPluginModel (from app)', AppAndPluginModel.report_location - assert_raises(NoMethodError) { AppAndPluginLibModel.defined_only_in_alpha_engine_version } - end - - def test_WITH_a_model_defined_in_both_app_and_plugin_lib_dirs_IT_should_load_the_one_in_app - assert_equal 'AppAndPluginLibModel (from lib)', AppAndPluginLibModel.report_location - assert_raises(NoMethodError) { AppAndPluginLibModel.defined_only_in_alpha_engine_version } - end - - # subsequently loaded plugins take precendence over previously loaded plugins - - # TODO - # - # this does work when we rely on $LOAD_PATH while it won't work when we use - # Dependency constant autoloading. This somewhat confusing difference has - # been there since at least Rails 1.2.x. See http://www.ruby-forum.com/topic/134529 - - def test_WITH_a_model_defined_in_two_plugins_IT_should_load_the_latter_of_both - require 'shared_plugin_model' - assert_equal SharedPluginModel.report_location, 'SharedPluginModel (from beta_plugin)' - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/unit/plugins_test.rb b/vendor/plugins/engines/test/unit/plugins_test.rb deleted file mode 100644 index f8627bcee..000000000 --- a/vendor/plugins/engines/test/unit/plugins_test.rb +++ /dev/null @@ -1,11 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class PluginsTest < Test::Unit::TestCase - - def test_should_allow_access_to_plugins_by_strings_or_symbols - p = Engines.plugins["alpha_plugin"] - q = Engines.plugins[:alpha_plugin] - assert_kind_of Engines::Plugin, p - assert_equal p, q - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/unit/test_testing/override_test.rb b/vendor/plugins/engines/test/unit/test_testing/override_test.rb deleted file mode 100644 index ea58a51c3..000000000 --- a/vendor/plugins/engines/test/unit/test_testing/override_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require File.join(File.dirname(__FILE__), *%w[.. .. test_helper]) - -class OverrideTest < ActiveSupport::TestCase - def test_overrides_from_the_application_should_work - assert true, "overriding plugin tests from the application should work" - end -end
\ No newline at end of file diff --git a/vendor/plugins/engines/test/unit/testing_test.rb b/vendor/plugins/engines/test/unit/testing_test.rb deleted file mode 100644 index c0c37ed40..000000000 --- a/vendor/plugins/engines/test/unit/testing_test.rb +++ /dev/null @@ -1,19 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class TestingTest < Test::Unit::TestCase - def setup - Engines::Testing.set_fixture_path - @filename = File.join(Engines::Testing.temporary_fixtures_directory, 'testing_fixtures.yml') - File.delete(@filename) if File.exists?(@filename) - end - - def teardown - File.delete(@filename) if File.exists?(@filename) - end - - def test_should_copy_fixtures_files_to_tmp_directory - assert !File.exists?(@filename) - Engines::Testing.setup_plugin_fixtures - assert File.exists?(@filename) - end -end
\ No newline at end of file diff --git a/vendor/plugins/open_id_authentication/CHANGELOG b/vendor/plugins/open_id_authentication/CHANGELOG index 7349bd3c0..0c8971efd 100644 --- a/vendor/plugins/open_id_authentication/CHANGELOG +++ b/vendor/plugins/open_id_authentication/CHANGELOG @@ -1,3 +1,5 @@ +* Dump heavy lifting off to rack-openid gem. OpenIdAuthentication is just a simple controller concern. + * Fake HTTP method from OpenID server since they only support a GET. Eliminates the need to set an extra route to match the server's reply. [Josh Peek] * OpenID 2.0 recommends that forms should use the field name "openid_identifier" rather than "openid_url" [Josh Peek] diff --git a/vendor/plugins/open_id_authentication/README b/vendor/plugins/open_id_authentication/README index 807cdc756..fe2b37e29 100644 --- a/vendor/plugins/open_id_authentication/README +++ b/vendor/plugins/open_id_authentication/README @@ -14,22 +14,14 @@ The specification used is http://openid.net/specs/openid-authentication-2_0.html Prerequisites ============= -OpenID authentication uses the session, so be sure that you haven't turned that off. It also relies on a number of -database tables to store the authentication keys. So you'll have to run the migration to create these before you get started: - - rake open_id_authentication:db:create - -Or, use the included generators to install or upgrade: - - ./script/generate open_id_authentication_tables MigrationName - ./script/generate upgrade_open_id_authentication_tables MigrationName +OpenID authentication uses the session, so be sure that you haven't turned that off. Alternatively, you can use the file-based store, which just relies on on tmp/openids being present in RAILS_ROOT. But be aware that this store only works if you have a single application server. And it's not safe to use across NFS. It's recommended that you use the database store if at all possible. To use the file-based store, you'll also have to add this line to your config/environment.rb: OpenIdAuthentication.store = :file This particular plugin also relies on the fact that the authentication action allows for both POST and GET operations. -If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb. +If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb. The plugin also expects to find a root_url method that points to the home page of your site. You can accomplish this by using a root route in config/routes.rb: @@ -53,7 +45,7 @@ Also of note is the following code block used in the example below: authenticate_with_open_id do |result, identity_url| ... end - + In the above code block, 'identity_url' will need to match user.identity_url exactly. 'identity_url' will be a string in the form of 'http://example.com' - If you are storing just 'example.com' with your user, the lookup will fail. @@ -131,8 +123,8 @@ app/controllers/sessions_controller.rb end end end - - + + private def successful_login session[:user_id] = @current_user.id @@ -171,7 +163,7 @@ You can support it in your app by changing #open_id_authentication def open_id_authentication(identity_url) # Pass optional :required and :optional keys to specify what sreg fields you want. # Be sure to yield registration, a third argument in the #authenticate_with_open_id block. - authenticate_with_open_id(identity_url, + authenticate_with_open_id(identity_url, :required => [ :nickname, :email ], :optional => :fullname) do |result, identity_url, registration| case result.status @@ -199,7 +191,7 @@ You can support it in your app by changing #open_id_authentication end end end - + # registration is a hash containing the valid sreg keys given above # use this to map them to fields of your user model def assign_registration_attributes!(registration) @@ -221,9 +213,9 @@ Some OpenID providers also support the OpenID AX (attribute exchange) protocol f Accessing AX data is very similar to the Simple Registration process, described above -- just add the URI identifier for the AX field to your :optional or :required parameters. For example: - authenticate_with_open_id(identity_url, + authenticate_with_open_id(identity_url, :required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration| - + This would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate' diff --git a/vendor/plugins/open_id_authentication/init.rb b/vendor/plugins/open_id_authentication/init.rb index 2055ef700..84ec11fc4 100644 --- a/vendor/plugins/open_id_authentication/init.rb +++ b/vendor/plugins/open_id_authentication/init.rb @@ -1,16 +1,12 @@ -begin
- require 'openid'
-rescue LoadError
- begin
- gem 'ruby-openid', '>=2.1.4'
- rescue Gem::LoadError
- # no openid support
- end
-end
-
-if Object.const_defined?(:OpenID)
- config.to_prepare do
- OpenID::Util.logger = Rails.logger
- ActionController::Base.send :include, OpenIdAuthentication
- end
-end
+if Rails.version < '3' + config.gem 'rack-openid', :lib => 'rack/openid', :version => '>=0.2.1' +end + +require 'open_id_authentication' + +config.middleware.use OpenIdAuthentication + +config.after_initialize do + OpenID::Util.logger = Rails.logger + ActionController::Base.send :include, OpenIdAuthentication +end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb index 70418fde7..48be8ddba 100644 --- a/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb +++ b/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb @@ -1,15 +1,16 @@ require 'uri' -require 'openid/extensions/sreg' -require 'openid/extensions/ax' -require 'openid/store/filesystem' - -require File.dirname(__FILE__) + '/open_id_authentication/db_store' -require File.dirname(__FILE__) + '/open_id_authentication/mem_cache_store' -require File.dirname(__FILE__) + '/open_id_authentication/request' -require File.dirname(__FILE__) + '/open_id_authentication/timeout_fixes' if OpenID::VERSION == "2.0.4" +require 'openid' +require 'rack/openid' module OpenIdAuthentication - OPEN_ID_AUTHENTICATION_DIR = RAILS_ROOT + "/tmp/openids" + def self.new(app) + store = OpenIdAuthentication.store + if store.nil? + Rails.logger.warn "OpenIdAuthentication.store is nil. Using in-memory store." + end + + ::Rack::OpenID.new(app, OpenIdAuthentication.store) + end def self.store @@store @@ -19,18 +20,22 @@ module OpenIdAuthentication store, *parameters = *([ store_option ].flatten) @@store = case store - when :db - OpenIdAuthentication::DbStore.new - when :mem_cache - OpenIdAuthentication::MemCacheStore.new(*parameters) + when :memory + require 'openid/store/memory' + OpenID::Store::Memory.new when :file - OpenID::Store::Filesystem.new(OPEN_ID_AUTHENTICATION_DIR) + require 'openid/store/filesystem' + OpenID::Store::Filesystem.new(Rails.root.join('tmp/openids')) + when :memcache + require 'memcache' + require 'openid/store/memcache' + OpenID::Store::Memcache.new(MemCache.new(parameters)) else - raise "Unknown store: #{store}" + store end end - self.store = :db + self.store = nil class InvalidOpenId < StandardError end @@ -99,143 +104,56 @@ module OpenIdAuthentication return identifier end - # deprecated for OpenID 2.0, where not all OpenIDs are URLs - def self.normalize_url(url) - ActiveSupport::Deprecation.warn "normalize_url has been deprecated, use normalize_identifier instead" - self.normalize_identifier(url) - end - protected - def normalize_url(url) - OpenIdAuthentication.normalize_url(url) - end - - def normalize_identifier(url) - OpenIdAuthentication.normalize_identifier(url) - end - - # The parameter name of "openid_identifier" is used rather than the Rails convention "open_id_identifier" - # because that's what the specification dictates in order to get browser auto-complete working across sites - def using_open_id?(identity_url = nil) #:doc: - identity_url ||= params[:openid_identifier] || params[:openid_url] - !identity_url.blank? || params[:open_id_complete] + # The parameter name of "openid_identifier" is used rather than + # the Rails convention "open_id_identifier" because that's what + # the specification dictates in order to get browser auto-complete + # working across sites + def using_open_id?(identifier = nil) #:doc: + identifier ||= open_id_identifier + !identifier.blank? || request.env[Rack::OpenID::RESPONSE] end - def authenticate_with_open_id(identity_url = nil, options = {}, &block) #:doc: - identity_url ||= params[:openid_identifier] || params[:openid_url] + def authenticate_with_open_id(identifier = nil, options = {}, &block) #:doc: + identifier ||= open_id_identifier - if params[:open_id_complete].nil? - begin_open_id_authentication(identity_url, options, &block) - else + if request.env[Rack::OpenID::RESPONSE] complete_open_id_authentication(&block) + else + begin_open_id_authentication(identifier, options, &block) end end private - def begin_open_id_authentication(identity_url, options = {}) - identity_url = normalize_identifier(identity_url) - return_to = options.delete(:return_to) - method = options.delete(:method) - - options[:required] ||= [] # reduces validation later - options[:optional] ||= [] - - open_id_request = open_id_consumer.begin(identity_url) - add_simple_registration_fields(open_id_request, options) - add_ax_fields(open_id_request, options) - redirect_to(open_id_redirect_url(open_id_request, return_to, method)) - rescue OpenIdAuthentication::InvalidOpenId => e - yield Result[:invalid], identity_url, nil - rescue OpenID::OpenIDError, Timeout::Error => e - logger.error("[OPENID] #{e}") - yield Result[:missing], identity_url, nil + def open_id_identifier + params[:openid_identifier] || params[:openid_url] + end + + def begin_open_id_authentication(identifier, options = {}) + options[:identifier] = identifier + value = Rack::OpenID.build_header(options) + response.headers[Rack::OpenID::AUTHENTICATE_HEADER] = value + head :unauthorized end def complete_open_id_authentication - params_with_path = params.reject { |key, value| request.path_parameters[key] } - params_with_path.delete(:format) - open_id_response = timeout_protection_from_identity_server { open_id_consumer.complete(params_with_path, requested_url) } - identity_url = normalize_identifier(open_id_response.display_identifier) if open_id_response.display_identifier + response = request.env[Rack::OpenID::RESPONSE] + identifier = response.display_identifier - case open_id_response.status + case response.status when OpenID::Consumer::SUCCESS - profile_data = {} - - # merge the SReg data and the AX data into a single hash of profile data - [ OpenID::SReg::Response, OpenID::AX::FetchResponse ].each do |data_response| - if data_response.from_success_response( open_id_response ) - profile_data.merge! data_response.from_success_response( open_id_response ).data - end - end - - yield Result[:successful], identity_url, profile_data + yield Result[:successful], identifier, + OpenID::SReg::Response.from_success_response(response) + when :missing + yield Result[:missing], identifier, nil + when :invalid + yield Result[:invalid], identifier, nil when OpenID::Consumer::CANCEL - yield Result[:canceled], identity_url, nil + yield Result[:canceled], identifier, nil when OpenID::Consumer::FAILURE - yield Result[:failed], identity_url, nil + yield Result[:failed], identifier, nil when OpenID::Consumer::SETUP_NEEDED - yield Result[:setup_needed], open_id_response.setup_url, nil + yield Result[:setup_needed], response.setup_url, nil end end - - def open_id_consumer - OpenID::Consumer.new(session, OpenIdAuthentication.store) - end - - def add_simple_registration_fields(open_id_request, fields) - sreg_request = OpenID::SReg::Request.new - - # filter out AX identifiers (URIs) - required_fields = fields[:required].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact - optional_fields = fields[:optional].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact - - sreg_request.request_fields(required_fields, true) unless required_fields.blank? - sreg_request.request_fields(optional_fields, false) unless optional_fields.blank? - sreg_request.policy_url = fields[:policy_url] if fields[:policy_url] - open_id_request.add_extension(sreg_request) - end - - def add_ax_fields( open_id_request, fields ) - ax_request = OpenID::AX::FetchRequest.new - - # look through the :required and :optional fields for URIs (AX identifiers) - fields[:required].each do |f| - next unless f =~ /^https?:\/\// - ax_request.add( OpenID::AX::AttrInfo.new( f, nil, true ) ) - end - - fields[:optional].each do |f| - next unless f =~ /^https?:\/\// - ax_request.add( OpenID::AX::AttrInfo.new( f, nil, false ) ) - end - - open_id_request.add_extension( ax_request ) - end - - def open_id_redirect_url(open_id_request, return_to = nil, method = nil) - open_id_request.return_to_args['_method'] = (method || request.method).to_s - open_id_request.return_to_args['open_id_complete'] = '1' - open_id_request.redirect_url(root_url, return_to || requested_url) - end - - def requested_url - relative_url_root = self.class.respond_to?(:relative_url_root) ? - self.class.relative_url_root.to_s : - request.relative_url_root - "#{request.protocol}#{request.host_with_port}#{relative_url_root}#{request.path}" - end - - def timeout_protection_from_identity_server - yield - rescue Timeout::Error - Class.new do - def status - OpenID::FAILURE - end - - def msg - "Identity server timed out" - end - end.new - end end diff --git a/vendor/plugins/prepend_engine_views/init.rb b/vendor/plugins/prepend_engine_views/init.rb deleted file mode 100644 index cbf0e89a9..000000000 --- a/vendor/plugins/prepend_engine_views/init.rb +++ /dev/null @@ -1,21 +0,0 @@ -module PrependEngineViews - def self.included(base) - base.send(:include, InstanceMethods) - base.class_eval do - alias_method_chain :add_engine_view_paths, :prepend - end - end - - module InstanceMethods - # Patch Rails so engine's views are prepended to the view_path, - # thereby letting plugins override application views - def add_engine_view_paths_with_prepend - paths = ActionView::PathSet.new(engines.collect(&:view_path)) - ActionController::Base.view_paths.unshift(*paths) - ActionMailer::Base.view_paths.unshift(*paths) if configuration.frameworks.include?(:action_mailer) - end - end -end - -Rails::Plugin::Loader.send :include, PrependEngineViews - diff --git a/vendor/plugins/prototype_legacy_helper/README.markdown b/vendor/plugins/prototype_legacy_helper/README.markdown new file mode 100644 index 000000000..8f87439e4 --- /dev/null +++ b/vendor/plugins/prototype_legacy_helper/README.markdown @@ -0,0 +1,13 @@ +# Prototype Legacy Helper + +This plugin adds support for `form_remote_tag`, etc from Rails 2 to Rails 3. + +## Installation + +Either add the following to your `Gemfile` and run `bundle`: + + gem 'prototype_legacy_helper', '0.0.0', :git => 'git://github.com/rails/prototype_legacy_helper.git' + +or run the following command to vendor the plugin within your app: + + rails plugin install git://github.com/rails/prototype_legacy_helper.git diff --git a/vendor/plugins/prototype_legacy_helper/init.rb b/vendor/plugins/prototype_legacy_helper/init.rb new file mode 100644 index 000000000..859005645 --- /dev/null +++ b/vendor/plugins/prototype_legacy_helper/init.rb @@ -0,0 +1 @@ +require 'prototype_legacy_helper' diff --git a/vendor/plugins/prototype_legacy_helper/lib/prototype_legacy_helper.rb b/vendor/plugins/prototype_legacy_helper/lib/prototype_legacy_helper.rb new file mode 100644 index 000000000..8161eed23 --- /dev/null +++ b/vendor/plugins/prototype_legacy_helper/lib/prototype_legacy_helper.rb @@ -0,0 +1,432 @@ +module PrototypeHelper + # Creates a button with an onclick event which calls a remote action + # via XMLHttpRequest + # The options for specifying the target with :url + # and defining callbacks is the same as link_to_remote. + def button_to_remote(name, options = {}, html_options = {}) + button_to_function(name, remote_function(options), html_options) + end + + # Returns a button input tag with the element name of +name+ and a value (i.e., display text) of +value+ + # that will submit form using XMLHttpRequest in the background instead of a regular POST request that + # reloads the page. + # + # # Create a button that submits to the create action + # # + # # Generates: <input name="create_btn" onclick="new Ajax.Request('/testing/create', + # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)}); + # # return false;" type="button" value="Create" /> + # <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %> + # + # # Submit to the remote action update and update the DIV succeed or fail based + # # on the success or failure of the request + # # + # # Generates: <input name="update_btn" onclick="new Ajax.Updater({success:'succeed',failure:'fail'}, + # # '/testing/update', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)}); + # # return false;" type="button" value="Update" /> + # <%= submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' }, + # :update => { :success => "succeed", :failure => "fail" } + # + # <tt>options</tt> argument is the same as in form_remote_tag. + def submit_to_remote(name, value, options = {}) + options[:with] ||= 'Form.serialize(this.form)' + + html_options = options.delete(:html) || {} + html_options[:name] = name + + button_to_remote(value, options, html_options) + end + + # Returns a link to a remote action defined by <tt>options[:url]</tt> + # (using the url_for format) that's called in the background using + # XMLHttpRequest. The result of that request can then be inserted into a + # DOM object whose id can be specified with <tt>options[:update]</tt>. + # Usually, the result would be a partial prepared by the controller with + # render :partial. + # + # Examples: + # # Generates: <a href="#" onclick="new Ajax.Updater('posts', '/blog/destroy/3', {asynchronous:true, evalScripts:true}); + # # return false;">Delete this post</a> + # link_to_remote "Delete this post", :update => "posts", + # :url => { :action => "destroy", :id => post.id } + # + # # Generates: <a href="#" onclick="new Ajax.Updater('emails', '/mail/list_emails', {asynchronous:true, evalScripts:true}); + # # return false;"><img alt="Refresh" src="/images/refresh.png?" /></a> + # link_to_remote(image_tag("refresh"), :update => "emails", + # :url => { :action => "list_emails" }) + # + # You can override the generated HTML options by specifying a hash in + # <tt>options[:html]</tt>. + # + # link_to_remote "Delete this post", :update => "posts", + # :url => post_url(@post), :method => :delete, + # :html => { :class => "destructive" } + # + # You can also specify a hash for <tt>options[:update]</tt> to allow for + # easy redirection of output to an other DOM element if a server-side + # error occurs: + # + # Example: + # # Generates: <a href="#" onclick="new Ajax.Updater({success:'posts',failure:'error'}, '/blog/destroy/5', + # # {asynchronous:true, evalScripts:true}); return false;">Delete this post</a> + # link_to_remote "Delete this post", + # :url => { :action => "destroy", :id => post.id }, + # :update => { :success => "posts", :failure => "error" } + # + # Optionally, you can use the <tt>options[:position]</tt> parameter to + # influence how the target DOM element is updated. It must be one of + # <tt>:before</tt>, <tt>:top</tt>, <tt>:bottom</tt>, or <tt>:after</tt>. + # + # The method used is by default POST. You can also specify GET or you + # can simulate PUT or DELETE over POST. All specified with <tt>options[:method]</tt> + # + # Example: + # # Generates: <a href="#" onclick="new Ajax.Request('/person/4', {asynchronous:true, evalScripts:true, method:'delete'}); + # # return false;">Destroy</a> + # link_to_remote "Destroy", :url => person_url(:id => person), :method => :delete + # + # By default, these remote requests are processed asynchronous during + # which various JavaScript callbacks can be triggered (for progress + # indicators and the likes). All callbacks get access to the + # <tt>request</tt> object, which holds the underlying XMLHttpRequest. + # + # To access the server response, use <tt>request.responseText</tt>, to + # find out the HTTP status, use <tt>request.status</tt>. + # + # Example: + # # Generates: <a href="#" onclick="new Ajax.Request('/words/undo?n=33', {asynchronous:true, evalScripts:true, + # # onComplete:function(request){undoRequestCompleted(request)}}); return false;">hello</a> + # word = 'hello' + # link_to_remote word, + # :url => { :action => "undo", :n => word_counter }, + # :complete => "undoRequestCompleted(request)" + # + # The callbacks that may be specified are (in order): + # + # <tt>:loading</tt>:: Called when the remote document is being + # loaded with data by the browser. + # <tt>:loaded</tt>:: Called when the browser has finished loading + # the remote document. + # <tt>:interactive</tt>:: Called when the user can interact with the + # remote document, even though it has not + # finished loading. + # <tt>:success</tt>:: Called when the XMLHttpRequest is completed, + # and the HTTP status code is in the 2XX range. + # <tt>:failure</tt>:: Called when the XMLHttpRequest is completed, + # and the HTTP status code is not in the 2XX + # range. + # <tt>:complete</tt>:: Called when the XMLHttpRequest is complete + # (fires after success/failure if they are + # present). + # + # You can further refine <tt>:success</tt> and <tt>:failure</tt> by + # adding additional callbacks for specific status codes. + # + # Example: + # # Generates: <a href="#" onclick="new Ajax.Request('/testing/action', {asynchronous:true, evalScripts:true, + # # on404:function(request){alert('Not found...? Wrong URL...?')}, + # # onFailure:function(request){alert('HTTP Error ' + request.status + '!')}}); return false;">hello</a> + # link_to_remote word, + # :url => { :action => "action" }, + # 404 => "alert('Not found...? Wrong URL...?')", + # :failure => "alert('HTTP Error ' + request.status + '!')" + # + # A status code callback overrides the success/failure handlers if + # present. + # + # If you for some reason or another need synchronous processing (that'll + # block the browser while the request is happening), you can specify + # <tt>options[:type] = :synchronous</tt>. + # + # You can customize further browser side call logic by passing in + # JavaScript code snippets via some optional parameters. In their order + # of use these are: + # + # <tt>:confirm</tt>:: Adds confirmation dialog. + # <tt>:condition</tt>:: Perform remote request conditionally + # by this expression. Use this to + # describe browser-side conditions when + # request should not be initiated. + # <tt>:before</tt>:: Called before request is initiated. + # <tt>:after</tt>:: Called immediately after request was + # initiated and before <tt>:loading</tt>. + # <tt>:submit</tt>:: Specifies the DOM element ID that's used + # as the parent of the form elements. By + # default this is the current form, but + # it could just as well be the ID of a + # table row or any other DOM element. + # <tt>:with</tt>:: A JavaScript expression specifying + # the parameters for the XMLHttpRequest. + # Any expressions should return a valid + # URL query string. + # + # Example: + # + # :with => "'name=' + $('name').value" + # + # You can generate a link that uses AJAX in the general case, while + # degrading gracefully to plain link behavior in the absence of + # JavaScript by setting <tt>html_options[:href]</tt> to an alternate URL. + # Note the extra curly braces around the <tt>options</tt> hash separate + # it as the second parameter from <tt>html_options</tt>, the third. + # + # Example: + # link_to_remote "Delete this post", + # { :update => "posts", :url => { :action => "destroy", :id => post.id } }, + # :href => url_for(:action => "destroy", :id => post.id) + def link_to_remote(name, options = {}, html_options = nil) + link_to_function(name, remote_function(options), html_options || options.delete(:html)) + end + + # Returns a form tag that will submit using XMLHttpRequest in the + # background instead of the regular reloading POST arrangement. Even + # though it's using JavaScript to serialize the form elements, the form + # submission will work just like a regular submission as viewed by the + # receiving side (all elements available in <tt>params</tt>). The options for + # specifying the target with <tt>:url</tt> and defining callbacks is the same as + # +link_to_remote+. + # + # A "fall-through" target for browsers that doesn't do JavaScript can be + # specified with the <tt>:action</tt>/<tt>:method</tt> options on <tt>:html</tt>. + # + # Example: + # # Generates: + # # <form action="/some/place" method="post" onsubmit="new Ajax.Request('', + # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;"> + # form_remote_tag :html => { :action => + # url_for(:controller => "some", :action => "place") } + # + # The Hash passed to the <tt>:html</tt> key is equivalent to the options (2nd) + # argument in the FormTagHelper.form_tag method. + # + # By default the fall-through action is the same as the one specified in + # the <tt>:url</tt> (and the default method is <tt>:post</tt>). + # + # form_remote_tag also takes a block, like form_tag: + # # Generates: + # # <form action="/" method="post" onsubmit="new Ajax.Request('/', + # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); + # # return false;"> <div><input name="commit" type="submit" value="Save" /></div> + # # </form> + # <% form_remote_tag :url => '/posts' do -%> + # <div><%= submit_tag 'Save' %></div> + # <% end -%> + def form_remote_tag(options = {}, &block) + options[:form] = true + + options[:html] ||= {} + options[:html][:onsubmit] = + (options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") + + "#{remote_function(options)}; return false;" + + form_tag(options[:html].delete(:action) || url_for(options[:url]), options[:html], &block) + end + + # Creates a form that will submit using XMLHttpRequest in the background + # instead of the regular reloading POST arrangement and a scope around a + # specific resource that is used as a base for questioning about + # values for the fields. + # + # === Resource + # + # Example: + # <% remote_form_for(@post) do |f| %> + # ... + # <% end %> + # + # This will expand to be the same as: + # + # <% remote_form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %> + # ... + # <% end %> + # + # === Nested Resource + # + # Example: + # <% remote_form_for([@post, @comment]) do |f| %> + # ... + # <% end %> + # + # This will expand to be the same as: + # + # <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), :html => { :method => :put, :class => "edit_comment", :id => "edit_comment_45" } do |f| %> + # ... + # <% end %> + # + # If you don't need to attach a form to a resource, then check out form_remote_tag. + # + # See FormHelper#form_for for additional semantics. + def remote_form_for(record_or_name_or_array, *args, &proc) + options = args.extract_options! + + case record_or_name_or_array + when String, Symbol + object_name = record_or_name_or_array + when Array + object = record_or_name_or_array.last + object_name = ActiveModel::Naming.singular(object) + apply_form_for_options!(record_or_name_or_array, options) + args.unshift object + else + object = record_or_name_or_array + object_name = ActiveModel::Naming.singular(record_or_name_or_array) + apply_form_for_options!(object, options) + args.unshift object + end + + form_remote_tag options do + fields_for object_name, *(args << options), &proc + end + end + alias_method :form_remote_for, :remote_form_for + + # Returns '<tt>eval(request.responseText)</tt>' which is the JavaScript function + # that +form_remote_tag+ can call in <tt>:complete</tt> to evaluate a multiple + # update return document using +update_element_function+ calls. + def evaluate_remote_response + "eval(request.responseText)" + end + + # Observes the field with the DOM ID specified by +field_id+ and calls a + # callback when its contents have changed. The default callback is an + # Ajax call. By default the value of the observed field is sent as a + # parameter with the Ajax call. + # + # Example: + # # Generates: new Form.Element.Observer('suggest', 0.25, function(element, value) {new Ajax.Updater('suggest', + # # '/testing/find_suggestion', {asynchronous:true, evalScripts:true, parameters:'q=' + value})}) + # <%= observe_field :suggest, :url => { :action => :find_suggestion }, + # :frequency => 0.25, + # :update => :suggest, + # :with => 'q' + # %> + # + # Required +options+ are either of: + # <tt>:url</tt>:: +url_for+-style options for the action to call + # when the field has changed. + # <tt>:function</tt>:: Instead of making a remote call to a URL, you + # can specify javascript code to be called instead. + # Note that the value of this option is used as the + # *body* of the javascript function, a function definition + # with parameters named element and value will be generated for you + # for example: + # observe_field("glass", :frequency => 1, :function => "alert('Element changed')") + # will generate: + # new Form.Element.Observer('glass', 1, function(element, value) {alert('Element changed')}) + # The element parameter is the DOM element being observed, and the value is its value at the + # time the observer is triggered. + # + # Additional options are: + # <tt>:frequency</tt>:: The frequency (in seconds) at which changes to + # this field will be detected. Not setting this + # option at all or to a value equal to or less than + # zero will use event based observation instead of + # time based observation. + # <tt>:update</tt>:: Specifies the DOM ID of the element whose + # innerHTML should be updated with the + # XMLHttpRequest response text. + # <tt>:with</tt>:: A JavaScript expression specifying the parameters + # for the XMLHttpRequest. The default is to send the + # key and value of the observed field. Any custom + # expressions should return a valid URL query string. + # The value of the field is stored in the JavaScript + # variable +value+. + # + # Examples + # + # :with => "'my_custom_key=' + value" + # :with => "'person[name]=' + prompt('New name')" + # :with => "Form.Element.serialize('other-field')" + # + # Finally + # :with => 'name' + # is shorthand for + # :with => "'name=' + value" + # This essentially just changes the key of the parameter. + # + # Additionally, you may specify any of the options documented in the + # <em>Common options</em> section at the top of this document. + # + # Example: + # + # # Sends params: {:title => 'Title of the book'} when the book_title input + # # field is changed. + # observe_field 'book_title', + # :url => 'http://example.com/books/edit/1', + # :with => 'title' + # + # + def observe_field(field_id, options = {}) + if options[:frequency] && options[:frequency] > 0 + build_observer('Form.Element.Observer', field_id, options) + else + build_observer('Form.Element.EventObserver', field_id, options) + end + end + + # Observes the form with the DOM ID specified by +form_id+ and calls a + # callback when its contents have changed. The default callback is an + # Ajax call. By default all fields of the observed field are sent as + # parameters with the Ajax call. + # + # The +options+ for +observe_form+ are the same as the options for + # +observe_field+. The JavaScript variable +value+ available to the + # <tt>:with</tt> option is set to the serialized form by default. + def observe_form(form_id, options = {}) + if options[:frequency] + build_observer('Form.Observer', form_id, options) + else + build_observer('Form.EventObserver', form_id, options) + end + end + + # Periodically calls the specified url (<tt>options[:url]</tt>) every + # <tt>options[:frequency]</tt> seconds (default is 10). Usually used to + # update a specified div (<tt>options[:update]</tt>) with the results + # of the remote call. The options for specifying the target with <tt>:url</tt> + # and defining callbacks is the same as link_to_remote. + # Examples: + # # Call get_averages and put its results in 'avg' every 10 seconds + # # Generates: + # # new PeriodicalExecuter(function() {new Ajax.Updater('avg', '/grades/get_averages', + # # {asynchronous:true, evalScripts:true})}, 10) + # periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg') + # + # # Call invoice every 10 seconds with the id of the customer + # # If it succeeds, update the invoice DIV; if it fails, update the error DIV + # # Generates: + # # new PeriodicalExecuter(function() {new Ajax.Updater({success:'invoice',failure:'error'}, + # # '/testing/invoice/16', {asynchronous:true, evalScripts:true})}, 10) + # periodically_call_remote(:url => { :action => 'invoice', :id => customer.id }, + # :update => { :success => "invoice", :failure => "error" } + # + # # Call update every 20 seconds and update the new_block DIV + # # Generates: + # # new PeriodicalExecuter(function() {new Ajax.Updater('news_block', 'update', {asynchronous:true, evalScripts:true})}, 20) + # periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block') + # + def periodically_call_remote(options = {}) + frequency = options[:frequency] || 10 # every ten seconds by default + code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})" + javascript_tag(code) + end + + protected + def build_observer(klass, name, options = {}) + if options[:with] && (options[:with] !~ /[\{=(.]/) + options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)" + else + options[:with] ||= 'value' unless options[:function] + end + + callback = options[:function] || remote_function(options) + javascript = "new #{klass}('#{name}', " + javascript << "#{options[:frequency]}, " if options[:frequency] + javascript << "function(element, value) {" + javascript << "#{callback}}" + javascript << ")" + javascript_tag(javascript) + end +end + +ActionController::Base.helper PrototypeHelper diff --git a/vendor/plugins/prototype_legacy_helper/test/test_prototype_helper.rb b/vendor/plugins/prototype_legacy_helper/test/test_prototype_helper.rb new file mode 100644 index 000000000..f21666fda --- /dev/null +++ b/vendor/plugins/prototype_legacy_helper/test/test_prototype_helper.rb @@ -0,0 +1,297 @@ +if ENV['RAILS_ROOT'] + environment = File.expand_path('vendor/gems/environment', ENV['RAILS_ROOT']) + require environment if File.exist?("#{environment}.rb") +end + +$:.unshift File.expand_path('../../lib', __FILE__) + +require 'test/unit' +require 'action_view' +require 'action_controller' +require 'active_model' +require 'prototype_helper' + +class Bunny < Struct.new(:Bunny, :id) +end + +class Author + extend ActiveModel::Naming + + attr_reader :id + def save; @id = 1 end + def new_record?; @id.nil? end + def name + @id.nil? ? 'new author' : "author ##{@id}" + end +end + +class Article + extend ActiveModel::Naming + + attr_reader :id + attr_reader :author_id + def save; @id = 1; @author_id = 1 end + def new_record?; @id.nil? end + def name + @id.nil? ? 'new article' : "article ##{@id}" + end +end + +class Author::Nested < Author; end + +class PrototypeHelperTest < ActionView::TestCase + attr_accessor :formats, :output_buffer, :template_format + + def _evaluate_assigns_and_ivars() end + + def reset_formats(format) + @format = format + end + + def setup + @record = @author = Author.new + @article = Article.new + super + @template = self + @controller = Class.new do + def url_for(options) + if options.is_a?(String) + options + else + url = "http://www.example.com/" + url << options[:action].to_s if options and options[:action] + url << "?a=#{options[:a]}" if options && options[:a] + url << "&b=#{options[:b]}" if options && options[:a] && options[:b] + url + end + end + end.new + end + + + def test_observe_form + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {new Ajax.Request('http://www.example.com/cart_changed', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>), + observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" }) + end + + def test_observe_form_using_function_for_callback + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {alert('Form changed')})\n//]]>\n</script>), + observe_form("cart", :frequency => 2, :function => "alert('Form changed')") + end + + def test_observe_field + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/reorder_if_empty', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>), + observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" }) + end + + def test_observe_field_using_with_option + expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(value)})})\n//]]>\n</script>) + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id') + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)") + end + + def test_observe_field_using_json_in_with_option + expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:{'id':value}})})\n//]]>\n</script>) + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}") + end + + def test_observe_field_using_function_for_callback + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {alert('Element changed')})\n//]]>\n</script>), + observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')") + end + + def test_observe_field_without_frequency + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.EventObserver('glass', function(element, value) {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>), + observe_field("glass") + end + + + def test_periodically_call_remote + assert_dom_equal %(<script type="text/javascript">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Updater('schremser_bier', 'http://www.example.com/mehr_bier', {asynchronous:true, evalScripts:true})}, 10)\n//]]>\n</script>), + periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" }) + end + + def test_periodically_call_remote_with_frequency + assert_dom_equal( + "<script type=\"text/javascript\">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true})}, 2)\n//]]>\n</script>", + periodically_call_remote(:frequency => 2) + ) + end + + + def test_form_remote_tag + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">), + form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }) + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">), + form_remote_tag(:update => { :failure => "glass_of_water" }, :url => { :action => :fast }) + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">), + form_remote_tag(:update => { :success => 'glass_of_beer', :failure => "glass_of_water" }, :url => { :action => :fast }) + end + + def test_form_remote_tag_with_method + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div>), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put }) + end + + def test_form_remote_tag_with_block_in_erb + __in_erb_template = '' + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" } + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), output_buffer + end + + def test_on_callbacks + callbacks = [:uninitialized, :loading, :loaded, :interactive, :complete, :success, :failure] + callbacks.each do |callback| + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">), + form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();") + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({failure:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">), + form_remote_tag(:update => { :failure => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();") + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">), + form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();") + end + + #HTTP status codes 200 up to 599 have callbacks + #these should work + 100.upto(599) do |callback| + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") + end + + #test 200 and 404 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, parameters:Form.serialize(this)}); return false;">), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();") + + #these shouldn't + 1.upto(99) do |callback| + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") + end + 600.upto(999) do |callback| + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();") + end + + #test ultimate combo + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, onComplete:function(request){c();}, onFailure:function(request){f();}, onLoading:function(request){c1()}, onSuccess:function(request){s()}, parameters:Form.serialize(this)}); return false;\">), + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();") + end + + def test_remote_form_for_with_record_identification_with_new_record + remote_form_for(@record, {:html => { :id => 'create-author' }}) {} + + expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' id='create-author' method='post'></form>) + assert_dom_equal expected, output_buffer + end + + def test_remote_form_for_with_record_identification_without_html_options + remote_form_for(@record) {} + + expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' method='post' id='new_author'></form>) + assert_dom_equal expected, output_buffer + end + + def test_remote_form_for_with_record_identification_with_existing_record + @record.save + remote_form_for(@record) {} + + expected = %(<form action='#{author_path(@record)}' id='edit_author_1' method='post' onsubmit="new Ajax.Request('#{author_path(@record)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_author'><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div></form>) + assert_dom_equal expected, output_buffer + end + + def test_remote_form_for_with_new_object_in_list + remote_form_for([@author, @article]) {} + + expected = %(<form action='#{author_articles_path(@author)}' onsubmit="new Ajax.Request('#{author_articles_path(@author)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_article' method='post' id='new_article'></form>) + assert_dom_equal expected, output_buffer + end + + def test_remote_form_for_with_existing_object_in_list + @author.save + @article.save + remote_form_for([@author, @article]) {} + + expected = %(<form action='#{author_article_path(@author, @article)}' id='edit_article_1' method='post' onsubmit="new Ajax.Request('#{author_article_path(@author, @article)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_article'><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div></form>) + assert_dom_equal expected, output_buffer + end + + + def test_button_to_remote + assert_dom_equal %(<input class=\"fine\" type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true});\" />), + button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" }) + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.reponseText)}});\" />), + button_to_remote("Remote outpost", :complete => "alert(request.reponseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.reponseText)}});\" />), + button_to_remote("Remote outpost", :success => "alert(request.reponseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}});\" />), + button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}});\" />), + button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) + end + + def test_submit_to_remote + assert_dom_equal %(<input name=\"More beer!\" onclick=\"new Ajax.Updater('empty_bottle', 'http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});\" type=\"button\" value=\"1000000\" />), + submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle") + end + + + def test_link_to_remote + assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>), + link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }}, { :class => "fine" }) + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>), + link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>), + link_to_remote("Remote outauthor", :success => "alert(request.responseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>), + link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot" }) + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>), + link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' }) + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:false, evalScripts:true}); return false;\">Remote outauthor</a>), + link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :type => :synchronous) + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, insertion:'bottom'}); return false;\">Remote outauthor</a>), + link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom) + end + + def test_link_to_remote_html_options + assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>), + link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } }) + end + + def test_link_to_remote_url_quote_escaping + assert_dom_equal %(<a href="#" onclick="new Ajax.Request('http://www.example.com/whatnot\\\'s', {asynchronous:true, evalScripts:true}); return false;">Remote</a>), + link_to_remote("Remote", { :url => { :action => "whatnot's" } }) + end + + protected + def request_forgery_protection_token + nil + end + + def protect_against_forgery? + false + end + + def create_generator + block = Proc.new { |*args| yield *args if block_given? } + JavaScriptGenerator.new self, &block + end + + def author_path(record) + "/authors/#{record.id}" + end + + def authors_path + "/authors" + end + + def author_articles_path(author) + "/authors/#{author.id}/articles" + end + + def author_article_path(author, article) + "/authors/#{author.id}/articles/#{article.id}" + end +end |