Reorganize autoloads:

* A new module (ActiveSupport::Autoload) is provide that extends
    autoloading with new behavior.
  * All autoloads in modules that have extended ActiveSupport::Autoload
    will be eagerly required in threadsafe environments
  * Autoloads can optionally leave off the path if the path is the same
    as full_constant_name.underscore
  * It is possible to specify that a group of autoloads live under an
    additional path. For instance, all of ActionDispatch's middlewares
    are ActionDispatch::MiddlewareName, but they live under 
    "action_dispatch/middlewares/middleware_name"
  * It is possible to specify that a group of autoloads are all found
    at the same path. For instance, a number of exceptions might all
    be declared there.
  * One consequence of this is that testing-related constants are not
    autoloaded. To get the testing helpers for a given component,
    require "component_name/test_case". For instance, "action_controller/test_case".
  * test_help.rb, which is automatically required by a Rails application's
    test helper, requires the test_case.rb for all active components, so
    this change will not be disruptive in existing or new applications.
This commit is contained in:
Carlhuda 2009-12-02 20:01:01 -08:00
parent 399909b11c
commit c1304098cc
52 changed files with 1018 additions and 822 deletions

View File

@ -25,32 +25,34 @@ actionpack_path = "#{File.dirname(__FILE__)}/../../actionpack/lib"
$:.unshift(actionpack_path) if File.directory?(actionpack_path) $:.unshift(actionpack_path) if File.directory?(actionpack_path)
require 'action_controller' require 'action_controller'
require 'action_view' require 'action_view'
require 'active_support/autoload'
module ActionMailer module ActionMailer
def self.load_all! extend ::ActiveSupport::Autoload
[Base, Part, ::Text::Format, ::Net::SMTP]
end
autoload :AdvAttrAccessor, 'action_mailer/adv_attr_accessor' autoload :AdvAttrAccessor
autoload :DeprecatedBody, 'action_mailer/deprecated_body' autoload :DeprecatedBody
autoload :Base, 'action_mailer/base' autoload :Base
autoload :DeliveryMethod, 'action_mailer/delivery_method' autoload :DeliveryMethod
autoload :Part, 'action_mailer/part' autoload :MailHelper
autoload :PartContainer, 'action_mailer/part_container' autoload :Part
autoload :Quoting, 'action_mailer/quoting' autoload :PartContainer
autoload :TestCase, 'action_mailer/test_case' autoload :Quoting
autoload :TestHelper, 'action_mailer/test_helper' autoload :TestHelper
autoload :Utils, 'action_mailer/utils' autoload :Utils
end end
module Text module Text
extend ActiveSupport::Autoload
autoload :Format, 'action_mailer/vendor/text_format' autoload :Format, 'action_mailer/vendor/text_format'
end end
module Net module Net
autoload :SMTP, 'net/smtp' extend ActiveSupport::Autoload
autoload :SMTP
end end
autoload :MailHelper, 'action_mailer/mail_helper'
require 'action_mailer/vendor/tmail' require 'action_mailer/vendor/tmail'

View File

@ -258,7 +258,7 @@ module ActionMailer #:nodoc:
include AbstractController::Layouts include AbstractController::Layouts
include AbstractController::Helpers include AbstractController::Helpers
helper MailHelper helper ActionMailer::MailHelper
if Object.const_defined?(:ActionController) if Object.const_defined?(:ActionController)
include ActionController::UrlWriter include ActionController::UrlWriter

View File

@ -6,7 +6,7 @@ module ActionMailer
# A delivery method implementation which writes all mails to a file. # A delivery method implementation which writes all mails to a file.
class File < Method class File < Method
self.settings = { self.settings = {
:location => defined?(Rails) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails" :location => defined?(Rails.root) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
} }
def perform_delivery(mail) def perform_delivery(mail)

View File

@ -1,17 +1,19 @@
module MailHelper module ActionMailer
# Uses Text::Format to take the text and format it, indented two spaces for module MailHelper
# each line, and wrapped at 72 columns. # Uses Text::Format to take the text and format it, indented two spaces for
def block_format(text) # each line, and wrapped at 72 columns.
formatted = text.split(/\n\r\n/).collect { |paragraph| def block_format(text)
Text::Format.new( formatted = text.split(/\n\r\n/).collect { |paragraph|
:columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph Text::Format.new(
).format :columns => 72, :first_indent => 2, :body_indent => 2, :text => paragraph
}.join("\n") ).format
}.join("\n")
# Make list points stand on their own line # Make list points stand on their own line
formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" } formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" }
formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" } formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" }
formatted formatted
end
end end
end end

View File

@ -2,15 +2,20 @@ require "active_support/core_ext/module/attr_internal"
require "active_support/core_ext/module/delegation" require "active_support/core_ext/module/delegation"
module AbstractController module AbstractController
autoload :Base, "abstract_controller/base" extend ActiveSupport::Autoload
autoload :Callbacks, "abstract_controller/callbacks"
autoload :Helpers, "abstract_controller/helpers" autoload :Base
autoload :Layouts, "abstract_controller/layouts" autoload :Callbacks
autoload :LocalizedCache, "abstract_controller/localized_cache" autoload :Helpers
autoload :Logger, "abstract_controller/logger" autoload :Layouts
autoload :RenderingController, "abstract_controller/rendering_controller" autoload :LocalizedCache
autoload :Logger
autoload :RenderingController
# === Exceptions # === Exceptions
autoload :ActionNotFound, "abstract_controller/exceptions" autoload_at "abstract_controller/exceptions" do
autoload :DoubleRenderError, "abstract_controller/exceptions" autoload :ActionNotFound
autoload :Error, "abstract_controller/exceptions" autoload :DoubleRenderError
autoload :Error
end
end end

View File

@ -115,7 +115,7 @@ module AbstractController
# _partial<TrueClass, FalseClass>:: Whether or not the file to look up is a partial # _partial<TrueClass, FalseClass>:: Whether or not the file to look up is a partial
def _determine_template(options) def _determine_template(options)
if options.key?(:text) if options.key?(:text)
options[:_template] = ActionView::TextTemplate.new(options[:text], format_for_text) options[:_template] = ActionView::Template::Text.new(options[:text], format_for_text)
elsif options.key?(:inline) elsif options.key?(:inline)
handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb") handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb")
template = ActionView::Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) template = ActionView::Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})

View File

@ -1,66 +1,72 @@
require "active_support"
module ActionController module ActionController
autoload :Base, "action_controller/base" extend ActiveSupport::Autoload
autoload :Benchmarking, "action_controller/metal/benchmarking"
autoload :ConditionalGet, "action_controller/metal/conditional_get"
autoload :Configuration, "action_controller/metal/configuration"
autoload :Head, "action_controller/metal/head"
autoload :Helpers, "action_controller/metal/helpers"
autoload :HideActions, "action_controller/metal/hide_actions"
autoload :Layouts, "action_controller/metal/layouts"
autoload :Metal, "action_controller/metal"
autoload :Middleware, "action_controller/middleware"
autoload :RackConvenience, "action_controller/metal/rack_convenience"
autoload :Rails2Compatibility, "action_controller/metal/compatibility"
autoload :Redirector, "action_controller/metal/redirector"
autoload :RenderingController, "action_controller/metal/rendering_controller"
autoload :RenderOptions, "action_controller/metal/render_options"
autoload :Rescue, "action_controller/metal/rescuable"
autoload :Responder, "action_controller/metal/responder"
autoload :Session, "action_controller/metal/session"
autoload :Testing, "action_controller/metal/testing"
autoload :UrlFor, "action_controller/metal/url_for"
autoload :Caching, 'action_controller/caching' autoload :Base
autoload :Dispatcher, 'action_controller/dispatch/dispatcher' autoload :Caching
autoload :Integration, 'action_controller/deprecated/integration_test' autoload :PolymorphicRoutes
autoload :IntegrationTest, 'action_controller/deprecated/integration_test' autoload :RecordIdentifier
autoload :MimeResponds, 'action_controller/metal/mime_responds' autoload :UrlRewriter
autoload :PerformanceTest, 'action_controller/deprecated/performance_test' autoload :Translation
autoload :PolymorphicRoutes, 'action_controller/polymorphic_routes' autoload :Metal
autoload :RecordIdentifier, 'action_controller/record_identifier' autoload :Middleware
autoload :Routing, 'action_controller/deprecated'
autoload :SessionManagement, 'action_controller/metal/session_management'
autoload :TestCase, 'action_controller/testing/test_case'
autoload :TestProcess, 'action_controller/testing/process'
autoload :UrlRewriter, 'action_controller/url_rewriter'
autoload :UrlWriter, 'action_controller/url_rewriter'
autoload :Verification, 'action_controller/metal/verification' autoload_under "metal" do
autoload :Flash, 'action_controller/metal/flash' autoload :Benchmarking
autoload :RequestForgeryProtection, 'action_controller/metal/request_forgery_protection' autoload :ConditionalGet
autoload :Streaming, 'action_controller/metal/streaming' autoload :Configuration
autoload :HttpAuthentication, 'action_controller/metal/http_authentication' autoload :Head
autoload :FilterParameterLogging, 'action_controller/metal/filter_parameter_logging' autoload :Helpers
autoload :Translation, 'action_controller/translation' autoload :HideActions
autoload :Cookies, 'action_controller/metal/cookies' autoload :Layouts
autoload :MimeResponds
autoload :RackConvenience
autoload :Compatibility
autoload :Redirector
autoload :RenderingController
autoload :RenderOptions
autoload :Rescue
autoload :Responder
autoload :Session
autoload :SessionManagement
autoload :UrlFor
autoload :Verification
autoload :Flash
autoload :RequestForgeryProtection
autoload :Streaming
autoload :HttpAuthentication
autoload :FilterParameterLogging
autoload :Cookies
end
autoload :ActionControllerError, 'action_controller/metal/exceptions' autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
autoload :RenderError, 'action_controller/metal/exceptions' autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
autoload :RoutingError, 'action_controller/metal/exceptions' autoload :Routing, 'action_controller/deprecated'
autoload :MethodNotAllowed, 'action_controller/metal/exceptions' autoload :Integration, 'action_controller/deprecated/integration_test'
autoload :NotImplemented, 'action_controller/metal/exceptions' autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
autoload :UnknownController, 'action_controller/metal/exceptions'
autoload :MissingFile, 'action_controller/metal/exceptions' autoload :UrlWriter, 'action_controller/url_rewriter'
autoload :RenderError, 'action_controller/metal/exceptions'
autoload :SessionOverflowError, 'action_controller/metal/exceptions' autoload_at "action_controller/metal/exceptions" do
autoload :UnknownHttpMethod, 'action_controller/metal/exceptions' autoload :ActionControllerError
autoload :RenderError
autoload :RoutingError
autoload :MethodNotAllowed
autoload :NotImplemented
autoload :UnknownController
autoload :MissingFile
autoload :RenderError
autoload :SessionOverflowError
autoload :UnknownHttpMethod
end
end end
autoload :HTML, 'action_controller/vendor/html-scanner' # All of these simply register additional autoloads
autoload :AbstractController, 'abstract_controller' require 'abstract_controller'
require 'action_dispatch' require 'action_dispatch'
require 'action_view' require 'action_view'
require 'action_controller/vendor/html-scanner'
# Common ActiveSupport usage in ActionController # Common ActiveSupport usage in ActionController
require "active_support/concern" require "active_support/concern"

