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

Ticket #8511: gems_loaded_from_vendor_like_plugins.diff

File gems_loaded_from_vendor_like_plugins.diff, 29.9 kB (added by marcel, 1 year ago)
  • test/plugin_locator_test.rb

    old new  
    11require File.dirname(__FILE__) + '/plugin_test_helper' 
     2require 'fileutils' 
     3require 'rubygems/builder' 
    24 
    35class TestPluginFileSystemLocator < Test::Unit::TestCase 
    46  def setup 
     
    911    @initializer = Rails::Initializer.new(configuration) 
    1012    @locator     = new_locator 
    1113  end 
    12    
     14 
    1315  def test_no_plugins_are_loaded_if_the_configuration_has_an_empty_plugin_list 
    1416    only_load_the_following_plugins! [] 
    1517    assert_equal [], @locator.plugins 
     
    3739  private 
    3840    def new_locator(initializer = @initializer) 
    3941      Rails::Plugin::FileSystemLocator.new(initializer) 
    40     end    
     42    end   
     43     
     44end 
     45 
     46class TestPluginGemLocator < Test::Unit::TestCase 
     47  def setup 
     48    configuration = Rails::Configuration.new 
     49    configuration.gem_home = gem_home_root_path 
     50    @initializer  = Rails::Initializer.new(configuration) 
     51    @locator      = new_gem_locator 
     52  end 
     53   
     54  def teardown 
     55    purge_gems 
     56  end 
     57 
     58  def test_gem_paths_are_set_to_the_appropriate_gem_home_for_the_app 
     59    application_gem_home_registered_with_rubygems = lambda do 
     60      !Gem.path.grep(/#{@initializer.configuration.gem_home}/).empty? 
     61    end 
     62    @locator.send(:setup_gem_environment) 
     63    assert application_gem_home_registered_with_rubygems.call 
     64  end 
     65 
     66  def test_gems_are_not_installed_unecessarily_if_they_are_already_installed 
     67    gem_home_ctime = lambda { File.ctime(@initializer.configuration.gem_home) } 
     68    using_scenario 'gem_with_dep_that_has_its_own_deps' do 
     69      gem_home_ctime_before_installing = gem_home_ctime.call 
     70      # Resolution of ctime on OS X is in seconds so we have to sleep to verify 
     71      sleep 1 
     72      @locator.send(:prepare_gems) 
     73      after_installing = gem_home_ctime.call 
     74      # Gems were unpacked 
     75      assert_not_equal gem_home_ctime_before_installing, after_installing 
     76      new_gem_locator.send(:prepare_gems) 
     77      # No need to unpack any gems 
     78      assert_equal after_installing, gem_home_ctime.call 
     79    end 
     80  end 
     81 
     82  def test_that_all_gems_in_the_bundled_gem_directory_are_installed_prior_to_loading 
     83    bundled_gems_are_installed = lambda do 
     84      !@locator.installer.installed_gems.empty? 
     85    end 
     86 
     87    using_scenario 'gem_with_no_deps' do 
     88      assert !bundled_gems_are_installed.call 
     89      @locator.send(:prepare_gems) 
     90      assert bundled_gems_are_installed.call 
     91    end 
     92  end 
     93   
     94  %w[gem_with_one_level_of_deps gem_with_dep_that_has_its_own_deps].each do |scenario| 
     95    define_method("test_unpacking_order_for_the_#{scenario}_scenario") do 
     96      using_scenario scenario do 
     97        @locator.send(:setup_gem_environment) 
     98        assert_equal expected_gem_loading_order, @locator.installer.send(:gems_to_install).map(&:full_name) 
     99      end 
     100    end 
     101  end 
     102   
     103  %w[gem_with_no_deps gem_with_one_level_of_deps gem_with_dep_that_has_its_own_deps].each do |scenario| 
     104    define_method("test_the_appropriate_gem_plugins_are_located_for_the_#{scenario}_scenario") do 
     105      using_scenario scenario do 
     106        assert_equal expected_gem_loading_order, @locator.plugin_names 
     107      end 
     108    end 
     109  end 
     110   
     111  def test_declaring_an_explicit_plugin_load_order_that_contradicts_the_gem_dependency_loading_order_raises_a_load_error 
     112    using_scenario 'gem_with_dep_that_has_its_own_deps' do 
     113      only_load_the_following_plugins! expected_gem_loading_order.reverse 
     114      assert_raises(LoadError) do 
     115        @initializer.load_plugins 
     116      end 
     117    end 
     118  end 
     119   
     120  def test_declaring_an_explicit_plugin_load_order_that_jives_with_the_gem_depency_loading_order_works 
     121    using_scenario 'gem_with_dep_that_has_its_own_deps' do 
     122      only_load_the_following_plugins! expected_gem_loading_order 
     123      assert_nothing_raised do 
     124        @initializer.load_plugins 
     125      end 
     126    end 
     127  end 
     128   
     129  def test_trying_to_load_a_gem_with_a_missing_depedency_raises_an_install_error 
     130    using_scenario 'gem_with_a_missing_dep' do 
     131      assert_raises(Gem::InstallError) do 
     132        @locator.send(:prepare_gems) 
     133      end 
     134    end 
     135  end 
     136   
     137  def test_trying_load_a_gem_whose_dependency_constraint_can_not_be_satisfied_raises 
     138    using_scenario 'gem_with_version_constraint_on_dep_that_can_not_be_satisfied' do 
     139      assert_raises(Gem::InstallError) do 
     140        @locator.send(:prepare_gems) 
     141      end 
     142    end 
     143  end 
     144 
     145  private 
     146    def new_gem_locator(initializer = @initializer) 
     147      Rails::Plugin::GemLocator.new(initializer) 
     148    end 
     149     
     150    def using_scenario(scenario) 
     151      set_bundled_gem_path! scenario 
     152      generate_gems 
     153      yield 
     154    ensure 
     155      purge_gems 
     156    end 
     157     
     158    def set_bundled_gem_path!(bundled_gem_path) 
     159      @initializer.configuration.bundled_gem_path = File.join(plugin_gem_fixture_root_path, bundled_gem_path) 
     160    end 
     161     
     162    def expected_gem_loading_order 
     163      @expected_gem_loading_order ||= YAML.load_file(File.join(bundled_gem_path, 'dependency_loading_order.yml')) 
     164    end 
     165     
     166    def bundled_gem_path 
     167      @initializer.configuration.bundled_gem_path 
     168    end 
     169     
     170    def generate_gems 
     171      Dir["#{bundled_gem_path}/**/*.gemspec"].each do |spec_file| 
     172        # Initialize outside the block so it is in scope 
     173        gem_path, specification = nil 
     174        execute_from_within(File.dirname(spec_file)) do  
     175          specification = Gem::Specification.load(File.basename(spec_file)) 
     176          # Usually the Gem::Builder prints out its progress. We want to silent that. 
     177          Gem::DefaultUserInteraction.use_ui(Gem::SilentUI.new) do 
     178            Gem::Builder.new(specification).build 
     179          end 
     180        end 
     181        FileUtils.mv File.join(File.dirname(spec_file), "#{specification.full_name}.gem"), bundled_gem_path 
     182      end 
     183    end 
     184     
     185    # This is a hack. Gem::Specification.load eval's the passed in spec file. Usually, 
     186    # when this is done with the gem command, it is executed from the same directory as  
     187    # where the gemspec is located. If this is not the case though, the eval is done relative to 
     188    # the calling code's directory. To work around this, while loading the gem spec, we move to  
     189    # the gemspec's directory. 
     190    def execute_from_within(path) 
     191      originating_path = Dir.pwd 
     192      Dir.chdir path 
     193      yield 
     194    ensure 
     195      Dir.chdir originating_path 
     196    end 
     197     
     198    def purge_gems 
     199      FileUtils.rm_rf(generated_gems) 
     200      FileUtils.rm_rf(installed_gems) 
     201    end 
     202     
     203    def generated_gems 
     204      Dir["#{bundled_gem_path}/*.gem"] 
     205    end 
     206     
     207    def installed_gems 
     208      Dir["#{gem_home_root_path}/*"] 
     209    end       
     210     
     211    def gem_home_root_path 
     212      File.join(fixture_path, 'tmp', 'gem_home') 
     213    end 
     214     
     215    def plugin_gem_fixture_root_path 
     216      File.join(fixture_path, 'gems') 
     217    end 
    41218end 
  • test/fixtures/gems/gem_with_version_constraint_on_dep_that_can_not_be_satisfied/dependency_one/dependency_one.gemspec

    old new  
     1Gem::Specification.new do |s| 
     2  s.name     = 'dependency_one' 
     3  s.version  = '1.0.0' 
     4  s.summary  = 'This gem is a terminal dependency on top_level_gem but its version is too low' 
     5  s.files    = Dir['*.rb'] + Dir['lib/*'] 
     6end 
  • test/fixtures/gems/gem_with_version_constraint_on_dep_that_can_not_be_satisfied/dependency_one/init.rb

    old new  
  • test/fixtures/gems/gem_with_version_constraint_on_dep_that_can_not_be_satisfied/top_level_gem_with_unsatisfiable_dependency/init.rb

    old new  
  • test/fixtures/gems/gem_with_version_constraint_on_dep_that_can_not_be_satisfied/top_level_gem_with_unsatisfiable_dependency/top_level_gem_with_unsatisfiable_dependency.gemspec

    old new  
     1Gem::Specification.new do |s| 
     2  s.name     = 'top_level_gem_with_unsatisfiable_dependency' 
     3  s.version  = '1.0.0' 
     4  s.summary  = 'This gem has a dependency on dependency_one' 
     5  s.files    = Dir['*.rb'] + Dir['lib/*'] 
     6  s.add_dependency 'dependency_one', '> 3.0.0' 
     7end 
  • test/fixtures/gems/gem_with_version_constraint_on_dep_that_can_not_be_satisfied/dependency_loading_order.yml

    old new  
     1- dependency_one-1.0.0 
     2- top_level_gem_with_unsatisfiable_dependency-1.0.0 
  • test/fixtures/gems/gem_with_dep_that_has_its_own_deps/dependency_loading_order.yml

    old new  
     1- second_generation_dep-1.0.0 
     2- first_generation_dep-1.0.0 
     3- top_level_gem_with_nested_deps-1.0.0 
  • test/fixtures/gems/gem_with_dep_that_has_its_own_deps/top_level_gem_with_nested_deps/init.rb

    old new  
  • test/fixtures/gems/gem_with_dep_that_has_its_own_deps/top_level_gem_with_nested_deps/top_level_gem_with_nested_deps.gemspec

    old new  
     1Gem::Specification.new do |s| 
     2  s.name     = 'top_level_gem_with_nested_deps' 
     3  s.version  = '1.0.0' 
     4  s.summary  = 'This gem has a depency on first_generation_dep which has its own dependency' 
     5  s.files    = Dir['*.rb'] + Dir['lib/*'] 
     6  s.add_dependency 'first_generation_dep' 
     7end 
  • test/fixtures/gems/gem_with_dep_that_has_its_own_deps/first_generation_dep/init.rb

    old new  
  • test/fixtures/gems/gem_with_dep_that_has_its_own_deps/first_generation_dep/first_generation_dep.gemspec

    old new  
     1Gem::Specification.new do |s| 
     2  s.name     = 'first_generation_dep' 
     3  s.version  = '1.0.0' 
     4  s.summary  = 'This gem is an intermediary dependency' 
     5  s.files    = Dir['*.rb'] + Dir['lib/*'] 
     6  s.add_dependency 'second_generation_dep' 
     7end 
  • test/fixtures/gems/gem_with_dep_that_has_its_own_deps/second_generation_dep/second_generation_dep.gemspec

    old new  
     1Gem::Specification.new do |s| 
     2  s.name     = 'second_generation_dep' 
     3  s.version  = '1.0.0' 
     4  s.summary  = 'This is the terminal dependency in multiple levels of dependencies' 
     5  s.files    = Dir['*.rb'] + Dir['lib/*'] 
     6end 
  • test/fixtures/gems/gem_with_dep_that_has_its_own_deps/second_generation_dep/init.rb

    old new  
  • test/fixtures/gems/gem_with_a_missing_dep/dependency_loading_order.yml

    old new  
     1- dependency_one-1.0.0 
     2- top_level_gem_with_missing_dep-1.0.0 
  • test/fixtures/gems/gem_with_a_missing_dep/top_level_gem_with_missing_dep/top_level_gem_with_missing_dep.gemspec

    old new  
     1Gem::Specification.new do |s| 
     2  s.name     = 'top_level_gem_with_missing_dep' 
     3  s.version  = '1.0.0' 
     4  s.summary  = 'This gem has a dependency on dependency_one but dependency_one is missing' 
     5  s.files    = Dir['*.rb'] + Dir['lib/*'] 
     6  s.add_dependency 'dependency_one' 
     7end 
  • test/fixtures/gems/gem_with_a_missing_dep/top_level_gem_with_missing_dep/init.rb

    old new  
  • test/fixtures/gems/gem_with_no_deps/top_level_gem_with_no_deps/init.rb

    old new  
  • test/fixtures/gems/gem_with_no_deps/top_level_gem_with_no_deps/top_level_gem_with_no_deps.gemspec

    old new  
     1Gem::Specification.new do |s| 
     2  s.name     = 'top_level_gem_with_no_deps' 
     3  s.version  = '1.0.0' 
     4  s.summary  = 'This gem has no depencies' 
     5  s.files    = Dir['*.rb'] + Dir['lib/*'] 
     6end 
  • test/fixtures/gems/gem_with_no_deps/dependency_loading_order.yml

    old new  
  • test/fixtures/gems/gem_with_one_level_of_deps/dependency_one/dependency_one.gemspec

    old new  
     1Gem::Specification.new do |s| 
     2  s.name     = 'dependency_one' 
     3  s.version  = '1.0.0' 
     4  s.summary  = 'This gem is a terminal dependency on top_level_gem' 
     5  s.files    = Dir['*.rb'] + Dir['lib/*'] 
     6end 
  • test/fixtures/gems/gem_with_one_level_of_deps/dependency_one/init.rb

    old new  
  • test/fixtures/gems/gem_with_one_level_of_deps/top_level_gem/top_level_gem.gemspec

    old new  
     1Gem::Specification.new do |s| 
     2  s.name     = 'top_level_gem' 
     3  s.version  = '1.0.0' 
     4  s.summary  = 'This gem has a dependency on dependency_one' 
     5  s.files    = Dir['*.rb'] + Dir['lib/*'] 
     6  s.add_dependency 'dependency_one' 
     7end 
  • test/fixtures/gems/gem_with_one_level_of_deps/top_level_gem/init.rb

    old new  
  • test/fixtures/gems/gem_with_one_level_of_deps/dependency_loading_order.yml

    old new  
     1- dependency_one-1.0.0 
     2- top_level_gem-1.0.0 
  • test/plugin_test_helper.rb

    old new  
    99RAILS_ROOT = '.' unless defined?(RAILS_ROOT) 
    1010class Test::Unit::TestCase 
    1111  def plugin_fixture_root_path 
    12     File.join(File.dirname(__FILE__), 'fixtures', 'plugins') 
     12    File.join(fixture_path, 'plugins') 
    1313  end 
    1414   
     15  def fixture_path 
     16    File.join(File.dirname(__FILE__), 'fixtures') 
     17  end 
     18   
    1519  def only_load_the_following_plugins!(plugins) 
    1620    @initializer.configuration.plugins = plugins 
    1721  end 
  • lib/rails_generator/generators/applications/app/app_generator.rb

    old new  
    155155    test/unit 
    156156    vendor 
    157157    vendor/plugins 
     158    vendor/gems 
     159    vendor/gems/home 
    158160    tmp/sessions 
    159161    tmp/sockets 
    160162    tmp/cache 
  • lib/initializer.rb

    old new  
    11require 'logger' 
    22require 'set' 
     3require 'fileutils' 
    34require 'pathname' 
    45 
    56$LOAD_PATH.unshift File.dirname(__FILE__) 
     
    346347        unless configuration.plugins.nil? 
    347348          unless loaded_plugins == configuration.plugins 
    348349            missing_plugins = configuration.plugins - loaded_plugins 
    349             raise LoadError, "Could not locate the following plugins: #{missing_plugins.to_sentence}" 
     350            message = if missing_plugins.any? 
     351              "Could not locate the following plugins: #{missing_plugins.to_sentence}" 
     352            else 
     353              "It seems as though you have specified an explicit plugin loading order "    + 
     354              "that contradicts the dependency loading order of a gem plugin. "            + 
     355              "Try comparing your explicit loading order with the dependency loading "     + 
     356              "order of the gem plugins you have installed in #{configuration.gem_home}. " + 
     357              "You probably should just remove the explicit plugin loading. "    
     358            end 
     359            raise LoadError, message 
    350360          end 
    351361        end 
    352362      end 
     
    442452    # <tt>vendor/plugins</tt>. 
    443453    attr_accessor :plugin_paths 
    444454 
     455    # The path to the root of the bundled gems directory. By default, it is in 
     456    # <tt>vendor/gems</tt>. 
     457    attr_accessor :bundled_gem_path 
     458 
     459    # The path into which Rails will on-the-fly install gems from its  
     460    # bundled_gem_path on startup.  By default, it is in <tt>vendor/gems/home</tt> 
     461    attr_accessor :gem_home 
     462         
    445463    # The classes that handle finding the desired plugins that you'd like to load for 
    446464    # your application. By default it is the Rails::Plugin::FileSystemLocator which finds 
    447465    # plugins to load in <tt>vendor/plugins</tt>. You can hook into gem location by subclassing 
     
    479497      self.whiny_nils                   = default_whiny_nils 
    480498      self.plugins                      = default_plugins 
    481499      self.plugin_paths                 = default_plugin_paths 
     500      self.bundled_gem_path             = default_bundled_gem_path       
     501      self.gem_home                     = default_gem_home       
    482502      self.plugin_locators              = default_plugin_locators 
    483503      self.plugin_loader                = default_plugin_loader 
    484504      self.database_configuration_file  = default_database_configuration_file 
     
    647667        ["#{root_path}/vendor/plugins"] 
    648668      end 
    649669 
     670      def default_bundled_gem_path 
     671        "#{root_path}/vendor/gems/" 
     672      end 
     673       
     674      def default_gem_home 
     675        "#{root_path}/vendor/gems/home" 
     676      end 
     677       
    650678      def default_plugin_locators 
    651         [Plugin::FileSystemLocator] 
     679        [Plugin::GemLocator, Plugin::FileSystemLocator] 
    652680      end 
    653681 
    654682      def default_plugin_loader 
  • lib/rails/plugin/locator.rb

    old new  
    2727    end 
    2828     
    2929    class FileSystemLocator < Locator 
    30         private 
    31           def located_plugins 
    32             initializer.configuration.plugin_paths.flatten.inject([]) do |plugins, path| 
     30      private 
     31        def located_plugins 
     32          initializer.configuration.plugin_paths.flatten.inject([]) do |plugins, path| 
     33            plugins.concat locate_plugins_under(path) 
     34            plugins 
     35          end.flatten 
     36        end 
     37 
     38        # This starts at the base path looking for directories that pass the plugin_path? test of the Plugin::Loader. 
     39        # Since plugins can be nested arbitrarily deep within an unspecified number of intermediary directories,  
     40        # this method runs recursively until it finds a plugin directory. 
     41        # 
     42        #   e.g. 
     43        # 
     44        #     locate_plugins_under('vendor/plugins/acts/acts_as_chunky_bacon') 
     45        #     => 'acts_as_chunky_bacon'  
     46        def locate_plugins_under(base_path) 
     47           Dir.glob(File.join(base_path, '*')).inject([]) do |plugins, path| 
     48            plugin_loader = initializer.configuration.plugin_loader.new(initializer, path) 
     49            if plugin_loader.loadable? 
     50              plugins << plugin_loader 
     51            elsif File.directory?(path) 
    3352              plugins.concat locate_plugins_under(path) 
    34               plugins 
    35             end.flatten 
     53            end 
     54            plugins 
    3655          end 
     56        end 
     57    end 
     58     
     59    class GemLocator < Locator 
     60      require 'rubygems/dependency_list' 
     61      require 'rubygems/format' 
     62      require 'rubygems/installer' 
     63       
     64      attr_reader :installer 
     65       
     66      def initialize(*args) 
     67        super 
     68        @installer = Installer.new(self) 
     69      end 
     70       
     71      def plugins 
     72        # Unlike the parent class, we don't want to sort the loaders,  
     73        # as RubyGems takes care of sorting them in depency order already. 
     74        located_plugins.select(&:enabled?) 
     75      end 
     76           
     77      def spec_to_path_mapping 
     78        @spec_to_path_mapping ||= Dir[File.join(initializer.configuration.bundled_gem_path, "*.gem")].inject({}) do |mapping, gem_path| 
     79          mapping[specification_for(gem_path)] = gem_path 
     80          mapping 
     81        end 
     82      end 
     83       
     84      def specification_for(gem_path) 
     85        Gem::Format.from_file_by_path(gem_path).spec 
     86      end 
     87       
     88      def bundled_gems 
     89        spec_to_path_mapping.values 
     90      end 
    3791 
    38           # This starts at the base path looking for directories that pass the plugin_path? test of the Plugin::Loader. 
    39           # Since plugins can be nested arbitrarily deep within an unspecified number of intermediary directories,  
    40           # this method runs recursively until it finds a plugin directory. 
    41           # 
    42           #   e.g. 
    43           # 
    44           #     locate_plugins_under('vendor/plugins/acts/acts_as_chunky_bacon') 
    45           #     => 'acts_as_chunky_bacon'  
    46           def locate_plugins_under(base_path) 
    47              Dir.glob(File.join(base_path, '*')).inject([]) do |plugins, path| 
    48               plugin_loader = initializer.configuration.plugin_loader.new(initializer, path) 
    49               if plugin_loader.plugin_path? && plugin_loader.enabled? 
    50                 plugins << plugin_loader 
    51               elsif File.directory?(path) 
    52                 plugins.concat locate_plugins_under(path) 
     92      def path_for(spec) 
     93        spec_to_path_mapping[spec] 
     94      end 
     95 
     96      def plugin_path_for(spec) 
     97        File.join(initializer.configuration.gem_home, 'gems', spec.full_name) 
     98      end 
     99       
     100      private         
     101        def located_plugins 
     102          prepare_gems 
     103 
     104          installer.installed_gems.inject([]) do |plugins, gem_plugin_directory| 
     105            plugin_loader = initializer.configuration.plugin_loader.new(initializer, gem_plugin_directory) 
     106            plugins << plugin_loader if plugin_loader.loadable? 
     107            plugins 
     108          end 
     109        end 
     110         
     111        def prepare_gems 
     112          setup_gem_environment 
     113          install_gems 
     114        end 
     115       
     116        # Sets a local GEM_HOME for this Rails application.  Installs all gems from vendor/gems  
     117        # (or configured bundled_gem_path) into this 
     118        # directory and makes them available to be loaded as plugins. 
     119        def setup_gem_environment 
     120          Gem.manage_gems 
     121          # N.B. the gem_home must be an absolute path or else the Gem::Installer will fail 
     122          Gem.use_paths(File.expand_path(initializer.configuration.gem_home), [Gem.dir]) 
     123        end 
     124         
     125        def install_gems 
     126          installer.install 
     127        end 
     128         
     129        class Installer           
     130          attr_reader :locator, :installed_gems, :source_index 
     131           
     132          def initialize(locator) 
     133            @locator        = locator 
     134            @source_index   = Gem::SourceIndex.from_gems_in(File.join(locator.initializer.configuration.gem_home, 'specifications')) 
     135            @installed_gems = [] 
     136          end 
     137           
     138          def install 
     139            gems_to_install.each do |spec| 
     140              gem_path = locator.path_for(spec) 
     141              Gem::Installer.new(gem_path).install unless installed?(spec) 
     142              @installed_gems << locator.plugin_path_for(spec) 
     143            end 
     144            uninstall_unused_gems! 
     145          end 
     146           
     147          private 
     148            def gems_to_install 
     149              @gems_to_install ||= locator.bundled_gems.inject(Gem::DependencyList.new) do |dependency_list, gem_path| 
     150                dependency_list.add locator.specification_for(gem_path) 
     151                dependency_list 
     152              end.dependency_order.reverse 
     153            end 
     154             
     155            def installed?(spec) 
     156              !source_index.find_name(spec.name, spec.version).empty? 
     157            end 
     158             
     159            def uninstall_unused_gems! 
     160              unused_gems.each do |spec| 
     161                Gem::DefaultUserInteraction.use_ui(Gem::SilentUI.new) do 
     162                  Gem::Uninstaller.new(spec.name, :version => "= #{spec.version}").uninstall 
     163                end 
    53164              end 
    54               plugins 
    55165            end 
    56           end 
     166             
     167            def unused_gems 
     168              previously_installed_gems - gems_to_install 
     169            end 
     170             
     171            def previously_installed_gems 
     172              source_index.latest_specs.values 
     173            end 
     174        end 
    57175    end 
    58176  end 
    59177end 
  • lib/rails/plugin/loader.rb

    old new  
    2828      def loaded? 
    2929        initializer.loaded_plugins.include?(name) 
    3030      end 
     31       
     32      def loadable? 
     33        plugin_path? && enabled? 
     34      end 
    3135   
    3236      def plugin_path? 
    3337        File.directory?(directory) && (has_lib_directory? || has_init_file?)