提交 74165eb6 编写于 作者: N Nicholas Seckar

New dependencies implementation

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4728 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 94a13091
*SVN*
* Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
* Mailer template root applies to a class and its subclasses rather than acting globally. #5555 [somekool@gmail.com]
* Resolve action naming collision. #5520 [ssinghi@kreeti.com]
......
......@@ -187,7 +187,7 @@ class Base
# Action Mailer subclasses should be reloaded by the dispatcher in Rails
# when Dependencies.mechanism = :load.
include Reloadable::Subclasses
include Reloadable::Deprecated
private_class_method :new #:nodoc:
......
*SVN*
<<<<<<< .mine
* Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
=======
* Deprecation: check whether instance variables have been monkeyed with before assigning them to deprecation proxies. Raises a RuntimeError if so. [Jeremy Kemper]
* Add support for the param_name parameter to the auto_complete_field helper. #5026 [david.a.williams@gmail.com]
* Deprecation! @params, @session, @flash will be removed after 1.2. Use the corresponding instance methods instead. You'll get printed warnings during tests and logged warnings in dev mode when you access either instance variable directly. [Jeremy Kemper]
>>>>>>> .r4727
* Make Routing noisy when an anchor regexp is assigned to a segment. #5674 [francois.beausoleil@gmail.com]
* Added months and years to the resolution of DateHelper#distance_of_time_in_words, such that "60 days ago" becomes "2 months ago" #5611 [pjhyett@gmail.com]
......
......@@ -206,7 +206,7 @@ def initialize(message = nil)
class Base
DEFAULT_RENDER_STATUS_CODE = "200 OK"
include Reloadable::Subclasses
include Reloadable::Deprecated
# Determines whether the view has access to controller internals @request, @response, @session, and @template.
# By default, it does.
......
require 'fileutils'
require 'uri'
module ActionController #:nodoc:
# Caching is a cheap way of speeding up slow applications by keeping the result of calculations, renderings, and database calls
......@@ -578,7 +579,7 @@ class Sweeper < ActiveRecord::Observer #:nodoc:
# ActiveRecord::Observer will mark this class as reloadable even though it should not be.
# However, subclasses of ActionController::Caching::Sweeper should be Reloadable
include Reloadable::Subclasses
include Reloadable::Deprecated
def before(controller)
self.controller = controller
......
......@@ -183,7 +183,6 @@ def default_layout #:nodoc:
private
def inherited_with_layout(child)
inherited_without_layout(child)
child.send :include, Reloadable
layout_match = child.name.underscore.sub(/_controller$/, '').sub(/^controllers\//, '')
child.layout(layout_match) unless layout_list.grep(%r{layouts/#{layout_match}\.[a-z][0-9a-z]*$}).empty?
end
......
require 'test/unit'
require File.dirname(__FILE__) + '/../../lib/action_view/helpers/date_helper'
require File.dirname(__FILE__) + '/../../lib/action_view/compiled_templates'
require File.dirname(__FILE__) + "/../abstract_unit"
class CompiledTemplateTests < Test::Unit::TestCase
......
*SVN*
* Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
* Fix invoke_layered since api_method didn't declare :expects. Closes #4720. [Kevin Ballard <kevin@sb.org>, Kent Sibilev]
* Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
......
......@@ -16,7 +16,7 @@ module API # :nodoc:
class Base
# Action WebService API subclasses should be reloaded by the dispatcher in Rails
# when Dependencies.mechanism = :load.
include Reloadable::Subclasses
include Reloadable::Deprecated
# Whether to transform the public API method names into camel-cased names
class_inheritable_option :inflect_names, true
......
......@@ -33,7 +33,7 @@ class ActionWebServiceError < StandardError # :nodoc:
class Base
# Action WebService subclasses should be reloaded by the dispatcher in Rails
# when Dependencies.mechanism = :load.
include Reloadable::Subclasses
include Reloadable::Deprecated
# Whether to report exceptions back to the caller in the protocol's exception
# format
......
......@@ -21,7 +21,7 @@ module ActionWebService
class Struct
# Action WebService Struct subclasses should be reloaded by the dispatcher in Rails
# when Dependencies.mechanism = :load.
include Reloadable::Subclasses
include Reloadable::Deprecated
# If a Hash is given as argument to an ActionWebService::Struct constructor,
# it can contain initial values for the structure member.
......
*SVN*
<<<<<<< .mine
* Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
=======
* Cache nil results for has_one associations so multiple calls don't call the database. Closes #5757. [Michael A. Schoen]
* Add documentation for how to disable timestamps on a per model basis. Closes #5684. [matt@mattmargolis.net Marcel Molina Jr.]
* Don't save has_one associations unnecessarily. #5735 [Jonathan Viney]
>>>>>>> .r4727
* Refactor ActiveRecord::Base.reset_subclasses to #reset, and add global observer resetting. [Rick Olson]
* Formally deprecate the deprecated finders. [Koz]
......
......@@ -264,7 +264,7 @@ class Base
# on to any new database connections made and which can be retrieved on both a class and instance level by calling +logger+.
cattr_accessor :logger
include Reloadable::Subclasses
include Reloadable::Deprecated
def self.inherited(child) #:nodoc:
@@subclasses[self] ||= []
......@@ -279,7 +279,7 @@ def self.reset
def self.reset_subclasses #:nodoc:
nonreloadables = []
subclasses.each do |klass|
unless klass.reloadable?
unless Dependencies.autoloaded? klass
nonreloadables << klass
next
end
......
......@@ -129,7 +129,7 @@ class Observer
# Observer subclasses should be reloaded by the dispatcher in Rails
# when Dependencies.mechanism = :load.
include Reloadable::Subclasses
include Reloadable::Deprecated
class << self
# Attaches the observer to the supplied model classes.
......
*SVN*
<<<<<<< .mine
* Replace Reloadable with improvements to the Dependencies mechanism. [Nicholas Seckar]
=======
* DateTime#to_time gives hour/minute/second resolution. #5747 [jon.evans@pobox.com]
* attr_internal to support namespacing and deprecation. Like attr_* except backed by internally-named instance variable. Set attr_internal_naming_format to change the format from the default '@_%s'. [Jeremy Kemper]
......@@ -8,6 +12,7 @@
self.attr_internal_naming_format = '@%s__rofl'
attr_internal :foo
>>>>>>> .r4727
* Raise fully qualified names upon name errors. #5533 [lars@pinds.com, Nicholas Seckar]
* Add extention to obtain the missing constant from NameError instances. [Nicholas Seckar]
......
......@@ -22,12 +22,20 @@ module Dependencies #:nodoc:
mattr_accessor :mechanism
self.mechanism = :load
# The set of directories from which we may autoload files
mattr_accessor :autoload_paths
self.autoload_paths = []
mattr_accessor :autoloaded_constants
self.autoloaded_constants = []
def load?
mechanism == :load
end
def depend_on(file_name, swallow_load_errors = false)
require_or_load(file_name)
path = search_for_autoload_file(file_name)
require_or_load(path || file_name)
rescue LoadError
raise unless swallow_load_errors
end
......@@ -38,9 +46,10 @@ def associate_with(file_name)
def clear
loaded.clear
remove_autoloaded_constants!
end
def require_or_load(file_name)
def require_or_load(file_name, const_path = nil)
file_name = $1 if file_name =~ /^(.*)\.rb$/
return if loaded.include?(file_name)
......@@ -52,10 +61,13 @@ def require_or_load(file_name)
begin
# Enable warnings iff this file has not been loaded before and
# warnings_on_first_load is set.
load_args = ["#{file_name}.rb"]
load_args << const_path unless const_path.nil?
if !warnings_on_first_load or history.include?(file_name)
load "#{file_name}.rb"
load_file(*load_args)
else
enable_warnings { load "#{file_name}.rb" }
enable_warnings { load_file(*load_args) }
end
rescue
loaded.delete file_name
......@@ -69,9 +81,127 @@ def require_or_load(file_name)
history << file_name
end
# Return the a constant path for the provided parent and constant name
def constant_path_for(mod, name)
([Object, Kernel].include? mod) ? name.to_s : "#{mod}::#{name}"
# Is the provided constant path defined?
def qualified_const_defined?(path)
raise NameError, "#{path.inspect} is not a valid constant name!" unless
/^(::)?([A-Z]\w*)(::[A-Z]\w*)*$/ =~ path
Object.module_eval("defined?(#{path})", __FILE__, __LINE__)
end
# Given +path+ return an array of constant paths which would cause Dependencies
# to attempt to load +path+.
def autoloadable_constants_for_path(path)
path = $1 if path =~ /\A(.*)\.rb\Z/
expanded_path = File.expand_path(path)
autoload_paths.collect do |root|
expanded_root = File.expand_path root
next unless expanded_path.starts_with? expanded_root
nesting = expanded_path[(expanded_root.size)..-1]
nesting = nesting[1..-1] if nesting && nesting[0] == ?/
next if nesting.blank?
nesting.camelize
end.compact.uniq
end
# Search for a file in the autoload_paths matching the provided suffix.
def search_for_autoload_file(path_suffix)
path_suffix = path_suffix + '.rb' unless path_suffix.ends_with? '.rb'
autoload_paths.each do |root|
path = File.join(root, path_suffix)
return path if File.file? path
end
nil # Gee, I sure wish we had first_match ;-)
end
# Does the provided path_suffix correspond to an autoloadable module?
def autoloadable_module?(path_suffix)
autoload_paths.any? do |autoload_path|
File.directory? File.join(autoload_path, path_suffix)
end
end
# Load the file at the provided path. +const_paths+ is a set of qualified
# constant names. When loading the file, Dependencies will watch for the
# addition of these constants. Each that is defined will be marked as
# autoloaded, and will be removed when Dependencies.clear is next called.
#
# If the second parameter is left off, then Dependencies will construct a set
# of names that the file at +path+ may define. See
# +autoloadable_constants_for_path+ for more details.
def load_file(path, const_paths = autoloadable_constants_for_path(path))
const_paths = [const_paths].compact unless const_paths.is_a? Array
undefined_before = const_paths.reject(&method(:qualified_const_defined?))
load path
autoloaded_constants.concat const_paths.select(&method(:qualified_const_defined?))
autoloaded_constants.uniq!
end
# Return the constant path for the provided parent and constant name.
def qualified_name_for(mod, name)
mod_name = to_constant_name mod
(%w(Object Kernel).include? mod_name) ? name.to_s : "#{mod_name}::#{name}"
end
# Load the constant named +const_name+ which is missing from +from_mod+. If
# it is not possible to laod the constant into from_mod, try its parent module
# using const_missing.
def load_missing_constant(from_mod, const_name)
qualified_name = qualified_name_for from_mod, const_name
path_suffix = qualified_name.underscore
name_error = NameError.new("uninitialized constant #{qualified_name}")
file_path = search_for_autoload_file(path_suffix)
if file_path # We found a matching file to load
require_or_load file_path, qualified_name
raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless from_mod.const_defined?(const_name)
return from_mod.const_get(const_name)
elsif autoloadable_module? path_suffix # Create modules for directories
mod = Module.new
from_mod.const_set const_name, mod
autoloaded_constants << qualified_name
return mod
elsif (parent = from_mod.parent) && parent != from_mod &&
! from_mod.parents.any? { |p| p.const_defined?(const_name) }
# If our parents do not have a constant named +const_name+ then we are free
# to attempt to load upwards. If they do have such a constant, then this
# const_missing must be due to from_mod::const_name, which should not
# return constants from from_mod's parents.
begin
return parent.const_missing(const_name)
rescue NameError => e
raise unless e.missing_name? qualified_name_for(parent, const_name)
raise name_error
end
else
raise name_error
end
end
# Remove the constants that have been autoloaded.
def remove_autoloaded_constants!
until autoloaded_constants.empty?
const = autoloaded_constants.shift
next unless qualified_const_defined? const
names = const.split('::')
if names.size == 1 || names.first.empty? # It's under Object
parent = Object
else
parent = (names[0..-2] * '::').constantize
end
parent.send :remove_const, names.last
true
end
end
# Determine if the given constant has been automatically loaded.
def autoloaded?(desc)
name = to_constant_name desc
return false unless qualified_const_defined? name
return autoloaded_constants.include?(name)
end
class LoadingModule
......@@ -84,6 +214,20 @@ def self.root(*args)
end
end
end
protected
# Convert the provided const desc to a qualified constant name (as a string).
# A module, class, symbol, or string may be provided.
def to_constant_name(desc)
name = case desc
when String then desc.starts_with?('::') ? desc[2..-1] : desc
when Symbol then desc.to_s
when Module then desc.name
else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
end
end
end
Object.send(:define_method, :require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load)
......@@ -97,37 +241,7 @@ class Module #:nodoc:
# Use const_missing to autoload associations so we don't have to
# require_association when using single-table inheritance.
def const_missing(class_id)
file_name = class_id.to_s.demodulize.underscore
file_path = as_load_path.empty? ? file_name : "#{as_load_path}/#{file_name}"
begin
require_dependency(file_path)
brief_name = self == Object ? '' : "#{name}::"
raise NameError.new("uninitialized constant #{brief_name}#{class_id}") unless const_defined?(class_id)
return const_get(class_id)
rescue MissingSourceFile => e
# Re-raise the error if it does not concern the file we were trying to load.
raise unless e.is_missing? file_path
# Look for a directory in the load path that we ought to load.
if $LOAD_PATH.any? { |base| File.directory? "#{base}/#{file_path}" }
mod = Module.new
const_set class_id, mod # Create the new module
return mod
end
# Attempt to access the name from the parent, unless we don't have a valid
# parent, or the constant is already defined in the parent. If the latter
# is the case, then we are being queried via self::class_id, and we should
# avoid returning the constant from the parent if possible.
if parent && parent != self && ! parents.any? { |p| p.const_defined?(class_id) }
suppress(NameError) do
return parent.send(:const_missing, class_id)
end
end
qualified_name = Dependencies.constant_path_for self, class_id
raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e)
end
Dependencies.load_missing_constant self, class_id
end
end
......@@ -140,9 +254,9 @@ def const_missing(class_id)
parent.send :const_missing, class_id
rescue NameError => e
# Make sure that the name we are missing is the one that caused the error
parent_qualified_name = Dependencies.constant_path_for parent, class_id
parent_qualified_name = Dependencies.qualified_name_for parent, class_id
raise unless e.missing_name? parent_qualified_name
qualified_name = Dependencies.constant_path_for self, class_id
qualified_name = Dependencies.qualified_name_for self, class_id
raise NameError.new("uninitialized constant #{qualified_name}").copy_blame!(e)
end
end
......
......@@ -49,24 +49,30 @@ def #{method_name}_with_deprecation(*args, &block)
module Assertions
def assert_deprecated(match = nil, &block)
last = with_last_message_tracking_deprecation_behavior(&block)
last = collect_deprecations(&block).last
assert last, "Expected a deprecation warning within the block but received none"
match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
assert_match match, last, "Deprecation warning didn't match #{match}: #{last}"
if match
match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
assert_match match, last, "Deprecation warning didn't match #{match}: #{last}"
end
end
def assert_not_deprecated(&block)
last = with_last_message_tracking_deprecation_behavior(&block)
assert_nil last, "Expected no deprecation warning within the block but received one: #{last}"
deprecations = collect_deprecations(&block)
assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
end
private
def with_last_message_tracking_deprecation_behavior
def collect_deprecations
old_behavior = ActiveSupport::Deprecation.behavior
last_message = nil
ActiveSupport::Deprecation.behavior = Proc.new { |message| last_message = message; old_behavior.call(message) if old_behavior }
deprecations = []
ActiveSupport::Deprecation.behavior = Proc.new do |message|
deprecations << message
old_behavior.call(message) if old_behavior
end
yield
last_message
return deprecations
ensure
ActiveSupport::Deprecation.behavior = old_behavior
end
......
# Classes that include this module will automatically be reloaded
# by the Rails dispatcher when Dependencies.mechanism = :load.
require 'active_support/deprecation'
# A deprecated mechanism to mark a class reloadable.
#
# Deprecated as of Rails 1.2.
# All autoloaded objects are now unloaded.
module Reloadable
class << self
def included(base) #nodoc:
unless base.ancestors.include?(Reloadable::Subclasses) # Avoid double warning
ActiveSupport::Deprecation.warn "Reloadable has been deprecated and has no effect.", caller
end
raise TypeError, "Only Classes can be Reloadable!" unless base.is_a? Class
unless base.respond_to?(:reloadable?)
class << base
define_method(:reloadable?) { true }
define_method(:reloadable?) do
ActiveSupport::Deprecation.warn "Reloadable has been deprecated and reloadable? has no effect", caller
true
end
end
end
end
......@@ -15,16 +27,37 @@ class << base
def reloadable_classes
included_in_classes.select { |klass| klass.reloadable? }
end
# Commented out so dispatcher doesn't warn. Should we just disable Reloadable?
# deprecate :reloadable_classes
end
# Captures the common pattern where a base class should not be reloaded,
# but its subclasses should be.
#
# Deprecated as of Rails 1.2.
# All autoloaded objects are now unloaded.
module Subclasses
def self.included(base) #nodoc:
base.send :include, Reloadable
ActiveSupport::Deprecation.warn "Reloadable::Subclasses has been deprecated and has no effect.", caller
(class << base; self; end).send(:define_method, :reloadable?) do
base != self
ActiveSupport::Deprecation.warn "Reloadable has been deprecated and reloadable? has no effect", caller
base != self
end
end
end
module Deprecated
def self.included(base)
class << base
define_method(:reloadable?) do
ActiveSupport::Deprecation.warn "Reloadable has been deprecated and reloadable? has no effect", caller
true # This might not have the desired effect, as AR::B.reloadable? => true.
end
end
end
end
end
\ No newline at end of file
Conflict = 2
\ No newline at end of file
require File.dirname(__FILE__) + '/abstract_unit'
require File.join(File.dirname(File.dirname(__FILE__)), 'lib/active_support/caching_tools.rb')
class HashCachingTests < Test::Unit::TestCase
def cached(&proc)
......
Conflict = 1
\ No newline at end of file
require File.dirname(__FILE__) + '/abstract_unit'
#require 'dependencies'
class DependenciesTest < Test::Unit::TestCase
def teardown
Dependencies.clear
end
def with_loading(from_dir = nil)
prior_path = $LOAD_PATH.clone
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/#{from_dir}" if from_dir
def with_loading(*from)
old_mechanism, Dependencies.mechanism = Dependencies.mechanism, :load
dir = File.dirname(__FILE__)
prior_autoload_paths = Dependencies.autoload_paths
Dependencies.autoload_paths = from.collect { |f| "#{dir}/#{f}" }
yield
ensure
$LOAD_PATH.clear
$LOAD_PATH.concat prior_path
Dependencies.autoload_paths = prior_autoload_paths
Dependencies.mechanism = old_mechanism
end
......@@ -159,13 +159,13 @@ def failing_test_access_thru_and_upwards_fails
def test_non_existing_const_raises_name_error_with_fully_qualified_name
with_loading 'autoloading_fixtures' do
begin
A::DoesNotExist
A::DoesNotExist.nil?
flunk "No raise!!"
rescue NameError => e
assert_equal "uninitialized constant A::DoesNotExist", e.message
end
begin
A::B::DoesNotExist
A::B::DoesNotExist.nil?
flunk "No raise!!"
rescue NameError => e
assert_equal "uninitialized constant A::B::DoesNotExist", e.message
......@@ -182,4 +182,122 @@ def test_smart_name_error_strings
end
end
def test_autoloadable_constants_for_path_should_handle_empty_autoloads
assert_equal [], Dependencies.autoloadable_constants_for_path('hello')
end
def test_autoloadable_constants_for_path_should_handle_relative_paths
fake_root = 'dependencies'
relative_root = File.dirname(__FILE__) + '/dependencies'
['', '/'].each do |suffix|
with_loading fake_root + suffix do
assert_equal ["A::B"], Dependencies.autoloadable_constants_for_path(relative_root + '/a/b')
end
end
end
def test_autoloadable_constants_for_path_should_provide_all_results
fake_root = '/usr/apps/backpack'
with_loading fake_root, fake_root + '/lib' do
root = Dependencies.autoload_paths.first
assert_equal ["Lib::A::B", "A::B"], Dependencies.autoloadable_constants_for_path(root + '/lib/a/b')
end
end
def test_autoloadable_constants_for_path_should_uniq_results
fake_root = '/usr/apps/backpack/lib'
with_loading fake_root, fake_root + '/' do
root = Dependencies.autoload_paths.first
assert_equal ["A::B"], Dependencies.autoloadable_constants_for_path(root + '/a/b')
end
end
def test_qualified_const_defined
assert Dependencies.qualified_const_defined?("Object")
assert Dependencies.qualified_const_defined?("::Object")
assert Dependencies.qualified_const_defined?("::Object::Kernel")
assert Dependencies.qualified_const_defined?("::Object::Dependencies")
assert Dependencies.qualified_const_defined?("::Test::Unit::TestCase")
end
def test_autoloaded?
with_loading 'autoloading_fixtures' do
assert ! Dependencies.autoloaded?("ModuleFolder")
assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
assert Dependencies.autoloaded?(ModuleFolder)
assert Dependencies.autoloaded?("ModuleFolder")
assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
assert Dependencies.autoloaded?(ModuleFolder::NestedClass)
assert Dependencies.autoloaded?("ModuleFolder")
assert Dependencies.autoloaded?("ModuleFolder::NestedClass")
assert Dependencies.autoloaded?("::ModuleFolder")
assert Dependencies.autoloaded?(:ModuleFolder)
Object.send :remove_const, :ModuleFolder
end
end
def test_qualified_name_for
assert_equal "A", Dependencies.qualified_name_for(Object, :A)
assert_equal "A", Dependencies.qualified_name_for(:Object, :A)
assert_equal "A", Dependencies.qualified_name_for("Object", :A)
assert_equal "A", Dependencies.qualified_name_for("::Object", :A)
assert_equal "A", Dependencies.qualified_name_for("::Kernel", :A)
assert_equal "Dependencies::A", Dependencies.qualified_name_for(:Dependencies, :A)
assert_equal "Dependencies::A", Dependencies.qualified_name_for(Dependencies, :A)
end
def test_file_search
with_loading 'dependencies' do
root = Dependencies.autoload_paths.first
assert_equal nil, Dependencies.search_for_autoload_file('service_three')
assert_equal nil, Dependencies.search_for_autoload_file('service_three.rb')
assert_equal root + '/service_one.rb', Dependencies.search_for_autoload_file('service_one')
assert_equal root + '/service_one.rb', Dependencies.search_for_autoload_file('service_one.rb')
end
end
def test_file_search_uses_first_in_autoload_path
with_loading 'dependencies', 'autoloading_fixtures' do
deps, autoload = Dependencies.autoload_paths
assert_match %r/dependencies/, deps
assert_match %r/autoloading_fixtures/, autoload
assert_equal deps + '/conflict.rb', Dependencies.search_for_autoload_file('conflict')
end
with_loading 'autoloading_fixtures', 'dependencies' do
autoload, deps = Dependencies.autoload_paths
assert_match %r/dependencies/, deps
assert_match %r/autoloading_fixtures/, autoload
assert_equal autoload + '/conflict.rb', Dependencies.search_for_autoload_file('conflict')
end
end
def test_custom_const_missing_should_work
Object.module_eval <<-end_eval
module ModuleWithCustomConstMissing
def self.const_missing(name)
const_set name, name.to_s.hash
end
module A
end
end
end_eval
with_loading 'autoloading_fixtures' do
assert_kind_of Integer, ::ModuleWithCustomConstMissing::B
assert_kind_of Module, ::ModuleWithCustomConstMissing::A
assert_kind_of String, ::ModuleWithCustomConstMissing::A::B
end
end
end
......@@ -39,7 +39,7 @@ def test_inline_deprecation_warning
@dtc.partially
end
end
def test_undeprecated
assert_not_deprecated do
assert_equal 2, @dtc.not
......@@ -67,8 +67,15 @@ def test_nil_behavior_is_ignored
def test_deprecated_instance_variable_proxy
assert_not_deprecated { @dtc.request.size }
assert_deprecated('@request.size') { assert_equal @dtc.request.size, @dtc.old_request.size }
assert_deprecated('@request.to_s') { assert_equal @dtc.request.to_s, @dtc.old_request.to_s }
end
def test_assert_deprecation_without_match
assert_deprecated do
@dtc.partially
end
end
end
......@@ -78,4 +78,36 @@ def test_removable_classes
assert ! results.include?(ReloadableTestSandbox.const_get(name)), "Expected #{name} NOT to be reloadable"
end
end
def test_including_reloadable_should_warn
c = Class.new
assert_deprecated %r{Reloadable} do
c.send :include, Reloadable
end
assert_deprecated { c.reloadable? }
end
def test_include_subclasses_should_warn
c = Class.new
deps = collect_deprecations do
c.send :include, Reloadable::Subclasses
end
assert_equal 1, deps.size
assert_match %r{Reloadable::Subclasses}, deps.first
assert_deprecated { c.reloadable? }
end
def test_include_deprecated_should_not_warn
c = Class.new
deps = collect_deprecations do
c.send :include, Reloadable::Deprecated
end
assert_equal 0, deps.size
assert c.respond_to?(:reloadable?)
assert_deprecated { c.reloadable? }
end
end
*SVN*
<<<<<<< .mine
* Add "require 'dispatcher'" to webrick server in the continuing quest to squash webrick weirdness. [Nicholas Seckar]
* Add autoload_paths support to Initializer. [Nicholas Seckar]
=======
* Fix Dispatcher.reset_application! so that AR subclasses are removed and Observers re-initialized *after* Reloadable classes are removed. Closes #5743. [Rick Olson]
* Clarify usage of script/plugin source. Closes #5344. [james.adam@gmail.com]
>>>>>>> .r4727
* Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook. [Nicholas Seckar]
* Tweak the Rails load order so observers are loaded after plugins, and reloaded in development mode. Closed #5279. [Rick Olson]
......
......@@ -80,6 +80,7 @@ def process
set_connection_adapters
require_frameworks
set_autoload_paths
load_environment
initialize_database
......@@ -125,6 +126,13 @@ def set_load_path
$LOAD_PATH.uniq!
end
# Set the paths from which Rails will automatically load source files.
def set_autoload_paths
Dependencies.autoload_paths = configuration.autoload_paths.uniq
# Freeze the array so future modifications will fail rather than do nothing mysteriously
configuration.autoload_paths.freeze
end
# Sets the +RAILS_CONNECTION_ADAPTERS+ constant based on the value of
# Configuration#connection_adapters. This constant is used to determine
# which database adapters should be loaded (by default, all adapters are
......@@ -412,6 +420,11 @@ class Configuration
# all +app+, +lib+, +vendor+ and mock paths are included in this list.
attr_accessor :load_paths
# An array of paths from which Rails will automatically load classes and
# modules from. By default, all +app+, +lib+, +vendor+ and mock paths are
# included in this list.
attr_accessor :autoload_paths
# The log level to use for the default Rails logger. In production mode,
# this defaults to <tt>:info</tt>. In development mode, it defaults to
# <tt>:debug</tt>.
......@@ -443,6 +456,7 @@ class Configuration
def initialize
self.frameworks = default_frameworks
self.load_paths = default_load_paths
self.autoload_paths = default_autoload_paths
self.log_path = default_log_path
self.log_level = default_log_level
self.view_path = default_view_path
......@@ -546,6 +560,33 @@ def default_load_paths
actionwebservice/lib
).map { |dir| "#{framework_root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
end
def default_autoload_paths
paths = []
# Add the app's controller directory
paths.concat(Dir["#{root_path}/app/controllers/"])
# Then model subdirectories.
# TODO: Don't include .rb models as load paths
paths.concat(Dir["#{root_path}/app/models/[_a-z]*"])
paths.concat(Dir["#{root_path}/components/[_a-z]*"])
# Followed by the standard includes.
paths.concat %w(
app
app/models
app/controllers
app/helpers
app/services
app/apis
components
config
lib
).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
paths.concat Dir["#{root_path}/vendor/plugins/*/lib/"]
end
def default_log_path
File.join(root_path, 'log', "#{environment}.log")
......
......@@ -3,6 +3,7 @@
require 'webrick'
require 'cgi'
require 'stringio'
require 'dispatcher'
include WEBrick
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册