View File

@ -24,7 +24,7 @@ module ActionController
include ActionController::MimeResponds include ActionController::MimeResponds
# Rails 2.x compatibility # Rails 2.x compatibility
include ActionController::Rails2Compatibility include ActionController::Compatibility
include ActionController::Cookies include ActionController::Cookies
include ActionController::Session include ActionController::Session

View File

@ -30,10 +30,11 @@ module ActionController #:nodoc:
# config.action_controller.cache_store = MyOwnStore.new("parameter") # config.action_controller.cache_store = MyOwnStore.new("parameter")
module Caching module Caching
extend ActiveSupport::Concern extend ActiveSupport::Concern
extend ActiveSupport::Autoload
autoload :Actions, 'action_controller/caching/actions' autoload :Actions
autoload :Fragments, 'action_controller/caching/fragments' autoload :Fragments
autoload :Pages, 'action_controller/caching/pages' autoload :Pages
autoload :Sweeper, 'action_controller/caching/sweeping' autoload :Sweeper, 'action_controller/caching/sweeping'
autoload :Sweeping, 'action_controller/caching/sweeping' autoload :Sweeping, 'action_controller/caching/sweeping'

View File

@ -1,2 +1,4 @@
require "action_dispatch/testing/integration"
ActionController::Integration = ActionDispatch::Integration ActionController::Integration = ActionDispatch::Integration
ActionController::IntegrationTest = ActionDispatch::IntegrationTest ActionController::IntegrationTest = ActionDispatch::IntegrationTest

View File

@ -1,5 +1,5 @@
module ActionController module ActionController
module Rails2Compatibility module Compatibility
extend ActiveSupport::Concern extend ActiveSupport::Concern
class ::ActionController::ActionControllerError < StandardError #:nodoc: class ::ActionController::ActionControllerError < StandardError #:nodoc:

View File

@ -52,7 +52,7 @@ module ActionController
included do included do
# Set the default directory for helpers # Set the default directory for helpers
extlib_inheritable_accessor(:helpers_dir) do extlib_inheritable_accessor(:helpers_dir) do
defined?(Rails) ? "#{Rails.root}/app/helpers" : "app/helpers" defined?(Rails.root) ? "#{Rails.root}/app/helpers" : "app/helpers"
end end
end end

View File

@ -1,5 +1,8 @@
require 'active_support/test_case' require 'active_support/test_case'
require 'rack/session/abstract/id' require 'rack/session/abstract/id'
require 'action_controller/metal/testing'
require 'action_controller/testing/process'
require 'action_dispatch/test_case'
module ActionController module ActionController
class TestRequest < ActionDispatch::TestRequest #:nodoc: class TestRequest < ActionDispatch::TestRequest #:nodoc:

View File

@ -1,6 +1,8 @@
$LOAD_PATH << "#{File.dirname(__FILE__)}/html-scanner" $LOAD_PATH << "#{File.dirname(__FILE__)}/html-scanner"
module HTML module HTML
extend ActiveSupport::Autoload
autoload :CDATA, 'html/node' autoload :CDATA, 'html/node'
autoload :Document, 'html/document' autoload :Document, 'html/document'
autoload :FullSanitizer, 'html/sanitizer' autoload :FullSanitizer, 'html/sanitizer'

View File

@ -28,37 +28,38 @@ module Rack
end end
module ActionDispatch module ActionDispatch
autoload :Request, 'action_dispatch/http/request' extend ActiveSupport::Autoload
autoload :Response, 'action_dispatch/http/response'
autoload :StatusCodes, 'action_dispatch/http/status_codes' autoload_under "http" do
autoload :Utils, 'action_dispatch/http/utils' autoload :Request
autoload :Response
autoload :StatusCodes
autoload :Utils
end
autoload_under "middleware" do
autoload :Callbacks
autoload :ParamsParser
autoload :Rescue
autoload :ShowExceptions
autoload :Static
autoload :StringCoercion
end
autoload :Callbacks, 'action_dispatch/middleware/callbacks'
autoload :MiddlewareStack, 'action_dispatch/middleware/stack' autoload :MiddlewareStack, 'action_dispatch/middleware/stack'
autoload :ParamsParser, 'action_dispatch/middleware/params_parser' autoload :Routing
autoload :Rescue, 'action_dispatch/middleware/rescue'
autoload :ShowExceptions, 'action_dispatch/middleware/show_exceptions'
autoload :Static, 'action_dispatch/middleware/static'
autoload :StringCoercion, 'action_dispatch/middleware/string_coercion'
autoload :Routing, 'action_dispatch/routing'
autoload :Assertions, 'action_dispatch/testing/assertions'
autoload :Integration, 'action_dispatch/testing/integration'
autoload :IntegrationTest, 'action_dispatch/testing/integration'
autoload :PerformanceTest, 'action_dispatch/testing/performance_test'
autoload :TestRequest, 'action_dispatch/testing/test_request'
autoload :TestResponse, 'action_dispatch/testing/test_response'
autoload :HTML, 'action_controller/vendor/html-scanner' autoload :HTML, 'action_controller/vendor/html-scanner'
module Http module Http
autoload :Headers, 'action_dispatch/http/headers' extend ActiveSupport::Autoload
autoload :Headers
end end
module Session module Session
autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store' autoload :AbstractStore, 'action_dispatch/middleware/session/abstract_store'
autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store' autoload :CookieStore, 'action_dispatch/middleware/session/cookie_store'
autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store' autoload :MemCacheStore, 'action_dispatch/middleware/session/mem_cache_store'
end end
end end

View File

