diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb index 7f5bcad922776..43d73e71b9b62 100644 --- a/actionmailer/lib/action_mailer.rb +++ b/actionmailer/lib/action_mailer.rb @@ -34,6 +34,7 @@ require 'active_support/core_ext/module/attr_internal' require 'active_support/core_ext/module/delegation' require 'active_support/core_ext/string/inflections' +require 'active_support/lazy_load_hooks' module ActionMailer extend ::ActiveSupport::Autoload diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index 48d6bbc8d9754..246816e9531c1 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -291,6 +291,8 @@ class Base < AbstractController::Base :parts_order => [ "text/plain", "text/enriched", "text/html" ] }.freeze + ActionMailer.run_base_hooks(self) + class << self def mailer_name diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index c5f18c7911c3a..0182e48425f64 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -6,19 +6,21 @@ class Railtie < Rails::Railtie railtie_name :action_mailer initializer "action_mailer.url_for", :before => :load_environment_config do |app| - ActionMailer::Base.send(:include, app.routes.url_helpers) + ActionMailer.base_hook { include app.routes.url_helpers } end require "action_mailer/railties/log_subscriber" log_subscriber ActionMailer::Railties::LogSubscriber.new initializer "action_mailer.logger" do - ActionMailer::Base.logger ||= Rails.logger + ActionMailer.base_hook { self.logger ||= Rails.logger } end initializer "action_mailer.set_configs" do |app| - app.config.action_mailer.each do |k,v| - ActionMailer::Base.send "#{k}=", v + ActionMailer.base_hook do + app.config.action_mailer.each do |k,v| + send "#{k}=", v + end end end end diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 78871154c3438..d00afa6d4e9c4 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -58,6 +58,8 @@ def self.filter_parameter_logging(*args, &block) filter end + ActionController.run_base_hooks(self) + end end diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index e9edf80451a88..ca03fc62da771 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -40,7 +40,7 @@ class Railtie < Rails::Railtie log_subscriber ActionController::Railties::LogSubscriber.new initializer "action_controller.logger" do - ActionController::Base.logger ||= Rails.logger + ActionController.base_hook { self.logger ||= Rails.logger } end initializer "action_controller.set_configs" do |app| @@ -51,19 +51,23 @@ class Railtie < Rails::Railtie ac.stylesheets_dir = paths.public.stylesheets.to_a.first ac.secret = app.config.cookie_secret - ActionController::Base.config.replace(ac) + ActionController.base_hook { self.config.replace(ac) } end initializer "action_controller.initialize_framework_caches" do - ActionController::Base.cache_store ||= RAILS_CACHE + ActionController.base_hook { self.cache_store ||= RAILS_CACHE } end initializer "action_controller.set_helpers_path" do |app| - ActionController::Base.helpers_path = app.config.paths.app.helpers.to_a + ActionController.base_hook do + self.helpers_path = app.config.paths.app.helpers.to_a + end end initializer "action_controller.url_helpers" do |app| - ActionController::Base.extend ::ActionController::Railtie::UrlHelpers.with(app.routes) + ActionController.base_hook do + extend ::ActionController::Railtie::UrlHelpers.with(app.routes) + end message = "ActionController::Routing::Routes is deprecated. " \ "Instead, use Rails.application.routes" diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index 522982e2024f9..f4c4324fb0f38 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -1,4 +1,3 @@ -require 'active_support/json' require 'action_dispatch/http/request' module ActionDispatch diff --git a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb index db64711052c81..22da82479e3df 100644 --- a/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb +++ b/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb @@ -1,5 +1,4 @@ require 'active_support/core_ext/hash/keys' -require 'rack/request' module ActionDispatch module Session diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb index 18a2922fa79e8..c52c8c0e6a6cd 100644 --- a/actionpack/lib/action_dispatch/middleware/stack.rb +++ b/actionpack/lib/action_dispatch/middleware/stack.rb @@ -58,7 +58,7 @@ def ==(middleware) if lazy_compare?(@klass) && lazy_compare?(middleware) normalize(@klass) == normalize(middleware) else - klass == ActiveSupport::Inflector.constantize(middleware.to_s) + klass.name == middleware.to_s end end end diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 52e7b0e77df80..52a8df4273c95 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -1,3 +1,5 @@ +require "active_support/core_ext/hash/except" + module ActionDispatch module Routing class Mapper @@ -85,7 +87,7 @@ def conditions end def requirements - @requirements ||= returning(@options[:constraints] || {}) do |requirements| + @requirements ||= (@options[:constraints] || {}).tap do |requirements| requirements.reverse_merge!(@scope[:constraints]) if @scope[:constraints] @options.each { |k, v| requirements[k] = v if v.is_a?(Regexp) } end diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index f5035fe45a2ff..33bf0b8debede 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -41,6 +41,7 @@ module ActionView autoload :Rendering end + autoload :Base autoload :MissingTemplate, 'action_view/base' autoload :Resolver, 'action_view/template/resolver' autoload :PathResolver, 'action_view/template/resolver' @@ -56,6 +57,5 @@ module ActionView end require 'active_support/core_ext/string/output_safety' -require 'action_view/base' I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml" diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 76f9eb2b0d72d..e88ccc645e281 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -177,6 +177,8 @@ module Subclasses extend ActiveSupport::Memoizable + ActionView.run_base_hooks(self) + attr_accessor :base_path, :assigns, :template_extension attr_internal :captures diff --git a/actionpack/lib/action_view/helpers/active_model_helper.rb b/actionpack/lib/action_view/helpers/active_model_helper.rb index ed83b8a8b2e22..4e12cdab5463e 100644 --- a/actionpack/lib/action_view/helpers/active_model_helper.rb +++ b/actionpack/lib/action_view/helpers/active_model_helper.rb @@ -5,9 +5,11 @@ require 'active_support/core_ext/kernel/reporting' module ActionView - class Base - @@field_error_proc = Proc.new{ |html_tag, instance| "
#{html_tag}
".html_safe } - cattr_accessor :field_error_proc + ActionView.base_hook do + class ActionView::Base + @@field_error_proc = Proc.new{ |html_tag, instance| "
#{html_tag}
".html_safe } + cattr_accessor :field_error_proc + end end module Helpers diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb index ace3bcfde37f2..742e873a4953e 100644 --- a/actionpack/lib/action_view/helpers/form_helper.rb +++ b/actionpack/lib/action_view/helpers/form_helper.rb @@ -1211,8 +1211,10 @@ def nested_child_index(name) end end - class Base - cattr_accessor :default_form_builder - @@default_form_builder = ::ActionView::Helpers::FormBuilder + ActionView.base_hook do + class ActionView::Base + cattr_accessor :default_form_builder + @@default_form_builder = ::ActionView::Helpers::FormBuilder + end end end diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb index 03f18ac172294..2e5d115630317 100644 --- a/actionpack/lib/action_view/railtie.rb +++ b/actionpack/lib/action_view/railtie.rb @@ -10,7 +10,9 @@ class Railtie < Rails::Railtie initializer "action_view.cache_asset_timestamps" do |app| unless app.config.cache_classes - ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false + ActionView.base_hook do + ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false + end end end end diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index 72dbead14be08..1578ac94794f4 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -1,4 +1,5 @@ require 'action_controller/test_case' +require 'action_view' module ActionView class Base diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index d103c4e485243..67aa412d3d085 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -16,7 +16,6 @@ require 'abstract_controller' require 'action_controller' require 'action_view' -require 'action_view/base' require 'action_dispatch' require 'fixture_template' require 'active_support/dependencies' diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb index b79da4565d858..5942640c855d7 100644 --- a/activerecord/lib/active_record.rb +++ b/activerecord/lib/active_record.rb @@ -30,7 +30,6 @@ require 'active_support' require 'active_model' -require 'arel' module ActiveRecord extend ActiveSupport::Autoload @@ -38,8 +37,8 @@ module ActiveRecord eager_autoload do autoload :VERSION - autoload :ActiveRecordError, 'active_record/base' - autoload :ConnectionNotEstablished, 'active_record/base' + autoload :ActiveRecordError, 'active_record/errors' + autoload :ConnectionNotEstablished, 'active_record/errors' autoload :Aggregations autoload :AssociationPreload @@ -106,12 +105,16 @@ module ConnectionAdapters eager_autoload do autoload :AbstractAdapter + autoload :ConnectionManagement, "active_record/connection_adapters/abstract/connection_pool" end end autoload :TestCase autoload :TestFixtures, 'active_record/fixtures' + + base_hook do + Arel::Table.engine = Arel::Sql::Engine.new(self) + end end -Arel::Table.engine = Arel::Sql::Engine.new(ActiveRecord::Base) -I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml' +I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml' \ No newline at end of file diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb index 042a67b490e26..52587ef251326 100755 --- a/activerecord/lib/active_record/base.rb +++ b/activerecord/lib/active_record/base.rb @@ -13,172 +13,10 @@ require 'active_support/core_ext/string/behavior' require 'active_support/core_ext/object/singleton_class' require 'active_support/core_ext/module/delegation' +require 'arel' +require 'active_record/errors' module ActiveRecord #:nodoc: - # Generic Active Record exception class. - class ActiveRecordError < StandardError - end - - # Raised when the single-table inheritance mechanism fails to locate the subclass - # (for example due to improper usage of column that +inheritance_column+ points to). - class SubclassNotFound < ActiveRecordError #:nodoc: - end - - # Raised when an object assigned to an association has an incorrect type. - # - # class Ticket < ActiveRecord::Base - # has_many :patches - # end - # - # class Patch < ActiveRecord::Base - # belongs_to :ticket - # end - # - # # Comments are not patches, this assignment raises AssociationTypeMismatch. - # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.") - class AssociationTypeMismatch < ActiveRecordError - end - - # Raised when unserialized object's type mismatches one specified for serializable field. - class SerializationTypeMismatch < ActiveRecordError - end - - # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). - class AdapterNotSpecified < ActiveRecordError - end - - # Raised when Active Record cannot find database adapter specified in config/database.yml or programmatically. - class AdapterNotFound < ActiveRecordError - end - - # Raised when connection to the database could not been established (for example when connection= is given a nil object). - class ConnectionNotEstablished < ActiveRecordError - end - - # Raised when Active Record cannot find record by given id or set of ids. - class RecordNotFound < ActiveRecordError - end - - # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be - # saved because record is invalid. - class RecordNotSaved < ActiveRecordError - end - - # Raised when SQL statement cannot be executed by the database (for example, it's often the case for MySQL when Ruby driver used is too old). - class StatementInvalid < ActiveRecordError - end - - # Raised when SQL statement is invalid and the application gets a blank result. - class ThrowResult < ActiveRecordError - end - - # Parent class for all specific exceptions which wrap database driver exceptions - # provides access to the original exception also. - class WrappedDatabaseException < StatementInvalid - attr_reader :original_exception - - def initialize(message, original_exception) - super(message) - @original_exception = original_exception - end - end - - # Raised when a record cannot be inserted because it would violate a uniqueness constraint. - class RecordNotUnique < WrappedDatabaseException - end - - # Raised when a record cannot be inserted or updated because it references a non-existent record. - class InvalidForeignKey < WrappedDatabaseException - end - - # Raised when number of bind variables in statement given to :condition key (for example, when using +find+ method) - # does not match number of expected variables. - # - # For example, in - # - # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362] - # - # two placeholders are given but only one variable to fill them. - class PreparedStatementInvalid < ActiveRecordError - end - - # Raised on attempt to save stale record. Record is stale when it's being saved in another query after - # instantiation, for example, when two users edit the same wiki page and one starts editing and saves - # the page before the other. - # - # Read more about optimistic locking in ActiveRecord::Locking module RDoc. - class StaleObjectError < ActiveRecordError - end - - # Raised when association is being configured improperly or - # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations. - class ConfigurationError < ActiveRecordError - end - - # Raised on attempt to update record that is instantiated as read only. - class ReadOnlyRecord < ActiveRecordError - end - - # ActiveRecord::Transactions::ClassMethods.transaction uses this exception - # to distinguish a deliberate rollback from other exceptional situations. - # Normally, raising an exception will cause the +transaction+ method to rollback - # the database transaction *and* pass on the exception. But if you raise an - # ActiveRecord::Rollback exception, then the database transaction will be rolled back, - # without passing on the exception. - # - # For example, you could do this in your controller to rollback a transaction: - # - # class BooksController < ActionController::Base - # def create - # Book.transaction do - # book = Book.new(params[:book]) - # book.save! - # if today_is_friday? - # # The system must fail on Friday so that our support department - # # won't be out of job. We silently rollback this transaction - # # without telling the user. - # raise ActiveRecord::Rollback, "Call tech support!" - # end - # end - # # ActiveRecord::Rollback is the only exception that won't be passed on - # # by ActiveRecord::Base.transaction, so this line will still be reached - # # even on Friday. - # redirect_to root_url - # end - # end - class Rollback < ActiveRecordError - end - - # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods). - class DangerousAttributeError < ActiveRecordError - end - - # Raised when unknown attributes are supplied via mass assignment. - class UnknownAttributeError < NoMethodError - end - - # Raised when an error occurred while doing a mass assignment to an attribute through the - # attributes= method. The exception has an +attribute+ property that is the name of the - # offending attribute. - class AttributeAssignmentError < ActiveRecordError - attr_reader :exception, :attribute - def initialize(message, exception, attribute) - @exception = exception - @attribute = attribute - @message = message - end - end - - # Raised when there are multiple errors while doing a mass assignment through the +attributes+ - # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError - # objects, each corresponding to the error while assigning to an attribute. - class MultiparameterAssignmentErrors < ActiveRecordError - attr_reader :errors - def initialize(errors) - @errors = errors - end - end - # Active Record objects don't specify their attributes directly, but rather infer them from the table definition with # which they're linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change # is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain @@ -551,7 +389,7 @@ def self.reset_subclasses #:nodoc: class << self # Class methods def colorize_logging(*args) ActiveSupport::Deprecation.warn "ActiveRecord::Base.colorize_logging and " << - "config.active_record.colorize_logging are deprecated. Please use " << + "config.active_record.colorize_logging are deprecated. Please use " << "Rails::LogSubscriber.colorize_logging or config.colorize_logging instead", caller end alias :colorize_logging= :colorize_logging @@ -2401,8 +2239,10 @@ def object_from_yaml(string) include Aggregations, Transactions, Reflection, Serialization + NilClass.add_whiner(self) if NilClass.respond_to?(:add_whiner) end end # TODO: Remove this and make it work with LAZY flag require 'active_record/connection_adapters/abstract_adapter' +ActiveRecord.run_base_hooks(ActiveRecord::Base) \ No newline at end of file diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb new file mode 100644 index 0000000000000..cf5ddca2ba981 --- /dev/null +++ b/activerecord/lib/active_record/errors.rb @@ -0,0 +1,165 @@ +module ActiveRecord + # Generic Active Record exception class. + class ActiveRecordError < StandardError + end + + # Raised when the single-table inheritance mechanism fails to locate the subclass + # (for example due to improper usage of column that +inheritance_column+ points to). + class SubclassNotFound < ActiveRecordError #:nodoc: + end + + # Raised when an object assigned to an association has an incorrect type. + # + # class Ticket < ActiveRecord::Base + # has_many :patches + # end + # + # class Patch < ActiveRecord::Base + # belongs_to :ticket + # end + # + # # Comments are not patches, this assignment raises AssociationTypeMismatch. + # @ticket.patches << Comment.new(:content => "Please attach tests to your patch.") + class AssociationTypeMismatch < ActiveRecordError + end + + # Raised when unserialized object's type mismatches one specified for serializable field. + class SerializationTypeMismatch < ActiveRecordError + end + + # Raised when adapter not specified on connection (or configuration file config/database.yml misses adapter field). + class AdapterNotSpecified < ActiveRecordError + end + + # Raised when Active Record cannot find database adapter specified in config/database.yml or programmatically. + class AdapterNotFound < ActiveRecordError + end + + # Raised when connection to the database could not been established (for example when connection= is given a nil object). + class ConnectionNotEstablished < ActiveRecordError + end + + # Raised when Active Record cannot find record by given id or set of ids. + class RecordNotFound < ActiveRecordError + end + + # Raised by ActiveRecord::Base.save! and ActiveRecord::Base.create! methods when record cannot be + # saved because record is invalid. + class RecordNotSaved < ActiveRecordError + end + + # Raised when SQL statement cannot be executed by the database (for example, it's often the case for MySQL when Ruby driver used is too old). + class StatementInvalid < ActiveRecordError + end + + # Raised when SQL statement is invalid and the application gets a blank result. + class ThrowResult < ActiveRecordError + end + + # Parent class for all specific exceptions which wrap database driver exceptions + # provides access to the original exception also. + class WrappedDatabaseException < StatementInvalid + attr_reader :original_exception + + def initialize(message, original_exception) + super(message) + @original_exception = original_exception + end + end + + # Raised when a record cannot be inserted because it would violate a uniqueness constraint. + class RecordNotUnique < WrappedDatabaseException + end + + # Raised when a record cannot be inserted or updated because it references a non-existent record. + class InvalidForeignKey < WrappedDatabaseException + end + + # Raised when number of bind variables in statement given to :condition key (for example, when using +find+ method) + # does not match number of expected variables. + # + # For example, in + # + # Location.find :all, :conditions => ["lat = ? AND lng = ?", 53.7362] + # + # two placeholders are given but only one variable to fill them. + class PreparedStatementInvalid < ActiveRecordError + end + + # Raised on attempt to save stale record. Record is stale when it's being saved in another query after + # instantiation, for example, when two users edit the same wiki page and one starts editing and saves + # the page before the other. + # + # Read more about optimistic locking in ActiveRecord::Locking module RDoc. + class StaleObjectError < ActiveRecordError + end + + # Raised when association is being configured improperly or + # user tries to use offset and limit together with has_many or has_and_belongs_to_many associations. + class ConfigurationError < ActiveRecordError + end + + # Raised on attempt to update record that is instantiated as read only. + class ReadOnlyRecord < ActiveRecordError + end + + # ActiveRecord::Transactions::ClassMethods.transaction uses this exception + # to distinguish a deliberate rollback from other exceptional situations. + # Normally, raising an exception will cause the +transaction+ method to rollback + # the database transaction *and* pass on the exception. But if you raise an + # ActiveRecord::Rollback exception, then the database transaction will be rolled back, + # without passing on the exception. + # + # For example, you could do this in your controller to rollback a transaction: + # + # class BooksController < ActionController::Base + # def create + # Book.transaction do + # book = Book.new(params[:book]) + # book.save! + # if today_is_friday? + # # The system must fail on Friday so that our support department + # # won't be out of job. We silently rollback this transaction + # # without telling the user. + # raise ActiveRecord::Rollback, "Call tech support!" + # end + # end + # # ActiveRecord::Rollback is the only exception that won't be passed on + # # by ActiveRecord::Base.transaction, so this line will still be reached + # # even on Friday. + # redirect_to root_url + # end + # end + class Rollback < ActiveRecordError + end + + # Raised when attribute has a name reserved by Active Record (when attribute has name of one of Active Record instance methods). + class DangerousAttributeError < ActiveRecordError + end + + # Raised when unknown attributes are supplied via mass assignment. + class UnknownAttributeError < NoMethodError + end + + # Raised when an error occurred while doing a mass assignment to an attribute through the + # attributes= method. The exception has an +attribute+ property that is the name of the + # offending attribute. + class AttributeAssignmentError < ActiveRecordError + attr_reader :exception, :attribute + def initialize(message, exception, attribute) + @exception = exception + @attribute = attribute + @message = message + end + end + + # Raised when there are multiple errors while doing a mass assignment through the +attributes+ + # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError + # objects, each corresponding to the error while assigning to an attribute. + class MultiparameterAssignmentErrors < ActiveRecordError + attr_reader :errors + def initialize(errors) + @errors = errors + end + end +end \ No newline at end of file diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index b38bd9a6445ae..60addd46c6220 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -24,31 +24,39 @@ class Railtie < Rails::Railtie log_subscriber ActiveRecord::Railties::LogSubscriber.new initializer "active_record.initialize_timezone" do - ActiveRecord::Base.time_zone_aware_attributes = true - ActiveRecord::Base.default_timezone = :utc + ActiveRecord.base_hook do + self.time_zone_aware_attributes = true + self.default_timezone = :utc + end end initializer "active_record.logger" do - ActiveRecord::Base.logger ||= ::Rails.logger + ActiveRecord.base_hook { self.logger ||= ::Rails.logger } end initializer "active_record.set_configs" do |app| - app.config.active_record.each do |k,v| - ActiveRecord::Base.send "#{k}=", v + ActiveRecord.base_hook do + app.config.active_record.each do |k,v| + send "#{k}=", v + end end end # This sets the database configuration from Configuration#database_configuration # and then establishes the connection. initializer "active_record.initialize_database" do |app| - ActiveRecord::Base.configurations = app.config.database_configuration - ActiveRecord::Base.establish_connection + ActiveRecord.base_hook do + self.configurations = app.config.database_configuration + establish_connection + end end # Expose database runtime to controller for logging. initializer "active_record.log_runtime" do |app| require "active_record/railties/controller_runtime" - ActionController::Base.send :include, ActiveRecord::Railties::ControllerRuntime + ActionController.base_hook do + include ActiveRecord::Railties::ControllerRuntime + end end # Setup database middleware after initializers have run @@ -64,18 +72,22 @@ class Railtie < Rails::Railtie end initializer "active_record.load_observers" do - ActiveRecord::Base.instantiate_observers + ActiveRecord.base_hook { instantiate_observers } - ActionDispatch::Callbacks.to_prepare(:activerecord_instantiate_observers) do - ActiveRecord::Base.instantiate_observers + ActiveRecord.base_hook do + ActionDispatch::Callbacks.to_prepare(:activerecord_instantiate_observers) do + ActiveRecord::Base.instantiate_observers + end end end initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app| - unless app.config.cache_classes - ActionDispatch::Callbacks.after do - ActiveRecord::Base.reset_subclasses - ActiveRecord::Base.clear_reloadable_connections! + ActiveRecord.base_hook do + unless app.config.cache_classes + ActionDispatch::Callbacks.after do + ActiveRecord::Base.reset_subclasses + ActiveRecord::Base.clear_reloadable_connections! + end end end end diff --git a/activerecord/test/cases/helper.rb b/activerecord/test/cases/helper.rb index f77dc801dcf30..e831ebf36c489 100644 --- a/activerecord/test/cases/helper.rb +++ b/activerecord/test/cases/helper.rb @@ -9,6 +9,7 @@ require 'stringio' require 'active_record' +require 'active_support/dependencies' require 'connection' begin diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index ae31d191c0874..e34e46b4cfd04 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -53,6 +53,7 @@ module ActiveSupport autoload :Deprecation autoload :Gzip autoload :Inflector + autoload :JSON autoload :Memoizable autoload :MessageEncryptor autoload :MessageVerifier @@ -70,3 +71,5 @@ module ActiveSupport autoload :SafeBuffer, "active_support/core_ext/string/output_safety" autoload :TestCase end + +autoload :I18n, "active_support/i18n" diff --git a/activesupport/lib/active_support/all.rb b/activesupport/lib/active_support/all.rb index 64600575d9059..f537818300bd4 100644 --- a/activesupport/lib/active_support/all.rb +++ b/activesupport/lib/active_support/all.rb @@ -1,4 +1,3 @@ require 'active_support' -require 'active_support/i18n' require 'active_support/time' require 'active_support/core_ext' diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 814567a5a6b1c..2119322bfe5c1 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -1,7 +1,6 @@ require 'active_support/core_ext/hash/keys' require 'active_support/core_ext/hash/reverse_merge' require 'active_support/inflector' -require 'active_support/i18n' class Array # Converts the array to a comma-separated sentence where the last element is joined by the connector word. Options: diff --git a/activesupport/lib/active_support/core_ext/string/interpolation.rb b/activesupport/lib/active_support/core_ext/string/interpolation.rb index 06d3505c60f41..932117cc106cb 100644 --- a/activesupport/lib/active_support/core_ext/string/interpolation.rb +++ b/activesupport/lib/active_support/core_ext/string/interpolation.rb @@ -1,91 +1 @@ -=begin - heavily based on Masao Mutoh's gettext String interpolation extension - http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb - Copyright (C) 2005-2010 Masao Mutoh - You may redistribute it and/or modify it under the same license terms as Ruby. -=end - -if RUBY_VERSION < '1.9' && !"".respond_to?(:interpolate_without_ruby_19_syntax) - - # KeyError is raised by String#% when the string contains a named placeholder - # that is not contained in the given arguments hash. Ruby 1.9 includes and - # raises this exception natively. We define it to mimic Ruby 1.9's behaviour - # in Ruby 1.8.x - - class KeyError < IndexError - def initialize(message = nil) - super(message || "key not found") - end - end unless defined?(KeyError) - - # Extension for String class. This feature is included in Ruby 1.9 or later but not occur TypeError. - # - # String#% method which accept "named argument". The translator can know - # the meaning of the msgids using "named argument" instead of %s/%d style. - - class String - alias :interpolate_without_ruby_19_syntax :% # :nodoc: - - INTERPOLATION_PATTERN = Regexp.union( - /%%/, - /%\{(\w+)\}/, # matches placeholders like "%{foo}" - /%<(\w+)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%.d" - ) - - # % uses self (i.e. the String) as a format specification and returns the - # result of applying it to the given arguments. In other words it interpolates - # the given arguments to the string according to the formats the string - # defines. - # - # There are three ways to use it: - # - # * Using a single argument or Array of arguments. - # - # This is the default behaviour of the String class. See Kernel#sprintf for - # more details about the format string. - # - # Example: - # - # "%d %s" % [1, "message"] - # # => "1 message" - # - # * Using a Hash as an argument and unformatted, named placeholders. - # - # When you pass a Hash as an argument and specify placeholders with %{foo} - # it will interpret the hash values as named arguments. - # - # Example: - # - # "%{firstname}, %{lastname}" % {:firstname => "Masao", :lastname => "Mutoh"} - # # => "Masao Mutoh" - # - # * Using a Hash as an argument and formatted, named placeholders. - # - # When you pass a Hash as an argument and specify placeholders with %d - # it will interpret the hash values as named arguments and format the value - # according to the formatting instruction appended to the closing >. - # - # Example: - # - # "%d, %.1f" % { :integer => 10, :float => 43.4 } - # # => "10, 43.3" - def %(args) - if args.kind_of?(Hash) - dup.gsub(INTERPOLATION_PATTERN) do |match| - if match == '%%' - '%' - else - key = ($1 || $2).to_sym - raise KeyError unless args.has_key?(key) - $3 ? sprintf("%#{$3}", args[key]) : args[key] - end - end - elsif self =~ INTERPOLATION_PATTERN - raise ArgumentError.new('one hash required') - else - result = gsub(/%([{<])/, '%%\1') - result.send :'interpolate_without_ruby_19_syntax', args - end - end - end -end +require 'i18n/core_ext/string/interpolate' diff --git a/activesupport/lib/active_support/dependencies/autoload.rb b/activesupport/lib/active_support/dependencies/autoload.rb index 44edb89ad58f9..f669f4a77e4b5 100644 --- a/activesupport/lib/active_support/dependencies/autoload.rb +++ b/activesupport/lib/active_support/dependencies/autoload.rb @@ -1,7 +1,12 @@ require "active_support/inflector/methods" +require "active_support/lazy_load_hooks" module ActiveSupport module Autoload + def self.extended(base) + base.extend(LazyLoadHooks) + end + @@autoloads = {} @@under_path = nil @@at_path = nil diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb index 854c60eec1de3..034d7d8ddce48 100644 --- a/activesupport/lib/active_support/i18n.rb +++ b/activesupport/lib/active_support/i18n.rb @@ -1,2 +1,3 @@ require 'i18n' -I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml" \ No newline at end of file +I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml" +ActiveSupport.run_base_hooks(:i18n) \ No newline at end of file diff --git a/activesupport/lib/active_support/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb new file mode 100644 index 0000000000000..36acfda52498a --- /dev/null +++ b/activesupport/lib/active_support/lazy_load_hooks.rb @@ -0,0 +1,25 @@ +module ActiveSupport + module LazyLoadHooks + def _setup_base_hooks + @base_hooks ||= Hash.new {|h,k| h[k] = [] } + @base ||= {} + end + + def base_hook(name = nil, &block) + _setup_base_hooks + + if base = @base[name] + base.instance_eval(&block) + else + @base_hooks[name] << block + end + end + + def run_base_hooks(base, name = nil) + _setup_base_hooks + + @base_hooks[name].each { |hook| base.instance_eval(&hook) } if @base_hooks + @base[name] = base + end + end +end \ No newline at end of file diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb index 58d11585bac98..d2c13e030da3d 100644 --- a/activesupport/lib/active_support/railtie.rb +++ b/activesupport/lib/active_support/railtie.rb @@ -37,10 +37,12 @@ class Railtie < Rails::Railtie config.i18n.load_path = [] initializer "i18n.initialize" do - require 'active_support/i18n' - - ActionDispatch::Callbacks.to_prepare do + ActiveSupport.base_hook(:i18n) do I18n.reload! + + ActionDispatch::Callbacks.to_prepare do + I18n.reload! + end end end diff --git a/activesupport/lib/active_support/whiny_nil.rb b/activesupport/lib/active_support/whiny_nil.rb index 0b68e936f60d7..91ddef26197f3 100644 --- a/activesupport/lib/active_support/whiny_nil.rb +++ b/activesupport/lib/active_support/whiny_nil.rb @@ -25,17 +25,16 @@ # By default it is on in development and test modes, and it is off in production # mode. class NilClass - WHINERS = [::Array] - WHINERS << ::ActiveRecord::Base if defined? ::ActiveRecord::Base - METHOD_CLASS_MAP = Hash.new - WHINERS.each do |klass| + def self.add_whiner(klass) methods = klass.public_instance_methods - public_instance_methods class_name = klass.name methods.each { |method| METHOD_CLASS_MAP[method.to_sym] = class_name } end + add_whiner ::Array + # Raises a RuntimeError when you attempt to call +id+ on +nil+. def id raise RuntimeError, "Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id", caller diff --git a/activesupport/test/whiny_nil_test.rb b/activesupport/test/whiny_nil_test.rb index 1e4f8d854a52a..4b9f06deada29 100644 --- a/activesupport/test/whiny_nil_test.rb +++ b/activesupport/test/whiny_nil_test.rb @@ -9,6 +9,8 @@ def save! require 'abstract_unit' require 'active_support/whiny_nil' +NilClass.add_whiner ::ActiveRecord::Base + class WhinyNilTest < Test::Unit::TestCase def test_unchanged nil.method_thats_not_in_whiners diff --git a/railties/lib/rails/application/routes_reloader.rb b/railties/lib/rails/application/routes_reloader.rb index fde6211c5daf0..a5154f4bbac2d 100644 --- a/railties/lib/rails/application/routes_reloader.rb +++ b/railties/lib/rails/application/routes_reloader.rb @@ -27,7 +27,7 @@ def reload! routes.clear! paths.each { |path| load(path) } - routes.finalize! + ActionController.base_hook { routes.finalize! } nil ensure diff --git a/railties/lib/rails/console/helpers.rb b/railties/lib/rails/console/helpers.rb index 039db667c40da..212fc6125a20d 100644 --- a/railties/lib/rails/console/helpers.rb +++ b/railties/lib/rails/console/helpers.rb @@ -2,4 +2,6 @@ def helper @helper ||= ApplicationController.helpers end -@controller = ApplicationController.new +def controller + @controller ||= ApplicationController.new +end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 8f5040ea13480..85b4ff84703bb 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -97,8 +97,8 @@ def load_tasks initializer :add_view_paths do views = paths.app.views.to_a - ActionController::Base.prepend_view_path(views) if defined?(ActionController::Base) - ActionMailer::Base.prepend_view_path(views) if defined?(ActionMailer::Base) + ActionController.base_hook { prepend_view_path(views) } if defined?(ActionController) + ActionMailer.base_hook { prepend_view_path(views) } if defined?(ActionMailer) end initializer :add_metals do |app|