aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib/plugin/locator.rb
blob: 326a2a74f5f324285c98a63601b83b506f1c842b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
module Rails
  module Plugin
    class Locator
      include Enumerable
      attr_reader :initializer
      
      def initialize(initializer)
        @initializer = initializer
      end
      
      def plugins
        located_plugins.select(&:enabled?).sort
      end
      
      def each(&block)
        plugins.each(&block)
      end
      
      def plugin_names
        plugins.map(&:name)
      end
      
      private
        def located_plugins
          raise "The `located_plugins' method must be defined by concrete subclasses of #{self.class}"
        end
    end
    
    class FileSystemLocator < Locator
        private
          def located_plugins
            returning locate_plugins do |loaders|
              ensure_all_registered_plugins_are_loaded!(loaders)
            end
          end
          
          def locate_plugins
            initializer.configuration.plugin_paths.flatten.inject([]) do |plugins, path|
              plugins.concat locate_plugins_under(path)
              plugins
            end.flatten
          end
          
          def ensure_all_registered_plugins_are_loaded!(loaders)
            registered_plugins = initializer.configuration.plugins
            unless registered_plugins.nil? || registered_plugins.empty?
              missing_plugins = registered_plugins - loaders.map(&:name)
              unless missing_plugins.empty?
                raise LoadError, "Could not locate the following plugins: #{missing_plugins.inspect}"
              end
            end
          end

          # This starts at the base path looking for directories that pass the plugin_path? test of the Plugin::Loader.
          # Since plugins can be nested arbitrarily deep within an unspecified number of intermediary directories, 
          # this method runs recursively until it finds a plugin directory.
          #
          #   e.g.
          #
          #     locate_plugins_under('vendor/plugins/acts/acts_as_chunky_bacon')
          #     => 'acts_as_chunky_bacon' 
          def locate_plugins_under(base_path)
             Dir.glob(File.join(base_path, '*')).inject([]) do |plugins, path|
              plugin_loader = initializer.configuration.plugin_loader.new(initializer, path)
              if plugin_loader.plugin_path? && plugin_loader.enabled?
                plugins << plugin_loader
              elsif File.directory?(path)
                plugins.concat locate_plugins_under(path)
              end
              plugins
            end
          end
    end
  end
end