@ -29,7 +29,7 @@ module ActionDispatch
'ActionView::MissingTemplate' => 'missing_template', 'ActionView::MissingTemplate' => 'missing_template',
'ActionController::RoutingError' => 'routing_error', 'ActionController::RoutingError' => 'routing_error',
ActionController::UnknownAction.name => 'unknown_action', ActionController::UnknownAction.name => 'unknown_action',
'ActionView::TemplateError' => 'template_error' 'ActionView::Template::Error' => 'template_error'
}) })
FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'}, FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'},
@ -119,7 +119,7 @@ module ActionDispatch
return unless logger return unless logger
ActiveSupport::Deprecation.silence do ActiveSupport::Deprecation.silence do
if ActionView::TemplateError === exception if ActionView::Template::Error === exception
logger.fatal(exception.to_s) logger.fatal(exception.to_s)
else else
logger.fatal( logger.fatal(

View File

@ -0,0 +1,6 @@
require "action_dispatch/testing/assertions"
require "action_dispatch/testing/integration"
require "action_dispatch/testing/performance_test"
require "action_dispatch/testing/test_request"
require "action_dispatch/testing/test_response"
require "action_dispatch/testing/integration"

View File

@ -24,27 +24,25 @@
require File.join(File.dirname(__FILE__), "action_pack") require File.join(File.dirname(__FILE__), "action_pack")
module ActionView module ActionView
def self.load_all! extend ActiveSupport::Autoload
[Context, Base, TemplateError]
autoload :Base
autoload :Context
autoload :Template
autoload :Helpers
autoload :SafeBuffer
autoload_under "render" do
autoload :Partials
autoload :Rendering
end end
autoload :Base, 'action_view/base'
autoload :Context, 'action_view/context'
autoload :Helpers, 'action_view/helpers'
autoload :MissingTemplate, 'action_view/base' autoload :MissingTemplate, 'action_view/base'
autoload :Partials, 'action_view/render/partials'
autoload :Resolver, 'action_view/template/resolver' autoload :Resolver, 'action_view/template/resolver'
autoload :PathResolver, 'action_view/template/resolver' autoload :PathResolver, 'action_view/template/resolver'
autoload :PathSet, 'action_view/paths' autoload :PathSet, 'action_view/paths'
autoload :Rendering, 'action_view/render/rendering'
autoload :Template, 'action_view/template/template'
autoload :TemplateError, 'action_view/template/error'
autoload :TemplateHandler, 'action_view/template/handler'
autoload :TemplateHandlers, 'action_view/template/handlers'
autoload :TextTemplate, 'action_view/template/text'
autoload :Helpers, 'action_view/helpers'
autoload :FileSystemResolverWithFallback, 'action_view/template/resolver' autoload :FileSystemResolverWithFallback, 'action_view/template/resolver'
autoload :SafeBuffer, 'action_view/safe_buffer'
end end
require 'action_view/erb/util' require 'action_view/erb/util'

View File

@ -196,7 +196,7 @@ module ActionView #:nodoc:
end end
class << self class << self
delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB' delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
delegate :logger, :to => 'ActionController::Base', :allow_nil => true delegate :logger, :to => 'ActionController::Base', :allow_nil => true
end end

View File

@ -4,7 +4,7 @@ module ActionView #:nodoc:
# TODO: Clean this up # TODO: Clean this up
if obj.is_a?(String) if obj.is_a?(String)
if cache.nil? if cache.nil?
cache = !defined?(Rails) || Rails.application.config.cache_classes cache = !defined?(Rails.application) || Rails.application.config.cache_classes
end end
FileSystemResolverWithFallback.new(obj, :cache => cache) FileSystemResolverWithFallback.new(obj, :cache => cache)
else else

View File

@ -6,7 +6,14 @@ require "action_view/template/resolver"
module ActionView module ActionView
class Template class Template
extend TemplateHandlers extend ActiveSupport::Autoload
autoload :Error
autoload :Handler
autoload :Handlers
autoload :Text
extend Template::Handlers
attr_reader :source, :identifier, :handler, :mime_type, :formats, :details attr_reader :source, :identifier, :handler, :mime_type, :formats, :details
def initialize(source, identifier, handler, details) def initialize(source, identifier, handler, details)
@ -32,11 +39,11 @@ module ActionView
view.send(method_name, locals, &block) view.send(method_name, locals, &block)
end end
rescue Exception => e rescue Exception => e
if e.is_a?(TemplateError) if e.is_a?(Template::Error)
e.sub_template_of(self) e.sub_template_of(self)
raise e raise e
else else
raise TemplateError.new(self, view.assigns, e) raise Template::Error.new(self, view.assigns, e)
end end
end end
@ -103,7 +110,7 @@ module ActionView
logger.debug "Backtrace: #{e.backtrace.join("\n")}" logger.debug "Backtrace: #{e.backtrace.join("\n")}"
end end
raise ActionView::TemplateError.new(self, {}, e) raise ActionView::Template::Error.new(self, {}, e)
end end
end end

View File

@ -1,101 +1,103 @@
require "active_support/core_ext/enumerable" require "active_support/core_ext/enumerable"
module ActionView module ActionView
# The TemplateError exception is raised when the compilation of the template fails. This exception then gathers a class Template
# bunch of intimate details and uses it to report a very precise exception message. # The Template::Error exception is raised when the compilation of the template fails. This exception then gathers a
class TemplateError < ActionViewError #:nodoc: # bunch of intimate details and uses it to report a very precise exception message.
SOURCE_CODE_RADIUS = 3 class Error < ActionViewError #:nodoc:
SOURCE_CODE_RADIUS = 3
attr_reader :original_exception attr_reader :original_exception
def initialize(template, assigns, original_exception) def initialize(template, assigns, original_exception)
@template, @assigns, @original_exception = template, assigns.dup, original_exception @template, @assigns, @original_exception = template, assigns.dup, original_exception
@backtrace = compute_backtrace @backtrace = compute_backtrace
end
def file_name
@template.identifier
end
def message
ActiveSupport::Deprecation.silence { original_exception.message }
end
def clean_backtrace
if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
Rails.backtrace_cleaner.clean(original_exception.backtrace)
else
original_exception.backtrace
end end
end
def sub_template_message def file_name
if @sub_templates @template.identifier
"Trace of template inclusion: " +
@sub_templates.collect { |template| template.inspect }.join(", ")
else
""
end end
end
def source_extract(indentation = 0) def message
return unless num = line_number ActiveSupport::Deprecation.silence { original_exception.message }
num = num.to_i
source_code = @template.source.split("\n")
start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
indent = ' ' * indentation
line_counter = start_on_line
return unless source_code = source_code[start_on_line..end_on_line]
source_code.sum do |line|
line_counter += 1
"#{indent}#{line_counter}: #{line}\n"
end end
end
def sub_template_of(template_path) def clean_backtrace
@sub_templates ||= [] if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
@sub_templates << template_path Rails.backtrace_cleaner.clean(original_exception.backtrace)
end else
original_exception.backtrace
end
end
def line_number def sub_template_message
@line_number ||= if @sub_templates
if file_name "Trace of template inclusion: " +
regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/ @sub_templates.collect { |template| template.inspect }.join(", ")
else
""
end
end
$1 if message =~ regexp or clean_backtrace.find { |line| line =~ regexp } def source_extract(indentation = 0)
return unless num = line_number
num = num.to_i
source_code = @template.source.split("\n")
start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
indent = ' ' * indentation
line_counter = start_on_line
return unless source_code = source_code[start_on_line..end_on_line]
source_code.sum do |line|
line_counter += 1
"#{indent}#{line_counter}: #{line}\n"
end
end
def sub_template_of(template_path)
@sub_templates ||= []
@sub_templates << template_path
end
def line_number
@line_number ||=
if file_name
regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/
$1 if message =~ regexp or clean_backtrace.find { |line| line =~ regexp }
end
end
def to_s
"\n#{self.class} (#{message}) #{source_location}:\n" +
"#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n"
end
# don't do anything nontrivial here. Any raised exception from here becomes fatal
# (and can't be rescued).
def backtrace
@backtrace
end
private
def compute_backtrace
[
"#{source_location.capitalize}\n\n#{source_extract(4)}\n " +
clean_backtrace.join("\n ")
]
end
def source_location
if line_number
"on line ##{line_number} of "
else
'in '
end + file_name
end end
end end
def to_s
"\n#{self.class} (#{message}) #{source_location}:\n" +
"#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n"
end
# don't do anything nontrivial here. Any raised exception from here becomes fatal
# (and can't be rescued).
def backtrace
@backtrace
end
private
def compute_backtrace
[
"#{source_location.capitalize}\n\n#{source_extract(4)}\n " +
clean_backtrace.join("\n ")
]
end
def source_location
if line_number
"on line ##{line_number} of "
else
'in '
end + file_name
end
end end
end end

View File

@ -3,34 +3,39 @@ require "action_dispatch/http/mime_type"
# Legacy TemplateHandler stub # Legacy TemplateHandler stub
module ActionView module ActionView
module TemplateHandlers #:nodoc: class Template
module Compilable module Handlers #:nodoc:
def self.included(base) module Compilable
base.extend(ClassMethods) def self.included(base)
end base.extend(ClassMethods)
module ClassMethods
def call(template)
new.compile(template)
end end
module ClassMethods
def call(template)
new.compile(template)
end
end
def compile(template)
raise "Need to implement #{self.class.name}#compile(template)"
end
end
end
class Template::Handler
extlib_inheritable_accessor :default_format
self.default_format = Mime::HTML
def self.call(template)
raise "Need to implement #{self.class.name}#call(template)"
end end
def compile(template) def render(template, local_assigns)
raise "Need to implement #{self.class.name}#compile(template)" raise "Need to implement #{self.class.name}#render(template, local_assigns)"
end end
end
end
class TemplateHandler
extlib_inheritable_accessor :default_format
self.default_format = Mime::HTML
def self.call(template)
raise "Need to implement #{self.class.name}#call(template)"
end
def render(template, local_assigns)
raise "Need to implement #{self.class.name}#render(template, local_assigns)"
end end
end end
TemplateHandlers = Template::Handlers
TemplateHandler = Template::Handler
end end

View File

@ -1,52 +1,54 @@
module ActionView #:nodoc: module ActionView #:nodoc:
module TemplateHandlers #:nodoc: class Template
autoload :ERB, 'action_view/template/handlers/erb' module Handlers #:nodoc:
autoload :RJS, 'action_view/template/handlers/rjs' autoload :ERB, 'action_view/template/handlers/erb'
autoload :Builder, 'action_view/template/handlers/builder' autoload :RJS, 'action_view/template/handlers/rjs'
autoload :Builder, 'action_view/template/handlers/builder'
def self.extended(base) def self.extended(base)
base.register_default_template_handler :erb, TemplateHandlers::ERB base.register_default_template_handler :erb, ERB
base.register_template_handler :rjs, TemplateHandlers::RJS base.register_template_handler :rjs, RJS
base.register_template_handler :builder, TemplateHandlers::Builder base.register_template_handler :builder, Builder
# TODO: Depreciate old template extensions # TODO: Depreciate old template extensions
base.register_template_handler :rhtml, TemplateHandlers::ERB base.register_template_handler :rhtml, ERB
base.register_template_handler :rxml, TemplateHandlers::Builder base.register_template_handler :rxml, Builder
end end
@@template_handlers = {} @@template_handlers = {}
@@default_template_handlers = nil @@default_template_handlers = nil
def self.extensions def self.extensions
@@template_handlers.keys @@template_handlers.keys
end end
# Register a class that knows how to handle template files with the given # Register a class that knows how to handle template files with the given
# extension. This can be used to implement new template types. # extension. This can be used to implement new template types.
# The constructor for the class must take the ActiveView::Base instance # The constructor for the class must take the ActiveView::Base instance
# as a parameter, and the class must implement a +render+ method that # as a parameter, and the class must implement a +render+ method that
# takes the contents of the template to render as well as the Hash of # takes the contents of the template to render as well as the Hash of
# local assigns available to the template. The +render+ method ought to # local assigns available to the template. The +render+ method ought to
# return the rendered template as a string. # return the rendered template as a string.
def register_template_handler(extension, klass) def register_template_handler(extension, klass)
@@template_handlers[extension.to_sym] = klass @@template_handlers[extension.to_sym] = klass
end end
def template_handler_extensions def template_handler_extensions
@@template_handlers.keys.map {|key| key.to_s }.sort @@template_handlers.keys.map {|key| key.to_s }.sort
end end
def registered_template_handler(extension) def registered_template_handler(extension)
extension && @@template_handlers[extension.to_sym] extension && @@template_handlers[extension.to_sym]
end end
def register_default_template_handler(extension, klass) def register_default_template_handler(extension, klass)
register_template_handler(extension, klass) register_template_handler(extension, klass)
@@default_template_handlers = klass @@default_template_handlers = klass
end end
def handler_class_for_extension(extension) def handler_class_for_extension(extension)
(extension && registered_template_handler(extension.to_sym)) || @@default_template_handlers (extension && registered_template_handler(extension.to_sym)) || @@default_template_handlers
end
end end
end end
end end

View File

@ -1,6 +1,6 @@
module ActionView module ActionView
module TemplateHandlers module Template::Handlers
class Builder < TemplateHandler class Builder < Template::Handler
include Compilable include Compilable
self.default_format = Mime::XML self.default_format = Mime::XML

View File

@ -3,7 +3,7 @@ require 'active_support/core_ext/string/output_safety'
require 'erubis' require 'erubis'
module ActionView module ActionView
module TemplateHandlers module Template::Handlers
class Erubis < ::Erubis::Eruby class Erubis < ::Erubis::Eruby
def add_preamble(src) def add_preamble(src)
src << "@output_buffer = ActionView::SafeBuffer.new;" src << "@output_buffer = ActionView::SafeBuffer.new;"
@ -26,7 +26,7 @@ module ActionView
end end
end end
class ERB < TemplateHandler class ERB < Template::Handler
include Compilable include Compilable
## ##

View File

@ -1,6 +1,6 @@
module ActionView module ActionView
module TemplateHandlers module Template::Handlers
class RJS < TemplateHandler class RJS < Template::Handler
include Compilable include Compilable
self.default_format = Mime::JS self.default_format = Mime::JS

View File

@ -1,6 +1,6 @@
require "pathname" require "pathname"
require "active_support/core_ext/class" require "active_support/core_ext/class"
require "action_view/template/template" require "action_view/template"
module ActionView module ActionView
# Abstract superclass # Abstract superclass
@ -20,7 +20,7 @@ module ActionView
register_detail(:locale) { [I18n.locale] } register_detail(:locale) { [I18n.locale] }
register_detail(:formats) { Mime::SET.symbols } register_detail(:formats) { Mime::SET.symbols }
register_detail(:handlers, :allow_nil => false) do register_detail(:handlers, :allow_nil => false) do
TemplateHandlers.extensions Template::Handlers.extensions
end end
def initialize(options = {}) def initialize(options = {})
@ -65,7 +65,7 @@ module ActionView
# as well as incorrectly putting part of the path in the template # as well as incorrectly putting part of the path in the template
# name instead of the prefix. # name instead of the prefix.
def normalize_name(name, prefix) def normalize_name(name, prefix)
handlers = TemplateHandlers.extensions.join('|') handlers = Template::Handlers.extensions.join('|')
name = name.to_s.gsub(/\.(?:#{handlers})$/, '') name = name.to_s.gsub(/\.(?:#{handlers})$/, '')
parts = name.split('/') parts = name.split('/')

View File

@ -1,38 +1,40 @@
module ActionView #:nodoc: module ActionView #:nodoc:
class TextTemplate < String #:nodoc: class Template
HTML = Mime[:html] class Text < String #:nodoc:
HTML = Mime[:html]
def initialize(string, content_type = HTML) def initialize(string, content_type = HTML)
super(string.to_s) super(string.to_s)
@content_type = Mime[content_type] || content_type @content_type = Mime[content_type] || content_type
end end
def details def details
{:formats => [@content_type.to_sym]} {:formats => [@content_type.to_sym]}
end end
def identifier def identifier
self self
end end
def inspect def inspect
'text template' 'text template'
end end
def render(*args) def render(*args)
to_s to_s
end end
def mime_type def mime_type
@content_type @content_type
end end
def formats def formats
[mime_type] [mime_type]
end end
def partial? def partial?
false false
end
end end
end end
end end

View File

@ -1,5 +1,5 @@
require 'active_support/test_case' require 'active_support/test_case'
require 'action_controller/testing/test_case' require 'action_controller/test_case'
module ActionView module ActionView
class Base class Base

View File

@ -23,7 +23,7 @@ module AbstractControllerTests
self.view_paths = [] self.view_paths = []
def index def index
render :_template => ActionView::TextTemplate.new("Hello blank!") render :_template => ActionView::Template::Text.new("Hello blank!")
end end
end end
@ -31,19 +31,19 @@ module AbstractControllerTests
layout "hello" layout "hello"
def index def index
render :_template => ActionView::TextTemplate.new("Hello string!") render :_template => ActionView::Template::Text.new("Hello string!")
end end
def overwrite_default def overwrite_default
render :_template => ActionView::TextTemplate.new("Hello string!"), :layout => :default render :_template => ActionView::Template::Text.new("Hello string!"), :layout => :default
end end
def overwrite_false def overwrite_false
render :_template => ActionView::TextTemplate.new("Hello string!"), :layout => false render :_template => ActionView::Template::Text.new("Hello string!"), :layout => false
end end
def overwrite_string def overwrite_string
render :_template => ActionView::TextTemplate.new("Hello string!"), :layout => "omg" render :_template => ActionView::Template::Text.new("Hello string!"), :layout => "omg"
end end
def overwrite_skip def overwrite_skip
@ -72,7 +72,7 @@ module AbstractControllerTests
layout :hello layout :hello
def index def index
render :_template => ActionView::TextTemplate.new("Hello symbol!") render :_template => ActionView::Template::Text.new("Hello symbol!")
end end
private private
def hello def hello
@ -84,7 +84,7 @@ module AbstractControllerTests
layout :no_hello layout :no_hello
def index def index
render :_template => ActionView::TextTemplate.new("Hello missing symbol!") render :_template => ActionView::Template::Text.new("Hello missing symbol!")
end end
private private
def no_hello def no_hello
@ -96,7 +96,7 @@ module AbstractControllerTests
layout :nilz layout :nilz
def index def index
render :_template => ActionView::TextTemplate.new("Hello nilz!") render :_template => ActionView::Template::Text.new("Hello nilz!")
end end
def nilz() end def nilz() end
@ -106,7 +106,7 @@ module AbstractControllerTests
layout :objekt layout :objekt
def index def index
render :_template => ActionView::TextTemplate.new("Hello nilz!") render :_template => ActionView::Template::Text.new("Hello nilz!")
end end
def objekt def objekt
@ -118,7 +118,7 @@ module AbstractControllerTests
layout :omg_no_method layout :omg_no_method
def index def index
render :_template => ActionView::TextTemplate.new("Hello boom!") render :_template => ActionView::Template::Text.new("Hello boom!")
end end
end end
@ -126,7 +126,7 @@ module AbstractControllerTests
layout "missing" layout "missing"
def index def index
render :_template => ActionView::TextTemplate.new("Hello missing!") render :_template => ActionView::Template::Text.new("Hello missing!")
end end
end end
@ -134,7 +134,7 @@ module AbstractControllerTests
layout false layout false
def index def index
render :_template => ActionView::TextTemplate.new("Hello false!") render :_template => ActionView::Template::Text.new("Hello false!")
end end
end end
@ -142,7 +142,7 @@ module AbstractControllerTests
layout nil layout nil
def index def index
render :_template => ActionView::TextTemplate.new("Hello nil!") render :_template => ActionView::Template::Text.new("Hello nil!")
end end
end end

View File

@ -38,7 +38,7 @@ module AbstractController
end end
def object def object
render :_template => ActionView::TextTemplate.new("With Object") render :_template => ActionView::Template::Text.new("With Object")
end end
end end

View File

@ -191,7 +191,7 @@ class IsolatedHelpersTest < Test::Unit::TestCase
end end
def test_helper_in_a def test_helper_in_a
assert_raise(ActionView::TemplateError) { call_controller(A, "index") } assert_raise(ActionView::Template::Error) { call_controller(A, "index") }
end end
def test_helper_in_b def test_helper_in_b

View File

@ -115,7 +115,7 @@ class RendersNoLayoutController < LayoutTest
end end
class LayoutSetInResponseTest < ActionController::TestCase class LayoutSetInResponseTest < ActionController::TestCase
include ActionView::TemplateHandlers include ActionView::Template::Handlers
def test_layout_set_when_using_default_layout def test_layout_set_when_using_default_layout
@controller = DefaultLayoutController.new @controller = DefaultLayoutController.new

View File

@ -106,8 +106,8 @@ module RenderTestCases
def test_render_partial_with_errors def test_render_partial_with_errors
@view.render(:partial => "test/raise") @view.render(:partial => "test/raise")
flunk "Render did not raise TemplateError" flunk "Render did not raise Template::Error"
rescue ActionView::TemplateError => e rescue ActionView::Template::Error => e
assert_match "undefined local variable or method `doesnt_exist'", e.message assert_match "undefined local variable or method `doesnt_exist'", e.message
assert_equal "", e.sub_template_message assert_equal "", e.sub_template_message
assert_equal "1", e.line_number assert_equal "1", e.line_number
@ -116,8 +116,8 @@ module RenderTestCases
def test_render_sub_template_with_errors def test_render_sub_template_with_errors
@view.render(:file => "test/sub_template_raise") @view.render(:file => "test/sub_template_raise")
flunk "Render did not raise TemplateError" flunk "Render did not raise Template::Error"
rescue ActionView::TemplateError => e rescue ActionView::Template::Error => e
assert_match "undefined local variable or method `doesnt_exist'", e.message assert_match "undefined local variable or method `doesnt_exist'", e.message
assert_equal "Trace of template inclusion: #{File.expand_path("#{FIXTURE_LOAD_PATH}/test/sub_template_raise.html.erb")}", e.sub_template_message assert_equal "Trace of template inclusion: #{File.expand_path("#{FIXTURE_LOAD_PATH}/test/sub_template_raise.html.erb")}", e.sub_template_message
assert_equal "1", e.line_number assert_equal "1", e.line_number

View File

@ -26,28 +26,31 @@ $:.unshift(activesupport_path) if File.directory?(activesupport_path)
require 'active_support' require 'active_support'
module ActiveModel module ActiveModel
autoload :AttributeMethods, 'active_model/attribute_methods' extend ActiveSupport::Autoload
autoload :Conversion, 'active_model/conversion'
autoload :DeprecatedErrorMethods, 'active_model/deprecated_error_methods' autoload :AttributeMethods
autoload :Dirty, 'active_model/dirty' autoload :Conversion
autoload :Errors, 'active_model/errors' autoload :DeprecatedErrorMethods
autoload :Lint, 'active_model/lint' autoload :Dirty
autoload :Name, 'active_model/naming' autoload :Errors
autoload :Naming, 'active_model/naming' autoload :Lint
autoload :Observer, 'active_model/observing' autoload :Name, 'active_model/naming'
autoload :Observing, 'active_model/observing' autoload :Naming
autoload :Serialization, 'active_model/serialization' autoload :Observer, 'active_model/observing'
autoload :StateMachine, 'active_model/state_machine' autoload :Observing
autoload :TestCase, 'active_model/test_case' autoload :Serialization
autoload :Translation, 'active_model/translation' autoload :StateMachine
autoload :Validations, 'active_model/validations' autoload :Translation
autoload :ValidationsRepairHelper, 'active_model/validations_repair_helper' autoload :Validations
autoload :Validator, 'active_model/validator' autoload :ValidationsRepairHelper
autoload :VERSION, 'active_model/version' autoload :Validator
autoload :VERSION
module Serializers module Serializers
autoload :JSON, 'active_model/serializers/json' extend ActiveSupport::Autoload
autoload :Xml, 'active_model/serializers/xml'
autoload :JSON
autoload :Xml
end end
end end

View File

@ -10,6 +10,7 @@ $:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
require 'config' require 'config'
require 'active_model' require 'active_model'
require 'active_model/test_case'
# Show backtraces for deprecated behavior for quicker cleanup. # Show backtraces for deprecated behavior for quicker cleanup.
ActiveSupport::Deprecation.debug = true ActiveSupport::Deprecation.debug = true

View File

@ -2,6 +2,7 @@ require 'logger'
$:.unshift(File.dirname(__FILE__) + '/../../../activerecord/lib') $:.unshift(File.dirname(__FILE__) + '/../../../activerecord/lib')
require 'active_record' require 'active_record'
require 'active_record/test_case'
require 'active_record/fixtures' require 'active_record/fixtures'
module ActiveModel module ActiveModel

View File

@ -32,64 +32,66 @@ require 'active_model'
require 'arel' require 'arel'
module ActiveRecord module ActiveRecord
# TODO: Review explicit loads to see if they will automatically be handled by the initializer. extend ActiveSupport::Autoload
def self.load_all!
[Base, DynamicFinderMatch, ConnectionAdapters::AbstractAdapter]
end
autoload :VERSION, 'active_record/version' autoload :VERSION
autoload :ActiveRecordError, 'active_record/base' autoload :ActiveRecordError, 'active_record/base'
autoload :ConnectionNotEstablished, 'active_record/base' autoload :ConnectionNotEstablished, 'active_record/base'
autoload :Aggregations, 'active_record/aggregations' autoload :Aggregations
autoload :AssociationPreload, 'active_record/association_preload' autoload :AssociationPreload
autoload :Associations, 'active_record/associations' autoload :Associations
autoload :AttributeMethods, 'active_record/attribute_methods' autoload :AttributeMethods
autoload :Attributes, 'active_record/attributes' autoload :Attributes
autoload :AutosaveAssociation, 'active_record/autosave_association' autoload :AutosaveAssociation
autoload :Relation, 'active_record/relation' autoload :Relation
autoload :Base, 'active_record/base' autoload :Base
autoload :Batches, 'active_record/batches' autoload :Batches
autoload :Calculations, 'active_record/calculations' autoload :Calculations
autoload :Callbacks, 'active_record/callbacks' autoload :Callbacks
autoload :DynamicFinderMatch, 'active_record/dynamic_finder_match' autoload :DynamicFinderMatch
autoload :DynamicScopeMatch, 'active_record/dynamic_scope_match' autoload :DynamicScopeMatch
autoload :Migration, 'active_record/migration' autoload :Migration
autoload :Migrator, 'active_record/migration' autoload :Migrator, 'active_record/migration'
autoload :NamedScope, 'active_record/named_scope' autoload :NamedScope
autoload :NestedAttributes, 'active_record/nested_attributes' autoload :NestedAttributes
autoload :Observer, 'active_record/observer' autoload :Observer
autoload :QueryCache, 'active_record/query_cache' autoload :QueryCache
autoload :Reflection, 'active_record/reflection' autoload :Reflection
autoload :Schema, 'active_record/schema' autoload :Schema
autoload :SchemaDumper, 'active_record/schema_dumper' autoload :SchemaDumper
autoload :Serialization, 'active_record/serialization' autoload :Serialization
autoload :SessionStore, 'active_record/session_store' autoload :SessionStore
autoload :StateMachine, 'active_record/state_machine' autoload :StateMachine
autoload :TestCase, 'active_record/test_case' autoload :Timestamp
autoload :Timestamp, 'active_record/timestamp' autoload :Transactions
autoload :Transactions, 'active_record/transactions' autoload :Types
autoload :Types, 'active_record/types' autoload :Validations
autoload :Validations, 'active_record/validations'
module AttributeMethods module AttributeMethods
autoload :BeforeTypeCast, 'active_record/attribute_methods/before_type_cast' extend ActiveSupport::Autoload
autoload :Dirty, 'active_record/attribute_methods/dirty'
autoload :PrimaryKey, 'active_record/attribute_methods/primary_key' autoload :BeforeTypeCast
autoload :Query, 'active_record/attribute_methods/query' autoload :Dirty
autoload :Read, 'active_record/attribute_methods/read' autoload :PrimaryKey
autoload :TimeZoneConversion, 'active_record/attribute_methods/time_zone_conversion' autoload :Query
autoload :Write, 'active_record/attribute_methods/write' autoload :Read
autoload :TimeZoneConversion
autoload :Write
end end
module Attributes module Attributes
autoload :Aliasing, 'active_record/attributes/aliasing' extend ActiveSupport::Autoload
autoload :Store, 'active_record/attributes/store'
autoload :Typecasting, 'active_record/attributes/typecasting' autoload :Aliasing
autoload :Store
autoload :Typecasting
end end
module Type module Type
extend ActiveSupport::Autoload
autoload :Number, 'active_record/types/number' autoload :Number, 'active_record/types/number'
autoload :Object, 'active_record/types/object' autoload :Object, 'active_record/types/object'
autoload :Serialize, 'active_record/types/serialize' autoload :Serialize, 'active_record/types/serialize'
@ -98,12 +100,16 @@ module ActiveRecord
end end
module Locking module Locking
autoload :Optimistic, 'active_record/locking/optimistic' extend ActiveSupport::Autoload
autoload :Pessimistic, 'active_record/locking/pessimistic'
autoload :Optimistic
autoload :Pessimistic
end end
module ConnectionAdapters module ConnectionAdapters
autoload :AbstractAdapter, 'active_record/connection_adapters/abstract_adapter' extend ActiveSupport::Autoload
autoload :AbstractAdapter
end end
end end

View File

@ -30,11 +30,13 @@ $:.unshift(activemodel_path) if File.directory?(activemodel_path)
require 'active_model' require 'active_model'
module ActiveResource module ActiveResource
autoload :Base, 'active_resource/base' extend ActiveSupport::Autoload
autoload :Connection, 'active_resource/connection'
autoload :CustomMethods, 'active_resource/custom_methods' autoload :Base
autoload :Formats, 'active_resource/formats' autoload :Connection
autoload :Observing, 'active_resource/observing' autoload :CustomMethods
autoload :Validations, 'active_resource/validations' autoload :Formats
autoload :HttpMock, 'active_resource/http_mock' autoload :Observing
autoload :Validations
autoload :HttpMock
end end

View File

@ -13,6 +13,7 @@ require 'test/unit'
require 'active_support' require 'active_support'
require 'active_support/test_case' require 'active_support/test_case'
require 'active_resource' require 'active_resource'
require 'active_model/test_case'
$:.unshift "#{File.dirname(__FILE__)}/../test" $:.unshift "#{File.dirname(__FILE__)}/../test"
require 'setter_trap' require 'setter_trap'

View File

@ -543,9 +543,9 @@ class BaseTest < Test::Unit::TestCase
assert Person.collection_path(:gender => 'male', :student => true).include?('gender=male') assert Person.collection_path(:gender => 'male', :student => true).include?('gender=male')
assert Person.collection_path(:gender => 'male', :student => true).include?('student=true') assert Person.collection_path(:gender => 'male', :student => true).include?('student=true')
assert_equal '/people.xml?name%5B%5D=bob&name%5B%5D=your+uncle%2Bme&name%5B%5D=&name%5B%5D=false', Person.collection_path(:name => ['bob', 'your uncle+me', nil, false]) assert_equal '/people.xml?name[]=bob&name[]=your+uncle%2Bme&name[]=&name[]=false', Person.collection_path(:name => ['bob', 'your uncle+me', nil, false])
assert_equal '/people.xml?struct%5Ba%5D%5B%5D=2&struct%5Ba%5D%5B%5D=1&struct%5Bb%5D=fred', Person.collection_path(:struct => {:a => [2,1], 'b' => 'fred'}) assert_equal '/people.xml?struct[a][]=2&struct[a][]=1&struct[b]=fred', Person.collection_path(:struct => {:a => [2,1], 'b' => 'fred'})
end end
def test_custom_element_path def test_custom_element_path
@ -581,7 +581,7 @@ class BaseTest < Test::Unit::TestCase
assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, :person_id => 1, :type => 'work') assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, :person_id => 1, :type => 'work')
assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, 'person_id' => 1, :type => 'work') assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, 'person_id' => 1, :type => 'work')
assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, :type => 'work', :person_id => 1) assert_equal '/people/1/addresses/1.xml?type=work', StreetAddress.element_path(1, :type => 'work', :person_id => 1)
assert_equal '/people/1/addresses/1.xml?type%5B%5D=work&type%5B%5D=play+time', StreetAddress.element_path(1, :person_id => 1, :type => ['work', 'play time']) assert_equal '/people/1/addresses/1.xml?type[]=work&type[]=play+time', StreetAddress.element_path(1, :person_id => 1, :type => ['work', 'play time'])
end end
def test_custom_element_path_with_prefix_and_parameters def test_custom_element_path_with_prefix_and_parameters

