padrino-core/lib/padrino-core/loader.rb
module Padrino
module Loader
##
# Hooks to be called before a load/reload.
#
# @yield []
# The given block will be called before Padrino was loaded/reloaded.
#
# @return [Array<Proc>]
# The load/reload before hooks.
#
# @example
# before_load do
# pre_initialize_something
# end
#
def before_load(&block)
@_before_load ||= []
@_before_load << block if block_given?
@_before_load
end
##
# Hooks to be called after a load/reload.
#
# @yield []
# The given block will be called after Padrino was loaded/reloaded.
#
# @return [Array<Proc>]
# The load/reload hooks.
#
# @example
# after_load do
# DataMapper.finalize
# end
#
def after_load(&block)
@_after_load ||= []
@_after_load << block if block_given?
@_after_load
end
##
# Requires necessary dependencies as well as application files from root
# lib and models.
#
# @return [Boolean]
# returns true if Padrino is not already bootstraped otherwise else.
#
def load!
return false if loaded?
began_at = Time.now
@_called_from = first_caller
Padrino.logger
Reloader.lock!
before_load.each(&:call)
require_dependencies(*dependency_paths)
after_load.each(&:call)
logger.devel "Loaded Padrino in #{Time.now - began_at} seconds"
precompile_all_routes!
Thread.current[:padrino_loaded] = true
end
##
# Precompiles all routes if :precompile_routes is set to true
#
def precompile_all_routes!
mounted_apps.each do |app|
app_obj = app.app_obj
next unless app_obj.respond_to?(:precompile_routes?) && app_obj.precompile_routes?
app_obj.setup_application!
logger.devel "Precompiled routes of #{app_obj} (routes size #{app_obj.compiled_router.routes.size})"
end
end
##
# Clear the padrino env.
#
# @return [NilClass]
#
def clear!
clear_middleware!
mounted_apps.clear
@_dependency_paths = nil
before_load.clear
after_load.clear
global_configurations.clear
Reloader.clear!
Thread.current[:padrino_loaded] = nil
end
##
# Method for reloading required applications and their files.
#
def reload!
return unless Reloader.changed?
before_load.each(&:call)
Reloader.reload!
after_load.each(&:call)
end
##
# This adds the ability to instantiate {Padrino.load!} after
# {Padrino::Application} definition.
#
def called_from
@_called_from || first_caller
end
##
# Determines whether Padrino was loaded with {Padrino.load!}.
#
# @return [Boolean]
# Specifies whether Padrino was loaded.
#
def loaded?
Thread.current[:padrino_loaded]
end
##
# Attempts to require all dependency libs that we need.
# If you use this method we can perform correctly a Padrino.reload!
# Another good thing that this method are dependency check, for example:
#
# # models
# # \-- a.rb => require something of b.rb
# # \-- b.rb
#
# In the example above if we do:
#
# Dir["/models/*.rb"].each { |r| require r }
#
# We get an error, because we try to require first +a.rb+ that need
# _something_ of +b.rb+.
#
# With this method we don't have this problem.
#
# @param [Array<String>] paths
# The paths to require.
#
# @example For require all our app libs we need to do:
# require_dependencies("#{Padrino.root}/lib/**/*.rb")
#
def require_dependencies(*paths)
options = { :cyclic => true }.update(paths.last.is_a?(Hash) ? paths.pop : {})
files = paths.flatten.flat_map{ |path| Dir.glob(path).sort_by{ |filename| filename.count('/') } }.uniq
until files.empty?
error = fatal = loaded = nil
files.dup.each do |file|
Reloader.safe_load(file, options)
files.delete(file)
loaded = true
rescue NameError, LoadError => error
raise if Reloader.exclude.any?{ |path| file.start_with?(path) } || options[:cyclic] == false
logger.devel "Cyclic dependency reload for #{error.class}: #{error.message}"
rescue Exception => fatal
break
end
next unless fatal || !loaded
exception = fatal || error
logger.exception exception, :short
raise exception
end
end
##
# Returns default list of path globs to load as dependencies.
# Appends custom dependency patterns to the be loaded for Padrino.
#
# @return [Array<String>]
# The dependencey paths.
#
# @example
# Padrino.dependency_paths << "#{Padrino.root}/uploaders/*.rb"
#
def dependency_paths
@_dependency_paths ||= default_dependency_paths + modules_dependency_paths
end
private
def modules_dependency_paths
modules.map(&:dependency_paths).flatten
end
def default_dependency_paths
@default_dependency_paths ||= [
"#{root}/config/database.rb",
"#{root}/lib/**/*.rb",
"#{root}/models/**/*.rb",
"#{root}/shared/**/*.rb",
"#{root}/config/apps.rb"
]
end
end
end