module TrustyCms class ExtensionPath # This class holds information about extensions that may be loaded. It has two roles: to remember the # location of the extension so that we don't have to search for it again, and to look within that path # for significant application subdirectories. # # We can't just retrieve this information from the Extension class because the initializer sets up # most of the application load_paths before plugins (including extensions) are loaded. You can think # of this as a sort of pre-extension class preparing the way for extension loading. # # You can use instances of this class to retrieve information about a particular extension: # # ExtensionPath.new(:name, :path) # ExtensionPath.find(:name) #=> ExtensionPath instance # ExtensionPath.find(:name).plugin_paths #=> "path/vendor/plugins" if it exists and is a directory # ExtensionPath.for(:name) #=> "path" # # The initializer calls class methods to get overall lists (in configured order) of enabled load paths: # # ExtensionPath.enabled #=> ["path", "path", "path", "path"] # ExtensionPath.plugin_paths #=> ["path/vendor/plugins", "path/vendor/plugins"] attr_accessor :name, :path @@known_paths = {} def initialize(options = {}) #:nodoc @name, @path = options[:name].underscore, options[:path] @@known_paths[@name.to_sym] = self end def required File.join(path, "#{name}_extension") end def to_s path end # Builds a new ExtensionPath object from the supplied path, working out the name of the extension by # stripping the extra bits from trusty-something-extension-1.0.0 to leave just 'something'. The object # is returned, and also remembered here for later use by the initializer (to find load paths) and the # ExtensionLoader, to load and activate the extension. # # If two arguments are given, the second is taken to be the full extension name. # def self.from_path(path, name=nil) name = path if name.blank? name = File.basename(name).gsub(/^trusty-|-extension(-[\d\.a-z]+|-[a-z\d]+)*$/, '') new(:name => name, :path => path) end # Forgets all recorded extension paths. # Currently only used in testing. # def self.clear_paths! @@known_paths = {} end # Returns a list of all the likely load paths found within this extension root. It includes all of these # that exist and are directories: # # * path # * path/lib # * path/app/models # * path/app/controllers # * path/app/metal # * path/app/helpers # * path/test/helpers # # You can call the class method ExtensionPath.load_paths to get a flattened list of all the load paths in all the enabled extensions. # def load_paths %w(lib app/models app/controllers app/metal app/helpers test/helpers).collect { |d| check_subdirectory(d) }.push(path).flatten.compact end # Returns a list of all the +vendor/plugin+ paths found within this extension root. # Call the class method ExtensionPath.plugin_paths to get a list of the plugin paths found in all enabled extensions. # def plugin_paths check_subdirectory("vendor/plugins") end # Returns a list of names of all the locale files found within this extension root. # Call the class method ExtensionPath.locale_paths to get a list of the locale files found in all enabled extensions # in reverse order so that locale definitions override one another correctly. # def locale_paths if check_subdirectory("config/locales") Dir[File.join("#{path}","config/locales","*.{rb,yml}")] end end # Returns the app/helpers path if it is found within this extension root. # Call the class method ExtensionPath.helper_paths to get a list of the helper paths found in all enabled extensions. # def helper_paths check_subdirectory("app/helpers") end # Returns the app/models path if it is found within this extension root. # Call the class method ExtensionPath.model_paths to get a list of the model paths found in all enabled extensions. # def model_paths check_subdirectory("app/models") end # Returns the app/controllers path if it is found within this extension root. # Call the class method ExtensionPath.controller_paths to get a list of the controller paths found in all enabled extensions. # def controller_paths check_subdirectory("app/controllers") end # Returns the app/views path if it is found within this extension root. # Call the class method ExtensionPath.view_paths to get a list of the view paths found in all enabled extensions # in reverse order so that views override one another correctly. # def view_paths check_subdirectory("app/views") end # Returns the app/metal path if it is found within this extension root. # Call the class method ExtensionPath.metal_paths to get a list of the metal paths found in all enabled extensions. # def metal_paths check_subdirectory("app/metal") end # Returns a list of all the rake task files found within this extension root. # def rake_task_paths if check_subdirectory("lib/tasks") Dir[File.join("#{path}","lib/tasks/**","*.rake")] end end # Returns a list of extension subdirectories that should be marked for eager loading. At the moment that # includes all the controller, model and helper paths. The main purpose here is to ensure that extension # controllers are loaded before running cucumber features, and there may be a better way to achieve that. # # Call the class method ExtensionPath.eager_load_paths to get a list for all enabled extensions. # def eager_load_paths [controller_paths, model_paths, helper_paths].flatten.compact end class << self # Returns the ExtensionPath object for the given extension name. # def find(name) raise LoadError, "Cannot return path for unknown extension: #{name}" unless @@known_paths[name.to_sym] @@known_paths[name.to_sym] end # Returns the root path recorded for the given extension name. # def for(name) find(name).path end # Returns a list of path objects for all the enabled extensions in the configured order. # If a configured extension has not been found during initialization, a LoadError will be thrown here. # # Note that at this stage, in line with the usage of config.extensions = [], the extension names # are being passed around as symbols. # def enabled enabled_extensions = TrustyCms::Application.config.enabled_extensions @@known_paths.values_at(*enabled_extensions).compact end # Returns a list of the root paths to all the enabled extensions, in the configured order. # def enabled_paths enabled.map(&:path) end [:load_paths, :plugin_paths, :helper_paths, :model_paths, :controller_paths, :eager_load_paths].each do |m| define_method(m) do enabled.map{|ep| ep.send(m)}.flatten.compact end end [:locale_paths, :view_paths, :metal_paths, :rake_task_paths].each do |m| define_method(m) do enabled.map{|ep| ep.send(m)}.flatten.compact.reverse end end end private # If the supplied path within the extension root exists and is a directory, its absolute path is returned. Otherwise, nil. # def check_subdirectory(subpath) subdirectory = File.join(path, subpath) subdirectory if File.directory?(subdirectory) end end end