View File

@ -1,28 +1,31 @@
require "active_support/dependencies/autoload"
module ActiveSupport module ActiveSupport
autoload :BacktraceCleaner, 'active_support/backtrace_cleaner' extend ActiveSupport::Autoload
autoload :Base64, 'active_support/base64'
autoload :BasicObject, 'active_support/basic_object' autoload :BacktraceCleaner
autoload :Benchmarkable, 'active_support/benchmarkable' autoload :Base64
autoload :BufferedLogger, 'active_support/buffered_logger' autoload :BasicObject
autoload :Cache, 'active_support/cache' autoload :Benchmarkable
autoload :Callbacks, 'active_support/callbacks' autoload :BufferedLogger
autoload :Concern, 'active_support/concern' autoload :Cache
autoload :Configurable, 'active_support/configurable' autoload :Callbacks
autoload :DependencyModule, 'active_support/dependency_module' autoload :Concern
autoload :DeprecatedCallbacks, 'active_support/deprecated_callbacks' autoload :Configurable
autoload :Deprecation, 'active_support/deprecation' autoload :DeprecatedCallbacks
autoload :Gzip, 'active_support/gzip' autoload :Deprecation
autoload :Inflector, 'active_support/inflector' autoload :Gzip
autoload :Memoizable, 'active_support/memoizable' autoload :Inflector
autoload :MessageEncryptor, 'active_support/message_encryptor' autoload :Memoizable
autoload :MessageVerifier, 'active_support/message_verifier' autoload :MessageEncryptor
autoload :Multibyte, 'active_support/multibyte' autoload :MessageVerifier
autoload :OptionMerger, 'active_support/option_merger' autoload :Multibyte
autoload :OrderedHash, 'active_support/ordered_hash' autoload :OptionMerger
autoload :OrderedOptions, 'active_support/ordered_options' autoload :OrderedHash
autoload :Notifications, 'active_support/notifications' autoload :OrderedOptions
autoload :Rescuable, 'active_support/rescuable' autoload :Notifications
autoload :SecureRandom, 'active_support/secure_random' autoload :Rescuable
autoload :StringInquirer, 'active_support/string_inquirer' autoload :SecureRandom
autoload :XmlMini, 'active_support/xml_mini' autoload :StringInquirer
autoload :XmlMini
end end

