Skip to content

Commit

Permalink
[padrino-core] Improved granularity of our reloader locking and preve…
Browse files Browse the repository at this point in the history
…nt reloading of unnecessary deps
  • Loading branch information
DAddYE committed May 15, 2011
1 parent b3fe72b commit 42bdac7
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGES.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* Make methods of Padrino::Application that act as Padrino Core
* Fixed error logging
* Added Padrino.clear, useful to clean a Padrino Enviroment
* Improved granularity of our reloader locking and prevent reloading of unnecessary deps

== 0.9.28

Expand Down
4 changes: 2 additions & 2 deletions padrino-core/lib/padrino-core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ def env
# Returns the resulting rack builder mapping each 'mounted' application
#
def application
raise ApplicationLoadError, "At least one app must be mounted!" unless self.mounted_apps && self.mounted_apps.any?
raise ApplicationLoadError, "At least one app must be mounted!" unless Padrino.mounted_apps && Padrino.mounted_apps.any?
router = Padrino::Router.new
self.mounted_apps.each { |app| app.map_onto(router) }
Padrino.mounted_apps.each { |app| app.map_onto(router) }

unless middleware.empty?
builder = Rack::Builder.new
Expand Down
4 changes: 3 additions & 1 deletion padrino-core/lib/padrino-core/loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ def load!
Padrino.set_encoding
Padrino.set_load_paths(*load_paths) # We set the padrino load paths
Padrino.logger # Initialize our logger
Padrino.require_dependencies("#{root}/config/database.rb") # Be sure to don't remove constants from dbs.
Padrino::Reloader::Stat.lock! # Now we can remove constant from here to down
Padrino.before_load.each(&:call) # Run before hooks
Padrino.dependency_paths.each { |path| require_dependencies(path) }
Padrino.dependency_paths.each { |path| Padrino.require_dependencies(path) }
Padrino.after_load.each(&:call) # Run after hooks
Padrino::Reloader::Stat.run!
Thread.current[:padrino_loaded] = true
Expand Down
22 changes: 15 additions & 7 deletions padrino-core/lib/padrino-core/reloader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,9 @@ def self.exclude

##
# Specified constants can be excluded from the code unloading process.
# Default excluded constants are: Padrino, Sinatra and HttpRouter
#
def self.exclude_constants
@_exclude_constants ||= %w(Padrino::Application Sinatra::Application Sinatra::Base HttpRouter)
@_exclude_constants ||= []
end

##
Expand Down Expand Up @@ -95,10 +94,11 @@ def clear!
MTIMES.clear
LOADED_CLASSES.each do |file, klasses|
klasses.each { |klass| remove_constant(klass) }
LOADED_CLASSES.delete(file)
end
FILES_LOADED.each do |file, dependencies|
$LOADED_FEATURES.delete(file)
dependencies.each { |dependency| $LOADED_FEATURES.delete(dependency) }
$LOADED_FEATURES.delete(file)
end
end

Expand All @@ -116,6 +116,14 @@ def changed?
end
alias :run! :changed?

##
# We lock dependencies sets to prevent reloading of protected constants
#
def lock!
klasses = ObjectSpace.classes.map { |klass| klass.to_s.split("::")[0] }.uniq
Padrino::Reloader.exclude_constants.concat(klasses)
end

##
# A safe Kernel::require which issues the necessary hooks depending on results
#
Expand Down Expand Up @@ -185,8 +193,8 @@ def safe_load(file, force=false)
end

# Store the file details after successful loading
LOADED_CLASSES[file] = ObjectSpace.classes - klasses
FILES_LOADED[file] = $LOADED_FEATURES - files_loaded
LOADED_CLASSES[file] ||= (ObjectSpace.classes - klasses)
FILES_LOADED[file] ||= ($LOADED_FEATURES - files_loaded)

nil
end
Expand All @@ -195,8 +203,8 @@ def safe_load(file, force=false)
# Removes the specified class and constant.
#
def remove_constant(const)
return if Padrino::Reloader.exclude_constants.any? { |base| (const.to_s =~ /^#{base}/ || const.superclass.to_s =~ /^#{base}/) } &&
!Padrino::Reloader.include_constants.any? { |base| (const.to_s =~ /^#{base}/ || const.superclass.to_s =~ /^#{base}/) }
return if Padrino::Reloader.exclude_constants.any? { |base| (const.to_s =~ /^#{base}/) } &&
!Padrino::Reloader.include_constants.any? { |base| (const.to_s =~ /^#{base}/) }

parts = const.to_s.split("::")
base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
Expand Down
15 changes: 13 additions & 2 deletions padrino-core/lib/padrino-core/support_lite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,19 @@ module ObjectSpace
class << self
# Returns all the classes in the object space.
def classes
klasses = []
ObjectSpace.each_object(Class) { |o| klasses << o }
klasses = ObjectSpace.each_object(Class).map
klasses.reject! { |klass| klass.to_s.blank? } # Remove some wrong constants
# If you use remove_const they will not be removed from the ObjectSpace. That's odd
klasses.reject! do |klass|
begin
parts = klass.to_s.split("::")
base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
object = parts[-1].to_s
!base.const_defined?(object)
rescue NameError
true
end
end
klasses
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
require 'bundler'
Bundler.setup(:default, PADRINO_ENV)
Bundler.require(:default, PADRINO_ENV)
puts "=> Located #{Padrino.bundle} Gemfile for #{Padrino.env}"

##
# Add your before load hooks here
Expand Down

0 comments on commit 42bdac7

Please sign in to comment.