mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Further improvements to reloading code
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3519 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
65c337ac85
commit
7a43a05a2b
10 changed files with 87 additions and 44 deletions
|
@ -523,8 +523,8 @@ module ActionController #:nodoc:
|
|||
|
||||
# ActiveRecord::Observer will mark this class as reloadable even though it should not be.
|
||||
# However, subclasses of ActionController::Caching::Sweeper should be Reloadable
|
||||
def self.included_modules
|
||||
self == Sweeper ? super() - [ Reloadable ] : super()
|
||||
def self.reloadable? #:nodoc:
|
||||
self != Sweeper
|
||||
end
|
||||
|
||||
def before(controller)
|
||||
|
|
|
@ -65,11 +65,6 @@ class CGI
|
|||
before_save :raise_on_session_data_overflow!
|
||||
|
||||
class << self
|
||||
# Don't try to reload ARStore::Session in dev mode.
|
||||
def included_modules
|
||||
super() - [ Reloadable ]
|
||||
end
|
||||
|
||||
# Don't try to reload ARStore::Session in dev mode.
|
||||
def reloadable? #:nodoc:
|
||||
false
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
*SVN*
|
||||
|
||||
* Further improvements to reloading code [Nicholas Seckar, Trevor Squires]
|
||||
|
||||
- All classes/modules which include Reloadable can define reloadable? for fine grained control of reloading
|
||||
- Class.remove_class uses Module#parent to access the parent module
|
||||
- Class.remove_class expanded to handle multiple classes in a single call
|
||||
- LoadingModule.clear! has been removed as it is no longer required
|
||||
- Module#remove_classes_including has been removed in favor of Reloadable.reloadable_classes
|
||||
|
||||
* Added reusable reloading support through the inclusion of the Relodable module that all subclasses of ActiveRecord::Base, ActiveRecord::Observer, ActiveController::Base, and ActionMailer::Base automatically gets. This means that these classes will be reloaded by the dispatcher when Dependencies.mechanism = :load. You can make your own models reloadable easily:
|
||||
|
||||
class Setting
|
||||
|
|
|
@ -7,15 +7,11 @@ class Class #:nodoc:
|
|||
Object.subclasses_of(self).map { |o| o.to_s }
|
||||
end
|
||||
|
||||
def remove_class(klass)
|
||||
if klass.to_s.include? "::"
|
||||
modules = klass.to_s.split("::")
|
||||
final_klass = modules.pop
|
||||
|
||||
final_module = modules.inject(Object) { |final_type, part| final_type.const_get(part) }
|
||||
final_module.send(:remove_const, final_klass) rescue nil
|
||||
else
|
||||
Object.send(:remove_const, klass.to_s) rescue nil
|
||||
def remove_class(*klasses)
|
||||
klasses.each do |klass|
|
||||
basename = klass.to_s.split("::").last
|
||||
parent = klass.parent
|
||||
parent.send :remove_const, basename unless parent == klass
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,8 +1,4 @@
|
|||
class Module
|
||||
def remove_classes_including
|
||||
included_in_classes.each { |klass| Class.remove_class(klass) }
|
||||
end
|
||||
|
||||
def included_in_classes
|
||||
classes = []
|
||||
ObjectSpace.each_object(Class) { |k| classes << k if k.included_modules.include?(self) }
|
||||
|
|
|
@ -159,14 +159,6 @@ module Dependencies #:nodoc:
|
|||
def load_file!(file_path)
|
||||
require_dependency(file_path)
|
||||
end
|
||||
|
||||
# Erase all items in this module
|
||||
def clear!
|
||||
constants.each do |name|
|
||||
Object.send(:remove_const, name) if Object.const_defined?(name) && Object.const_get(name).object_id == self.const_get(name).object_id
|
||||
self.send(:remove_const, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This object defines a path from which Constants can be loaded.
|
||||
|
|
|
@ -1,4 +1,17 @@
|
|||
# Classes that include this module will automatically be reloaded
|
||||
# by the Rails dispatcher when Dependencies.mechanism = :load.
|
||||
module Reloadable
|
||||
class << self
|
||||
def included(base) #nodoc:
|
||||
if base.is_a?(Class) && ! base.respond_to?(:reloadable?)
|
||||
class << base
|
||||
define_method(:reloadable?) { true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def reloadable_classes
|
||||
included_in_classes.select { |klass| klass.reloadable? }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -34,18 +34,4 @@ class ModuleTest < Test::Unit::TestCase
|
|||
assert !One.included_in_classes.include?(De)
|
||||
end
|
||||
|
||||
def test_remove_classes_including
|
||||
assert Ab.is_a?(Class)
|
||||
assert Xy::Bc.is_a?(Class)
|
||||
assert Yz::Zy::Cd.is_a?(Class)
|
||||
assert De.is_a?(Class)
|
||||
|
||||
One.remove_classes_including
|
||||
|
||||
assert_raises(NameError) { Ae.is_a?(Class) }
|
||||
assert_raises(NameError) { Xy::Bc.is_a?(Class) }
|
||||
assert_raises(NameError) { Yz::Zy::Cd.is_a?(Class) }
|
||||
|
||||
assert De.is_a?(Class)
|
||||
end
|
||||
end
|
58
activesupport/test/reloadable_test.rb
Normal file
58
activesupport/test/reloadable_test.rb
Normal file
|
@ -0,0 +1,58 @@
|
|||
require 'test/unit'
|
||||
require File.dirname(__FILE__) + '/../lib/active_support/core_ext/class'
|
||||
require File.dirname(__FILE__) + '/../lib/active_support/core_ext/module'
|
||||
require File.dirname(__FILE__) + '/../lib/active_support/reloadable'
|
||||
|
||||
module ReloadableTestSandbox
|
||||
|
||||
module AModuleIncludingReloadable
|
||||
include Reloadable
|
||||
end
|
||||
class AReloadableClass
|
||||
include Reloadable
|
||||
end
|
||||
class AReloadableClassWithSubclasses
|
||||
include Reloadable
|
||||
end
|
||||
class AReloadableSubclass < AReloadableClassWithSubclasses
|
||||
end
|
||||
class ANonReloadableSubclass < AReloadableClassWithSubclasses
|
||||
def self.reloadable?
|
||||
false
|
||||
end
|
||||
end
|
||||
class AClassWhichDefinesItsOwnReloadable
|
||||
def self.reloadable?
|
||||
10
|
||||
end
|
||||
include Reloadable
|
||||
end
|
||||
end
|
||||
|
||||
class ReloadableTest < Test::Unit::TestCase
|
||||
def test_modules_do_not_receive_reloadable_method
|
||||
assert ! ReloadableTestSandbox::AModuleIncludingReloadable.respond_to?(:reloadable?)
|
||||
end
|
||||
def test_classes_receive_reloadable
|
||||
assert ReloadableTestSandbox::AReloadableClass.respond_to?(:reloadable?)
|
||||
end
|
||||
def test_classes_inherit_reloadable
|
||||
assert ReloadableTestSandbox::AReloadableSubclass.respond_to?(:reloadable?)
|
||||
end
|
||||
def test_reloadable_is_not_overwritten_if_present
|
||||
assert_equal 10, ReloadableTestSandbox::AClassWhichDefinesItsOwnReloadable.reloadable?
|
||||
end
|
||||
|
||||
def test_removable_classes
|
||||
reloadables = %w(AReloadableClass AReloadableClassWithSubclasses AReloadableSubclass AClassWhichDefinesItsOwnReloadable)
|
||||
non_reloadables = %w(ANonReloadableSubclass AModuleIncludingReloadable)
|
||||
|
||||
results = Reloadable.reloadable_classes
|
||||
reloadables.each do |name|
|
||||
assert results.include?(ReloadableTestSandbox.const_get(name)), "Expected #{name} to be reloadable"
|
||||
end
|
||||
non_reloadables.each do |name|
|
||||
assert ! results.include?(ReloadableTestSandbox.const_get(name)), "Expected #{name} NOT to be reloadable"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -50,10 +50,9 @@ class Dispatcher
|
|||
# mailers, and so forth. This allows them to be loaded again without having
|
||||
# to restart the server (WEBrick, FastCGI, etc.).
|
||||
def reset_application!
|
||||
Controllers.clear!
|
||||
Dependencies.clear
|
||||
ActiveRecord::Base.reset_subclasses
|
||||
Reloadable.remove_classes_including
|
||||
Class.remove_classes(*Reloadable.reloadable_classes)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
Loading…
Reference in a new issue