Upgraded to Rails 2.3.4 (#3597)

* Ran the Rails upgrade
* Upgraded to Rails Engines 2.3.2
* Added a plugin to let Engines override application views.
* Converted tests to use the new classes:
** ActionController::TestCase for functional
** ActiveSupport::TestCase for units
* Converted ActiveRecord::Error message to a string.
* ActiveRecord grouping returns an ordered hash which doesn't have #sort!
* Updated the I18n storage_units format.
* Added some default initializers from a fresh rails app
* Changed the order of check_box_tags and hidden_field_tags.  The hidden tag
  needs to appear first in Rails 2.3, otherwise it will override any value in
  the check_box_tag.
* Removed the custom handler for when the cookie store is tampered with.
  Rails 2.3 removed the TamperedWithCookie exception and instead Rails will not
  load the data from it when it's been tampered with (e.g. no user login).
* Fixed mail layouts, 2.3 has problems with implicit multipart emails that
  use layouts.  Also removed some custom Redmine mailer code.
* Fixed a bug that occurred in tests where the "required" span tag would be
  added to the :field_status translation.  This resulted in an email string of:

    <li>Status<span class="required"> *</span><span class="required"> *</span>

  Instead of:

    <li>Status: New</li>

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2887 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Eric Davis
2009-09-13 17:14:35 +00:00
parent fb349dc4ab
commit 7b0cb6aba8
263 changed files with 1636 additions and 440 deletions
+18 -5
View File
@@ -172,16 +172,29 @@ namespace :test do
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 "> Modifying default config files to load engines plugin"
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')")
insert_line('map.from_plugin :test_routing', :into => 'config/routes.rb',
:after => /\AActionController::Routing::Routes/)
# 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')
+1 -1
View File
@@ -4,4 +4,4 @@ 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.1.0
version: 2.3.2
+2 -2
View File
@@ -1,7 +1,7 @@
begin
require 'rails/version'
unless Rails::VERSION::MAJOR >= 2 && Rails::VERSION::MINOR >= 2 && Rails::VERSION::TINY >= 0
raise "This version of the engines plugin requires Rails 2.2.0 or later!"
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
+2 -2
View File
@@ -1,5 +1,5 @@
# 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 if defined? :Engines
end
Engines.init(initializer) if defined? :Engines
end
+5 -5
View File
@@ -43,7 +43,7 @@ module Engines
# List of extensions to load, can be changed in init.rb before calling Engines.init
mattr_accessor :rails_extensions
self.rails_extensions = %w(action_mailer asset_helpers form_tag_helpers routing migrations dependencies)
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>.
@@ -68,7 +68,7 @@ module Engines
mattr_accessor :disable_application_code_loading
self.disable_application_code_loading = false
# Set this ti true if code should not be mixed (i.e. it will be loaded
# 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
@@ -81,7 +81,7 @@ module Engines
self.code_mixing_file_types = %w(controller helper)
class << self
def init
def init(initializer)
load_extensions
Engines::Assets.initialize_base_public_directory
end
@@ -124,9 +124,9 @@ module Engines
# 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 in your plugin's init.rb:
# on your load path by including them in Rails load path mechanism, e.g. in init.rb:
#
# Rails.plugins[:my_plugin].code_paths << "app/things"
# 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 }
+1 -48
View File
@@ -4,23 +4,9 @@
#
# Engines.plugins[:plugin_name]
#
# If this plugin contains paths in directories other than <tt>app/controllers</tt>,
# <tt>app/helpers</tt>, <tt>app/models</tt> and <tt>components</tt>, authors can
# declare this by adding extra paths to #code_paths:
#
# Rails.plugin[:my_plugin].code_paths << "app/sweepers" << "vendor/my_lib"
#
# Other properties of the Plugin instance can also be set.
module Engines
class Plugin < Rails::Plugin
# Plugins can add code paths to this attribute in init.rb if they
# need plugin directories to be added to the load path, i.e.
#
# plugin.code_paths << 'app/other_classes'
#
# Defaults to ["app/controllers", "app/helpers", "app/models", "components"]
attr_accessor :code_paths
# Plugins can add paths to this attribute in init.rb if they need
# controllers loaded from additional locations.
attr_accessor :controller_paths
@@ -32,16 +18,6 @@ module Engines
attr_accessor :public_directory
protected
# The default set of code paths which will be added to $LOAD_PATH
# and Dependencies.load_paths
def default_code_paths
# lib will actually be removed from the load paths when we call
# uniq! in #inject_into_load_paths, but it's important to keep it
# around (for the documentation tasks, for instance).
%w(app/controllers app/helpers app/models components lib)
end
# The default set of code paths which will be added to the routing system
def default_controller_paths
%w(app/controllers components)
@@ -58,41 +34,23 @@ module Engines
def initialize(directory)
super directory
@code_paths = default_code_paths
@controller_paths = default_controller_paths
@public_directory = default_public_directory
end
# Returns a list of paths this plugin wishes to make available in $LOAD_PATH
#
# Overwrites the correspondend method in the superclass
def load_paths
report_nonexistant_or_empty_plugin! unless valid?
select_existing_paths :code_paths
end
# Extends the superclass' load method to additionally mirror public assets
def load(initializer)
return if loaded?
super initializer
add_plugin_view_paths
add_plugin_locale_paths
Assets.mirror_files_for(self)
end
# for code_paths and controller_paths select those paths that actually
# exist in the plugin's directory
# 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_view_paths
view_path = File.join(directory, 'app', 'views')
if File.exist?(view_path)
ActionController::Base.prepend_view_path(view_path) # push it just underneath the app
end
end
def add_plugin_locale_paths
locale_path = File.join(directory, 'locales')
return unless File.exists?(locale_path)
@@ -112,11 +70,6 @@ module Engines
"#{File.basename(Engines.public_directory)}/#{name}"
end
# The path to this plugin's routes file
def routes_path
File.join(directory, "routes.rb")
end
# The directory containing this plugin's migrations (<tt>plugin/db/migrate</tt>)
def migration_directory
File.join(self.directory, 'db', 'migrate')
-7
View File
@@ -5,14 +5,7 @@ module Engines
def register_plugin_as_loaded(plugin)
super plugin
Engines.plugins << plugin
register_to_routing(plugin)
end
# Registers the plugin's controller_paths for the routing system.
def register_to_routing(plugin)
initializer.configuration.controller_paths += plugin.select_existing_paths(:controller_paths)
initializer.configuration.controller_paths.uniq!
end
end
end
end
@@ -1,82 +0,0 @@
# The way ActionMailer is coded in terms of finding templates is very restrictive, to the point
# where all templates for rendering must exist under the single base path. This is difficult to
# work around without re-coding significant parts of the action mailer code.
#
# ---
#
# The MailTemplates module overrides two (private) methods from ActionMailer to enable mail
# templates within plugins:
#
# [+template_path+] which now produces the contents of #template_paths
# [+initialize_template_class+] which now find the first matching template and creates
# an ActionVew::Base instance with the correct view_paths
#
# Ideally ActionMailer would use the same template-location logic as ActionView, and the same
# view paths as ActionController::Base.view_paths, but it currently does not.
module Engines::RailsExtensions::ActionMailer
def self.included(base) #:nodoc:
base.class_eval do
alias_method_chain :template_path, :engine_additions
alias_method_chain :initialize_template_class, :engine_additions
end
end
private
#--
# ActionMailer::Base#create uses two mechanisms to determine the proper template file(s)
# to load. Firstly, it searches within the template_root for files that much the explicit
# (or implicit) part encodings (like signup.text.plain.erb for the signup action).
# This is how implicit multipart emails are built, by the way.
#
# Secondly, it then creates an ActionMailer::Base instance with it's view_paths parameter
# set to the template_root, so that ActionMailer will then take over rendering the
# templates.
#
# Ideally, ActionMailer would pass the same set of view paths as it gets in a normal
# request (i.e. ActionController::Base.view_paths), so that all possible view paths
# were searched. However, this seems to introduce some problems with helper modules.
#
# So instead, and because we have to fool these two independent parts of ActionMailer,
# we fudge with the mechanisms it uses to find the templates (via template_paths, and
# template_path_with_engine_additions), and then intercept the creation of the ActionView
# instance so we can set the view_paths (in initialize_template_class_with_engine_additions).
#++
# Returns all possible template paths for the current mailer, including those
# within the loaded plugins.
def template_paths
paths = Engines.plugins.by_precedence.map { |p| "#{p.directory}/app/views/#{mailer_name}" }
paths.unshift(template_path_without_engine_additions) unless Engines.disable_application_view_loading
paths
end
# Return something that Dir[] can glob against. This method is called in
# ActionMailer::Base#create! and used as part of an argument to Dir. We can
# take advantage of this by using some of the features of Dir.glob to search
# multiple paths for matching files.
def template_path_with_engine_additions
"{#{template_paths.join(",")}}"
end
# Return an instance of ActionView::Base with the view paths set to all paths
# in ActionController::Base.view_paths (i.e. including all plugin view paths)
def initialize_template_class_with_engine_additions(assigns)
# I'd like to just return this, but I get problems finding methods in helper
# modules if the method implemention from the regular class is not called
#
# ActionView::Base.new(ActionController::Base.view_paths.dup, assigns, self)
renderer = initialize_template_class_without_engine_additions(assigns)
renderer.view_paths.unshift(*ActionController::Base.view_paths.dup)
renderer
end
end
# We don't need to do this if ActionMailer hasn't been loaded.
if Object.const_defined?(:ActionMailer)
module ::ActionMailer #:nodoc:
class Base #:nodoc:
include Engines::RailsExtensions::ActionMailer
end
end
end
@@ -1,83 +0,0 @@
# Effective use of Rails' routes can help create a tidy and elegant set of URLs,
# and is a significant part of creating an external API for your web application.
#
# When developing plugins which contain controllers, it seems obvious that including
# the corresponding routes would be extremely useful. This is particularly true
# when exposing RESTful resources using the new REST-ian features of Rails.
#
# == Including routes in your plugin
#
# The engines plugin makes it possible to include a set of routes within your plugin
# very simply, as it turns out. Include a <tt>routes.rb</tt> file like the one below
# at the root of your plugin (along-side <tt>init.rb</tt> and <tt>lib/</tt>):
#
# connect "/login", :controller => "account", :action => "login"
#
# # add a named route
# logout "/logout", :controller => "account", :action => "logout"
#
# # some restful stuff
# resources :things do |t|
# t.resources :other_things
# end
#
# Everywhere in a normal <tt>RAILS_ROOT/config/routes.rb</tt> file
# where you might have <tt>map.connect</tt>, you just use <tt>connect</tt> in your
# plugin's <tt>routes.rb</tt>.
#
# === Hooking it up in your application
#
# While it would be possible to have each plugin's routes automagically included into
# the application's route set, to do so would actually be a stunningly bad idea. Route
# priority is the key issue here. You, the application developer, needs to be in complete
# control when it comes to specifying the priority of routes in your application, since
# the ordering of your routes directly affects how Rails will interpret incoming requests.
#
# To add plugin routes into your application's <tt>routes.rb</tt> file, you need to explicitly
# map them in using the Engines::RailsExtensions::Routing#from_plugin method:
#
# ApplicationController::Routing::Routes.draw do |map|
#
# map.connect "/app_stuff", :controller => "application_thing" # etc...
#
# # This line includes the routes from the given plugin at this point, giving you
# # control over the priority of your application routes
# map.from_plugin :your_plugin
#
# map.connect ":controller/:action/:id"
# end
#
# By including routes in plugins which have controllers, you can now share in a simple way
# a compact and elegant URL scheme which corresponds to those controllers.
#
# ---
#
# The Engines::RailsExtensions::Routing module defines extensions to Rails'
# routing (ActionController::Routing) mechanism such that routes can be loaded
# from a given plugin.
#
# The key method is Engines::RailsExtensions::Routing#from_plugin, which can be called
# within your application's <tt>config/routes.rb</tt> file to load plugin routes at that point.
#
module Engines::RailsExtensions::Routing
# Loads the set of routes from within a plugin and evaluates them at this
# point within an application's main <tt>routes.rb</tt> file.
#
# Plugin routes are loaded from <tt><plugin_root>/routes.rb</tt>.
def from_plugin(name)
map = self # to make 'map' available within the plugin route file
routes_path = Engines.plugins[name].routes_path
eval(IO.read(routes_path), binding, routes_path) if File.file?(routes_path)
end
end
module ::ActionController #:nodoc:
module Routing #:nodoc:
class RouteSet #:nodoc:
class Mapper #:nodoc:
include Engines::RailsExtensions::Routing
end
end
end
end
+15 -1
View File
@@ -67,10 +67,14 @@ module Engines::Testing
# 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")
if File.directory?(plugin_fixtures_directory)
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
@@ -84,4 +88,14 @@ module Engines::Testing
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
+35 -7
View File
@@ -118,10 +118,10 @@ namespace :db do
end
desc 'Migrate a specified plugin.'
task({:plugin => :environment}, :name, :version) do |task, args|
name = args[:name] || ENV['NAME']
task(:plugin => :environment) do
name = ENV['NAME']
if plugin = Engines.plugins[name]
version = args[:version] || ENV['VERSION']
version = ENV['VERSION']
puts "Migrating #{plugin.name} to " + (version ? "version #{version}" : 'latest version') + " ..."
plugin.migrate(version ? version.to_i : nil)
else
@@ -152,8 +152,8 @@ 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 code paths (see
# Plugin#code_paths).
# <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) }
@@ -172,9 +172,9 @@ namespace :doc do
options << '--line-numbers' << '--inline-source'
options << '-T html'
# Include every file in the plugin's code_paths (see Plugin#code_paths)
# Include every file in the plugin's load_paths (see Plugin#load_paths)
if Engines.plugins[plugin]
files.include("#{plugin_base}/{#{Engines.plugins[plugin].code_paths.join(",")}}/**/*.rb")
files.include("#{plugin_base}/{#{Engines.plugins[plugin].load_paths.join(",")}}/**/*.rb")
end
if File.exists?("#{plugin_base}/README")
files.include("#{plugin_base}/README")
@@ -217,6 +217,34 @@ 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)"
@@ -0,0 +1,5 @@
class AppAndPluginController < ApplicationController
def an_action
render_class_and_action 'from app'
end
end
@@ -0,0 +1,5 @@
class Namespace::AppAndPluginController < ApplicationController
def an_action
render_class_and_action 'from app'
end
end
@@ -0,0 +1,5 @@
module MailHelper
def do_something_helpful(var)
var.to_s.reverse
end
end
@@ -0,0 +1,3 @@
class AppAndPluginModel < ActiveRecord::Base
def self.report_location; TestHelper::report_location(__FILE__); end
end
+26
View File
@@ -0,0 +1,26 @@
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
+3
View File
@@ -0,0 +1,3 @@
class Thing
def self.from_app; TestHelper::report_location(__FILE__); end
end
@@ -0,0 +1 @@
<%= TestHelper.view_path_for __FILE__ %> (from app)
@@ -0,0 +1 @@
<%= TestHelper.view_path_for __FILE__ %> (from app)
@@ -0,0 +1 @@
the implicit html part of the email <%= do_something_helpful("semaj") %>
@@ -0,0 +1 @@
the implicit plaintext part of the email
@@ -0,0 +1 @@
the html part of the email <%= do_something_helpful("semaj") %>
@@ -0,0 +1 @@
the plaintext part of the email
@@ -0,0 +1,5 @@
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) %>
@@ -0,0 +1 @@
<%= @note %> (from application)
@@ -0,0 +1 @@
plugin mail template loaded from application
@@ -0,0 +1,51 @@
# 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
@@ -0,0 +1,29 @@
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
@@ -0,0 +1,26 @@
# 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
+29
View File
@@ -0,0 +1,29 @@
# 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
@@ -0,0 +1,37 @@
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
@@ -0,0 +1,60 @@
# 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
@@ -0,0 +1,3 @@
class AppAndPluginLibModel < ActiveRecord::Base
def self.report_location; TestHelper::report_location(__FILE__); end
end
+42
View File
@@ -0,0 +1,42 @@
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
+7
View File
@@ -0,0 +1,7 @@
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
@@ -0,0 +1,8 @@
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
@@ -0,0 +1,5 @@
class AppAndPluginController < ApplicationController
def an_action
render_class_and_action 'from alpha_plugin'
end
end
@@ -0,0 +1,5 @@
class Namespace::AlphaPluginController < ApplicationController
def an_action
render_class_and_action
end
end
@@ -0,0 +1,5 @@
class Namespace::AppAndPluginController < ApplicationController
def an_action
render_class_and_action 'from alpha_plugin'
end
end
@@ -0,0 +1,5 @@
class Namespace::SharedPluginController < ApplicationController
def an_action
render_class_and_action 'from alpha_plugin'
end
end
@@ -0,0 +1,5 @@
class SharedEngineController < ApplicationController
def an_action
render_class_and_action 'from alpha_engine'
end
end
@@ -0,0 +1,3 @@
class AlphaPluginModel < ActiveRecord::Base
def self.report_location; TestHelper::report_location(__FILE__); end
end
@@ -0,0 +1,7 @@
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
@@ -0,0 +1,3 @@
class SharedPluginModel < ActiveRecord::Base
def self.report_location; TestHelper::report_location(__FILE__); end
end
@@ -0,0 +1 @@
<%= TestHelper.view_path_for __FILE__ %>
@@ -0,0 +1 @@
<%= TestHelper.view_path_for __FILE__ %> (from a_view)
@@ -0,0 +1 @@
<%= yield %> (with plugin layout)
@@ -0,0 +1 @@
<%= TestHelper.view_path_for __FILE__ %>
@@ -0,0 +1 @@
<%= TestHelper.view_path_for __FILE__ %>
@@ -0,0 +1 @@
<%= TestHelper.view_path_for __FILE__ %> (from alpha_plugin)
@@ -0,0 +1 @@
<%= TestHelper.view_path_for __FILE__ %> (from alpha_plugin)
@@ -0,0 +1,3 @@
class AlphaPluginLibModel < ActiveRecord::Base
def self.report_location; TestHelper::report_location(__FILE__); end
end
@@ -0,0 +1,7 @@
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
@@ -0,0 +1,3 @@
en:
hello: "Hello from alfa"
plugin: "alfa"
@@ -0,0 +1,5 @@
class AppAndPluginController < ApplicationController
def an_action
render_class_and_action 'from beta_plugin'
end
end
@@ -0,0 +1,5 @@
class Namespace::SharedPluginController < ApplicationController
def an_action
render_class_and_action 'from beta_plugin'
end
end
@@ -0,0 +1,5 @@
class SharedPluginController < ApplicationController
def an_action
render_class_and_action 'from beta_plugin'
end
end
@@ -0,0 +1,3 @@
class SharedPluginModel < ActiveRecord::Base
def self.report_location; TestHelper::report_location(__FILE__); end
end
@@ -0,0 +1 @@
<%= TestHelper.view_path_for __FILE__ %> (from beta_plugin)
@@ -0,0 +1 @@
<%= TestHelper.view_path_for __FILE__ %> (from beta_plugin)
@@ -0,0 +1 @@
# just here so that Rails recognizes this as a plugin
@@ -0,0 +1,3 @@
en:
hello: "Hello from beta"
plugin: "beta"
@@ -0,0 +1,2 @@
class AssetsController < ApplicationController
end
@@ -0,0 +1,4 @@
<%= 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" %>
@@ -0,0 +1,3 @@
<div id="assets_layout">
<%= yield %>
</div>
@@ -0,0 +1,3 @@
class Thing
def self.from_plugin; TestHelper::report_location(__FILE__); end
end
@@ -0,0 +1 @@
# just here so that Rails recognizes this as a plugin
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,26 @@
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
@@ -0,0 +1,5 @@
class Namespace::TestRoutingController < ApplicationController
def routed_action
render_class_and_action
end
end
@@ -0,0 +1,9 @@
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
@@ -0,0 +1,4 @@
ActionController::Routing::Routes.draw do |map|
map.connect 'routes/:action', :controller => "test_routing"
map.plugin_route 'somespace/routes/:action', :controller => "namespace/test_routing"
end
@@ -0,0 +1 @@
Fixtures are only copied from plugins with an +app+ directory, but git needs this directory to be non-empty
@@ -0,0 +1,13 @@
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
+54
View File
@@ -0,0 +1,54 @@
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
@@ -0,0 +1,41 @@
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
+52
View File
@@ -0,0 +1,52 @@
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
@@ -0,0 +1,8 @@
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

Some files were not shown because too many files have changed in this diff Show More