aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib/rails/plugin/loader.rb
blob: e935f9b34b9ac1970c86903399948dbd57eecc60 (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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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)
      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 <=> other_plugin_loader.name
            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 <=> other_plugin_loader.name
          end
        end
    end
  end
end