/
initializer.rb
322 lines (275 loc) · 11.1 KB
/
initializer.rb
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
require "pathname"
require 'rails/initializable'
require 'rails/application'
require 'rails/railties_path'
require 'rails/version'
require 'rails/gem_dependency'
require 'rails/rack'
require 'rails/paths'
require 'rails/core'
require 'rails/configuration'
RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
module Rails
class Initializer
class Error < StandardError ; end
class Base
class << self
def run(&blk)
define_method(:run, &blk)
end
def config=(config)
@@config = config
end
def config
@@config || Configuration.new
end
alias configuration config
def gems_dependencies_loaded
config.gems_dependencies_loaded
end
def plugin_loader
@plugin_loader ||= configuration.plugin_loader.new(self)
end
end
def gems_dependencies_loaded
self.class.gems_dependencies_loaded
end
def plugin_loader
self.class.plugin_loader
end
end
class Runner
attr_reader :names, :initializers
attr_accessor :config
alias configuration config
def initialize(parent = nil)
@names = parent ? parent.names.dup : {}
@initializers = parent ? parent.initializers.dup : []
end
def add(name, options = {}, &block)
# If :before or :after is specified, set the index to the right spot
if other = options[:before] || options[:after]
raise Error, "The #{other.inspect} initializer does not exist" unless @names[other]
index = @initializers.index(@names[other])
index += 1 if options[:after]
end
@initializers.insert(index || -1, block)
@names[name] = block
end
def delete(name)
@names[name].tap do |initializer|
@initializers.delete(initializer)
@names.delete(name)
end
end
def run_initializer(initializer)
init_block = initializer.is_a?(Proc) ? initializer : @names[initializer]
container = Class.new(Base, &init_block).new
container.run if container.respond_to?(:run)
end
def run(initializer = nil)
Rails.configuration = Base.config = @config
if initializer
run_initializer(initializer)
else
@initializers.each {|block| run_initializer(block) }
end
end
end
def self.default
@default ||= Runner.new
end
def self.run(initializer = nil, config = nil)
# TODO: Clean this all up
if initializer
default.config = config
default.run(initializer)
else
Rails.application = Class.new(Application)
yield Rails.application.config if block_given?
# Trigger the initializer
Rails.application.new
default.config = Rails.application.config
default.run
end
end
end
# Initializes framework-specific settings for each of the loaded frameworks
# (Configuration#frameworks). The available settings map to the accessors
# on each of the corresponding Base classes.
Initializer.default.add :initialize_framework_settings do
configuration.frameworks.each do |framework|
base_class = framework.to_s.camelize.constantize.const_get("Base")
configuration.send(framework).each do |setting, value|
base_class.send("#{setting}=", value)
end
end
configuration.active_support.each do |setting, value|
ActiveSupport.send("#{setting}=", value)
end
end
# Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
# (but only for those frameworks that are to be loaded). If the framework's
# paths have already been set, it is not changed, otherwise it is
# set to use Configuration#view_path.
Initializer.default.add :initialize_framework_views do
if configuration.frameworks.include?(:action_view)
view_path = ActionView::PathSet.type_cast(configuration.view_path)
ActionMailer::Base.template_root = view_path if configuration.frameworks.include?(:action_mailer) && ActionMailer::Base.view_paths.blank?
ActionController::Base.view_paths = view_path if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.blank?
end
end
Initializer.default.add :initialize_metal do
# TODO: Make Rails and metal work without ActionController
if configuration.frameworks.include?(:action_controller)
Rails::Rack::Metal.requested_metals = configuration.metals
Rails::Rack::Metal.metal_paths += plugin_loader.engine_metal_paths
configuration.middleware.insert_before(
:"ActionDispatch::ParamsParser",
Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?)
end
end
Initializer.default.add :check_for_unbuilt_gems do
unbuilt_gems = config.gems.select {|gem| gem.frozen? && !gem.built? }
if unbuilt_gems.size > 0
# don't print if the gems:build rake tasks are being run
unless $gems_build_rake_task
abort <<-end_error
The following gems have native components that need to be built
#{unbuilt_gems.map { |gemm| "#{gemm.name} #{gemm.requirement}" } * "\n "}
You're running:
ruby #{Gem.ruby_version} at #{Gem.ruby}
rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
Run `rake gems:build` to build the unbuilt gems.
end_error
end
end
end
Initializer.default.add :load_gems do
unless $gems_rake_task
config.gems.each { |gem| gem.load }
end
end
# Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt>
# defaults to <tt>vendor/plugins</tt> but may also be set to a list of
# paths, such as
# config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]
#
# In the default implementation, as each plugin discovered in <tt>plugin_paths</tt> is initialized:
# * its +lib+ directory, if present, is added to the load path (immediately after the applications lib directory)
# * <tt>init.rb</tt> is evaluated, if present
#
# After all plugins are loaded, duplicates are removed from the load path.
# If an array of plugin names is specified in config.plugins, only those plugins will be loaded
# and they plugins will be loaded in that order. Otherwise, plugins are loaded in alphabetical
# order.
#
# if config.plugins ends contains :all then the named plugins will be loaded in the given order and all other
# plugins will be loaded in alphabetical order
Initializer.default.add :load_plugins do
plugin_loader.load_plugins
end
# TODO: Figure out if this needs to run a second time
# load_gems
Initializer.default.add :check_gem_dependencies do
unloaded_gems = config.gems.reject { |g| g.loaded? }
if unloaded_gems.size > 0
configuration.gems_dependencies_loaded = false
# don't print if the gems rake tasks are being run
unless $gems_rake_task
abort <<-end_error
Missing these required gems:
#{unloaded_gems.map { |gemm| "#{gemm.name} #{gemm.requirement}" } * "\n "}
You're running:
ruby #{Gem.ruby_version} at #{Gem.ruby}
rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
Run `rake gems:install` to install the missing gems.
end_error
end
else
configuration.gems_dependencies_loaded = true
end
end
# # bail out if gems are missing - note that check_gem_dependencies will have
# # already called abort() unless $gems_rake_task is set
# return unless gems_dependencies_loaded
Initializer.default.add :load_application_initializers do
if gems_dependencies_loaded
Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
load(initializer)
end
end
end
# Fires the user-supplied after_initialize block (Configuration#after_initialize)
Initializer.default.add :after_initialize do
if gems_dependencies_loaded
configuration.after_initialize_blocks.each do |block|
block.call
end
end
end
# # Setup database middleware after initializers have run
Initializer.default.add :initialize_database_middleware do
if configuration.frameworks.include?(:active_record)
if configuration.frameworks.include?(:action_controller) && ActionController::Base.session_store &&
ActionController::Base.session_store.name == 'ActiveRecord::SessionStore'
configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement
configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::QueryCache
else
configuration.middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement
configuration.middleware.use ActiveRecord::QueryCache
end
end
end
# TODO: Make a DSL way to limit an initializer to a particular framework
# # Prepare dispatcher callbacks and run 'prepare' callbacks
Initializer.default.add :prepare_dispatcher do
next unless configuration.frameworks.include?(:action_controller)
require 'rails/dispatcher' unless defined?(::Dispatcher)
Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
end
# Routing must be initialized after plugins to allow the former to extend the routes
# ---
# If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
# this does nothing. Otherwise, it loads the routing definitions and sets up
# loading module used to lazily load controllers (Configuration#controller_paths).
Initializer.default.add :initialize_routing do
next unless configuration.frameworks.include?(:action_controller)
ActionController::Routing.controller_paths += configuration.controller_paths
ActionController::Routing::Routes.add_configuration_file(configuration.routes_configuration_file)
ActionController::Routing::Routes.reload!
end
#
# # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
Initializer.default.add :load_observers do
if gems_dependencies_loaded && configuration.frameworks.include?(:active_record)
ActiveRecord::Base.instantiate_observers
end
end
# Eager load application classes
Initializer.default.add :load_application_classes do
next if $rails_rake_task
if configuration.cache_classes
configuration.eager_load_paths.each do |load_path|
matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
require_dependency file.sub(matcher, '\1')
end
end
end
end
# Disable dependency loading during request cycle
Initializer.default.add :disable_dependency_loading do
if configuration.cache_classes && !configuration.dependency_loading
ActiveSupport::Dependencies.unhook!
end
end
# Configure generators if they were already loaded
Initializer.default.add :initialize_generators do
if defined?(Rails::Generators)
Rails::Generators.no_color! unless config.generators.colorize_logging
Rails::Generators.aliases.deep_merge! config.generators.aliases
Rails::Generators.options.deep_merge! config.generators.options
end
end
end