aboutsummaryrefslogblamecommitdiffstats
path: root/railties/lib/rails/plugin/loader.rb
blob: 016bcc6c506223ca90224013ee6842008b5aef3e (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15














                                                 
                                                      

















                                                                            
      
                  

                                                      




                                                                 
                     



                                                                                




                                                                           


             







                                                                                                     



                                                                                       



                                          
                                               
                                                    
           
        









































                                                                                   
                                                                                             


                                    
                                           
                                                                                                                                   


                                                              
                                                                               
                                                         









                                                                                                                         
              
                                                       
             


           
  
module Rails
  module Plugin
    class Loader
      include Comparable
      attr_reader :initializer, :directory, :name
  
      class << self
        def load(*args)
          new(*args).load
        end
      end
  
      def initialize(initializer, directory)
        @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
      end
  
      def loaded?
        initializer.loaded_plugins.include?(name)
      end
  
      def plugin_path?
        File.directory?(directory) && (has_lib_directory? || has_init_file?)
      end
      
      def enabled?
        !explicit_plugin_loading_order? || registered?
      end
      
      def explicitly_enabled?
        !explicit_plugin_loading_order? || explicitly_registered?
      end
      
      def registered?
        explicit_plugin_loading_order? && registered_plugins_names_plugin?(name)
      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
        end
        
        def registered_plugins_names_plugin?(plugin_name)
          registered_plugins.include?(plugin_name) || registered_plugins.include?(:all)
        end
        
        def explicit_plugin_loading_order?
          !registered_plugins.nil?
        end
        
        def report_nonexistant_or_empty_plugin!
          plugin_does_not_exist! unless plugin_path?
        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 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
        end
      
        def application_library_path
          File.join(RAILS_ROOT, 'lib')
        end
  
        # Allow plugins to reference the current configuration object
        def config
          initializer.configuration
        end
  
        def register_plugin_as_loaded
          initializer.loaded_plugins << name
        end
  
        # Evaluate in init.rb
        def evaluate
          silence_warnings { eval(IO.read(init_path), binding, init_path) } if has_init_file?
        end
      
        def <=>(other_plugin_loader)
          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)
            end
            
          else
            name.to_s <=> other_plugin_loader.name.to_s
          end
        end
    end
  end
end