Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 2904

Show
Ignore:
Timestamp:
11/07/05 08:09:38 (5 years ago)
Author:
bitsweat
Message:

New configuration option config.plugin_paths which may be a single path like the default 'vendor/plugins' or an array of paths: ['vendor/plugins', 'lib/plugins']. Plugins are discovered in nested paths, so you can organize your plugins directory as you like. Refactor load_plugin from load_plugins. Simplify initializer unit test. Closes #2757.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/railties/CHANGELOG

    r2903 r2904  
    11*SVN* 
     2 
     3* New configuration option config.plugin_paths which may be a single path like the default 'vendor/plugins' or an array of paths: ['vendor/plugins', 'lib/plugins'].  [Jeremy Kemper] 
     4 
     5* Plugins are discovered in nested paths, so you can organize your plugins directory as you like.  [Jeremy Kemper] 
     6 
     7* Refactor load_plugin from load_plugins.  #2757 [alex.r.moon@gmail.com] 
    28 
    39* Make use of silence_stderr in script/lighttpd, script/plugin, and Rails::Info [Sam Stephenson] 
  • trunk/railties/lib/initializer.rb

    r2884 r2904  
    11require 'logger' 
     2require 'set' 
    23 
    34RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV) 
     
    2324    # The Configuration instance used by this Initializer instance. 
    2425    attr_reader :configuration 
    25      
     26 
     27    # The set of loaded plugins. 
     28    attr_reader :loaded_plugins 
     29 
    2630    # Runs the initializer. By default, this will invoke the #process method, 
    2731    # which simply executes all of the initialization routines. Alternately, 
     
    4145    def initialize(configuration) 
    4246      @configuration = configuration 
    43     end 
    44      
     47      @loaded_plugins = Set.new 
     48    end 
     49 
    4550    # Sequentially step through all of the available initialization routines, 
    4651    # in order: 
     
    121126      require 'rails_info' 
    122127    end 
    123      
    124     # Loads all plugins in the <tt>vendor/plugins</tt> directory. Each 
    125     # subdirectory of <tt>vendor/plugins</tt> is inspected as follows: 
    126     # 
    127     # * if the directory has a +lib+ subdirectory, add it to the load path 
    128     # * if the directory contains an <tt>init.rb</tt> file, read it in and 
    129     #   eval it. 
     128 
     129    # Loads all plugins in <tt>config.plugin_paths</tt>.  <tt>plugin_paths</tt> 
     130    # defaults to <tt>vendor/plugins</tt> but may also be set to a list of 
     131    # paths, such as 
     132    #   config.plugin_paths = ['lib/plugins', 'vendor/plugins'] 
     133    # 
     134    # Each plugin discovered in <tt>plugin_paths</tt> is initialized: 
     135    # * add its +lib+ directory, if present, to the beginning of the load path 
     136    # * evaluate <tt>init.rb</tt> if present 
    130137    # 
    131138    # After all plugins are loaded, duplicates are removed from the load path. 
    132139    def load_plugins 
    133       config = configuration 
    134  
    135       Dir.glob("#{configuration.plugins_path}/*") do |directory| 
    136         next if File.basename(directory)[0] == ?. || !File.directory?(directory) 
    137  
    138         if File.directory?("#{directory}/lib") 
    139           $LOAD_PATH.unshift "#{directory}/lib" 
    140         end 
    141  
    142         if File.exist?("#{directory}/init.rb") 
    143           silence_warnings do 
    144             eval(IO.read("#{directory}/init.rb"), binding) 
    145           end 
    146         end 
    147       end 
    148  
     140      find_plugins(configuration.plugin_paths).each { |path| load_plugin path } 
    149141      $LOAD_PATH.uniq! 
    150142    end 
     
    261253      end 
    262254    end 
     255 
     256    protected 
     257      # Return a list of plugin paths within base_path.  A plugin path is 
     258      # a directory that contains either a lib directory or an init.rb file. 
     259      # This recurses into directories which are not plugin paths, so you 
     260      # may organize your plugins which the plugin path. 
     261      def find_plugins(*base_paths) 
     262        base_paths.flatten.inject([]) do |plugins, base_path| 
     263          Dir.glob(File.join(base_path, '*')).each do |path| 
     264            if plugin_path?(path) 
     265              plugins << path 
     266            elsif File.directory?(path) 
     267              plugins += find_plugins(path) 
     268            end 
     269          end 
     270          plugins 
     271        end 
     272      end 
     273 
     274      def plugin_path?(path) 
     275        File.directory?(path) and (File.directory?(File.join(path, 'lib')) or File.file?(File.join(path, 'init.rb'))) 
     276      end 
     277 
     278      # Load the plugin at <tt>path</tt> unless already loaded. 
     279      # 
     280      # Each plugin is initialized: 
     281      # * add its +lib+ directory, if present, to the beginning of the load path 
     282      # * evaluate <tt>init.rb</tt> if present 
     283      # 
     284      # Returns <tt>true</tt> if the plugin is successfully loaded or 
     285      # <tt>false</tt> if it is already loaded (similar to Kernel#require). 
     286      # Raises <tt>LoadError</tt> if the plugin is not found. 
     287      def load_plugin(path) 
     288        name = File.basename(path) 
     289        return false if loaded_plugins.include?(name) 
     290 
     291        # Catch nonexistent and empty plugins. 
     292        raise LoadError, "No such plugin: #{path}" unless plugin_path?(path) 
     293 
     294        lib_path  = File.join(path, 'lib') 
     295        init_path = File.join(path, 'init.rb') 
     296        has_lib   = File.directory?(lib_path) 
     297        has_init  = File.file?(init_path) 
     298 
     299        # Add lib to load path. 
     300        $LOAD_PATH.unshift(lib_path) if has_lib 
     301 
     302        # Evaluate init.rb. 
     303        silence_warnings { eval(IO.read(init_path), binding) } if has_init 
     304 
     305        # Add to set of loaded plugins. 
     306        loaded_plugins << name 
     307        true 
     308      end 
    263309  end 
    264    
     310 
    265311  # The Configuration class holds all the parameters for the Initializer and 
    266312  # ships with defaults that suites most Rails applications. But it's possible 
     
    340386    attr_accessor :whiny_nils 
    341387     
     388    # The path to the root of the plugins directory. By default, it is in 
     389    # <tt>vendor/plugins</tt>. 
     390    attr_accessor :plugin_paths 
     391 
    342392    # Create a new Configuration instance, initialized with the default 
    343393    # values. 
     
    352402      self.breakpoint_server            = default_breakpoint_server 
    353403      self.whiny_nils                   = default_whiny_nils 
     404      self.plugin_paths                 = default_plugin_paths 
    354405      self.database_configuration_file  = default_database_configuration_file 
    355        
     406 
    356407      for framework in default_frameworks 
    357408        self.send("#{framework}=", OrderedOptions.new) 
     
    369420    # default the file is at <tt>config/environments/#{environment}.rb</tt>. 
    370421    def environment_path 
    371       "#{RAILS_ROOT}/config/environments/#{environment}.rb" 
    372     end 
    373  
    374     # The path to the root of the plugins directory. By default, it is in 
    375     # <tt>vendor/plugins</tt>. 
    376     def plugins_path 
    377       "#{RAILS_ROOT}/vendor/plugins" 
    378     end 
    379      
     422      "#{root_path}/config/environments/#{environment}.rb" 
     423    end 
     424 
    380425    # Return the currently selected environment. By default, it returns the 
    381426    # value of the +RAILS_ENV+ constant. 
     
    385430 
    386431    private 
     432      def root_path 
     433        ::RAILS_ROOT 
     434      end 
     435 
    387436      def default_frameworks 
    388437        [ :active_record, :action_controller, :action_view, :action_mailer, :action_web_service ] 
     
    390439     
    391440      def default_load_paths 
    392         paths = ["#{RAILS_ROOT}/test/mocks/#{environment}"] 
     441        paths = ["#{root_path}/test/mocks/#{environment}"] 
    393442 
    394443        # Then model subdirectories. 
    395444        # TODO: Don't include .rb models as load paths 
    396         paths.concat(Dir["#{RAILS_ROOT}/app/models/[_a-z]*"]) 
    397         paths.concat(Dir["#{RAILS_ROOT}/components/[_a-z]*"]) 
     445        paths.concat(Dir["#{root_path}/app/models/[_a-z]*"]) 
     446        paths.concat(Dir["#{root_path}/components/[_a-z]*"]) 
    398447 
    399448        # Followed by the standard includes. 
     
    417466          vendor/rails/actionmailer/lib 
    418467          vendor/rails/actionwebservice/lib 
    419         ).map { |dir| "#{RAILS_ROOT}/#{dir}" }.select { |dir| File.directory?(dir) } 
     468        ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) } 
    420469      end 
    421470 
    422471      def default_log_path 
    423         File.join(RAILS_ROOT, 'log', "#{environment}.log") 
     472        File.join(root_path, 'log', "#{environment}.log") 
    424473      end 
    425474       
     
    429478       
    430479      def default_database_configuration_file 
    431         File.join(RAILS_ROOT, 'config', 'database.yml') 
     480        File.join(root_path, 'config', 'database.yml') 
    432481      end 
    433482       
    434483      def default_view_path 
    435         File.join(RAILS_ROOT, 'app', 'views') 
     484        File.join(root_path, 'app', 'views') 
    436485      end 
    437486       
    438487      def default_controller_paths 
    439         [ File.join(RAILS_ROOT, 'app', 'controllers'), File.join(RAILS_ROOT, 'components') ] 
     488        [ File.join(root_path, 'app', 'controllers'), File.join(root_path, 'components') ] 
    440489      end 
    441490       
     
    454503      def default_whiny_nils 
    455504        false 
     505      end 
     506 
     507      def default_plugin_paths 
     508        ["#{root_path}/vendor/plugins"] 
    456509      end 
    457510  end 
  • trunk/railties/test/fixtures/environment_with_constant.rb

    r2711 r2904  
    1 SET_FROM_ENV = "success" 
     1$initialize_test_set_from_env = "success" 
  • trunk/railties/test/initializer_test.rb

    r2711 r2904  
    1616      @envpath 
    1717    end 
     18 
     19    protected 
     20      def root_path 
     21        File.dirname(__FILE__) 
     22      end 
    1823  end 
    1924 
    20   def setup 
    21     Object.const_set(:RAILS_ROOT, "") rescue nil 
    22   end 
    23    
    24   def teardown 
    25     Object.remove_const(:RAILS_ROOT) rescue nil 
    26   end 
    27    
    2825  def test_load_environment_with_constant 
    2926    config = ConfigurationMock.new("#{File.dirname(__FILE__)}/fixtures/environment_with_constant.rb") 
     27    assert_nil $initialize_test_set_from_env 
    3028    Rails::Initializer.run(:load_environment, config) 
    31     assert Object.const_defined?(:SET_FROM_ENV) 
    32     assert_equal "success", SET_FROM_ENV 
     29    assert_equal "success", $initialize_test_set_from_env 
    3330  ensure 
    34     Object.remove_const(:SET_FROM_ENV) rescue nil 
     31    $initialize_test_set_from_env = nil 
    3532  end 
    3633end