Permalink
Browse files

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

…ests. Closes #9795 [lazyatom]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8115 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent c443a61 commit f1b1af88b530c101dc4bf6157bbd1f9c39a670d7 @technoweenie technoweenie committed Nov 8, 2007
View
@@ -1,5 +1,7 @@
*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
@@ -0,0 +1,83 @@
+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
Oops, something went wrong.

0 comments on commit f1b1af8

Please sign in to comment.