aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/CHANGELOG2
-rw-r--r--actionmailer/lib/action_mailer/base.rb2
-rw-r--r--actionpack/CHANGELOG5
-rwxr-xr-xactionpack/lib/action_controller/base.rb2
-rw-r--r--actionpack/lib/action_controller/caching.rb3
-rw-r--r--actionpack/lib/action_controller/layout.rb1
-rw-r--r--actionpack/test/template/compiled_templates_test.rb1
-rw-r--r--actionwebservice/CHANGELOG2
-rw-r--r--actionwebservice/lib/action_web_service/api.rb2
-rw-r--r--actionwebservice/lib/action_web_service/base.rb2
-rw-r--r--actionwebservice/lib/action_web_service/struct.rb2
-rw-r--r--activerecord/CHANGELOG5
-rwxr-xr-xactiverecord/lib/active_record/base.rb4
-rw-r--r--activerecord/lib/active_record/observer.rb2
-rw-r--r--activesupport/CHANGELOG5
-rw-r--r--activesupport/lib/active_support/dependencies.rb194
-rw-r--r--activesupport/lib/active_support/deprecation.rb24
-rw-r--r--activesupport/lib/active_support/reloadable.rb41
-rw-r--r--activesupport/test/autoloading_fixtures/conflict.rb1
-rw-r--r--activesupport/test/caching_tools_test.rb1
-rw-r--r--activesupport/test/dependencies/conflict.rb1
-rw-r--r--activesupport/test/dependencies_test.rb134
-rw-r--r--activesupport/test/deprecation_test.rb11
-rw-r--r--activesupport/test/reloadable_test.rb32
-rw-r--r--railties/CHANGELOG7
-rw-r--r--railties/lib/initializer.rb41
-rw-r--r--railties/lib/webrick_server.rb1
27 files changed, 455 insertions, 73 deletions
diff --git a/actionmailer/CHANGELOG b/actionmailer/CHANGELOG
index 15d482bf2c..01bcc9a2d7 100644
--- a/actionmailer/CHANGELOG
+++ b/actionmailer/CHANGELOG
@@ -1,5 +1,7 @@
*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]
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index d667ef1f4b..873eb3c9c9 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -187,7 +187,7 @@ module ActionMailer #:nodoc:
# 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:
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index faf5228dee..92dee9b40f 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,11 +1,16 @@
*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]
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 2125637192..8c03f86609 100755
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -206,7 +206,7 @@ module ActionController #:nodoc:
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.
diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb
index 0536cf43ff..5e1475357e 100644
--- a/actionpack/lib/action_controller/caching.rb
+++ b/actionpack/lib/action_controller/caching.rb
@@ -1,4 +1,5 @@
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 @@ 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
- include Reloadable::Subclasses
+ include Reloadable::Deprecated
def before(controller)
self.controller = controller
diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/layout.rb
index 91ca16913e..338d5980ab 100644
--- a/actionpack/lib/action_controller/layout.rb
+++ b/actionpack/lib/action_controller/layout.rb
@@ -183,7 +183,6 @@ module ActionController #: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
diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb
index 3bb1e58c1a..e46543d645 100644
--- a/actionpack/test/template/compiled_templates_test.rb
+++ b/actionpack/test/template/compiled_templates_test.rb
@@ -1,5 +1,6 @@
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
diff --git a/actionwebservice/CHANGELOG b/actionwebservice/CHANGELOG
index ee3e8b3746..a389382c75 100644
--- a/actionwebservice/CHANGELOG
+++ b/actionwebservice/CHANGELOG
@@ -1,5 +1,7 @@
*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.]
diff --git a/actionwebservice/lib/action_web_service/api.rb b/actionwebservice/lib/action_web_service/api.rb
index 7193bd8a51..73fb886e6d 100644
--- a/actionwebservice/lib/action_web_service/api.rb
+++ b/actionwebservice/lib/action_web_service/api.rb
@@ -16,7 +16,7 @@ module ActionWebService # :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
diff --git a/actionwebservice/lib/action_web_service/base.rb b/actionwebservice/lib/action_web_service/base.rb
index 5675a5bd2b..43c7b6fa26 100644
--- a/actionwebservice/lib/action_web_service/base.rb
+++ b/actionwebservice/lib/action_web_service/base.rb
@@ -33,7 +33,7 @@ module ActionWebService # :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
diff --git a/actionwebservice/lib/action_web_service/struct.rb b/actionwebservice/lib/action_web_service/struct.rb
index d065dae03b..af93f65a4e 100644
--- a/actionwebservice/lib/action_web_service/struct.rb
+++ b/actionwebservice/lib/action_web_service/struct.rb
@@ -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.
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index a700efb112..c9ffa888cb 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,11 +1,16 @@
*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]
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 5e9d18e5d4..d1d10b41b4 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -264,7 +264,7 @@ module ActiveRecord #:nodoc:
# 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 @@ module ActiveRecord #:nodoc:
def self.reset_subclasses #:nodoc:
nonreloadables = []
subclasses.each do |klass|
- unless klass.reloadable?
+ unless Dependencies.autoloaded? klass
nonreloadables << klass
next
end
diff --git a/activerecord/lib/active_record/observer.rb b/activerecord/lib/active_record/observer.rb
index 262f12d91e..e8ab95642f 100644
--- a/activerecord/lib/active_record/observer.rb
+++ b/activerecord/lib/active_record/observer.rb
@@ -129,7 +129,7 @@ module ActiveRecord
# 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.
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 3ddfc19643..d8cc98cd97 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,9 @@
*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]
diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb
index a58989173e..e845408137 100644
--- a/activesupport/lib/active_support/dependencies.rb
+++ b/activesupport/lib/active_support/dependencies.rb
@@ -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 @@ module Dependencies #:nodoc:
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 @@ module Dependencies #:nodoc:
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 @@ module Dependencies #:nodoc:
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 @@ module Dependencies #:nodoc:
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 @@ class Class
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
diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb
index 5aff753616..d6c9317f06 100644
--- a/activesupport/lib/active_support/deprecation.rb
+++ b/activesupport/lib/active_support/deprecation.rb
@@ -49,24 +49,30 @@ module ActiveSupport
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
diff --git a/activesupport/lib/active_support/reloadable.rb b/activesupport/lib/active_support/reloadable.rb
index 3fd13e3d0f..3f57723e15 100644
--- a/activesupport/lib/active_support/reloadable.rb
+++ b/activesupport/lib/active_support/reloadable.rb
@@ -1,13 +1,25 @@
-# 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 @@ module Reloadable
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
diff --git a/activesupport/test/autoloading_fixtures/conflict.rb b/activesupport/test/autoloading_fixtures/conflict.rb
new file mode 100644
index 0000000000..4ac6201902
--- /dev/null
+++ b/activesupport/test/autoloading_fixtures/conflict.rb
@@ -0,0 +1 @@
+Conflict = 2 \ No newline at end of file
diff --git a/activesupport/test/caching_tools_test.rb b/activesupport/test/caching_tools_test.rb
index c9890e4d13..e1cd4e433c 100644
--- a/activesupport/test/caching_tools_test.rb
+++ b/activesupport/test/caching_tools_test.rb
@@ -1,4 +1,5 @@
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)
diff --git a/activesupport/test/dependencies/conflict.rb b/activesupport/test/dependencies/conflict.rb
new file mode 100644
index 0000000000..e888b7b54c
--- /dev/null
+++ b/activesupport/test/dependencies/conflict.rb
@@ -0,0 +1 @@
+Conflict = 1 \ No newline at end of file
diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb
index f19542bdb0..bf9aaac8c1 100644
--- a/activesupport/test/dependencies_test.rb
+++ b/activesupport/test/dependencies_test.rb
@@ -1,19 +1,19 @@
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 @@ class DependenciesTest < Test::Unit::TestCase
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 @@ class DependenciesTest < Test::Unit::TestCase
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
diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb
index 472fdecaaf..1a054335d7 100644
--- a/activesupport/test/deprecation_test.rb
+++ b/activesupport/test/deprecation_test.rb
@@ -39,7 +39,7 @@ class DeprecationTest < Test::Unit::TestCase
@dtc.partially
end
end
-
+
def test_undeprecated
assert_not_deprecated do
assert_equal 2, @dtc.not
@@ -67,8 +67,15 @@ class DeprecationTest < Test::Unit::TestCase
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
diff --git a/activesupport/test/reloadable_test.rb b/activesupport/test/reloadable_test.rb
index c330394b29..2ab19db77e 100644
--- a/activesupport/test/reloadable_test.rb
+++ b/activesupport/test/reloadable_test.rb
@@ -78,4 +78,36 @@ class ReloadableTest < Test::Unit::TestCase
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
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 50daa2f009..413639a61d 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,9 +1,16 @@
*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]
diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb
index 8abc3231db..ef83c2c259 100644
--- a/railties/lib/initializer.rb
+++ b/railties/lib/initializer.rb
@@ -80,6 +80,7 @@ module Rails
set_connection_adapters
require_frameworks
+ set_autoload_paths
load_environment
initialize_database
@@ -125,6 +126,13 @@ module Rails
$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 @@ module Rails
# 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 @@ module Rails
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 @@ module Rails
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")
diff --git a/railties/lib/webrick_server.rb b/railties/lib/webrick_server.rb
index 8f4ddb11a3..984638c8cc 100644
--- a/railties/lib/webrick_server.rb
+++ b/railties/lib/webrick_server.rb
@@ -3,6 +3,7 @@
require 'webrick'
require 'cgi'
require 'stringio'
+require 'dispatcher'
include WEBrick