提交 f1b1af88 编写于 作者: R Rick Olson

Refactor Plugin Loader. Add plugin lib paths early, and add lots of tests. ...

Refactor Plugin Loader.  Add plugin lib paths early, and add lots of tests.  Closes #9795 [lazyatom]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8115 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 c443a619
*SVN*
* Refactor Plugin Loader. Add plugin lib paths early, and add lots of tests. Closes #9795 [lazyatom]
* Added --skip-timestamps to generators that produce models #10036 [tpope]
* Update Prototype to 1.6.0 and script.aculo.us to 1.8.0. [sam, madrobby]
......
......@@ -34,7 +34,7 @@ class Initializer
# The set of loaded plugins.
attr_reader :loaded_plugins
# Runs the initializer. By default, this will invoke the #process method,
# which simply executes all of the initialization routines. Alternately,
# you can specify explicitly which initialization routine you want:
......@@ -64,6 +64,7 @@ def initialize(configuration)
# * #set_load_path
# * #require_frameworks
# * #set_autoload_paths
# * add_plugin_load_paths
# * #load_environment
# * #initialize_encoding
# * #initialize_database
......@@ -83,9 +84,10 @@ def initialize(configuration)
def process
check_ruby_version
set_load_path
require_frameworks
set_autoload_paths
add_plugin_load_paths
load_environment
initialize_encoding
......@@ -161,14 +163,20 @@ def require_frameworks
def add_support_load_paths
end
# Adds all load paths from plugins to the global set of load paths, so that
# code from plugins can be required (explicitly or automatically via Dependencies).
def add_plugin_load_paths
plugin_loader.add_plugin_load_paths
end
# Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt>
# defaults to <tt>vendor/plugins</tt> but may also be set to a list of
# paths, such as
# config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]
#
# Each plugin discovered in <tt>plugin_paths</tt> is initialized:
# * add its +lib+ directory, if present, to the beginning of the load path
# * evaluate <tt>init.rb</tt> if present
# In the default implementation, as each plugin discovered in <tt>plugin_paths</tt> is initialized:
# * its +lib+ directory, if present, is added to the load path (immediately after the applications lib directory)
# * <tt>init.rb</tt> is evalutated, if present
#
# After all plugins are loaded, duplicates are removed from the load path.
# If an array of plugin names is specified in config.plugins, only those plugins will be loaded
......@@ -178,13 +186,11 @@ def add_support_load_paths
# if config.plugins ends contains :all then the named plugins will be loaded in the given order and all other
# plugins will be loaded in alphabetical order
def load_plugins
configuration.plugin_locators.each do |locator|
locator.new(self).each do |plugin|
plugin.load
end
end
ensure_all_registered_plugins_are_loaded!
$LOAD_PATH.uniq!
plugin_loader.load_plugins
end
def plugin_loader
@plugin_loader ||= configuration.plugin_loader.new(self)
end
# Loads the environment specified by Configuration#environment_path, which
......@@ -337,15 +343,6 @@ def load_application_initializers
end
end
private
def ensure_all_registered_plugins_are_loaded!
unless configuration.plugins.nil?
if configuration.plugins.detect {|plugin| plugin != :all && !loaded_plugins.include?( plugin)}
missing_plugins = configuration.plugins - (loaded_plugins + [:all])
raise LoadError, "Could not locate the following plugins: #{missing_plugins.to_sentence}"
end
end
end
end
# The Configuration class holds all the parameters for the Initializer and
......
module Rails
# The Plugin class should be an object which provides the following methods:
#
# * +name+ - used during initialisation to order the plugin (based on name and
# the contents of <tt>config.plugins</tt>)
# * +valid?+ - returns true if this plugin can be loaded
# * +load_paths+ - each path within the returned array will be added to the $LOAD_PATH
# * +load+ - finally 'load' the plugin.
#
# These methods are expected by the Rails::Plugin::Locator and Rails::Plugin::Loader classes.
# The default implementation returns the <tt>lib</tt> directory as its </tt>load_paths</tt>,
# and evaluates <tt>init.rb</tt> when <tt>load</tt> is called.
class Plugin
include Comparable
attr_reader :directory, :name
def initialize(directory)
@directory = directory
@name = File.basename(@directory) rescue nil
@loaded = false
end
def valid?
File.directory?(directory) && (has_lib_directory? || has_init_file?)
end
# Returns a list of paths this plugin wishes to make available in $LOAD_PATH
def load_paths
report_nonexistant_or_empty_plugin! unless valid?
has_lib_directory? ? [lib_path] : []
end
# Evaluates a plugin's init.rb file
def load(initializer)
report_nonexistant_or_empty_plugin! unless valid?
evaluate_init_rb(initializer)
@loaded = true
end
def loaded?
@loaded
end
def <=>(other_plugin)
name <=> other_plugin.name
end
private
def report_nonexistant_or_empty_plugin!
raise LoadError, "Can not find the plugin named: #{name}"
end
def lib_path
File.join(directory, 'lib')
end
def init_path
File.join(directory, 'init.rb')
end
def has_lib_directory?
File.directory?(lib_path)
end
def has_init_file?
File.file?(init_path)
end
def evaluate_init_rb(initializer)
if has_init_file?
silence_warnings do
# Allow plugins to reference the current configuration object
config = initializer.configuration
eval(IO.read(init_path), binding, init_path)
end
end
end
end
end
\ No newline at end of file
require "rails/plugin"
module Rails
module Plugin
class Plugin
class Loader
include Comparable
attr_reader :initializer, :directory, :name
class << self
def load(*args)
new(*args).load
end
end
def initialize(initializer, directory)
attr_reader :initializer
# Creates a new Plugin::Loader instance, associated with the given
# Rails::Initializer. This default implementation automatically locates
# all plugins, and adds all plugin load paths, when it is created. The plugins
# are then fully loaded (init.rb is evaluated) when load_plugins is called.
#
# It is the loader's responsibilty to ensure that only the plugins specified
# in the configuration are actually loaded, and that the order defined
# is respected.
def initialize(initializer)
@initializer = initializer
@directory = directory
@name = File.basename(directory).to_sym
end
def load
return false if loaded?
report_nonexistant_or_empty_plugin!
add_to_load_path!
register_plugin_as_loaded
evaluate
true
# Returns the plugins to be loaded, in the order they should be loaded.
def plugins
@plugins ||= all_plugins.select { |plugin| should_load?(plugin) }.sort { |p1, p2| order_plugins(p1, p2) }
end
def loaded?
initializer.loaded_plugins.include?(name)
# Returns all the plugins that could be found by the current locators.
def all_plugins
@all_plugins ||= locate_plugins
@all_plugins
end
def plugin_path?
File.directory?(directory) && (has_lib_directory? || has_init_file?)
def load_plugins
plugins.each do |plugin|
plugin.load(initializer)
register_plugin_as_loaded(plugin)
end
ensure_all_registered_plugins_are_loaded!
end
def enabled?
!explicit_plugin_loading_order? || registered?
end
# Adds the load paths for every plugin into the $LOAD_PATH. Plugin load paths are
# added *after* the application's <tt>lib</tt> directory, to ensure that an application
# can always override code within a plugin.
#
# Plugin load paths are also added to Dependencies.load_paths, and Dependencies.load_once_paths.
def add_plugin_load_paths
plugins.each do |plugin|
plugin.load_paths.each do |path|
$LOAD_PATH.insert(application_lib_index + 1, path)
Dependencies.load_paths << path
Dependencies.load_once_paths << path
end
end
$LOAD_PATH.uniq!
end
def explicitly_enabled?
!explicit_plugin_loading_order? || explicitly_registered?
end
protected
def registered?
explicit_plugin_loading_order? && registered_plugins_names_plugin?(name)
end
# The locate_plugins method uses each class in config.plugin_locators to
# find the set of all plugins available to this Rails application.
def locate_plugins
configuration.plugin_locators.map { |locator|
locator.new(initializer).plugins
}.flatten
# TODO: sorting based on config.plugins
end
def explicitly_registered?
explicit_plugin_loading_order? && registered_plugins.include?(name)
end
def plugin_does_not_exist!(plugin_name = name)
raise LoadError, "Can not find the plugin named: #{plugin_name}"
end
private
# The plugins that have been explicitly listed with config.plugins. If this list is nil
# then it means the client does not care which plugins or in what order they are loaded,
# so we load all in alphabetical order. If it is an empty array, we load no plugins, if it is
# non empty, we load the named plugins in the order specified.
def registered_plugins
config.plugins
def register_plugin_as_loaded(plugin)
initializer.loaded_plugins << plugin
end
def registered_plugins_names_plugin?(plugin_name)
registered_plugins.include?(plugin_name) || registered_plugins.include?(:all)
def configuration
initializer.configuration
end
def explicit_plugin_loading_order?
!registered_plugins.nil?
def should_load?(plugin)
# uses Plugin#name and Plugin#valid?
enabled?(plugin) && plugin.valid?
end
def report_nonexistant_or_empty_plugin!
plugin_does_not_exist! unless plugin_path?
def order_plugins(plugin_a, plugin_b)
if !explicit_plugin_loading_order?
plugin_a <=> plugin_b
else
if !explicitly_enabled?(plugin_a) && !explicitly_enabled?(plugin_b)
plugin_a <=> plugin_b
else
effective_order_of(plugin_a) <=> effective_order_of(plugin_b)
end
end
end
def lib_path
File.join(directory, 'lib')
def effective_order_of(plugin)
if explicitly_enabled?(plugin)
registered_plugin_names.index(plugin.name)
else
registered_plugin_names.index('all')
end
end
def init_path
File.join(directory, 'init.rb')
def application_lib_index
$LOAD_PATH.index(File.join(RAILS_ROOT, 'lib')) || 0
end
def enabled?(plugin)
!explicit_plugin_loading_order? || registered?(plugin)
end
def has_lib_directory?
File.directory?(lib_path)
def explicit_plugin_loading_order?
!registered_plugin_names.nil?
end
def has_init_file?
File.file?(init_path)
def registered?(plugin)
explicit_plugin_loading_order? && registered_plugins_names_plugin?(plugin)
end
def add_to_load_path!
# Add lib to load path *after* the application lib, to allow
# application libraries to override plugin libraries.
if has_lib_directory?
application_lib_index = $LOAD_PATH.index(application_library_path) || 0
$LOAD_PATH.insert(application_lib_index + 1, lib_path)
Dependencies.load_paths << lib_path
Dependencies.load_once_paths << lib_path
end
def explicitly_enabled?(plugin)
!explicit_plugin_loading_order? || explicitly_registered?(plugin)
end
def application_library_path
File.join(RAILS_ROOT, 'lib')
def explicitly_registered?(plugin)
explicit_plugin_loading_order? && registered_plugin_names.include?(plugin.name)
end
# Allow plugins to reference the current configuration object
def config
initializer.configuration
def registered_plugins_names_plugin?(plugin)
registered_plugin_names.include?(plugin.name) || registered_plugin_names.include?('all')
end
def register_plugin_as_loaded
initializer.loaded_plugins << name
# The plugins that have been explicitly listed with config.plugins. If this list is nil
# then it means the client does not care which plugins or in what order they are loaded,
# so we load all in alphabetical order. If it is an empty array, we load no plugins, if it is
# non empty, we load the named plugins in the order specified.
def registered_plugin_names
configuration.plugins ? configuration.plugins.map(&:to_s) : nil
end
# Evaluate in init.rb
def evaluate
silence_warnings { eval(IO.read(init_path), binding, init_path) } if has_init_file?
def loaded?(plugin_name)
initializer.loaded_plugins.detect { |plugin| plugin.name == plugin_name.to_s }
end
def <=>(other_plugin_loader)
def ensure_all_registered_plugins_are_loaded!
if explicit_plugin_loading_order?
if non_existent_plugin = [self, other_plugin_loader].detect { |plugin| !registered_plugins_names_plugin?(plugin.name) }
plugin_does_not_exist!(non_existent_plugin.name)
end
if !explicitly_enabled? && !other_plugin_loader.explicitly_enabled?
name.to_s <=> other_plugin_loader.name.to_s
elsif registered_plugins.include?(:all) && (!explicitly_enabled? || !other_plugin_loader.explicitly_enabled?)
effective_index = explicitly_enabled? ? registered_plugins.index(name) : registered_plugins.index(:all)
other_effective_index = other_plugin_loader.explicitly_enabled? ?
registered_plugins.index(other_plugin_loader.name) : registered_plugins.index(:all)
effective_index <=> other_effective_index
else
registered_plugins.index(name) <=> registered_plugins.index(other_plugin_loader.name)
if configuration.plugins.detect {|plugin| plugin != :all && !loaded?(plugin) }
missing_plugins = configuration.plugins - (plugins + [:all])
raise LoadError, "Could not locate the following plugins: #{missing_plugins.to_sentence}"
end
else
name.to_s <=> other_plugin_loader.name.to_s
end
end
end
end
end
\ No newline at end of file
module Rails
module Plugin
class Plugin
# The Plugin::Locator class should be subclasses to provide custom plugin-finding
# abilities to Rails (i.e. loading plugins from Gems, etc). Each subclass should implement
# the <tt>located_plugins</tt> method, which return an array of Plugin objects that have been found.
class Locator
include Enumerable
attr_reader :initializer
def initialize(initializer)
@initializer = initializer
end
# This method should return all the plugins which this Plugin::Locator can find
# These will then be used by the current Plugin::Loader, which is responsible for actually
# loading the plugins themselves
def plugins
located_plugins.select(&:enabled?).sort
raise "The `plugins' method must be defined by concrete subclasses of #{self.class}"
end
def each(&block)
......@@ -19,41 +27,52 @@ def each(&block)
def plugin_names
plugins.map(&:name)
end
private
def located_plugins
raise "The `located_plugins' method must be defined by concrete subclasses of #{self.class}"
end
end
# The Rails::Plugin::FileSystemLocator will try to locate plugins by examining the directories
# the the paths given in configuration.plugin_paths. Any plugins that can be found are returned
# in a list.
#
# The criteria for a valid plugin in this case is found in Rails::Plugin#valid?, although
# other subclasses of Rails::Plugin::Locator can of course use different conditions.
class FileSystemLocator < Locator
private
def located_plugins
initializer.configuration.plugin_paths.flatten.inject([]) do |plugins, path|
plugins.concat locate_plugins_under(path)
plugins
end.flatten
end
# Returns all the plugins which can be loaded in the filesystem, under the paths given
# by configuration.plugin_paths.
def plugins
initializer.configuration.plugin_paths.flatten.inject([]) do |plugins, path|
plugins.concat locate_plugins_under(path)
plugins
end.flatten
end
private
# Attempts to create a plugin from the given path. If the created plugin is valid?
# (see Rails::Plugin#valid?) then the plugin instance is returned; otherwise nil.
def create_plugin(path)
plugin = Rails::Plugin.new(path)
plugin.valid? ? plugin : nil
end
# This starts at the base path looking for directories that pass the plugin_path? test of the Plugin::Loader.
# Since plugins can be nested arbitrarily deep within an unspecified number of intermediary directories,
# this method runs recursively until it finds a plugin directory.
#
# e.g.
#
# locate_plugins_under('vendor/plugins/acts/acts_as_chunky_bacon')
# => 'acts_as_chunky_bacon'
def locate_plugins_under(base_path)
Dir.glob(File.join(base_path, '*')).inject([]) do |plugins, path|
plugin_loader = initializer.configuration.plugin_loader.new(initializer, path)
if plugin_loader.plugin_path? && plugin_loader.enabled?
plugins << plugin_loader
elsif File.directory?(path)
plugins.concat locate_plugins_under(path)
end
plugins
# This starts at the base path looking for valid plugins (see Rails::Plugin#valid?).
# Since plugins can be nested arbitrarily deep within an unspecified number of intermediary
# directories, this method runs recursively until it finds a plugin directory, e.g.
#
# locate_plugins_under('vendor/plugins/acts/acts_as_chunky_bacon')
# => <Rails::Plugin name: 'acts_as_chunky_bacon' ... >
#
def locate_plugins_under(base_path)
Dir.glob(File.join(base_path, '*')).inject([]) do |plugins, path|
if plugin = create_plugin(path)
plugins << plugin
elsif File.directory?(path)
plugins.concat locate_plugins_under(path)
end
plugins
end
end
end
end
end
\ No newline at end of file
......@@ -135,3 +135,84 @@ def assert_framework_path(path)
end
end
end
uses_mocha "Initializer plugin loading tests" do
require File.dirname(__FILE__) + '/plugin_test_helper'
class InitializerPluginLoadingTests < Test::Unit::TestCase
def setup
@configuration = Rails::Configuration.new
@configuration.plugin_paths << plugin_fixture_root_path
@initializer = Rails::Initializer.new(@configuration)
@valid_plugin_path = plugin_fixture_path('default/stubby')
@empty_plugin_path = plugin_fixture_path('default/empty')
end
def test_no_plugins_are_loaded_if_the_configuration_has_an_empty_plugin_list
only_load_the_following_plugins! []
@initializer.load_plugins
assert_equal [], @initializer.loaded_plugins
end
def test_only_the_specified_plugins_are_located_in_the_order_listed
plugin_names = [:plugin_with_no_lib_dir, :acts_as_chunky_bacon]
only_load_the_following_plugins! plugin_names
load_plugins!
assert_plugins plugin_names, @initializer.loaded_plugins
end
def test_all_plugins_are_loaded_when_registered_plugin_list_is_untouched
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
load_plugins!
assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @initializer.loaded_plugins, failure_tip
end
def test_all_plugins_loaded_when_all_is_used
plugin_names = [:stubby, :acts_as_chunky_bacon, :all]
only_load_the_following_plugins! plugin_names
load_plugins!
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @initializer.loaded_plugins, failure_tip
end
def test_all_plugins_loaded_after_all
plugin_names = [:stubby, :all, :acts_as_chunky_bacon]
only_load_the_following_plugins! plugin_names
load_plugins!
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_plugins [:stubby, :a, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @initializer.loaded_plugins, failure_tip
end
def test_plugin_names_may_be_strings
plugin_names = ['stubby', 'acts_as_chunky_bacon', :a, :plugin_with_no_lib_dir]
only_load_the_following_plugins! plugin_names
load_plugins!
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_plugins plugin_names, @initializer.loaded_plugins, failure_tip
end
def test_registering_a_plugin_name_that_does_not_exist_raises_a_load_error
only_load_the_following_plugins! [:stubby, :acts_as_a_non_existant_plugin]
assert_raises(LoadError) do
load_plugins!
end
end
def test_should_ensure_all_loaded_plugins_load_paths_are_added_to_the_load_path
only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
@initializer.add_plugin_load_paths
assert $LOAD_PATH.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
assert $LOAD_PATH.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
end
private
def load_plugins!
@initializer.add_plugin_load_paths
@initializer.load_plugins
end
end
end
require File.dirname(__FILE__) + '/plugin_test_helper'
class TestPluginLoader < Test::Unit::TestCase
def setup
@initializer = Rails::Initializer.new(Rails::Configuration.new)
@valid_plugin_path = plugin_fixture_path('default/stubby')
@empty_plugin_path = plugin_fixture_path('default/empty')
end
def test_determining_if_the_plugin_order_has_been_explicitly_set
loader = loader_for(@valid_plugin_path)
assert !loader.send(:explicit_plugin_loading_order?)
only_load_the_following_plugins! %w(stubby acts_as_chunky_bacon)
assert loader.send(:explicit_plugin_loading_order?)
end
def test_enabled_if_not_named_explicitly
stubby_loader = loader_for(@valid_plugin_path)
acts_as_loader = loader_for('acts_as/acts_as_chunky_bacon')
uses_mocha "Plugin Loader Tests" do
class TestPluginLoader < Test::Unit::TestCase
ORIGINAL_LOAD_PATH = $LOAD_PATH.dup
only_load_the_following_plugins! ['stubby', :all]
assert stubby_loader.send(:enabled?)
assert acts_as_loader.send(:enabled?)
def setup
reset_load_path!
@configuration = Rails::Configuration.new
@configuration.plugin_paths << plugin_fixture_root_path
@initializer = Rails::Initializer.new(@configuration)
@valid_plugin_path = plugin_fixture_path('default/stubby')
@empty_plugin_path = plugin_fixture_path('default/empty')
@loader = Rails::Plugin::Loader.new(@initializer)
end
def test_should_locate_plugins_by_asking_each_locator_specifed_in_configuration_for_its_plugins_result
locator_1 = stub(:plugins => [:a, :b, :c])
locator_2 = stub(:plugins => [:d, :e, :f])
locator_class_1 = stub(:new => locator_1)
locator_class_2 = stub(:new => locator_2)
@configuration.plugin_locators = [locator_class_1, locator_class_2]
assert_equal [:a, :b, :c, :d, :e, :f], @loader.send(:locate_plugins)
end
assert stubby_loader.send(:explicitly_enabled?)
assert !acts_as_loader.send(:explicitly_enabled?)
end
def test_determining_whether_a_given_plugin_is_loaded
plugin_loader = loader_for(@valid_plugin_path)
assert !plugin_loader.loaded?
assert_nothing_raised do
plugin_loader.send(:register_plugin_as_loaded)
end
assert plugin_loader.loaded?
end
def test_if_a_path_is_a_plugin_path
# This is a plugin path, with a lib dir
assert loader_for(@valid_plugin_path).plugin_path?
# This just has an init.rb and no lib dir
assert loader_for(plugin_fixture_path('default/plugin_with_no_lib_dir')).plugin_path?
# This would be a plugin path, but the directory is empty
assert !loader_for(plugin_fixture_path('default/empty')).plugin_path?
# This is a non sense path
assert !loader_for(plugin_fixture_path('default/this_directory_does_not_exist')).plugin_path?
end
def test_if_you_try_to_load_a_non_plugin_path_you_get_a_load_error
# This path is fine so nothing is raised
assert_nothing_raised do
loader_for(@valid_plugin_path).send(:report_nonexistant_or_empty_plugin!)
def test_should_memoize_the_result_of_locate_plugins_as_all_plugins
plugin_list = [:a, :b, :c]
@loader.expects(:locate_plugins).once.returns(plugin_list)
assert_equal plugin_list, @loader.all_plugins
assert_equal plugin_list, @loader.all_plugins # ensuring that locate_plugins isn't called again
end
# This is an empty path so it raises
assert_raises(LoadError) do
loader_for(@empty_plugin_path).send(:report_nonexistant_or_empty_plugin!)
def test_should_return_empty_array_if_configuration_plugins_is_empty
@configuration.plugins = []
assert_equal [], @loader.plugins
end
assert_raises(LoadError) do
loader_for('this_is_not_a_plugin_directory').send(:report_nonexistant_or_empty_plugin!)
def test_should_find_all_availble_plugins_and_return_as_all_plugins
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.all_plugins, failure_tip
end
end
def test_loading_a_plugin_gives_the_init_file_access_to_all_it_needs
failure_tip = "Perhaps someone has written another test that loads this same plugin and therefore makes the StubbyMixin constant defined already."
assert !defined?(StubbyMixin), failure_tip
assert !added_to_load_path?(@valid_plugin_path)
# The init.rb of this plugin raises if it doesn't have access to all the things it needs
assert_nothing_raised do
loader_for(@valid_plugin_path).load
end
assert added_to_load_path?(@valid_plugin_path)
assert defined?(StubbyMixin)
end
private
def loader_for(path, initializer = @initializer)
Rails::Plugin::Loader.new(initializer, path)
def test_should_return_all_plugins_as_plugins_when_registered_plugin_list_is_untouched
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, failure_tip
end
def test_should_return_all_plugins_as_plugins_when_registered_plugin_list_is_nil
@configuration.plugins = nil
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, failure_tip
end
def test_should_return_specific_plugins_named_in_config_plugins_array_if_set
plugin_names = [:acts_as_chunky_bacon, :stubby]
only_load_the_following_plugins! plugin_names
assert_plugins plugin_names, @loader.plugins
end
def test_should_respect_the_order_of_plugins_given_in_configuration
plugin_names = [:stubby, :acts_as_chunky_bacon]
only_load_the_following_plugins! plugin_names
assert_plugins plugin_names, @loader.plugins
end
def test_should_load_all_plugins_in_natural_order_when_all_is_used
only_load_the_following_plugins! [:all]
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_plugins [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @loader.plugins, failure_tip
end
def plugin_fixture_path(path)
File.join(plugin_fixture_root_path, path)
def test_should_load_specified_plugins_in_order_and_then_all_remaining_plugins_when_all_is_used
only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon, :all]
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @loader.plugins, failure_tip
end
def added_to_load_path?(path)
$LOAD_PATH.grep(/#{path}/).size == 1
def test_should_be_able_to_specify_loading_of_plugins_loaded_after_all
only_load_the_following_plugins! [:stubby, :all, :acts_as_chunky_bacon]
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_plugins [:stubby, :a, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @loader.plugins, failure_tip
end
def test_should_accept_plugin_names_given_as_strings
only_load_the_following_plugins! ['stubby', 'acts_as_chunky_bacon', :a, :plugin_with_no_lib_dir]
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @loader.plugins, failure_tip
end
def test_should_add_plugin_load_paths_to_global_LOAD_PATH_array
only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
stubbed_application_lib_index_in_LOAD_PATHS = 5
@loader.stubs(:application_lib_index).returns(stubbed_application_lib_index_in_LOAD_PATHS)
@loader.add_plugin_load_paths
assert $LOAD_PATH.index(File.join(plugin_fixture_path('default/stubby'), 'lib')) >= stubbed_application_lib_index_in_LOAD_PATHS
assert $LOAD_PATH.index(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib')) >= stubbed_application_lib_index_in_LOAD_PATHS
end
def test_should_add_plugin_load_paths_to_Dependencies_load_paths
only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
@loader.add_plugin_load_paths
assert Dependencies.load_paths.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
assert Dependencies.load_paths.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
end
def test_should_add_plugin_load_paths_to_Dependencies_load_once_paths
only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
@loader.add_plugin_load_paths
assert Dependencies.load_once_paths.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
assert Dependencies.load_once_paths.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
end
def test_should_add_all_load_paths_from_a_plugin_to_LOAD_PATH_array
plugin_load_paths = ["a", "b"]
plugin = stub(:load_paths => plugin_load_paths)
@loader.stubs(:plugins).returns([plugin])
@loader.add_plugin_load_paths
plugin_load_paths.each { |path| assert $LOAD_PATH.include?(path) }
end
private
def reset_load_path!
$LOAD_PATH.clear
ORIGINAL_LOAD_PATH.each { |path| $LOAD_PATH << path }
end
end
end
\ No newline at end of file
require File.dirname(__FILE__) + '/plugin_test_helper'
class TestPluginFileSystemLocator < Test::Unit::TestCase
def setup
configuration = Rails::Configuration.new
# We need to add our testing plugin directory to the plugin paths so
# the locator knows where to look for our plugins
configuration.plugin_paths << plugin_fixture_root_path
@initializer = Rails::Initializer.new(configuration)
@locator = new_locator
end
uses_mocha "Plugin Locator Tests" do
class PluginLocatorTest < Test::Unit::TestCase
def test_no_plugins_are_loaded_if_the_configuration_has_an_empty_plugin_list
only_load_the_following_plugins! []
assert_equal [], @locator.plugins
end
def test_should_require_subclasses_to_implement_the_plugins_method
assert_raises(RuntimeError) do
Rails::Plugin::Locator.new(nil).plugins
end
end
def test_only_the_specified_plugins_are_located_in_the_order_listed
plugin_names = [:stubby, :acts_as_chunky_bacon]
only_load_the_following_plugins! plugin_names
assert_equal plugin_names, @locator.plugin_names
end
def test_should_iterator_over_plugins_returned_by_plugins_when_calling_each
locator = Rails::Plugin::Locator.new(nil)
locator.stubs(:plugins).returns([:a, :b, :c])
plugin_consumer = mock
plugin_consumer.expects(:consume).with(:a)
plugin_consumer.expects(:consume).with(:b)
plugin_consumer.expects(:consume).with(:c)
locator.each do |plugin|
plugin_consumer.consume(plugin)
end
end
def test_all_plugins_are_loaded_when_registered_plugin_list_is_untouched
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_equal [:a, :acts_as_chunky_bacon, :plugin_with_no_lib_dir, :stubby], @locator.plugin_names, failure_tip
end
class PluginFileSystemLocatorTest < Test::Unit::TestCase
def setup
@configuration = Rails::Configuration.new
# We need to add our testing plugin directory to the plugin paths so
# the locator knows where to look for our plugins
@configuration.plugin_paths << plugin_fixture_root_path
@initializer = Rails::Initializer.new(@configuration)
@locator = Rails::Plugin::FileSystemLocator.new(@initializer)
@valid_plugin_path = plugin_fixture_path('default/stubby')
@empty_plugin_path = plugin_fixture_path('default/empty')
end
def test_should_return_rails_plugin_instances_when_calling_create_plugin_with_a_valid_plugin_directory
assert_kind_of Rails::Plugin, @locator.send(:create_plugin, @valid_plugin_path)
end
def test_all_plugins_loaded_when_all_is_used
plugin_names = [:stubby, :acts_as_chunky_bacon, :all]
only_load_the_following_plugins! plugin_names
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_equal [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @locator.plugin_names, failure_tip
end
def test_should_return_nil_when_calling_create_plugin_with_an_invalid_plugin_directory
assert_nil @locator.send(:create_plugin, @empty_plugin_path)
end
def test_all_plugins_loaded_after_all
plugin_names = [:stubby, :all, :acts_as_chunky_bacon]
only_load_the_following_plugins! plugin_names
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_equal [:stubby, :a, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @locator.plugin_names, failure_tip
end
def test_should_return_all_plugins_found_under_the_set_plugin_paths
assert_equal ["a", "acts_as_chunky_bacon", "plugin_with_no_lib_dir", "stubby"], @locator.plugins.map(&:name)
end
def test_plugin_names_may_be_strings
plugin_names = ['stubby', 'acts_as_chunky_bacon', :a, :plugin_with_no_lib_dir]
only_load_the_following_plugins! plugin_names
failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
assert_equal [:stubby, :acts_as_chunky_bacon, :a, :plugin_with_no_lib_dir], @locator.plugin_names, failure_tip
end
def test_should_find_plugins_only_under_the_plugin_paths_set_in_configuration
@configuration.plugin_paths = [File.join(plugin_fixture_root_path, "default")]
assert_equal ["acts_as_chunky_bacon", "plugin_with_no_lib_dir", "stubby"], @locator.plugins.map(&:name)
@configuration.plugin_paths = [File.join(plugin_fixture_root_path, "alternate")]
assert_equal ["a"], @locator.plugins.map(&:name)
end
def test_registering_a_plugin_name_that_does_not_exist_raises_a_load_error
only_load_the_following_plugins! [:stubby, :acts_as_a_non_existant_plugin]
assert_raises(LoadError) do
@initializer.load_plugins
def test_should_not_raise_any_error_and_return_no_plugins_if_the_plugin_path_value_does_not_exist
@configuration.plugin_paths = ["some_missing_directory"]
assert_nothing_raised do
assert @locator.plugins.empty?
end
end
end
private
def new_locator(initializer = @initializer)
Rails::Plugin::FileSystemLocator.new(initializer)
end
end
\ No newline at end of file
end # uses_mocha
\ No newline at end of file
require File.dirname(__FILE__) + '/plugin_test_helper'
uses_mocha "Plugin Tests" do
class PluginTest < Test::Unit::TestCase
def setup
@initializer = Rails::Initializer.new(Rails::Configuration.new)
@valid_plugin_path = plugin_fixture_path('default/stubby')
@empty_plugin_path = plugin_fixture_path('default/empty')
end
def test_should_determine_plugin_name_from_the_directory_of_the_plugin
assert_equal 'stubby', plugin_for(@valid_plugin_path).name
assert_equal 'empty', plugin_for(@empty_plugin_path).name
end
def test_should_not_be_loaded_when_created
assert !plugin_for(@valid_plugin_path).loaded?
end
def test_should_be_marked_as_loaded_when_load_is_called
plugin = plugin_for(@valid_plugin_path)
assert !plugin.loaded?
plugin.stubs(:evaluate_init_rb)
assert_nothing_raised do
plugin.send(:load, anything)
end
assert plugin.loaded?
end
def test_should_determine_validity_of_given_path
# This is a plugin path, with a lib dir
assert plugin_for(@valid_plugin_path).valid?
# This just has an init.rb and no lib dir
assert plugin_for(plugin_fixture_path('default/plugin_with_no_lib_dir')).valid?
# This would be a plugin path, but the directory is empty
assert !plugin_for(plugin_fixture_path('default/empty')).valid?
# This is a non sense path
assert !plugin_for(plugin_fixture_path('default/this_directory_does_not_exist')).valid?
end
def test_should_return_empty_array_for_load_paths_when_plugin_has_no_lib_directory
assert_equal [], plugin_for(plugin_fixture_path('default/plugin_with_no_lib_dir')).load_paths
end
def test_should_return_array_with_lib_path_for_load_paths_when_plugin_has_a_lib_directory
expected_lib_dir = File.join(plugin_fixture_path('default/stubby'), 'lib')
assert_equal [expected_lib_dir], plugin_for(plugin_fixture_path('default/stubby')).load_paths
end
def test_should_raise_a_load_error_when_trying_to_determine_the_load_paths_from_an_invalid_plugin
assert_nothing_raised do
plugin_for(@valid_plugin_path).load_paths
end
assert_raises(LoadError) do
plugin_for(@empty_plugin_path).load_paths
end
assert_raises(LoadError) do
plugin_for('this_is_not_a_plugin_directory').load_paths
end
end
def test_should_raise_a_load_error_when_trying_to_load_an_invalid_plugin
# This path is fine so nothing is raised
assert_nothing_raised do
plugin = plugin_for(@valid_plugin_path)
plugin.stubs(:evaluate_init_rb)
plugin.send(:load, @initializer)
end
# This is an empty path so it raises
assert_raises(LoadError) do
plugin = plugin_for(@empty_plugin_path)
plugin.stubs(:evaluate_init_rb)
plugin.send(:load, @initializer)
end
assert_raises(LoadError) do
plugin = plugin_for('this_is_not_a_plugin_directory')
plugin.stubs(:evaluate_init_rb)
plugin.send(:load, @initializer)
end
end
def test_should_raise_a_load_error_when_trying_to_access_load_paths_of_an_invalid_plugin
# This path is fine so nothing is raised
assert_nothing_raised do
plugin_for(@valid_plugin_path).load_paths
end
# This is an empty path so it raises
assert_raises(LoadError) do
plugin_for(@empty_plugin_path).load_paths
end
assert_raises(LoadError) do
plugin_for('this_is_not_a_plugin_directory').load_paths
end
end
def test_loading_a_plugin_gives_the_init_file_access_to_all_it_needs
failure_tip = "Perhaps someone has written another test that loads this same plugin and therefore makes the StubbyMixin constant defined already."
assert !defined?(StubbyMixin), failure_tip
plugin = plugin_for(@valid_plugin_path)
plugin.load_paths.each { |path| $LOAD_PATH.unshift(path) }
# The init.rb of this plugin raises if it doesn't have access to all the things it needs
assert_nothing_raised do
plugin.load(@initializer)
end
assert defined?(StubbyMixin)
end
def test_should_sort_naturally_by_name
a = plugin_for("path/a")
b = plugin_for("path/b")
z = plugin_for("path/z")
assert_equal [a, b, z], [b, z, a].sort
end
private
def plugin_for(path)
Rails::Plugin.new(path)
end
end
end # uses_mocha
\ No newline at end of file
......@@ -4,15 +4,26 @@
require 'test/unit'
require 'active_support'
require 'initializer'
require File.join(File.dirname(__FILE__), 'abstract_unit')
# We need to set RAILS_ROOT if it isn't already set
RAILS_ROOT = '.' unless defined?(RAILS_ROOT)
class Test::Unit::TestCase
def plugin_fixture_root_path
File.join(File.dirname(__FILE__), 'fixtures', 'plugins')
end
private
def plugin_fixture_root_path
File.join(File.dirname(__FILE__), 'fixtures', 'plugins')
end
def only_load_the_following_plugins!(plugins)
@initializer.configuration.plugins = plugins
end
def only_load_the_following_plugins!(plugins)
@initializer.configuration.plugins = plugins
end
def plugin_fixture_path(path)
File.join(plugin_fixture_root_path, path)
end
def assert_plugins(list_of_names, array_of_plugins, message=nil)
assert_equal list_of_names.map(&:to_s), array_of_plugins.map(&:name), message
end
end
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册