Merged updates from trunk into stable branch
[feedcatcher.git] / vendor / rails / railties / lib / rails / plugin / loader.rb
1 require "rails/plugin"
2
3 module Rails
4 class Plugin
5 class Loader
6 attr_reader :initializer
7
8 # Creates a new Plugin::Loader instance, associated with the given
9 # Rails::Initializer. This default implementation automatically locates
10 # all plugins, and adds all plugin load paths, when it is created. The plugins
11 # are then fully loaded (init.rb is evaluated) when load_plugins is called.
12 #
13 # It is the loader's responsibility to ensure that only the plugins specified
14 # in the configuration are actually loaded, and that the order defined
15 # is respected.
16 def initialize(initializer)
17 @initializer = initializer
18 end
19
20 # Returns the plugins to be loaded, in the order they should be loaded.
21 def plugins
22 @plugins ||= all_plugins.select { |plugin| should_load?(plugin) }.sort { |p1, p2| order_plugins(p1, p2) }
23 end
24
25 # Returns the plugins that are in engine-form (have an app/ directory)
26 def engines
27 @engines ||= plugins.select(&:engine?)
28 end
29
30 # Returns all the plugins that could be found by the current locators.
31 def all_plugins
32 @all_plugins ||= locate_plugins
33 @all_plugins
34 end
35
36 def load_plugins
37 plugins.each do |plugin|
38 plugin.load(initializer)
39 register_plugin_as_loaded(plugin)
40 end
41
42 configure_engines
43
44 ensure_all_registered_plugins_are_loaded!
45 end
46
47 # Adds the load paths for every plugin into the $LOAD_PATH. Plugin load paths are
48 # added *after* the application's <tt>lib</tt> directory, to ensure that an application
49 # can always override code within a plugin.
50 #
51 # Plugin load paths are also added to Dependencies.load_paths, and Dependencies.load_once_paths.
52 def add_plugin_load_paths
53 plugins.each do |plugin|
54 plugin.load_paths.each do |path|
55 $LOAD_PATH.insert(application_lib_index + 1, path)
56
57 ActiveSupport::Dependencies.load_paths << path
58
59 unless configuration.reload_plugins?
60 ActiveSupport::Dependencies.load_once_paths << path
61 end
62 end
63 end
64
65 $LOAD_PATH.uniq!
66 end
67
68 def engine_metal_paths
69 engines.collect(&:metal_path)
70 end
71
72 protected
73 def configure_engines
74 if engines.any?
75 add_engine_routing_configurations
76 add_engine_controller_paths
77 add_engine_view_paths
78 end
79 end
80
81 def add_engine_routing_configurations
82 engines.select(&:routed?).collect(&:routing_file).each do |routing_file|
83 ActionController::Routing::Routes.add_configuration_file(routing_file)
84 end
85 end
86
87 def add_engine_controller_paths
88 ActionController::Routing.controller_paths += engines.collect(&:controller_path)
89 end
90
91 def add_engine_view_paths
92 # reverse it such that the last engine can overwrite view paths from the first, like with routes
93 paths = ActionView::PathSet.new(engines.collect(&:view_path).reverse)
94 ActionController::Base.view_paths.concat(paths)
95 ActionMailer::Base.view_paths.concat(paths) if configuration.frameworks.include?(:action_mailer)
96 end
97
98 # The locate_plugins method uses each class in config.plugin_locators to
99 # find the set of all plugins available to this Rails application.
100 def locate_plugins
101 configuration.plugin_locators.map do |locator|
102 locator.new(initializer).plugins
103 end.flatten
104 # TODO: sorting based on config.plugins
105 end
106
107 def register_plugin_as_loaded(plugin)
108 initializer.loaded_plugins << plugin
109 end
110
111 def configuration
112 initializer.configuration
113 end
114
115 def should_load?(plugin)
116 # uses Plugin#name and Plugin#valid?
117 enabled?(plugin) && plugin.valid?
118 end
119
120 def order_plugins(plugin_a, plugin_b)
121 if !explicit_plugin_loading_order?
122 plugin_a <=> plugin_b
123 else
124 if !explicitly_enabled?(plugin_a) && !explicitly_enabled?(plugin_b)
125 plugin_a <=> plugin_b
126 else
127 effective_order_of(plugin_a) <=> effective_order_of(plugin_b)
128 end
129 end
130 end
131
132 def effective_order_of(plugin)
133 if explicitly_enabled?(plugin)
134 registered_plugin_names.index(plugin.name)
135 else
136 registered_plugin_names.index('all')
137 end
138 end
139
140 def application_lib_index
141 $LOAD_PATH.index(File.join(RAILS_ROOT, 'lib')) || 0
142 end
143
144 def enabled?(plugin)
145 !explicit_plugin_loading_order? || registered?(plugin)
146 end
147
148 def explicit_plugin_loading_order?
149 !registered_plugin_names.nil?
150 end
151
152 def registered?(plugin)
153 explicit_plugin_loading_order? && registered_plugins_names_plugin?(plugin)
154 end
155
156 def explicitly_enabled?(plugin)
157 !explicit_plugin_loading_order? || explicitly_registered?(plugin)
158 end
159
160 def explicitly_registered?(plugin)
161 explicit_plugin_loading_order? && registered_plugin_names.include?(plugin.name)
162 end
163
164 def registered_plugins_names_plugin?(plugin)
165 registered_plugin_names.include?(plugin.name) || registered_plugin_names.include?('all')
166 end
167
168 # The plugins that have been explicitly listed with config.plugins. If this list is nil
169 # then it means the client does not care which plugins or in what order they are loaded,
170 # so we load all in alphabetical order. If it is an empty array, we load no plugins, if it is
171 # non empty, we load the named plugins in the order specified.
172 def registered_plugin_names
173 configuration.plugins ? configuration.plugins.map(&:to_s) : nil
174 end
175
176 def loaded?(plugin_name)
177 initializer.loaded_plugins.detect { |plugin| plugin.name == plugin_name.to_s }
178 end
179
180 def ensure_all_registered_plugins_are_loaded!
181 if explicit_plugin_loading_order?
182 if configuration.plugins.detect {|plugin| plugin != :all && !loaded?(plugin) }
183 missing_plugins = configuration.plugins - (plugins.map{|p| p.name.to_sym} + [:all])
184 raise LoadError, "Could not locate the following plugins: #{missing_plugins.to_sentence(:locale => :en)}"
185 end
186 end
187 end
188
189 end
190 end
191 end