View File

@ -0,0 +1,37 @@
require "active_support/inflector/methods"
module ActiveSupport
module Autoload
@@autoloads = {}
@@under_path = nil
@@at_path = nil
def autoload(const_name, path = @@at_path)
full = [self.name, @@under_path, const_name.to_s, path].compact.join("::")
location = path || Inflector.underscore(full)
@@autoloads[const_name] = location
super const_name, location
end
def autoload_under(path)
@@under_path, old_path = path, @@under_path
yield
ensure
@@under_path = old_path
end
def autoload_at(path)
@@at_path, old_path = path, @@at_path
yield
ensure
@@at_path = old_path
end
def self.eager_autoload!
@@autoloads.values.each {|file| require file }
end
end
end

View File

@ -1,450 +1,454 @@
require 'ruby-prof' begin
require 'ruby-prof'
require 'fileutils' require 'fileutils'
require 'rails/version' require 'rails/version'
require 'active_support/core_ext/class/delegating_attributes'
module ActiveSupport module ActiveSupport
module Testing module Testing
module Performance module Performance
DEFAULTS = DEFAULTS =
if benchmark = ARGV.include?('--benchmark') # HAX for rake test if benchmark = ARGV.include?('--benchmark') # HAX for rake test
{ :benchmark => true, { :benchmark => true,
:runs => 4, :runs => 4,
:metrics => [:wall_time, :memory, :objects, :gc_runs, :gc_time], :metrics => [:wall_time, :memory, :objects, :gc_runs, :gc_time],
:output => 'tmp/performance' } :output => 'tmp/performance' }
else else
{ :benchmark => false, { :benchmark => false,
:runs => 1, :runs => 1,
:min_percent => 0.01, :min_percent => 0.01,
:metrics => [:process_time, :memory, :objects], :metrics => [:process_time, :memory, :objects],
:formats => [:flat, :graph_html, :call_tree], :formats => [:flat, :graph_html, :call_tree],
:output => 'tmp/performance' } :output => 'tmp/performance' }
end.freeze end.freeze
def self.included(base) def self.included(base)
base.superclass_delegating_accessor :profile_options base.superclass_delegating_accessor :profile_options
base.profile_options = DEFAULTS base.profile_options = DEFAULTS
end
def full_test_name
"#{self.class.name}##{method_name}"
end
def run(result)
return if method_name =~ /^default_test$/
yield(self.class::STARTED, name)
@_result = result
run_warmup
if profile_options && metrics = profile_options[:metrics]
metrics.each do |metric_name|
if klass = Metrics[metric_name.to_sym]
run_profile(klass.new)
result.add_run
end
end
end end
yield(self.class::FINISHED, name) def full_test_name
end "#{self.class.name}##{method_name}"
end
def run_test(metric, mode) def run(result)
run_callbacks :setup return if method_name =~ /^default_test$/
setup
metric.send(mode) { __send__ @method_name } yield(self.class::STARTED, name)
rescue ::Test::Unit::AssertionFailedError => e @_result = result
add_failure(e.message, e.backtrace)
rescue StandardError, ScriptError run_warmup
add_error($!) if profile_options && metrics = profile_options[:metrics]
ensure metrics.each do |metric_name|
begin if klass = Metrics[metric_name.to_sym]
teardown run_profile(klass.new)
run_callbacks :teardown, :enumerator => :reverse_each result.add_run
end
end
end
yield(self.class::FINISHED, name)
end
def run_test(metric, mode)
run_callbacks :setup
setup
metric.send(mode) { __send__ @method_name }
rescue ::Test::Unit::AssertionFailedError => e rescue ::Test::Unit::AssertionFailedError => e
add_failure(e.message, e.backtrace) add_failure(e.message, e.backtrace)
rescue StandardError, ScriptError rescue StandardError, ScriptError
add_error($!) add_error($!)
end ensure
end begin
teardown
protected run_callbacks :teardown, :enumerator => :reverse_each
def run_warmup rescue ::Test::Unit::AssertionFailedError => e
GC.start add_failure(e.message, e.backtrace)
rescue StandardError, ScriptError
time = Metrics::Time.new add_error($!)
run_test(time, :benchmark)
puts "%s (%s warmup)" % [full_test_name, time.format(time.total)]
GC.start
end
def run_profile(metric)
klass = profile_options[:benchmark] ? Benchmarker : Profiler
performer = klass.new(self, metric)
performer.run
puts performer.report
performer.record
end
class Performer
delegate :run_test, :profile_options, :full_test_name, :to => :@harness
def initialize(harness, metric)
@harness, @metric = harness, metric
end
def report
rate = @total / profile_options[:runs]
'%20s: %s' % [@metric.name, @metric.format(rate)]
end
protected
def output_filename
"#{profile_options[:output]}/#{full_test_name}_#{@metric.name}"
end
end
class Benchmarker < Performer
def run
profile_options[:runs].to_i.times { run_test(@metric, :benchmark) }
@total = @metric.total
end
def record
avg = @metric.total / profile_options[:runs].to_i
now = Time.now.utc.xmlschema
with_output_file do |file|
file.puts "#{avg},#{now},#{environment}"
end
end
def environment
unless defined? @env
app = "#{$1}.#{$2}" if File.directory?('.git') && `git branch -v` =~ /^\* (\S+)\s+(\S+)/
rails = Rails::VERSION::STRING
if File.directory?('vendor/rails/.git')
Dir.chdir('vendor/rails') do
rails += ".#{$1}.#{$2}" if `git branch -v` =~ /^\* (\S+)\s+(\S+)/
end
end
ruby = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
ruby += "-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
@env = [app, rails, ruby, RUBY_PLATFORM] * ','
end
@env
end
protected
HEADER = 'measurement,created_at,app,rails,ruby,platform'
def with_output_file
fname = output_filename
if new = !File.exist?(fname)
FileUtils.mkdir_p(File.dirname(fname))
end
File.open(fname, 'ab') do |file|
file.puts(HEADER) if new
yield file
end
end
def output_filename
"#{super}.csv"
end
end
class Profiler < Performer
def initialize(*args)
super
@supported = @metric.measure_mode rescue false
end
def run
return unless @supported
RubyProf.measure_mode = @metric.measure_mode
RubyProf.start
RubyProf.pause
profile_options[:runs].to_i.times { run_test(@metric, :profile) }
@data = RubyProf.stop
@total = @data.threads.values.sum(0) { |method_infos| method_infos.sort.last.total_time }
end
def report
if @supported
super
else
'%20s: unsupported' % @metric.name
end
end
def record
return unless @supported
klasses = profile_options[:formats].map { |f| RubyProf.const_get("#{f.to_s.camelize}Printer") }.compact
klasses.each do |klass|
fname = output_filename(klass)
FileUtils.mkdir_p(File.dirname(fname))
File.open(fname, 'wb') do |file|
klass.new(@data).print(file, profile_options.slice(:min_percent))
end
end end
end end
protected protected
def output_filename(printer_class) def run_warmup
suffix = GC.start
case printer_class.name.demodulize
when 'FlatPrinter'; 'flat.txt'
when 'GraphPrinter'; 'graph.txt'
when 'GraphHtmlPrinter'; 'graph.html'
when 'CallTreePrinter'; 'tree.txt'
else printer_class.name.sub(/Printer$/, '').underscore
end
"#{super()}_#{suffix}" time = Metrics::Time.new
end run_test(time, :benchmark)
end puts "%s (%s warmup)" % [full_test_name, time.format(time.total)]
module Metrics GC.start
def self.[](name)
const_get(name.to_s.camelize)
rescue NameError
nil
end
class Base
attr_reader :total
def initialize
@total = 0
end end
def name def run_profile(metric)
@name ||= self.class.name.demodulize.underscore klass = profile_options[:benchmark] ? Benchmarker : Profiler
performer = klass.new(self, metric)
performer.run
puts performer.report
performer.record
end end
def measure_mode class Performer
self.class::Mode delegate :run_test, :profile_options, :full_test_name, :to => :@harness
def initialize(harness, metric)
@harness, @metric = harness, metric
end end
def measure def report
0 rate = @total / profile_options[:runs]
end '%20s: %s' % [@metric.name, @metric.format(rate)]
def benchmark
with_gc_stats do
before = measure
yield
@total += (measure - before)
end
end
def profile
RubyProf.resume
yield
ensure
RubyProf.pause
end end
protected protected
if GC.respond_to?(:enable_stats) def output_filename
def with_gc_stats "#{profile_options[:output]}/#{full_test_name}_#{@metric.name}"
GC.enable_stats
yield
ensure
GC.disable_stats
end
elsif defined?(GC::Profiler)
def with_gc_stats
GC.start
GC.disable
GC::Profiler.enable
yield
ensure
GC::Profiler.disable
GC.enable
end
else
def with_gc_stats
yield
end
end end
end end
class Time < Base class Benchmarker < Performer
def measure def run
::Time.now.to_f profile_options[:runs].to_i.times { run_test(@metric, :benchmark) }
@total = @metric.total
end end
def format(measurement) def record
if measurement < 2 avg = @metric.total / profile_options[:runs].to_i
'%d ms' % (measurement * 1000) now = Time.now.utc.xmlschema
else with_output_file do |file|
'%.2f sec' % measurement file.puts "#{avg},#{now},#{environment}"
end end
end end
end
class ProcessTime < Time def environment
Mode = RubyProf::PROCESS_TIME unless defined? @env
app = "#{$1}.#{$2}" if File.directory?('.git') && `git branch -v` =~ /^\* (\S+)\s+(\S+)/
def measure rails = Rails::VERSION::STRING
RubyProf.measure_process_time if File.directory?('vendor/rails/.git')
Dir.chdir('vendor/rails') do
rails += ".#{$1}.#{$2}" if `git branch -v` =~ /^\* (\S+)\s+(\S+)/
end
end
ruby = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
ruby += "-#{RUBY_VERSION}.#{RUBY_PATCHLEVEL}"
@env = [app, rails, ruby, RUBY_PLATFORM] * ','
end
@env
end end
protected
HEADER = 'measurement,created_at,app,rails,ruby,platform'
def with_output_file
fname = output_filename
if new = !File.exist?(fname)
FileUtils.mkdir_p(File.dirname(fname))
end
File.open(fname, 'ab') do |file|
file.puts(HEADER) if new
yield file
end
end
def output_filename
"#{super}.csv"
end
end end
class WallTime < Time class Profiler < Performer
Mode = RubyProf::WALL_TIME
def measure
RubyProf.measure_wall_time
end
end
class CpuTime < Time
Mode = RubyProf::CPU_TIME if RubyProf.const_defined?(:CPU_TIME)
def initialize(*args) def initialize(*args)
# FIXME: yeah my CPU is 2.33 GHz
RubyProf.cpu_frequency = 2.33e9
super super
@supported = @metric.measure_mode rescue false
end end
def measure def run
RubyProf.measure_cpu_time return unless @supported
RubyProf.measure_mode = @metric.measure_mode
RubyProf.start
RubyProf.pause
profile_options[:runs].to_i.times { run_test(@metric, :profile) }
@data = RubyProf.stop
@total = @data.threads.values.sum(0) { |method_infos| method_infos.sort.last.total_time }
end end
def report
if @supported
super
else
'%20s: unsupported' % @metric.name
end
end
def record
return unless @supported
klasses = profile_options[:formats].map { |f| RubyProf.const_get("#{f.to_s.camelize}Printer") }.compact
klasses.each do |klass|
fname = output_filename(klass)
FileUtils.mkdir_p(File.dirname(fname))
File.open(fname, 'wb') do |file|
klass.new(@data).print(file, profile_options.slice(:min_percent))
end
end
end
protected
def output_filename(printer_class)
suffix =
case printer_class.name.demodulize
when 'FlatPrinter'; 'flat.txt'
when 'GraphPrinter'; 'graph.txt'
when 'GraphHtmlPrinter'; 'graph.html'
when 'CallTreePrinter'; 'tree.txt'
else printer_class.name.sub(/Printer$/, '').underscore
end
"#{super()}_#{suffix}"
end
end end
class Memory < Base module Metrics
Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY) def self.[](name)
const_get(name.to_s.camelize)
rescue NameError
nil
end
# ruby-prof wrapper class Base
if RubyProf.respond_to?(:measure_memory) attr_reader :total
def measure
RubyProf.measure_memory / 1024.0 def initialize
@total = 0
end end
# Ruby 1.8 + railsbench patch def name
elsif GC.respond_to?(:allocated_size) @name ||= self.class.name.demodulize.underscore
def measure
GC.allocated_size / 1024.0
end end
# Ruby 1.8 + lloyd patch def measure_mode
elsif GC.respond_to?(:heap_info) self.class::Mode
def measure
GC.heap_info['heap_current_memory'] / 1024.0
end end
# Ruby 1.9 with total_malloc_allocated_size patch
elsif GC.respond_to?(:malloc_total_allocated_size)
def measure def measure
GC.total_malloc_allocated_size / 1024.0 0
end end
# Ruby 1.9 unpatched def benchmark
elsif GC.respond_to?(:malloc_allocated_size) with_gc_stats do
def measure before = measure
GC.malloc_allocated_size / 1024.0 yield
@total += (measure - before)
end
end end
# Ruby 1.9 + GC profiler patch def profile
elsif defined?(GC::Profiler) RubyProf.resume
yield
ensure
RubyProf.pause
end
protected
if GC.respond_to?(:enable_stats)
def with_gc_stats
GC.enable_stats
yield
ensure
GC.disable_stats
end
elsif defined?(GC::Profiler)
def with_gc_stats
GC.start
GC.disable
GC::Profiler.enable
yield
ensure
GC::Profiler.disable
GC.enable
end
else
def with_gc_stats
yield
end
end
end
class Time < Base
def measure def measure
GC.enable ::Time.now.to_f
GC.start end
kb = GC::Profiler.data.last[:HEAP_USE_SIZE] / 1024.0
GC.disable def format(measurement)
kb if measurement < 2
'%d ms' % (measurement * 1000)
else
'%.2f sec' % measurement
end
end end
end end
def format(measurement) class ProcessTime < Time
'%.2f KB' % measurement Mode = RubyProf::PROCESS_TIME
end
end
class Objects < Base
Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
if RubyProf.respond_to?(:measure_allocations)
def measure def measure
RubyProf.measure_allocations RubyProf.measure_process_time
end
# Ruby 1.8 + railsbench patch
elsif ObjectSpace.respond_to?(:allocated_objects)
def measure
ObjectSpace.allocated_objects
end
# Ruby 1.9 + GC profiler patch
elsif defined?(GC::Profiler)
def measure
GC.enable
GC.start
last = GC::Profiler.data.last
count = last[:HEAP_LIVE_OBJECTS] + last[:HEAP_FREE_OBJECTS]
GC.disable
count
end end
end end
def format(measurement) class WallTime < Time
measurement.to_i.to_s Mode = RubyProf::WALL_TIME
end
end
class GcRuns < Base
Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
if RubyProf.respond_to?(:measure_gc_runs)
def measure def measure
RubyProf.measure_gc_runs RubyProf.measure_wall_time
end
elsif GC.respond_to?(:collections)
def measure
GC.collections
end
elsif GC.respond_to?(:heap_info)
def measure
GC.heap_info['num_gc_passes']
end end
end end
def format(measurement) class CpuTime < Time
measurement.to_i.to_s Mode = RubyProf::CPU_TIME if RubyProf.const_defined?(:CPU_TIME)
end
end
class GcTime < Base def initialize(*args)
Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME) # FIXME: yeah my CPU is 2.33 GHz
RubyProf.cpu_frequency = 2.33e9
if RubyProf.respond_to?(:measure_gc_time) super
def measure
RubyProf.measure_gc_time
end end
elsif GC.respond_to?(:time)
def measure def measure
GC.time RubyProf.measure_cpu_time
end end
end end
def format(measurement) class Memory < Base
'%d ms' % (measurement / 1000) Mode = RubyProf::MEMORY if RubyProf.const_defined?(:MEMORY)
# ruby-prof wrapper
if RubyProf.respond_to?(:measure_memory)
def measure
RubyProf.measure_memory / 1024.0
end
# Ruby 1.8 + railsbench patch
elsif GC.respond_to?(:allocated_size)
def measure
GC.allocated_size / 1024.0
end
# Ruby 1.8 + lloyd patch
elsif GC.respond_to?(:heap_info)
def measure
GC.heap_info['heap_current_memory'] / 1024.0
end
# Ruby 1.9 with total_malloc_allocated_size patch
elsif GC.respond_to?(:malloc_total_allocated_size)
def measure
GC.total_malloc_allocated_size / 1024.0
end
# Ruby 1.9 unpatched
elsif GC.respond_to?(:malloc_allocated_size)
def measure
GC.malloc_allocated_size / 1024.0
end
# Ruby 1.9 + GC profiler patch
elsif defined?(GC::Profiler)
def measure
GC.enable
GC.start
kb = GC::Profiler.data.last[:HEAP_USE_SIZE] / 1024.0
GC.disable
kb
end
end
def format(measurement)
'%.2f KB' % measurement
end
end
class Objects < Base
Mode = RubyProf::ALLOCATIONS if RubyProf.const_defined?(:ALLOCATIONS)
if RubyProf.respond_to?(:measure_allocations)
def measure
RubyProf.measure_allocations
end
# Ruby 1.8 + railsbench patch
elsif ObjectSpace.respond_to?(:allocated_objects)
def measure
ObjectSpace.allocated_objects
end
# Ruby 1.9 + GC profiler patch
elsif defined?(GC::Profiler)
def measure
GC.enable
GC.start
last = GC::Profiler.data.last
count = last[:HEAP_LIVE_OBJECTS] + last[:HEAP_FREE_OBJECTS]
GC.disable
count
end
end
def format(measurement)
measurement.to_i.to_s
end
end
class GcRuns < Base
Mode = RubyProf::GC_RUNS if RubyProf.const_defined?(:GC_RUNS)
if RubyProf.respond_to?(:measure_gc_runs)
def measure
RubyProf.measure_gc_runs
end
elsif GC.respond_to?(:collections)
def measure
GC.collections
end
elsif GC.respond_to?(:heap_info)
def measure
GC.heap_info['num_gc_passes']
end
end
def format(measurement)
measurement.to_i.to_s
end
end
class GcTime < Base
Mode = RubyProf::GC_TIME if RubyProf.const_defined?(:GC_TIME)
if RubyProf.respond_to?(:measure_gc_time)
def measure
RubyProf.measure_gc_time
end
elsif GC.respond_to?(:time)
def measure
GC.time
end
end
def format(measurement)
'%d ms' % (measurement / 1000)
end
end end
end end
end end
end end
end end
end rescue LoadError
end

