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 config.plugins) # * +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 lib directory as its load_paths, # and evaluates init.rb when load is called. # # You can also inspect the about.yml data programmatically: # # plugin = Rails::Plugin.new(path_to_my_plugin) # plugin.about["author"] # => "James Adam" # plugin.about["url"] # => "http://interblah.net" 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) return if loaded? 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 def about @about ||= load_about_information end private def load_about_information about_yml_path = File.join(@directory, "about.yml") parsed_yml = File.exist?(about_yml_path) ? YAML.load(File.read(about_yml_path)) : {} parsed_yml || {} rescue Exception {} end 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 # This Plugin subclass represents a Gem plugin. It behaves exactly like a # "traditional" Rails plugin, but doesn't expose any additional load paths, # since RubyGems has already taken care of things. class GemPlugin < Plugin # Initialize this plugin from a Gem::Specification. def initialize(spec) super(File.join(spec.full_gem_path, "rails")) @name = spec.name end def valid? true end def load_paths [] end end end