View File

@ -0,0 +1,80 @@
require 'abstract_unit'
class TestAutoloadModule < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
module ::Fixtures
extend ActiveSupport::Autoload
module Autoload
extend ActiveSupport::Autoload
end
end
test "the autoload module works like normal autoload" do
module ::Fixtures::Autoload
autoload :SomeClass, "fixtures/autoload/some_class"
end
assert_nothing_raised { ::Fixtures::Autoload::SomeClass }
end
test "when specifying an :eager constant it still works like normal autoload by default" do
module ::Fixtures::Autoload
autoload :SomeClass, "fixtures/autoload/some_class"
end
assert !$LOADED_FEATURES.include?("fixtures/autoload/some_class.rb")
assert_nothing_raised { ::Fixtures::Autoload::SomeClass }
end
test ":eager constants can be triggered via ActiveSupport::Autoload.eager_autoload!" do
module ::Fixtures::Autoload
autoload :SomeClass, "fixtures/autoload/some_class"
end
ActiveSupport::Autoload.eager_autoload!
assert $LOADED_FEATURES.include?("fixtures/autoload/some_class.rb")
assert_nothing_raised { ::Fixtures::Autoload::SomeClass }
end
test "the location of autoloaded constants defaults to :name.underscore" do
module ::Fixtures::Autoload
autoload :SomeClass
end
assert !$LOADED_FEATURES.include?("fixtures/autoload/some_class.rb")
assert_nothing_raised { ::Fixtures::Autoload::SomeClass }
end
test "the location of :eager autoloaded constants defaults to :name.underscore" do
module ::Fixtures::Autoload
autoload :SomeClass
end
ActiveSupport::Autoload.eager_autoload!
assert $LOADED_FEATURES.include?("fixtures/autoload/some_class.rb")
assert_nothing_raised { ::Fixtures::Autoload::SomeClass }
end
test "a directory for a block of autoloads can be specified" do
module ::Fixtures
autoload_under "autoload" do
autoload :AnotherClass
end
end
assert !$LOADED_FEATURES.include?("fixtures/autoload/another_class.rb")
assert_nothing_raised { ::Fixtures::AnotherClass }
end
test "a path for a block of autoloads can be specified" do
module ::Fixtures
autoload_at "fixtures/autoload/another_class" do
autoload :AnotherClass
end
end
assert !$LOADED_FEATURES.include?("fixtures/autoload/another_class.rb")
assert_nothing_raised { ::Fixtures::AnotherClass }
end
end

View File

@ -0,0 +1,2 @@
class Fixtures::AnotherClass
end

View File

@ -0,0 +1,2 @@
class Fixtures::Autoload::SomeClass
end

View File

@ -1,6 +1,7 @@
require 'active_support/all' require 'active_support/all'
require 'active_support/test_case' require 'active_support/test_case'
require 'action_controller' require 'action_controller'
require 'action_dispatch/test_case'
# work around the at_exit hook in test/unit, which kills IRB # work around the at_exit hook in test/unit, which kills IRB
Test::Unit.run = true if Test::Unit.respond_to?(:run=) Test::Unit.run = true if Test::Unit.respond_to?(:run=)

View File

@ -8,8 +8,14 @@ gem "rack-test", "~> 0.5.0"
require 'test/unit' require 'test/unit'
require 'active_support/core_ext/kernel/requires' require 'active_support/core_ext/kernel/requires'
# AP is always present
require 'action_controller/test_case'
require 'action_view/test_case' require 'action_view/test_case'
require 'action_dispatch/test_case'
require 'action_mailer/test_case' if defined?(ActionMailer) require 'action_mailer/test_case' if defined?(ActionMailer)
require 'active_model/test_case' if defined?(ActiveModel)
if defined?(ActiveRecord) if defined?(ActiveRecord)
require 'active_record/test_case' require 'active_record/test_case'

View File

@ -1,5 +1,6 @@
require 'abstract_unit' require 'abstract_unit'
require 'action_controller' require 'action_controller'
require 'action_controller/test_case'
require 'rails/info' require 'rails/info'
require 'rails/info_controller' require 'rails/info_controller'