aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionmailer/test/fixtures/helpers/example_helper.rb2
-rw-r--r--actionpack/Gemfile2
-rw-r--r--actionpack/lib/abstract_controller/callbacks.rb10
-rw-r--r--actionpack/lib/action_controller/metal/session_management.rb2
-rw-r--r--actionpack/lib/action_dispatch/http/mime_type.rb7
-rw-r--r--actionpack/lib/action_dispatch/middleware/callbacks.rb8
-rw-r--r--actionpack/lib/action_view/base.rb18
-rw-r--r--actionpack/lib/action_view/helpers/record_tag_helper.rb6
-rw-r--r--actionpack/lib/action_view/paths.rb7
-rw-r--r--actionpack/lib/action_view/render/partials.rb5
-rw-r--r--actionpack/lib/action_view/render/rendering.rb22
-rw-r--r--actionpack/test/controller/routing_test.rb28
-rw-r--r--actionpack/test/lib/controller/fake_controllers.rb2
-rw-r--r--actionpack/test/template/record_tag_helper_test.rb2
-rw-r--r--actionpack/test/template/safe_buffer_test.rb (renamed from actionpack/test/view/safe_buffer_test.rb)2
-rw-r--r--activemodel/lib/active_model/validations.rb10
-rw-r--r--activerecord/lib/active_record/associations/association_collection.rb2
-rw-r--r--activerecord/lib/active_record/callbacks.rb4
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/abstract_adapter.rb4
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb42
-rw-r--r--activerecord/lib/active_record/validations.rb14
-rw-r--r--activerecord/test/cases/nested_attributes_test.rb38
-rw-r--r--activesupport/lib/active_support/autoload.rb2
-rw-r--r--activesupport/lib/active_support/cache.rb7
-rw-r--r--activesupport/lib/active_support/cache/memory_store.rb2
-rw-r--r--activesupport/lib/active_support/cache/strategy/local_cache.rb10
-rw-r--r--activesupport/lib/active_support/callbacks.rb622
-rw-r--r--activesupport/lib/active_support/deprecated_callbacks.rb283
-rw-r--r--activesupport/lib/active_support/deprecation/behaviors.rb2
-rw-r--r--activesupport/lib/active_support/memoizable.rb13
-rw-r--r--activesupport/lib/active_support/message_verifier.rb2
-rw-r--r--activesupport/lib/active_support/new_callbacks.rb563
-rw-r--r--activesupport/lib/active_support/testing/isolation.rb4
-rw-r--r--activesupport/lib/active_support/testing/setup_and_teardown.rb69
-rw-r--r--activesupport/test/caching_test.rb19
-rw-r--r--activesupport/test/callback_inheritance_test.rb (renamed from activesupport/test/new_callback_inheritance_test.rb)42
-rw-r--r--activesupport/test/callbacks_test.rb632
-rw-r--r--activesupport/test/message_verifier_test.rb1
-rw-r--r--activesupport/test/new_callbacks_test.rb528
-rw-r--r--activesupport/test/test_test.rb56
-rw-r--r--ci/geminstaller.yml2
-rw-r--r--railties/Rakefile3
-rw-r--r--railties/lib/rails/application.rb484
-rw-r--r--railties/lib/rails/core.rb6
-rw-r--r--railties/lib/rails/generators.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/boot.rb13
-rw-r--r--railties/lib/rails/initializable.rb99
-rw-r--r--railties/lib/rails/initializer.rb561
-rw-r--r--railties/lib/rails/initializer_old.rb1137
-rw-r--r--railties/test/application/generators_test.rb89
-rw-r--r--railties/test/application/initializer_test.rb194
-rw-r--r--railties/test/application/load_test.rb4
-rw-r--r--railties/test/application/plugins_test.rb101
-rw-r--r--railties/test/initializable_test.rb68
-rw-r--r--railties/test/initializer/initialize_i18n_test.rb51
-rw-r--r--railties/test/initializer/path_test.rb2
-rw-r--r--railties/test/initializer_test.rb482
-rw-r--r--railties/test/isolation/abstract_unit.rb9
-rw-r--r--railties/test/new_initializer_test.rb165
-rw-r--r--railties/test/plugin_loader_test.rb17
-rw-r--r--railties/test/plugin_locator_test.rb16
-rw-r--r--railties/test/plugin_test.rb15
62 files changed, 2595 insertions, 4019 deletions
diff --git a/actionmailer/test/fixtures/helpers/example_helper.rb b/actionmailer/test/fixtures/helpers/example_helper.rb
index d66927aa60..f6a6a49ced 100644
--- a/actionmailer/test/fixtures/helpers/example_helper.rb
+++ b/actionmailer/test/fixtures/helpers/example_helper.rb
@@ -1,5 +1,5 @@
module ExampleHelper
def example_format(text)
- "<em><strong><small>#{text}</small></strong></em>"
+ "<em><strong><small>#{h(text)}</small></strong></em>".html_safe!
end
end
diff --git a/actionpack/Gemfile b/actionpack/Gemfile
index 60d24104d2..8ee7026f05 100644
--- a/actionpack/Gemfile
+++ b/actionpack/Gemfile
@@ -1,5 +1,7 @@
rails_root = Pathname.new(File.dirname(__FILE__)).join("..")
+Gem.sources.each { |uri| source uri }
+
gem "rack", "~> 1.0.0"
gem "rack-test", "~> 0.5.0"
gem "activesupport", "3.0.pre", :vendored_at => rails_root.join("activesupport")
diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb
index 379eaf6d8e..ee496dadc5 100644
--- a/actionpack/lib/abstract_controller/callbacks.rb
+++ b/actionpack/lib/abstract_controller/callbacks.rb
@@ -1,13 +1,11 @@
-require "active_support/new_callbacks"
-
module AbstractController
module Callbacks
extend ActiveSupport::Concern
- # Uses ActiveSupport::NewCallbacks as the base functionality. For
+ # Uses ActiveSupport::Callbacks as the base functionality. For
# more details on the whole callback system, read the documentation
- # for ActiveSupport::NewCallbacks.
- include ActiveSupport::NewCallbacks
+ # for ActiveSupport::Callbacks.
+ include ActiveSupport::Callbacks
included do
define_callbacks :process_action, :terminator => "response_body"
@@ -16,7 +14,7 @@ module AbstractController
# Override AbstractController::Base's process_action to run the
# process_action callbacks around the normal behavior.
def process_action(method_name)
- _run_process_action_callbacks(method_name) do
+ run_callbacks(:process_action, method_name) do
super
end
end
diff --git a/actionpack/lib/action_controller/metal/session_management.rb b/actionpack/lib/action_controller/metal/session_management.rb
index ffce8e1bd1..654aa08cd3 100644
--- a/actionpack/lib/action_controller/metal/session_management.rb
+++ b/actionpack/lib/action_controller/metal/session_management.rb
@@ -16,7 +16,7 @@ module ActionController #:nodoc:
self.session_store = ActiveRecord::SessionStore
else
@@session_store = store.is_a?(Symbol) ?
- Session.const_get(store.to_s.camelize) :
+ ActionDispatch::Session.const_get(store.to_s.camelize) :
store
end
end
diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb
index cc989d6625..e85823d8db 100644
--- a/actionpack/lib/action_dispatch/http/mime_type.rb
+++ b/actionpack/lib/action_dispatch/http/mime_type.rb
@@ -10,7 +10,12 @@ module Mime
%w(<< concat shift unshift push pop []= clear compact! collect!
delete delete_at delete_if flatten! map! insert reject! reverse!
replace slice! sort! uniq!).each do |method|
- define_method(method) {|*args| @symbols = nil; super(*args) }
+ module_eval <<-CODE
+ def #{method}(*args)
+ @symbols = nil
+ super
+ end
+ CODE
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb
index 56d6da1706..49bc20f11f 100644
--- a/actionpack/lib/action_dispatch/middleware/callbacks.rb
+++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb
@@ -1,6 +1,6 @@
module ActionDispatch
class Callbacks
- include ActiveSupport::NewCallbacks
+ include ActiveSupport::Callbacks
define_callbacks :call, :terminator => "result == false", :rescuable => true
define_callbacks :prepare, :scope => :name
@@ -37,12 +37,12 @@ module ActionDispatch
def initialize(app, prepare_each_request = false)
@app, @prepare_each_request = app, prepare_each_request
- _run_prepare_callbacks
+ run_callbacks(:prepare)
end
def call(env)
- _run_call_callbacks do
- _run_prepare_callbacks if @prepare_each_request
+ run_callbacks(:call) do
+ run_callbacks(:prepare) if @prepare_each_request
@app.call(env)
end
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 82b419d846..31e9c5ef9d 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -236,15 +236,15 @@ module ActionView #:nodoc:
# they are in AC.
if controller.class.respond_to?(:_helper_serial)
klass = @views[controller.class._helper_serial] ||= Class.new(self) do
- name = controller.class.name.gsub(/::/, '__')
-
- Subclasses.class_eval do
- if method(:const_defined?).arity == 1
- remove_const(name) if const_defined?(name) # Ruby 1.8.x
- else
- remove_const(name) if const_defined?(name, false) # Ruby 1.9.x
- end
- const_set(name, self)
+ const_set(:CONTROLLER_CLASS, controller.class)
+
+ # Try to make stack traces clearer
+ def self.name
+ "ActionView for #{CONTROLLER_CLASS}"
+ end
+
+ def inspect
+ "#<#{self.class.name}>"
end
if controller.respond_to?(:_helpers)
diff --git a/actionpack/lib/action_view/helpers/record_tag_helper.rb b/actionpack/lib/action_view/helpers/record_tag_helper.rb
index 0cdb70e217..31411dc08a 100644
--- a/actionpack/lib/action_view/helpers/record_tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/record_tag_helper.rb
@@ -15,7 +15,7 @@ module ActionView
def div_for(record, *args, &block)
content_tag_for(:div, record, *args, &block)
end
-
+
# content_tag_for creates an HTML element with id and class parameters
# that relate to the specified Active Record object. For example:
#
@@ -34,7 +34,7 @@ module ActionView
# <% content_tag_for(:tr, @person, :foo) do %> ...
#
# produces:
- #
+ #
# <tr id="foo_person_123" class="person">...
#
# content_tag_for also accepts a hash of options, which will be converted to
@@ -50,7 +50,7 @@ module ActionView
def content_tag_for(tag_name, record, *args, &block)
prefix = args.first.is_a?(Hash) ? nil : args.shift
options = args.extract_options!
- options.merge!({ :class => "#{dom_class(record)} #{options[:class]}".strip, :id => dom_id(record, prefix) })
+ options.merge!({ :class => "#{dom_class(record, prefix)} #{options[:class]}".strip, :id => dom_id(record, prefix) })
content_tag(tag_name, options, &block)
end
end
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb
index 5524a3219a..23bde61f9c 100644
--- a/actionpack/lib/action_view/paths.rb
+++ b/actionpack/lib/action_view/paths.rb
@@ -1,8 +1,11 @@
module ActionView #:nodoc:
class PathSet < Array #:nodoc:
- def self.type_cast(obj)
+ def self.type_cast(obj, cache = nil)
+ # TODO: Clean this up
if obj.is_a?(String)
- cache = !defined?(Rails) || !Rails.respond_to?(:configuration) || Rails.configuration.cache_classes
+ if cache.nil?
+ cache = !defined?(Rails) || Rails.application.config.cache_classes
+ end
FileSystemResolverWithFallback.new(obj, :cache => cache)
else
obj
diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb
index 4f60566a09..2eb88ae3e5 100644
--- a/actionpack/lib/action_view/render/partials.rb
+++ b/actionpack/lib/action_view/render/partials.rb
@@ -296,7 +296,10 @@ module ActionView
end
def _find_template(path)
- prefix = @view.controller.controller_path unless path.include?(?/)
+ if controller = @view.controller
+ prefix = controller.controller_path unless path.include?(?/)
+ end
+
@view.find(path, {:formats => @view.formats}, prefix, true)
end
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
index 0cab035ede..b6f5b9b6d1 100644
--- a/actionpack/lib/action_view/render/rendering.rb
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -14,6 +14,7 @@ module ActionView
case options
when Hash
layout = options[:layout]
+ options[:locals] ||= {}
if block_given?
return concat(_render_partial(options.merge(:partial => layout), &block))
@@ -25,11 +26,11 @@ module ActionView
if file = options[:file]
template = find(file, {:formats => formats})
- _render_template(template, layout, :locals => options[:locals] || {})
+ _render_template(template, layout, :locals => options[:locals])
elsif inline = options[:inline]
_render_inline(inline, layout, options)
elsif text = options[:text]
- _render_text(text, layout, options)
+ _render_text(text, layout, options[:locals])
end
when :update
update_page(&block)
@@ -80,16 +81,19 @@ module ActionView
def _render_inline(inline, layout, options)
handler = Template.handler_class_for_extension(options[:type] || "erb")
- template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})
- locals = options[:locals] || {}
+ template = Template.new(options[:inline],
+ "inline #{options[:inline].inspect}", handler, {})
+
+ locals = options[:locals]
content = template.render(self, locals)
- content = layout.render(self, locals) {|*name| _layout_for(*name) { content } } if layout
- content
+ _render_text(content, layout, locals)
end
- def _render_text(text, layout, options)
- text = layout.render(self, options[:locals]) { text } if layout
- text
+ def _render_text(content, layout, locals)
+ content = layout.render(self, locals) do |*name|
+ _layout_for(*name) { content }
+ end if layout
+ content
end
# This is the API to render a ViewContext's template from a controller.
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index edf243337f..7c88520bac 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -240,18 +240,6 @@ class LegacyRouteSetTests < Test::Unit::TestCase
x.send(:home_url))
end
- def test_basic_named_route_with_relative_url_root
- rs.draw do |map|
- map.home '', :controller => 'content', :action => 'list'
- end
- x = setup_for_named_route
- ActionController::Base.relative_url_root = "/foo"
- assert_equal("http://test.host/foo/",
- x.send(:home_url))
- assert_equal "/foo/", x.send(:home_path)
- ActionController::Base.relative_url_root = nil
- end
-
def test_named_route_with_option
rs.draw do |map|
map.page 'page/:title', :controller => 'content', :action => 'show_page'
@@ -307,19 +295,6 @@ class LegacyRouteSetTests < Test::Unit::TestCase
x.send(:users_url))
end
- def test_optimised_named_route_call_never_uses_url_for
- rs.draw do |map|
- map.users 'admin/user', :controller => '/admin/user', :action => 'index'
- map.user 'admin/user/:id', :controller=>'/admin/user', :action=>'show'
- end
- x = setup_for_named_route
- x.expects(:url_for).never
- x.send(:users_url)
- x.send(:users_path)
- x.send(:user_url, 2, :foo=>"bar")
- x.send(:user_path, 3, :bar=>"foo")
- end
-
def test_optimised_named_route_with_host
rs.draw do |map|
map.pages 'pages', :controller => 'content', :action => 'show_page', :host => 'foo.com'
@@ -984,9 +959,6 @@ class RouteSetTest < ActiveSupport::TestCase
end
assert_equal 1, set.routes.size
- route = set.routes.first
-
- assert route.segments.last.optional?
assert_equal '/users/show/10', set.generate(:controller => 'users', :action => 'show', :id => 10)
assert_equal '/users/index/10', set.generate(:controller => 'users', :id => 10)
diff --git a/actionpack/test/lib/controller/fake_controllers.rb b/actionpack/test/lib/controller/fake_controllers.rb
index 9ec7f330b8..c993836a61 100644
--- a/actionpack/test/lib/controller/fake_controllers.rb
+++ b/actionpack/test/lib/controller/fake_controllers.rb
@@ -7,6 +7,7 @@ module Admin
class << self; alias_method :const_available?, :const_defined?; end
class UserController < ActionController::Base; end
class NewsFeedController < ActionController::Base; end
+ class StuffController < ActionController::Base; end
end
module Api
@@ -26,6 +27,7 @@ class HiController < ActionController::Base; end
class ImageController < ActionController::Base; end
class PeopleController < ActionController::Base; end
class SessionsController < ActionController::Base; end
+class StuffController < ActionController::Base; end
class SubpathBooksController < ActionController::Base; end
class WeblogController < ActionController::Base; end
diff --git a/actionpack/test/template/record_tag_helper_test.rb b/actionpack/test/template/record_tag_helper_test.rb
index 77d1374020..1cd18c0692 100644
--- a/actionpack/test/template/record_tag_helper_test.rb
+++ b/actionpack/test/template/record_tag_helper_test.rb
@@ -27,7 +27,7 @@ class RecordTagHelperTest < ActionView::TestCase
end
def test_content_tag_for_prefix
- expected = %(<ul class="post" id="archived_post_45"></ul>)
+ expected = %(<ul class="archived_post" id="archived_post_45"></ul>)
actual = content_tag_for(:ul, @post, :archived) { }
assert_dom_equal expected, actual
end
diff --git a/actionpack/test/view/safe_buffer_test.rb b/actionpack/test/template/safe_buffer_test.rb
index 2236709627..6a18201d16 100644
--- a/actionpack/test/view/safe_buffer_test.rb
+++ b/actionpack/test/template/safe_buffer_test.rb
@@ -26,7 +26,7 @@ class SafeBufferTest < ActionView::TestCase
end
test "Should not mess with a previously escape test" do
- @buffer << CGI.escapeHTML("<script>")
+ @buffer << ERB::Util.html_escape("<script>")
assert_equal "&lt;script&gt;", @buffer
end
diff --git a/activemodel/lib/active_model/validations.rb b/activemodel/lib/active_model/validations.rb
index edeb508a08..0f178a07c8 100644
--- a/activemodel/lib/active_model/validations.rb
+++ b/activemodel/lib/active_model/validations.rb
@@ -1,12 +1,10 @@
require 'active_support/core_ext/array/extract_options'
require 'active_support/core_ext/hash/keys'
-require 'active_support/concern'
-require 'active_support/callbacks'
module ActiveModel
module Validations
extend ActiveSupport::Concern
- include ActiveSupport::NewCallbacks
+ include ActiveSupport::Callbacks
included do
define_callbacks :validate, :scope => :name
@@ -99,7 +97,7 @@ module ActiveModel
def invalid?
!valid?
end
-
+
protected
# Hook method defining how an attribute value should be retieved. By default this is assumed
# to be an instance named after the attribute. Override this method in subclasses should you
@@ -110,9 +108,9 @@ module ActiveModel
# def initialize(data = {})
# @data = data
# end
- #
+ #
# private
- #
+ #
# def read_attribute_for_validation(key)
# @data[key]
# end
diff --git a/activerecord/lib/active_record/associations/association_collection.rb b/activerecord/lib/active_record/associations/association_collection.rb
index 1b7bf42b91..25e329c0c1 100644
--- a/activerecord/lib/active_record/associations/association_collection.rb
+++ b/activerecord/lib/active_record/associations/association_collection.rb
@@ -476,7 +476,7 @@ module ActiveRecord
def callback(method, record)
callbacks_for(method).each do |callback|
- ActiveSupport::Callbacks::Callback.new(method, callback, record).call(@owner, record)
+ ActiveSupport::DeprecatedCallbacks::Callback.new(method, callback, record).call(@owner, record)
end
end
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index 40a25811c4..b25893a1c3 100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -20,7 +20,7 @@ module ActiveRecord
# * (6) <tt>after_save</tt>
#
# That's a total of eight callbacks, which gives you immense power to react and prepare for each state in the
- # Active Record lifecycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar, except that each
+ # Active Record lifecycle. The sequence for calling <tt>Base#save</tt> for an existing record is similar, except that each
# <tt>_on_create</tt> callback is replaced by the corresponding <tt>_on_update</tt> callback.
#
# Examples:
@@ -210,7 +210,7 @@ module ActiveRecord
# instead of quietly returning +false+.
module Callbacks
extend ActiveSupport::Concern
- include ActiveSupport::NewCallbacks
+ include ActiveSupport::Callbacks
CALLBACKS = [
:after_initialize, :after_find, :before_validation, :after_validation,
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 78c7a4b697..cdf0aebfee 100755
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -32,7 +32,7 @@ module ActiveRecord
class AbstractAdapter
include Quoting, DatabaseStatements, SchemaStatements
include QueryCache
- include ActiveSupport::Callbacks
+ include ActiveSupport::DeprecatedCallbacks
define_callbacks :checkout, :checkin
@@row_even = true
@@ -75,7 +75,7 @@ module ActiveRecord
def supports_ddl_transactions?
false
end
-
+
# Does this adapter support savepoints? PostgreSQL and MySQL do, SQLite
# does not.
def supports_savepoints?
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index ec6c02db38..edcf547e01 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -3,11 +3,14 @@ require 'active_support/core_ext/object/try'
module ActiveRecord
module NestedAttributes #:nodoc:
+ class TooManyRecords < ActiveRecordError
+ end
+
extend ActiveSupport::Concern
included do
- class_inheritable_accessor :reject_new_nested_attributes_procs, :instance_writer => false
- self.reject_new_nested_attributes_procs = {}
+ class_inheritable_accessor :nested_attributes_options, :instance_writer => false
+ self.nested_attributes_options = {}
end
# == Nested Attributes
@@ -203,6 +206,12 @@ module ActiveRecord
# do not have a <tt>_destroy</tt> value that evaluates to true.
# Passing <tt>:all_blank</tt> instead of a Proc will create a proc
# that will reject a record where all the attributes are blank.
+ # [:limit]
+ # Allows you to specify the maximum number of the associated records that
+ # can be processes with the nested attributes. If the size of the
+ # nested attributes array exceeds the specified limit, NestedAttributes::TooManyRecords
+ # exception is raised. If omitted, any number associations can be processed.
+ # Note that the :limit option is only applicable to one-to-many associations.
#
# Examples:
# # creates avatar_attributes=
@@ -214,7 +223,7 @@ module ActiveRecord
def accepts_nested_attributes_for(*attr_names)
options = { :allow_destroy => false }
options.update(attr_names.extract_options!)
- options.assert_valid_keys(:allow_destroy, :reject_if)
+ options.assert_valid_keys(:allow_destroy, :reject_if, :limit)
attr_names.each do |association_name|
if reflection = reflect_on_association(association_name)
@@ -227,10 +236,10 @@ module ActiveRecord
reflection.options[:autosave] = true
- self.reject_new_nested_attributes_procs[association_name.to_sym] = if options[:reject_if] == :all_blank
- proc { |attributes| attributes.all? {|k,v| v.blank?} }
- else
- options[:reject_if]
+ self.nested_attributes_options[association_name.to_sym] = options
+
+ if options[:reject_if] == :all_blank
+ self.nested_attributes_options[association_name.to_sym][:reject_if] = proc { |attributes| attributes.all? {|k,v| v.blank?} }
end
# def pirate_attributes=(attributes)
@@ -238,7 +247,7 @@ module ActiveRecord
# end
class_eval %{
def #{association_name}_attributes=(attributes)
- assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes, #{options[:allow_destroy]})
+ assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
end
}, __FILE__, __LINE__
else
@@ -282,7 +291,8 @@ module ActiveRecord
# If the given attributes include a matching <tt>:id</tt> attribute _and_ a
# <tt>:_destroy</tt> key set to a truthy value, then the existing record
# will be marked for destruction.
- def assign_nested_attributes_for_one_to_one_association(association_name, attributes, allow_destroy)
+ def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
+ options = self.nested_attributes_options[association_name]
attributes = attributes.with_indifferent_access
if attributes['id'].blank?
@@ -295,7 +305,7 @@ module ActiveRecord
end
end
elsif (existing_record = send(association_name)) && existing_record.id.to_s == attributes['id'].to_s
- assign_to_or_mark_for_destruction(existing_record, attributes, allow_destroy)
+ assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
end
end
@@ -326,11 +336,17 @@ module ActiveRecord
# { :name => 'John' },
# { :id => '2', :_destroy => true }
# ])
- def assign_nested_attributes_for_collection_association(association_name, attributes_collection, allow_destroy)
+ def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
+ options = self.nested_attributes_options[association_name]
+
unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
end
+ if options[:limit] && attributes_collection.size > options[:limit]
+ raise TooManyRecords, "Maximum #{options[:limit]} records are allowed. Got #{attributes_collection.size} records instead."
+ end
+
if attributes_collection.is_a? Hash
attributes_collection = attributes_collection.sort_by { |index, _| index.to_i }.map { |_, attributes| attributes }
end
@@ -343,7 +359,7 @@ module ActiveRecord
send(association_name).build(attributes.except(*UNASSIGNABLE_KEYS))
end
elsif existing_record = send(association_name).detect { |record| record.id.to_s == attributes['id'].to_s }
- assign_to_or_mark_for_destruction(existing_record, attributes, allow_destroy)
+ assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
end
end
end
@@ -372,7 +388,7 @@ module ActiveRecord
end
def call_reject_if(association_name, attributes)
- callback = self.class.reject_new_nested_attributes_procs[association_name]
+ callback = self.nested_attributes_options[association_name][:reject_if]
case callback
when Symbol
diff --git a/activerecord/lib/active_record/validations.rb b/activerecord/lib/active_record/validations.rb
index ab79b520a2..e61b253192 100644
--- a/activerecord/lib/active_record/validations.rb
+++ b/activerecord/lib/active_record/validations.rb
@@ -59,15 +59,15 @@ module ActiveRecord
end
# Translates an error message in it's default scope (<tt>activerecord.errrors.messages</tt>).
- # Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>, if it's not there,
- # it's looked up in <tt>models.MODEL.MESSAGE</tt> and if that is not there it returns the translation of the
- # default message (e.g. <tt>activerecord.errors.messages.MESSAGE</tt>). The translated model name,
+ # Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>, if it's not there,
+ # it's looked up in <tt>models.MODEL.MESSAGE</tt> and if that is not there it returns the translation of the
+ # default message (e.g. <tt>activerecord.errors.messages.MESSAGE</tt>). The translated model name,
# translated attribute name and the value are available for interpolation.
#
# When using inheritance in your models, it will check all the inherited models too, but only if the model itself
# hasn't been found. Say you have <tt>class Admin < User; end</tt> and you wanted the translation for the <tt>:blank</tt>
# error +message+ for the <tt>title</tt> +attribute+, it looks for these translations:
- #
+ #
# <ol>
# <li><tt>activerecord.errors.models.admin.attributes.title.blank</tt></li>
# <li><tt>activerecord.errors.models.admin.blank</tt></li>
@@ -80,10 +80,10 @@ module ActiveRecord
message, options[:default] = options[:default], message if options[:default].is_a?(Symbol)
defaults = @base.class.self_and_descendants_from_active_record.map do |klass|
- [ :"models.#{klass.name.underscore}.attributes.#{attribute}.#{message}",
+ [ :"models.#{klass.name.underscore}.attributes.#{attribute}.#{message}",
:"models.#{klass.name.underscore}.#{message}" ]
end
-
+
defaults << options.delete(:default)
defaults = defaults.compact.flatten << :"messages.#{message}"
@@ -104,7 +104,7 @@ module ActiveRecord
module Validations
extend ActiveSupport::Concern
- include ActiveSupport::Callbacks
+ include ActiveSupport::DeprecatedCallbacks
include ActiveModel::Validations
included do
diff --git a/activerecord/test/cases/nested_attributes_test.rb b/activerecord/test/cases/nested_attributes_test.rb
index e57e361520..53fd168e1b 100644
--- a/activerecord/test/cases/nested_attributes_test.rb
+++ b/activerecord/test/cases/nested_attributes_test.rb
@@ -29,13 +29,13 @@ class TestNestedAttributesInGeneral < ActiveRecord::TestCase
Pirate.accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
end
- def test_base_should_have_an_empty_reject_new_nested_attributes_procs
- assert_equal Hash.new, ActiveRecord::Base.reject_new_nested_attributes_procs
+ def test_base_should_have_an_empty_nested_attributes_options
+ assert_equal Hash.new, ActiveRecord::Base.nested_attributes_options
end
- def test_should_add_a_proc_to_reject_new_nested_attributes_procs
+ def test_should_add_a_proc_to_nested_attributes_options
[:parrots, :birds, :birds_with_reject_all_blank].each do |name|
- assert_instance_of Proc, Pirate.reject_new_nested_attributes_procs[name]
+ assert_instance_of Proc, Pirate.nested_attributes_options[name][:reject_if]
end
end
@@ -603,3 +603,33 @@ class TestNestedAttributesOnAHasAndBelongsToManyAssociation < ActiveRecord::Test
include NestedAttributesOnACollectionAssociationTests
end
+
+class TestNestedAttributesLimit < ActiveRecord::TestCase
+ def setup
+ Pirate.accepts_nested_attributes_for :parrots, :limit => 2
+
+ @pirate = Pirate.create!(:catchphrase => "Don' botharrr talkin' like one, savvy?")
+ end
+
+ def teardown
+ Pirate.accepts_nested_attributes_for :parrots, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
+ end
+
+ def test_limit_with_less_records
+ @pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Big Big Love' } } }
+ assert_difference('Parrot.count') { @pirate.save! }
+ end
+
+ def test_limit_with_number_exact_records
+ @pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' }, 'bar' => { :name => 'Blown Away' } } }
+ assert_difference('Parrot.count', 2) { @pirate.save! }
+ end
+
+ def test_limit_with_exceeding_records
+ assert_raises(ActiveRecord::NestedAttributes::TooManyRecords) do
+ @pirate.attributes = { :parrots_attributes => { 'foo' => { :name => 'Lovely Day' },
+ 'bar' => { :name => 'Blown Away' },
+ 'car' => { :name => 'The Happening' }} }
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/autoload.rb b/activesupport/lib/active_support/autoload.rb
index 423d5448c3..71f4b395ce 100644
--- a/activesupport/lib/active_support/autoload.rb
+++ b/activesupport/lib/active_support/autoload.rb
@@ -8,6 +8,7 @@ module ActiveSupport
autoload :Concern, 'active_support/concern'
autoload :ConcurrentHash, 'active_support/concurrent_hash'
autoload :DependencyModule, 'active_support/dependency_module'
+ autoload :DeprecatedCallbacks, 'active_support/deprecated_callbacks'
autoload :Deprecation, 'active_support/deprecation'
autoload :Gzip, 'active_support/gzip'
autoload :Inflector, 'active_support/inflector'
@@ -15,7 +16,6 @@ module ActiveSupport
autoload :MessageEncryptor, 'active_support/message_encryptor'
autoload :MessageVerifier, 'active_support/message_verifier'
autoload :Multibyte, 'active_support/multibyte'
- autoload :NewCallbacks, 'active_support/new_callbacks'
autoload :OptionMerger, 'active_support/option_merger'
autoload :Orchestra, 'active_support/orchestra'
autoload :OrderedHash, 'active_support/ordered_hash'
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index 25f9555388..a415686020 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -115,6 +115,13 @@ module ActiveSupport
self
end
+ def mute
+ previous_silence, @silence = defined?(@silence) && @silence, true
+ yield
+ ensure
+ @silence = previous_silence
+ end
+
# Fetches data from the cache, using the given key. If there is data in
# the cache with the given key, then that data is returned.
#
diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb
index 66ce1bc93a..e6085d97ec 100644
--- a/activesupport/lib/active_support/cache/memory_store.rb
+++ b/activesupport/lib/active_support/cache/memory_store.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/object/duplicable'
+
module ActiveSupport
module Cache
# A cache store implementation which stores everything into memory in the
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb
index 3b5fccc737..5f6fe22416 100644
--- a/activesupport/lib/active_support/cache/strategy/local_cache.rb
+++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb
@@ -44,7 +44,7 @@ module ActiveSupport
nil
elsif value.nil?
value = super
- local_cache.write(key, value || NULL) if local_cache
+ local_cache.mute { local_cache.write(key, value || NULL) } if local_cache
value.duplicable? ? value.dup : value
else
# forcing the value to be immutable
@@ -54,12 +54,12 @@ module ActiveSupport
def write(key, value, options = nil)
value = value.to_s if respond_to?(:raw?) && raw?(options)
- local_cache.write(key, value || NULL) if local_cache
+ local_cache.mute { local_cache.write(key, value || NULL) } if local_cache
super
end
def delete(key, options = nil)
- local_cache.write(key, NULL) if local_cache
+ local_cache.mute { local_cache.write(key, NULL) } if local_cache
super
end
@@ -76,7 +76,7 @@ module ActiveSupport
def increment(key, amount = 1)
if value = super
- local_cache.write(key, value.to_s) if local_cache
+ local_cache.mute { local_cache.write(key, value.to_s) } if local_cache
value
else
nil
@@ -85,7 +85,7 @@ module ActiveSupport
def decrement(key, amount = 1)
if value = super
- local_cache.write(key, value.to_s) if local_cache
+ local_cache.mute { local_cache.write(key, value.to_s) } if local_cache
value
else
nil
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 238d1b6804..21388d7a58 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -1,4 +1,6 @@
-require 'active_support/core_ext/array/extract_options'
+require 'active_support/core_ext/array/wrap'
+require 'active_support/core_ext/class/inheritable_attributes'
+require 'active_support/core_ext/kernel/reporting'
module ActiveSupport
# Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
@@ -10,23 +12,23 @@ module ActiveSupport
# class Storage
# include ActiveSupport::Callbacks
#
- # define_callbacks :before_save, :after_save
+ # define_callbacks :save
# end
#
# class ConfigStorage < Storage
- # before_save :saving_message
+ # set_callback :save, :before, :saving_message
# def saving_message
# puts "saving..."
# end
#
- # after_save do |object|
+ # set_callback :save, :after do |object|
# puts "saved"
# end
#
# def save
- # run_callbacks(:before_save)
- # puts "- save"
- # run_callbacks(:after_save)
+ # run_callbacks :save do
+ # puts "- save"
+ # end
# end
# end
#
@@ -44,28 +46,28 @@ module ActiveSupport
# class Storage
# include ActiveSupport::Callbacks
#
- # define_callbacks :before_save, :after_save
+ # define_callbacks :save
#
- # before_save :prepare
+ # set_callback :save, :before, :prepare
# def prepare
# puts "preparing save"
# end
# end
#
# class ConfigStorage < Storage
- # before_save :saving_message
+ # set_callback :save, :before, :saving_message
# def saving_message
# puts "saving..."
# end
#
- # after_save do |object|
+ # set_callback :save, :after do |object|
# puts "saved"
# end
#
# def save
- # run_callbacks(:before_save)
- # puts "- save"
- # run_callbacks(:after_save)
+ # run_callbacks :save do
+ # puts "- save"
+ # end
# end
# end
#
@@ -77,205 +79,485 @@ module ActiveSupport
# saving...
# - save
# saved
+ #
module Callbacks
- class CallbackChain < Array
- def self.build(kind, *methods, &block)
- methods, options = extract_options(*methods, &block)
- methods.map! { |method| Callback.new(kind, method, options) }
- new(methods)
+ def self.included(klass)
+ klass.extend ClassMethods
+ end
+
+ def run_callbacks(kind, *args, &block)
+ send("_run_#{kind}_callbacks", *args, &block)
+ end
+
+ class Callback
+ @@_callback_sequence = 0
+
+ attr_accessor :chain, :filter, :kind, :options, :per_key, :klass
+
+ def initialize(chain, filter, kind, options, klass)
+ @chain, @kind, @klass = chain, kind, klass
+ normalize_options!(options)
+
+ @per_key = options.delete(:per_key)
+ @raw_filter, @options = filter, options
+ @filter = _compile_filter(filter)
+ @compiled_options = _compile_options(options)
+ @callback_id = next_id
+
+ _compile_per_key_options
+ end
+
+ def clone(chain, klass)
+ obj = super()
+ obj.chain = chain
+ obj.klass = klass
+ obj.per_key = @per_key.dup
+ obj.options = @options.dup
+ obj.per_key[:if] = @per_key[:if].dup
+ obj.per_key[:unless] = @per_key[:unless].dup
+ obj.options[:if] = @options[:if].dup
+ obj.options[:unless] = @options[:unless].dup
+ obj
end
- def run(object, options = {}, &terminator)
- enumerator = options[:enumerator] || :each
+ def normalize_options!(options)
+ options[:if] = Array.wrap(options[:if])
+ options[:unless] = Array.wrap(options[:unless])
- unless block_given?
- send(enumerator) { |callback| callback.call(object) }
- else
- send(enumerator) do |callback|
- result = callback.call(object)
- break result if terminator.call(result, object)
+ options[:per_key] ||= {}
+ options[:per_key][:if] = Array.wrap(options[:per_key][:if])
+ options[:per_key][:unless] = Array.wrap(options[:per_key][:unless])
+ end
+
+ def name
+ chain.name
+ end
+
+ def next_id
+ @@_callback_sequence += 1
+ end
+
+ def matches?(_kind, _filter)
+ @kind == _kind && @filter == _filter
+ end
+
+ def _update_filter(filter_options, new_options)
+ filter_options[:if].push(new_options[:unless]) if new_options.key?(:unless)
+ filter_options[:unless].push(new_options[:if]) if new_options.key?(:if)
+ end
+
+ def recompile!(_options, _per_key)
+ _update_filter(self.options, _options)
+ _update_filter(self.per_key, _per_key)
+
+ @callback_id = next_id
+ @filter = _compile_filter(@raw_filter)
+ @compiled_options = _compile_options(@options)
+ _compile_per_key_options
+ end
+
+ def _compile_per_key_options
+ key_options = _compile_options(@per_key)
+
+ @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def _one_time_conditions_valid_#{@callback_id}?
+ true #{key_options[0]}
end
- end
+ RUBY_EVAL
end
- # TODO: Decompose into more Array like behavior
- def replace_or_append!(chain)
- if index = index(chain)
- self[index] = chain
- else
- self << chain
+ # This will supply contents for before and around filters, and no
+ # contents for after filters (for the forward pass).
+ def start(key=nil, object=nil)
+ return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
+
+ # options[0] is the compiled form of supplied conditions
+ # options[1] is the "end" for the conditional
+ #
+ if @kind == :before || @kind == :around
+ if @kind == :before
+ # if condition # before_save :filter_name, :if => :condition
+ # filter_name
+ # end
+ filter = <<-RUBY_EVAL
+ unless halted
+ result = #{@filter}
+ halted = (#{chain.config[:terminator]})
+ end
+ RUBY_EVAL
+
+ [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
+ else
+ # Compile around filters with conditions into proxy methods
+ # that contain the conditions.
+ #
+ # For `around_save :filter_name, :if => :condition':
+ #
+ # def _conditional_callback_save_17
+ # if condition
+ # filter_name do
+ # yield self
+ # end
+ # else
+ # yield self
+ # end
+ # end
+ #
+ name = "_conditional_callback_#{@kind}_#{next_id}"
+ txt, line = <<-RUBY_EVAL, __LINE__ + 1
+ def #{name}(halted)
+ #{@compiled_options[0] || "if true"} && !halted
+ #{@filter} do
+ yield self
+ end
+ else
+ yield self
+ end
+ end
+ RUBY_EVAL
+ @klass.class_eval(txt, __FILE__, line)
+ "#{name}(halted) do"
+ end
end
- self
end
- def find(callback, &block)
- select { |c| c == callback && (!block_given? || yield(c)) }.first
- end
+ # This will supply contents for around and after filters, but not
+ # before filters (for the backward pass).
+ def end(key=nil, object=nil)
+ return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
- def delete(callback)
- super(callback.is_a?(Callback) ? callback : find(callback))
+ if @kind == :around || @kind == :after
+ # if condition # after_save :filter_name, :if => :condition
+ # filter_name
+ # end
+ if @kind == :after
+ [@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
+ else
+ "end"
+ end
+ end
end
private
- def self.extract_options(*methods, &block)
- methods.flatten!
- options = methods.extract_options!
- methods << block if block_given?
- return methods, options
- end
- def extract_options(*methods, &block)
- self.class.extract_options(*methods, &block)
+ # Options support the same options as filters themselves (and support
+ # symbols, string, procs, and objects), so compile a conditional
+ # expression based on the options
+ def _compile_options(options)
+ return [] if options[:if].empty? && options[:unless].empty?
+
+ conditions = []
+
+ unless options[:if].empty?
+ conditions << Array.wrap(_compile_filter(options[:if]))
end
- end
- class Callback
- attr_reader :kind, :method, :identifier, :options
+ unless options[:unless].empty?
+ conditions << Array.wrap(_compile_filter(options[:unless])).map {|f| "!#{f}"}
+ end
- def initialize(kind, method, options = {})
- @kind = kind
- @method = method
- @identifier = options[:identifier]
- @options = options
+ ["if #{conditions.flatten.join(" && ")}", "end"]
end
- def ==(other)
- case other
- when Callback
- (self.identifier && self.identifier == other.identifier) || self.method == other.method
+ # Filters support:
+ #
+ # Arrays:: Used in conditions. This is used to specify
+ # multiple conditions. Used internally to
+ # merge conditions from skip_* filters
+ # Symbols:: A method to call
+ # Strings:: Some content to evaluate
+ # Procs:: A proc to call with the object
+ # Objects:: An object with a before_foo method on it to call
+ #
+ # All of these objects are compiled into methods and handled
+ # the same after this point:
+ #
+ # Arrays:: Merged together into a single filter
+ # Symbols:: Already methods
+ # Strings:: class_eval'ed into methods
+ # Procs:: define_method'ed into methods
+ # Objects::
+ # a method is created that calls the before_foo method
+ # on the object.
+ #
+ def _compile_filter(filter)
+ method_name = "_callback_#{@kind}_#{next_id}"
+ case filter
+ when Array
+ filter.map {|f| _compile_filter(f)}
+ when Symbol
+ filter
+ when String
+ "(#{filter})"
+ when Proc
+ @klass.send(:define_method, method_name, &filter)
+ return method_name if filter.arity <= 0
+
+ method_name << (filter.arity == 1 ? "(self)" : " self, Proc.new ")
else
- (self.identifier && self.identifier == other) || self.method == other
+ @klass.send(:define_method, "#{method_name}_object") { filter }
+
+ _normalize_legacy_filter(kind, filter)
+ scopes = Array.wrap(chain.config[:scope])
+ method_to_call = scopes.map{ |s| s.is_a?(Symbol) ? send(s) : s }.join("_")
+
+ @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def #{method_name}(&blk)
+ #{method_name}_object.send(:#{method_to_call}, self, &blk)
+ end
+ RUBY_EVAL
+
+ method_name
end
end
- def eql?(other)
- self == other
+ def _normalize_legacy_filter(kind, filter)
+ if !filter.respond_to?(kind) && filter.respond_to?(:filter)
+ filter.metaclass.class_eval(
+ "def #{kind}(context, &block) filter(context, &block) end",
+ __FILE__, __LINE__ - 1)
+ elsif filter.respond_to?(:before) && filter.respond_to?(:after) && kind == :around
+ def filter.around(context)
+ should_continue = before(context)
+ yield if should_continue
+ after(context)
+ end
+ end
end
+ end
- def dup
- self.class.new(@kind, @method, @options.dup)
+ # An Array with a compile method
+ class CallbackChain < Array
+ attr_reader :name, :config
+
+ def initialize(name, config)
+ @name = name
+ @config = {
+ :terminator => "false",
+ :rescuable => false,
+ :scope => [ :kind ]
+ }.merge(config)
end
- def hash
- if @identifier
- @identifier.hash
- else
- @method.hash
+ def compile(key=nil, object=nil)
+ method = []
+ method << "value = nil"
+ method << "halted = false"
+
+ each do |callback|
+ method << callback.start(key, object)
+ end
+
+ if config[:rescuable]
+ method << "rescued_error = nil"
+ method << "begin"
+ end
+
+ method << "value = yield if block_given? && !halted"
+
+ if config[:rescuable]
+ method << "rescue Exception => e"
+ method << "rescued_error = e"
+ method << "end"
end
+
+ reverse_each do |callback|
+ method << callback.end(key, object)
+ end
+
+ method << "raise rescued_error if rescued_error" if config[:rescuable]
+ method << "halted ? false : (block_given? ? value : true)"
+ method.compact.join("\n")
end
- def call(*args, &block)
- evaluate_method(method, *args, &block) if should_run_callback?(*args)
- rescue LocalJumpError
- raise ArgumentError,
- "Cannot yield from a Proc type filter. The Proc must take two " +
- "arguments and execute #call on the second argument."
+ def clone(klass)
+ chain = CallbackChain.new(@name, @config.dup)
+ callbacks = map { |c| c.clone(chain, klass) }
+ chain.push(*callbacks)
end
+ end
- private
- def evaluate_method(method, *args, &block)
- case method
- when Symbol
- object = args.shift
- object.send(method, *args, &block)
- when String
- eval(method, args.first.instance_eval { binding })
- when Proc, Method
- method.call(*args, &block)
- else
- if method.respond_to?(kind)
- method.send(kind, *args, &block)
- else
- raise ArgumentError,
- "Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
- "a block to be invoked, or an object responding to the callback method."
+ module ClassMethods
+ # Make the run_callbacks :save method. The generated method takes
+ # a block that it'll yield to. It'll call the before and around filters
+ # in order, yield the block, and then run the after filters.
+ #
+ # run_callbacks :save do
+ # save
+ # end
+ #
+ # The run_callbacks :save method can optionally take a key, which
+ # will be used to compile an optimized callback method for each
+ # key. See #define_callbacks for more information.
+ #
+ def __define_runner(symbol) #:nodoc:
+ body = send("_#{symbol}_callbacks").compile(nil)
+
+ body, line = <<-RUBY_EVAL, __LINE__
+ def _run_#{symbol}_callbacks(key = nil, &blk)
+ if key
+ name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
+
+ unless respond_to?(name)
+ self.class.__create_keyed_callback(name, :#{symbol}, self, &blk)
end
+
+ send(name, &blk)
+ else
+ #{body}
+ end
end
+ private :_run_#{symbol}_callbacks
+ RUBY_EVAL
+
+ silence_warnings do
+ undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
+ class_eval body, __FILE__, line
end
+ end
- def should_run_callback?(*args)
- [options[:if]].flatten.compact.all? { |a| evaluate_method(a, *args) } &&
- ![options[:unless]].flatten.compact.any? { |a| evaluate_method(a, *args) }
+ # This is called the first time a callback is called with a particular
+ # key. It creates a new callback method for the key, calculating
+ # which callbacks can be omitted because of per_key conditions.
+ #
+ def __create_keyed_callback(name, kind, object, &blk) #:nodoc:
+ @_keyed_callbacks ||= {}
+ @_keyed_callbacks[name] ||= begin
+ str = send("_#{kind}_callbacks").compile(name, object)
+ class_eval "def #{name}() #{str} end", __FILE__, __LINE__
+ true
end
- end
+ end
- def self.included(base)
- base.extend ClassMethods
- end
+ # This is used internally to append, prepend and skip callbacks to the
+ # CallbackChain.
+ #
+ def __update_callbacks(name, filters = [], block = nil) #:nodoc:
+ type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
+ options = filters.last.is_a?(Hash) ? filters.pop : {}
+ filters.unshift(block) if block
- module ClassMethods
- def define_callbacks(*callbacks)
- callbacks.each do |callback|
- class_eval <<-"end_eval", __FILE__, __LINE__ + 1
- def self.#{callback}(*methods, &block) # def self.before_save(*methods, &block)
- callbacks = CallbackChain.build(:#{callback}, *methods, &block) # callbacks = CallbackChain.build(:before_save, *methods, &block)
- @#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
- @#{callback}_callbacks.concat callbacks # @before_save_callbacks.concat callbacks
- end # end
- #
- def self.#{callback}_callback_chain # def self.before_save_callback_chain
- @#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
- #
- if superclass.respond_to?(:#{callback}_callback_chain) # if superclass.respond_to?(:before_save_callback_chain)
- CallbackChain.new( # CallbackChain.new(
- superclass.#{callback}_callback_chain + # superclass.before_save_callback_chain +
- @#{callback}_callbacks # @before_save_callbacks
- ) # )
- else # else
- @#{callback}_callbacks # @before_save_callbacks
- end # end
- end # end
- end_eval
+ chain = send("_#{name}_callbacks")
+ yield chain, type, filters, options if block_given?
+
+ __define_runner(name)
+ end
+
+ # Set callbacks for a previously defined callback.
+ #
+ # Syntax:
+ # set_callback :save, :before, :before_meth
+ # set_callback :save, :after, :after_meth, :if => :condition
+ # set_callback :save, :around, lambda { |r| stuff; yield; stuff }
+ #
+ # Use skip_callback to skip any defined one.
+ #
+ # When creating or skipping callbacks, you can specify conditions that
+ # are always the same for a given key. For instance, in ActionPack,
+ # we convert :only and :except conditions into per-key conditions.
+ #
+ # before_filter :authenticate, :except => "index"
+ # becomes
+ # dispatch_callback :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
+ #
+ # Per-Key conditions are evaluated only once per use of a given key.
+ # In the case of the above example, you would do:
+ #
+ # run_callbacks(:dispatch, action_name) { ... dispatch stuff ... }
+ #
+ # In that case, each action_name would get its own compiled callback
+ # method that took into consideration the per_key conditions. This
+ # is a speed improvement for ActionPack.
+ #
+ def set_callback(name, *filters, &block)
+ __update_callbacks(name, filters, block) do |chain, type, filters, options|
+ filters.map! do |filter|
+ chain.delete_if {|c| c.matches?(type, filter) }
+ Callback.new(chain, filter, type, options.dup, self)
+ end
+
+ options[:prepend] ? chain.unshift(*filters) : chain.push(*filters)
end
end
- end
- # Runs all the callbacks defined for the given options.
- #
- # If a block is given it will be called after each callback receiving as arguments:
- #
- # * the result from the callback
- # * the object which has the callback
- #
- # If the result from the block evaluates to +true+, the callback chain is stopped.
- #
- # Example:
- # class Storage
- # include ActiveSupport::Callbacks
- #
- # define_callbacks :before_save, :after_save
- # end
- #
- # class ConfigStorage < Storage
- # before_save :pass
- # before_save :pass
- # before_save :stop
- # before_save :pass
- #
- # def pass
- # puts "pass"
- # end
- #
- # def stop
- # puts "stop"
- # return false
- # end
- #
- # def save
- # result = run_callbacks(:before_save) { |result, object| result == false }
- # puts "- save" if result
- # end
- # end
- #
- # config = ConfigStorage.new
- # config.save
- #
- # Output:
- # pass
- # pass
- # stop
- def run_callbacks(kind, options = {}, &block)
- self.class.send("#{kind}_callback_chain").run(self, options, &block)
+ # Skip a previously defined callback for a given type.
+ #
+ def skip_callback(name, *filters, &block)
+ __update_callbacks(name, filters, block) do |chain, type, filters, options|
+ chain = send("_#{name}_callbacks=", chain.clone(self))
+
+ filters.each do |filter|
+ filter = chain.find {|c| c.matches?(type, filter) }
+
+ if filter && options.any?
+ filter.recompile!(options, options[:per_key] || {})
+ else
+ chain.delete(filter)
+ end
+ end
+ end
+ end
+
+ # Reset callbacks for a given type.
+ #
+ def reset_callbacks(symbol)
+ send("_#{symbol}_callbacks").clear
+ __define_runner(symbol)
+ end
+
+ # Define callbacks types.
+ #
+ # ==== Example
+ #
+ # define_callbacks :validate
+ #
+ # ==== Options
+ #
+ # * <tt>:terminator</tt> - Indicates when a before filter is considered
+ # to be halted.
+ #
+ # define_callbacks :validate, :terminator => "result == false"
+ #
+ # In the example above, if any before validate callbacks returns false,
+ # other callbacks are not executed. Defaults to "false".
+ #
+ # * <tt>:rescuable</tt> - By default, after filters are not executed if
+ # the given block or an before_filter raises an error. Supply :rescuable => true
+ # to change this behavior.
+ #
+ # * <tt>:scope</tt> - Show which methods should be executed when a class
+ # is giben as callback:
+ #
+ # define_callbacks :filters, :scope => [ :kind ]
+ #
+ # When a class is given:
+ #
+ # before_filter MyFilter
+ #
+ # It will call the type of the filter in the given class, which in this
+ # case, is "before".
+ #
+ # If, for instance, you supply the given scope:
+ #
+ # define_callbacks :validate, :scope => [ :kind, :name ]
+ #
+ # It will call "#{kind}_#{name}" in the given class. So "before_validate"
+ # will be called in the class below:
+ #
+ # before_validate MyValidation
+ #
+ # Defaults to :kind.
+ #
+ def define_callbacks(*symbols)
+ config = symbols.last.is_a?(Hash) ? symbols.pop : {}
+ symbols.each do |symbol|
+ extlib_inheritable_accessor("_#{symbol}_callbacks") do
+ CallbackChain.new(symbol, config)
+ end
+
+ __define_runner(symbol)
+ end
+ end
end
end
end
diff --git a/activesupport/lib/active_support/deprecated_callbacks.rb b/activesupport/lib/active_support/deprecated_callbacks.rb
new file mode 100644
index 0000000000..20fb03cbeb
--- /dev/null
+++ b/activesupport/lib/active_support/deprecated_callbacks.rb
@@ -0,0 +1,283 @@
+require 'active_support/core_ext/array/extract_options'
+
+module ActiveSupport
+ # Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
+ # before or after an alteration of the object state.
+ #
+ # Mixing in this module allows you to define callbacks in your class.
+ #
+ # Example:
+ # class Storage
+ # include ActiveSupport::DeprecatedCallbacks
+ #
+ # define_callbacks :before_save, :after_save
+ # end
+ #
+ # class ConfigStorage < Storage
+ # before_save :saving_message
+ # def saving_message
+ # puts "saving..."
+ # end
+ #
+ # after_save do |object|
+ # puts "saved"
+ # end
+ #
+ # def save
+ # run_callbacks(:before_save)
+ # puts "- save"
+ # run_callbacks(:after_save)
+ # end
+ # end
+ #
+ # config = ConfigStorage.new
+ # config.save
+ #
+ # Output:
+ # saving...
+ # - save
+ # saved
+ #
+ # Callbacks from parent classes are inherited.
+ #
+ # Example:
+ # class Storage
+ # include ActiveSupport::DeprecatedCallbacks
+ #
+ # define_callbacks :before_save, :after_save
+ #
+ # before_save :prepare
+ # def prepare
+ # puts "preparing save"
+ # end
+ # end
+ #
+ # class ConfigStorage < Storage
+ # before_save :saving_message
+ # def saving_message
+ # puts "saving..."
+ # end
+ #
+ # after_save do |object|
+ # puts "saved"
+ # end
+ #
+ # def save
+ # run_callbacks(:before_save)
+ # puts "- save"
+ # run_callbacks(:after_save)
+ # end
+ # end
+ #
+ # config = ConfigStorage.new
+ # config.save
+ #
+ # Output:
+ # preparing save
+ # saving...
+ # - save
+ # saved
+ module DeprecatedCallbacks
+ class CallbackChain < Array
+ def self.build(kind, *methods, &block)
+ methods, options = extract_options(*methods, &block)
+ methods.map! { |method| Callback.new(kind, method, options) }
+ new(methods)
+ end
+
+ def run(object, options = {}, &terminator)
+ enumerator = options[:enumerator] || :each
+
+ unless block_given?
+ send(enumerator) { |callback| callback.call(object) }
+ else
+ send(enumerator) do |callback|
+ result = callback.call(object)
+ break result if terminator.call(result, object)
+ end
+ end
+ end
+
+ # TODO: Decompose into more Array like behavior
+ def replace_or_append!(chain)
+ if index = index(chain)
+ self[index] = chain
+ else
+ self << chain
+ end
+ self
+ end
+
+ def find(callback, &block)
+ select { |c| c == callback && (!block_given? || yield(c)) }.first
+ end
+
+ def delete(callback)
+ super(callback.is_a?(Callback) ? callback : find(callback))
+ end
+
+ private
+ def self.extract_options(*methods, &block)
+ methods.flatten!
+ options = methods.extract_options!
+ methods << block if block_given?
+ return methods, options
+ end
+
+ def extract_options(*methods, &block)
+ self.class.extract_options(*methods, &block)
+ end
+ end
+
+ class Callback
+ attr_reader :kind, :method, :identifier, :options
+
+ def initialize(kind, method, options = {})
+ @kind = kind
+ @method = method
+ @identifier = options[:identifier]
+ @options = options
+ end
+
+ def ==(other)
+ case other
+ when Callback
+ (self.identifier && self.identifier == other.identifier) || self.method == other.method
+ else
+ (self.identifier && self.identifier == other) || self.method == other
+ end
+ end
+
+ def eql?(other)
+ self == other
+ end
+
+ def dup
+ self.class.new(@kind, @method, @options.dup)
+ end
+
+ def hash
+ if @identifier
+ @identifier.hash
+ else
+ @method.hash
+ end
+ end
+
+ def call(*args, &block)
+ evaluate_method(method, *args, &block) if should_run_callback?(*args)
+ rescue LocalJumpError
+ raise ArgumentError,
+ "Cannot yield from a Proc type filter. The Proc must take two " +
+ "arguments and execute #call on the second argument."
+ end
+
+ private
+ def evaluate_method(method, *args, &block)
+ case method
+ when Symbol
+ object = args.shift
+ object.send(method, *args, &block)
+ when String
+ eval(method, args.first.instance_eval { binding })
+ when Proc, Method
+ method.call(*args, &block)
+ else
+ if method.respond_to?(kind)
+ method.send(kind, *args, &block)
+ else
+ raise ArgumentError,
+ "Callbacks must be a symbol denoting the method to call, a string to be evaluated, " +
+ "a block to be invoked, or an object responding to the callback method."
+ end
+ end
+ end
+
+ def should_run_callback?(*args)
+ [options[:if]].flatten.compact.all? { |a| evaluate_method(a, *args) } &&
+ ![options[:unless]].flatten.compact.any? { |a| evaluate_method(a, *args) }
+ end
+ end
+
+ def self.included(base)
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ def define_callbacks(*callbacks)
+ ActiveSupport::Deprecation.warn('ActiveSupport::DeprecatedCallbacks has been deprecated in favor of ActiveSupport::Callbacks', caller)
+
+ callbacks.each do |callback|
+ class_eval <<-"end_eval", __FILE__, __LINE__ + 1
+ def self.#{callback}(*methods, &block) # def self.before_save(*methods, &block)
+ callbacks = CallbackChain.build(:#{callback}, *methods, &block) # callbacks = CallbackChain.build(:before_save, *methods, &block)
+ @#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
+ @#{callback}_callbacks.concat callbacks # @before_save_callbacks.concat callbacks
+ end # end
+ #
+ def self.#{callback}_callback_chain # def self.before_save_callback_chain
+ @#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
+ #
+ if superclass.respond_to?(:#{callback}_callback_chain) # if superclass.respond_to?(:before_save_callback_chain)
+ CallbackChain.new( # CallbackChain.new(
+ superclass.#{callback}_callback_chain + # superclass.before_save_callback_chain +
+ @#{callback}_callbacks # @before_save_callbacks
+ ) # )
+ else # else
+ @#{callback}_callbacks # @before_save_callbacks
+ end # end
+ end # end
+ end_eval
+ end
+ end
+ end
+
+ # Runs all the callbacks defined for the given options.
+ #
+ # If a block is given it will be called after each callback receiving as arguments:
+ #
+ # * the result from the callback
+ # * the object which has the callback
+ #
+ # If the result from the block evaluates to +true+, the callback chain is stopped.
+ #
+ # Example:
+ # class Storage
+ # include ActiveSupport::DeprecatedCallbacks
+ #
+ # define_callbacks :before_save, :after_save
+ # end
+ #
+ # class ConfigStorage < Storage
+ # before_save :pass
+ # before_save :pass
+ # before_save :stop
+ # before_save :pass
+ #
+ # def pass
+ # puts "pass"
+ # end
+ #
+ # def stop
+ # puts "stop"
+ # return false
+ # end
+ #
+ # def save
+ # result = run_callbacks(:before_save) { |result, object| result == false }
+ # puts "- save" if result
+ # end
+ # end
+ #
+ # config = ConfigStorage.new
+ # config.save
+ #
+ # Output:
+ # pass
+ # pass
+ # stop
+ def run_callbacks(kind, options = {}, &block)
+ self.class.send("#{kind}_callback_chain").run(self, options, &block)
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/deprecation/behaviors.rb b/activesupport/lib/active_support/deprecation/behaviors.rb
index c531a1aa58..0c065fb103 100644
--- a/activesupport/lib/active_support/deprecation/behaviors.rb
+++ b/activesupport/lib/active_support/deprecation/behaviors.rb
@@ -23,7 +23,7 @@ module ActiveSupport
$stderr.puts callstack.join("\n ") if debug
},
'development' => Proc.new { |message, callstack|
- logger = defined?(Rails) ? Rails.logger : Logger.new($stderr)
+ logger = (Rails.logger if defined?(Rails)) || Logger.new($stderr)
logger.warn message
logger.debug callstack.join("\n ") if debug
}
diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb
index b197fbc9bf..f810f53029 100644
--- a/activesupport/lib/active_support/memoizable.rb
+++ b/activesupport/lib/active_support/memoizable.rb
@@ -2,19 +2,6 @@ require 'active_support/core_ext/object/metaclass'
require 'active_support/core_ext/module/aliasing'
module ActiveSupport
- module SafelyMemoizable
- def safely_memoize(*symbols)
- symbols.each do |symbol|
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def #{symbol}(*args)
- memoized = @_memoized_#{symbol} || ::ActiveSupport::ConcurrentHash.new
- memoized[args] ||= memoized_#{symbol}(*args)
- end
- RUBY
- end
- end
- end
-
module Memoizable
def self.memoized_ivar_for(symbol)
"@_memoized_#{symbol.to_s.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')}".to_sym
diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb
index fcdc09ff08..282346b1a6 100644
--- a/activesupport/lib/active_support/message_verifier.rb
+++ b/activesupport/lib/active_support/message_verifier.rb
@@ -29,7 +29,7 @@ module ActiveSupport
raise InvalidSignature if signed_message.blank?
data, digest = signed_message.split("--")
- if secure_compare(digest, generate_digest(data))
+ if data.present? && digest.present? && secure_compare(digest, generate_digest(data))
Marshal.load(ActiveSupport::Base64.decode64(data))
else
raise InvalidSignature
diff --git a/activesupport/lib/active_support/new_callbacks.rb b/activesupport/lib/active_support/new_callbacks.rb
deleted file mode 100644
index 2f0853d84a..0000000000
--- a/activesupport/lib/active_support/new_callbacks.rb
+++ /dev/null
@@ -1,563 +0,0 @@
-require 'active_support/core_ext/array/wrap'
-require 'active_support/core_ext/class/inheritable_attributes'
-require 'active_support/core_ext/kernel/reporting'
-
-module ActiveSupport
- # Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
- # before or after an alteration of the object state.
- #
- # Mixing in this module allows you to define callbacks in your class.
- #
- # Example:
- # class Storage
- # include ActiveSupport::Callbacks
- #
- # define_callbacks :save
- # end
- #
- # class ConfigStorage < Storage
- # set_callback :save, :before, :saving_message
- # def saving_message
- # puts "saving..."
- # end
- #
- # set_callback :save, :after do |object|
- # puts "saved"
- # end
- #
- # def save
- # _run_set_callback :save,s do
- # puts "- save"
- # end
- # end
- # end
- #
- # config = ConfigStorage.new
- # config.save
- #
- # Output:
- # saving...
- # - save
- # saved
- #
- # Callbacks from parent classes are inherited.
- #
- # Example:
- # class Storage
- # include ActiveSupport::Callbacks
- #
- # define_callbacks :save
- #
- # set_callback :save, :before, :prepare
- # def prepare
- # puts "preparing save"
- # end
- # end
- #
- # class ConfigStorage < Storage
- # set_callback :save, :before, :saving_message
- # def saving_message
- # puts "saving..."
- # end
- #
- # set_callback :save, :after do |object|
- # puts "saved"
- # end
- #
- # def save
- # _run_set_callback :save,s do
- # puts "- save"
- # end
- # end
- # end
- #
- # config = ConfigStorage.new
- # config.save
- #
- # Output:
- # preparing save
- # saving...
- # - save
- # saved
- #
- module NewCallbacks
- def self.included(klass)
- klass.extend ClassMethods
- end
-
- def run_callbacks(kind, options = {}, &blk)
- send("_run_#{kind}_callbacks", &blk)
- end
-
- class Callback
- @@_callback_sequence = 0
-
- attr_accessor :chain, :filter, :kind, :options, :per_key, :klass
-
- def initialize(chain, filter, kind, options, klass)
- @chain, @kind, @klass = chain, kind, klass
- normalize_options!(options)
-
- @per_key = options.delete(:per_key)
- @raw_filter, @options = filter, options
- @filter = _compile_filter(filter)
- @compiled_options = _compile_options(options)
- @callback_id = next_id
-
- _compile_per_key_options
- end
-
- def clone(chain, klass)
- obj = super()
- obj.chain = chain
- obj.klass = klass
- obj.per_key = @per_key.dup
- obj.options = @options.dup
- obj.per_key[:if] = @per_key[:if].dup
- obj.per_key[:unless] = @per_key[:unless].dup
- obj.options[:if] = @options[:if].dup
- obj.options[:unless] = @options[:unless].dup
- obj
- end
-
- def normalize_options!(options)
- options[:if] = Array.wrap(options[:if])
- options[:unless] = Array.wrap(options[:unless])
-
- options[:per_key] ||= {}
- options[:per_key][:if] = Array.wrap(options[:per_key][:if])
- options[:per_key][:unless] = Array.wrap(options[:per_key][:unless])
- end
-
- def name
- chain.name
- end
-
- def next_id
- @@_callback_sequence += 1
- end
-
- def matches?(_kind, _filter)
- @kind == _kind && @filter == _filter
- end
-
- def _update_filter(filter_options, new_options)
- filter_options[:if].push(new_options[:unless]) if new_options.key?(:unless)
- filter_options[:unless].push(new_options[:if]) if new_options.key?(:if)
- end
-
- def recompile!(_options, _per_key)
- _update_filter(self.options, _options)
- _update_filter(self.per_key, _per_key)
-
- @callback_id = next_id
- @filter = _compile_filter(@raw_filter)
- @compiled_options = _compile_options(@options)
- _compile_per_key_options
- end
-
- def _compile_per_key_options
- key_options = _compile_options(@per_key)
-
- @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def _one_time_conditions_valid_#{@callback_id}?
- true #{key_options[0]}
- end
- RUBY_EVAL
- end
-
- # This will supply contents for before and around filters, and no
- # contents for after filters (for the forward pass).
- def start(key=nil, object=nil)
- return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
-
- # options[0] is the compiled form of supplied conditions
- # options[1] is the "end" for the conditional
- #
- if @kind == :before || @kind == :around
- if @kind == :before
- # if condition # before_save :filter_name, :if => :condition
- # filter_name
- # end
- filter = <<-RUBY_EVAL
- unless halted
- result = #{@filter}
- halted = (#{chain.config[:terminator]})
- end
- RUBY_EVAL
-
- [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
- else
- # Compile around filters with conditions into proxy methods
- # that contain the conditions.
- #
- # For `around_save :filter_name, :if => :condition':
- #
- # def _conditional_callback_save_17
- # if condition
- # filter_name do
- # yield self
- # end
- # else
- # yield self
- # end
- # end
- #
- name = "_conditional_callback_#{@kind}_#{next_id}"
- txt, line = <<-RUBY_EVAL, __LINE__ + 1
- def #{name}(halted)
- #{@compiled_options[0] || "if true"} && !halted
- #{@filter} do
- yield self
- end
- else
- yield self
- end
- end
- RUBY_EVAL
- @klass.class_eval(txt, __FILE__, line)
- "#{name}(halted) do"
- end
- end
- end
-
- # This will supply contents for around and after filters, but not
- # before filters (for the backward pass).
- def end(key=nil, object=nil)
- return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
-
- if @kind == :around || @kind == :after
- # if condition # after_save :filter_name, :if => :condition
- # filter_name
- # end
- if @kind == :after
- [@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
- else
- "end"
- end
- end
- end
-
- private
-
- # Options support the same options as filters themselves (and support
- # symbols, string, procs, and objects), so compile a conditional
- # expression based on the options
- def _compile_options(options)
- return [] if options[:if].empty? && options[:unless].empty?
-
- conditions = []
-
- unless options[:if].empty?
- conditions << Array.wrap(_compile_filter(options[:if]))
- end
-
- unless options[:unless].empty?
- conditions << Array.wrap(_compile_filter(options[:unless])).map {|f| "!#{f}"}
- end
-
- ["if #{conditions.flatten.join(" && ")}", "end"]
- end
-
- # Filters support:
- #
- # Arrays:: Used in conditions. This is used to specify
- # multiple conditions. Used internally to
- # merge conditions from skip_* filters
- # Symbols:: A method to call
- # Strings:: Some content to evaluate
- # Procs:: A proc to call with the object
- # Objects:: An object with a before_foo method on it to call
- #
- # All of these objects are compiled into methods and handled
- # the same after this point:
- #
- # Arrays:: Merged together into a single filter
- # Symbols:: Already methods
- # Strings:: class_eval'ed into methods
- # Procs:: define_method'ed into methods
- # Objects::
- # a method is created that calls the before_foo method
- # on the object.
- #
- def _compile_filter(filter)
- method_name = "_callback_#{@kind}_#{next_id}"
- case filter
- when Array
- filter.map {|f| _compile_filter(f)}
- when Symbol
- filter
- when String
- "(#{filter})"
- when Proc
- @klass.send(:define_method, method_name, &filter)
- return method_name if filter.arity <= 0
-
- method_name << (filter.arity == 1 ? "(self)" : " self, Proc.new ")
- else
- @klass.send(:define_method, "#{method_name}_object") { filter }
-
- _normalize_legacy_filter(kind, filter)
- scopes = Array.wrap(chain.config[:scope])
- method_to_call = scopes.map{ |s| s.is_a?(Symbol) ? send(s) : s }.join("_")
-
- @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def #{method_name}(&blk)
- #{method_name}_object.send(:#{method_to_call}, self, &blk)
- end
- RUBY_EVAL
-
- method_name
- end
- end
-
- def _normalize_legacy_filter(kind, filter)
- if !filter.respond_to?(kind) && filter.respond_to?(:filter)
- filter.metaclass.class_eval(
- "def #{kind}(context, &block) filter(context, &block) end",
- __FILE__, __LINE__ - 1)
- elsif filter.respond_to?(:before) && filter.respond_to?(:after) && kind == :around
- def filter.around(context)
- should_continue = before(context)
- yield if should_continue
- after(context)
- end
- end
- end
- end
-
- # An Array with a compile method
- class CallbackChain < Array
- attr_reader :name, :config
-
- def initialize(name, config)
- @name = name
- @config = {
- :terminator => "false",
- :rescuable => false,
- :scope => [ :kind ]
- }.merge(config)
- end
-
- def compile(key=nil, object=nil)
- method = []
- method << "value = nil"
- method << "halted = false"
-
- each do |callback|
- method << callback.start(key, object)
- end
-
- if config[:rescuable]
- method << "rescued_error = nil"
- method << "begin"
- end
-
- method << "value = yield if block_given? && !halted"
-
- if config[:rescuable]
- method << "rescue Exception => e"
- method << "rescued_error = e"
- method << "end"
- end
-
- reverse_each do |callback|
- method << callback.end(key, object)
- end
-
- method << "raise rescued_error if rescued_error" if config[:rescuable]
- method << "halted ? false : (block_given? ? value : true)"
- method.compact.join("\n")
- end
-
- def clone(klass)
- chain = CallbackChain.new(@name, @config.dup)
- callbacks = map { |c| c.clone(chain, klass) }
- chain.push(*callbacks)
- end
- end
-
- module ClassMethods
- # Make the _run_set_callback :save method. The generated method takes
- # a block that it'll yield to. It'll call the before and around filters
- # in order, yield the block, and then run the after filters.
- #
- # _run_set_callback :save do
- # save
- # end
- #
- # The _run_set_callback :save method can optionally take a key, which
- # will be used to compile an optimized callback method for each
- # key. See #define_callbacks for more information.
- #
- def __define_runner(symbol) #:nodoc:
- body = send("_#{symbol}_callbacks").compile(nil)
-
- body, line = <<-RUBY_EVAL, __LINE__
- def _run_#{symbol}_callbacks(key = nil, &blk)
- if key
- name = "_run__\#{self.class.name.hash.abs}__#{symbol}__\#{key.hash.abs}__callbacks"
-
- unless respond_to?(name)
- self.class.__create_keyed_callback(name, :#{symbol}, self, &blk)
- end
-
- send(name, &blk)
- else
- #{body}
- end
- end
- RUBY_EVAL
-
- silence_warnings do
- undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
- class_eval body, __FILE__, line
- end
- end
-
- # This is called the first time a callback is called with a particular
- # key. It creates a new callback method for the key, calculating
- # which callbacks can be omitted because of per_key conditions.
- #
- def __create_keyed_callback(name, kind, object, &blk) #:nodoc:
- @_keyed_callbacks ||= {}
- @_keyed_callbacks[name] ||= begin
- str = send("_#{kind}_callbacks").compile(name, object)
- class_eval "def #{name}() #{str} end", __FILE__, __LINE__
- true
- end
- end
-
- # This is used internally to append, prepend and skip callbacks to the
- # CallbackChain.
- #
- def __update_callbacks(name, filters = [], block = nil) #:nodoc:
- type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
- options = filters.last.is_a?(Hash) ? filters.pop : {}
- filters.unshift(block) if block
-
- chain = send("_#{name}_callbacks")
- yield chain, type, filters, options if block_given?
-
- __define_runner(name)
- end
-
- # Set callbacks for a previously defined callback.
- #
- # Syntax:
- # set_callback :save, :before, :before_meth
- # set_callback :save, :after, :after_meth, :if => :condition
- # set_callback :save, :around, lambda { |r| stuff; yield; stuff }
- #
- # It also updates the _run_<name>_callbacks method, which is the public
- # API to run the callbacks. Use skip_callback to skip any defined one.
- #
- # When creating or skipping callbacks, you can specify conditions that
- # are always the same for a given key. For instance, in ActionPack,
- # we convert :only and :except conditions into per-key conditions.
- #
- # before_filter :authenticate, :except => "index"
- # becomes
- # dispatch_callback :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
- #
- # Per-Key conditions are evaluated only once per use of a given key.
- # In the case of the above example, you would do:
- #
- # _run_dispatch_callbacks(action_name) { ... dispatch stuff ... }
- #
- # In that case, each action_name would get its own compiled callback
- # method that took into consideration the per_key conditions. This
- # is a speed improvement for ActionPack.
- #
- def set_callback(name, *filters, &block)
- __update_callbacks(name, filters, block) do |chain, type, filters, options|
- filters.map! do |filter|
- chain.delete_if {|c| c.matches?(type, filter) }
- Callback.new(chain, filter, type, options.dup, self)
- end
-
- options[:prepend] ? chain.unshift(*filters) : chain.push(*filters)
- end
- end
-
- # Skip a previously defined callback for a given type.
- #
- def skip_callback(name, *filters, &block)
- __update_callbacks(name, filters, block) do |chain, type, filters, options|
- chain = send("_#{name}_callbacks=", chain.clone(self))
-
- filters.each do |filter|
- filter = chain.find {|c| c.matches?(type, filter) }
-
- if filter && options.any?
- filter.recompile!(options, options[:per_key] || {})
- else
- chain.delete(filter)
- end
- end
- end
- end
-
- # Reset callbacks for a given type.
- #
- def reset_callbacks(symbol)
- send("_#{symbol}_callbacks").clear
- __define_runner(symbol)
- end
-
- # Define callbacks types.
- #
- # ==== Example
- #
- # define_callbacks :validate
- #
- # ==== Options
- #
- # * <tt>:terminator</tt> - Indicates when a before filter is considered
- # to be halted.
- #
- # define_callbacks :validate, :terminator => "result == false"
- #
- # In the example above, if any before validate callbacks returns false,
- # other callbacks are not executed. Defaults to "false".
- #
- # * <tt>:rescuable</tt> - By default, after filters are not executed if
- # the given block or an before_filter raises an error. Supply :rescuable => true
- # to change this behavior.
- #
- # * <tt>:scope</tt> - Show which methods should be executed when a class
- # is giben as callback:
- #
- # define_callbacks :filters, :scope => [ :kind ]
- #
- # When a class is given:
- #
- # before_filter MyFilter
- #
- # It will call the type of the filter in the given class, which in this
- # case, is "before".
- #
- # If, for instance, you supply the given scope:
- #
- # define_callbacks :validate, :scope => [ :kind, :name ]
- #
- # It will call "#{kind}_#{name}" in the given class. So "before_validate"
- # will be called in the class below:
- #
- # before_validate MyValidation
- #
- # Defaults to :kind.
- #
- def define_callbacks(*symbols)
- config = symbols.last.is_a?(Hash) ? symbols.pop : {}
- symbols.each do |symbol|
- extlib_inheritable_accessor("_#{symbol}_callbacks") do
- CallbackChain.new(symbol, config)
- end
-
- __define_runner(symbol)
- end
- end
- end
- end
-end
diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb
index cdd6d5f49b..bec303f6ab 100644
--- a/activesupport/lib/active_support/testing/isolation.rb
+++ b/activesupport/lib/active_support/testing/isolation.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/load_error'
+
module ActiveSupport
module Testing
class ProxyTestResult
@@ -107,4 +109,4 @@ if ENV['ISOLATION_TEST']
super && test.method_name == ENV['ISOLATION_TEST']
end
end
-end \ No newline at end of file
+end
diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb
index b59ac79e7b..b738ef334c 100644
--- a/activesupport/lib/active_support/testing/setup_and_teardown.rb
+++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb
@@ -1,12 +1,12 @@
-require 'active_support/callbacks'
-
module ActiveSupport
module Testing
module SetupAndTeardown
def self.included(base)
base.class_eval do
+ extend ClassMethods
+
include ActiveSupport::Callbacks
- define_callbacks :setup, :teardown
+ define_callbacks :test
if defined?(MiniTest::Assertions) && TestCase < MiniTest::Assertions
include ForMiniTest
@@ -16,25 +16,38 @@ module ActiveSupport
end
end
+ module ClassMethods
+ def setup(*args, &block)
+ set_callback(:test, :before, *args, &block)
+ end
+
+ def teardown(*args, &block)
+ set_callback(:test, :after, *args, &block)
+ end
+
+ def wrap(*args, &block)
+ set_callback(:test, :around, *args, &block)
+ end
+ end
+
module ForMiniTest
def run(runner)
result = '.'
begin
- run_callbacks :setup
- result = super
+ run_callbacks :test do
+ begin
+ result = super
+ rescue Exception => e
+ result = runner.puke(self.class, self.name, e)
+ end
+ end
rescue Exception => e
result = runner.puke(self.class, self.name, e)
- ensure
- begin
- run_callbacks :teardown, :enumerator => :reverse_each
- rescue Exception => e
- result = runner.puke(self.class, self.name, e)
- end
end
result
end
end
-
+
module ForClassicTestUnit
# For compatibility with Ruby < 1.8.6
PASSTHROUGH_EXCEPTIONS = Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS rescue [NoMemoryError, SignalException, Interrupt, SystemExit]
@@ -57,27 +70,27 @@ module ActiveSupport
@_result = result
begin
begin
- run_callbacks :setup
- setup
- __send__(@method_name)
- mocha_verify(assertion_counter) if using_mocha
- rescue Mocha::ExpectationError => e
- add_failure(e.message, e.backtrace)
+ run_callbacks :test do
+ begin
+ setup
+ __send__(@method_name)
+ mocha_verify(assertion_counter) if using_mocha
+ rescue Mocha::ExpectationError => e
+ add_failure(e.message, e.backtrace)
+ rescue Test::Unit::AssertionFailedError => e
+ add_failure(e.message, e.backtrace)
+ rescue Exception => e
+ raise if PASSTHROUGH_EXCEPTIONS.include?(e.class)
+ add_error(e)
+ ensure
+ teardown
+ end
+ end
rescue Test::Unit::AssertionFailedError => e
add_failure(e.message, e.backtrace)
rescue Exception => e
raise if PASSTHROUGH_EXCEPTIONS.include?(e.class)
add_error(e)
- ensure
- begin
- teardown
- run_callbacks :teardown, :enumerator => :reverse_each
- rescue Test::Unit::AssertionFailedError => e
- add_failure(e.message, e.backtrace)
- rescue Exception => e
- raise if PASSTHROUGH_EXCEPTIONS.include?(e.class)
- add_error(e)
- end
end
ensure
mocha_teardown if using_mocha
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb
index 7667f11343..892aa97ad7 100644
--- a/activesupport/test/caching_test.rb
+++ b/activesupport/test/caching_test.rb
@@ -342,3 +342,22 @@ uses_memcached 'memcached backed store' do
include CacheStoreBehavior
end
end
+
+class CacheStoreLoggerTest < ActiveSupport::TestCase
+ def setup
+ @cache = ActiveSupport::Cache.lookup_store(:memory_store)
+
+ @buffer = StringIO.new
+ @cache.logger = Logger.new(@buffer)
+ end
+
+ def test_logging
+ @cache.fetch('foo') { 'bar' }
+ assert @buffer.string.present?
+ end
+
+ def test_mute_logging
+ @cache.mute { @cache.fetch('foo') { 'bar' } }
+ assert @buffer.string.blank?
+ end
+end
diff --git a/activesupport/test/new_callback_inheritance_test.rb b/activesupport/test/callback_inheritance_test.rb
index fe316ae3da..18721eab19 100644
--- a/activesupport/test/new_callback_inheritance_test.rb
+++ b/activesupport/test/callback_inheritance_test.rb
@@ -3,35 +3,35 @@ $:.unshift "#{File.dirname(__FILE__)}/../lib"
require 'active_support'
class GrandParent
- include ActiveSupport::NewCallbacks
-
+ include ActiveSupport::Callbacks
+
attr_reader :log, :action_name
def initialize(action_name)
@action_name, @log = action_name, []
end
-
+
define_callbacks :dispatch
set_callback :dispatch, :before, :before1, :before2, :per_key => {:if => proc {|c| c.action_name == "index" || c.action_name == "update" }}
- set_callback :dispatch, :after, :after1, :after2, :per_key => {:if => proc {|c| c.action_name == "update" || c.action_name == "delete" }}
-
+ set_callback :dispatch, :after, :after1, :after2, :per_key => {:if => proc {|c| c.action_name == "update" || c.action_name == "delete" }}
+
def before1
@log << "before1"
end
-
+
def before2
@log << "before2"
end
-
- def after1
+
+ def after1
@log << "after1"
end
-
+
def after2
@log << "after2"
end
-
+
def dispatch
- _run_dispatch_callbacks(action_name) do
+ run_callbacks(:dispatch, action_name) do
@log << action_name
end
self
@@ -45,11 +45,11 @@ end
class Child < GrandParent
skip_callback :dispatch, :before, :before2, :per_key => {:unless => proc {|c| c.action_name == "update" }}, :if => :state_open?
-
+
def state_open?
@state == :open
end
-
+
def initialize(action_name, state)
super(action_name)
@state = state
@@ -64,15 +64,15 @@ class BasicCallbacksTest < Test::Unit::TestCase
@delete = GrandParent.new("delete").dispatch
@unknown = GrandParent.new("unknown").dispatch
end
-
+
def test_basic_per_key1
assert_equal %w(before1 before2 index), @index.log
end
-
+
def test_basic_per_key2
assert_equal %w(before1 before2 update after2 after1), @update.log
end
-
+
def test_basic_per_key3
assert_equal %w(delete after2 after1), @delete.log
end
@@ -85,15 +85,15 @@ class InheritedCallbacksTest < Test::Unit::TestCase
@delete = Parent.new("delete").dispatch
@unknown = Parent.new("unknown").dispatch
end
-
+
def test_inherited_excluded
assert_equal %w(before1 index), @index.log
end
-
+
def test_inherited_not_excluded
assert_equal %w(before1 before2 update after1), @update.log
end
-
+
def test_partially_excluded
assert_equal %w(delete after2 after1), @delete.log
end
@@ -104,11 +104,11 @@ class InheritedCallbacksTest2 < Test::Unit::TestCase
@update1 = Child.new("update", :open).dispatch
@update2 = Child.new("update", :closed).dispatch
end
-
+
def test_crazy_mix_on
assert_equal %w(before1 update after2 after1), @update1.log
end
-
+
def test_crazy_mix_off
assert_equal %w(before1 before2 update after2 after1), @update2.log
end
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index 2f747e2238..df98644436 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -1,188 +1,528 @@
-require 'abstract_unit'
+# require 'abstract_unit'
+require 'test/unit'
+$:.unshift "#{File.dirname(__FILE__)}/../lib"
+require 'active_support'
-class Record
- include ActiveSupport::Callbacks
+module CallbacksTest
+ class Record
+ include ActiveSupport::Callbacks
- define_callbacks :before_save, :after_save
+ define_callbacks :save
- class << self
- def callback_symbol(callback_method)
- method_name = "#{callback_method}_method"
- define_method(method_name) do
- history << [callback_method, :symbol]
+ def self.before_save(*filters, &blk)
+ set_callback(:save, :before, *filters, &blk)
+ end
+
+ def self.after_save(*filters, &blk)
+ set_callback(:save, :after, *filters, &blk)
+ end
+
+ class << self
+ def callback_symbol(callback_method)
+ method_name = :"#{callback_method}_method"
+ define_method(method_name) do
+ history << [callback_method, :symbol]
+ end
+ method_name
+ end
+
+ def callback_string(callback_method)
+ "history << [#{callback_method.to_sym.inspect}, :string]"
+ end
+
+ def callback_proc(callback_method)
+ Proc.new { |model| model.history << [callback_method, :proc] }
+ end
+
+ def callback_object(callback_method)
+ klass = Class.new
+ klass.send(:define_method, callback_method) do |model|
+ model.history << [:"#{callback_method}_save", :object]
+ end
+ klass.new
end
- method_name
end
- def callback_string(callback_method)
- "history << [#{callback_method.to_sym.inspect}, :string]"
+ def history
+ @history ||= []
+ end
+ end
+
+ class Person < Record
+ [:before_save, :after_save].each do |callback_method|
+ callback_method_sym = callback_method.to_sym
+ send(callback_method, callback_symbol(callback_method_sym))
+ send(callback_method, callback_string(callback_method_sym))
+ send(callback_method, callback_proc(callback_method_sym))
+ send(callback_method, callback_object(callback_method_sym.to_s.gsub(/_save/, '')))
+ send(callback_method) { |model| model.history << [callback_method_sym, :block] }
end
- def callback_proc(callback_method)
- Proc.new { |model| model.history << [callback_method, :proc] }
+ def save
+ run_callbacks :save
end
+ end
+
+ class PersonSkipper < Person
+ skip_callback :save, :before, :before_save_method, :if => :yes
+ skip_callback :save, :after, :before_save_method, :unless => :yes
+ skip_callback :save, :after, :before_save_method, :if => :no
+ skip_callback :save, :before, :before_save_method, :unless => :no
+ def yes; true; end
+ def no; false; end
+ end
+
+ class ParentController
+ include ActiveSupport::Callbacks
+
+ define_callbacks :dispatch
+
+ set_callback :dispatch, :before, :log, :per_key => {:unless => proc {|c| c.action_name == :index || c.action_name == :show }}
+ set_callback :dispatch, :after, :log2
- def callback_object(callback_method)
- klass = Class.new
- klass.send(:define_method, callback_method) do |model|
- model.history << [callback_method, :object]
+ attr_reader :action_name, :logger
+ def initialize(action_name)
+ @action_name, @logger = action_name, []
+ end
+
+ def log
+ @logger << action_name
+ end
+
+ def log2
+ @logger << action_name
+ end
+
+ def dispatch
+ run_callbacks :dispatch, action_name do
+ @logger << "Done"
end
- klass.new
+ self
end
end
- def history
- @history ||= []
+ class Child < ParentController
+ skip_callback :dispatch, :before, :log, :per_key => {:if => proc {|c| c.action_name == :update} }
+ skip_callback :dispatch, :after, :log2
end
-end
-class Person < Record
- [:before_save, :after_save].each do |callback_method|
- callback_method_sym = callback_method.to_sym
- send(callback_method, callback_symbol(callback_method_sym))
- send(callback_method, callback_string(callback_method_sym))
- send(callback_method, callback_proc(callback_method_sym))
- send(callback_method, callback_object(callback_method_sym))
- send(callback_method) { |model| model.history << [callback_method_sym, :block] }
+ class OneTimeCompile < Record
+ @@starts_true, @@starts_false = true, false
+
+ def initialize
+ super
+ end
+
+ before_save Proc.new {|r| r.history << [:before_save, :starts_true, :if] }, :per_key => {:if => :starts_true}
+ before_save Proc.new {|r| r.history << [:before_save, :starts_false, :if] }, :per_key => {:if => :starts_false}
+ before_save Proc.new {|r| r.history << [:before_save, :starts_true, :unless] }, :per_key => {:unless => :starts_true}
+ before_save Proc.new {|r| r.history << [:before_save, :starts_false, :unless] }, :per_key => {:unless => :starts_false}
+
+ def starts_true
+ if @@starts_true
+ @@starts_true = false
+ return true
+ end
+ @@starts_true
+ end
+
+ def starts_false
+ unless @@starts_false
+ @@starts_false = true
+ return false
+ end
+ @@starts_false
+ end
+
+ def save
+ run_callbacks :save, :action
+ end
end
- def save
- run_callbacks(:before_save)
- run_callbacks(:after_save)
+ class OneTimeCompileTest < Test::Unit::TestCase
+ def test_optimized_first_compile
+ around = OneTimeCompile.new
+ around.save
+ assert_equal [
+ [:before_save, :starts_true, :if],
+ [:before_save, :starts_true, :unless]
+ ], around.history
+ end
end
-end
-class ConditionalPerson < Record
- # proc
- before_save Proc.new { |r| r.history << [:before_save, :proc] }, :if => Proc.new { |r| true }
- before_save Proc.new { |r| r.history << "b00m" }, :if => Proc.new { |r| false }
- before_save Proc.new { |r| r.history << [:before_save, :proc] }, :unless => Proc.new { |r| false }
- before_save Proc.new { |r| r.history << "b00m" }, :unless => Proc.new { |r| true }
- # symbol
- before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :if => :yes
- before_save Proc.new { |r| r.history << "b00m" }, :if => :no
- before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :unless => :no
- before_save Proc.new { |r| r.history << "b00m" }, :unless => :yes
- # string
- before_save Proc.new { |r| r.history << [:before_save, :string] }, :if => 'yes'
- before_save Proc.new { |r| r.history << "b00m" }, :if => 'no'
- before_save Proc.new { |r| r.history << [:before_save, :string] }, :unless => 'no'
- before_save Proc.new { |r| r.history << "b00m" }, :unless => 'yes'
- # Array with conditions
- before_save Proc.new { |r| r.history << [:before_save, :symbol_array] }, :if => [:yes, :other_yes]
- before_save Proc.new { |r| r.history << "b00m" }, :if => [:yes, :no]
- before_save Proc.new { |r| r.history << [:before_save, :symbol_array] }, :unless => [:no, :other_no]
- before_save Proc.new { |r| r.history << "b00m" }, :unless => [:yes, :no]
- # Combined if and unless
- before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, :if => :yes, :unless => :no
- before_save Proc.new { |r| r.history << "b00m" }, :if => :yes, :unless => :yes
- # Array with different types of conditions
- before_save Proc.new { |r| r.history << [:before_save, :symbol_proc_string_array] }, :if => [:yes, Proc.new { |r| true }, 'yes']
- before_save Proc.new { |r| r.history << "b00m" }, :if => [:yes, Proc.new { |r| true }, 'no']
- # Array with different types of conditions comibned if and unless
- before_save Proc.new { |r| r.history << [:before_save, :combined_symbol_proc_string_array] },
- :if => [:yes, Proc.new { |r| true }, 'yes'], :unless => [:no, 'no']
- before_save Proc.new { |r| r.history << "b00m" }, :if => [:yes, Proc.new { |r| true }, 'no'], :unless => [:no, 'no']
-
- def yes; true; end
- def other_yes; true; end
- def no; false; end
- def other_no; false; end
-
- def save
- run_callbacks(:before_save)
- run_callbacks(:after_save)
+ class ConditionalPerson < Record
+ # proc
+ before_save Proc.new { |r| r.history << [:before_save, :proc] }, :if => Proc.new { |r| true }
+ before_save Proc.new { |r| r.history << "b00m" }, :if => Proc.new { |r| false }
+ before_save Proc.new { |r| r.history << [:before_save, :proc] }, :unless => Proc.new { |r| false }
+ before_save Proc.new { |r| r.history << "b00m" }, :unless => Proc.new { |r| true }
+ # symbol
+ before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :if => :yes
+ before_save Proc.new { |r| r.history << "b00m" }, :if => :no
+ before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :unless => :no
+ before_save Proc.new { |r| r.history << "b00m" }, :unless => :yes
+ # string
+ before_save Proc.new { |r| r.history << [:before_save, :string] }, :if => 'yes'
+ before_save Proc.new { |r| r.history << "b00m" }, :if => 'no'
+ before_save Proc.new { |r| r.history << [:before_save, :string] }, :unless => 'no'
+ before_save Proc.new { |r| r.history << "b00m" }, :unless => 'yes'
+ # Combined if and unless
+ before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, :if => :yes, :unless => :no
+ before_save Proc.new { |r| r.history << "b00m" }, :if => :yes, :unless => :yes
+
+ def yes; true; end
+ def other_yes; true; end
+ def no; false; end
+ def other_no; false; end
+
+ def save
+ run_callbacks :save
+ end
end
-end
-class CallbacksTest < Test::Unit::TestCase
- def test_save_person
- person = Person.new
- assert_equal [], person.history
- person.save
- assert_equal [
- [:before_save, :symbol],
- [:before_save, :string],
- [:before_save, :proc],
- [:before_save, :object],
- [:before_save, :block],
- [:after_save, :symbol],
- [:after_save, :string],
- [:after_save, :proc],
- [:after_save, :object],
- [:after_save, :block]
- ], person.history
+ class CleanPerson < ConditionalPerson
+ reset_callbacks :save
end
-end
-class ConditionalCallbackTest < Test::Unit::TestCase
- def test_save_conditional_person
- person = ConditionalPerson.new
- person.save
- assert_equal [
- [:before_save, :proc],
- [:before_save, :proc],
- [:before_save, :symbol],
- [:before_save, :symbol],
- [:before_save, :string],
- [:before_save, :string],
- [:before_save, :symbol_array],
- [:before_save, :symbol_array],
- [:before_save, :combined_symbol],
- [:before_save, :symbol_proc_string_array],
- [:before_save, :combined_symbol_proc_string_array]
- ], person.history
+ class MySuper
+ include ActiveSupport::Callbacks
+ define_callbacks :save
end
-end
-class CallbackTest < Test::Unit::TestCase
- include ActiveSupport::Callbacks
+ class AroundPerson < MySuper
+ attr_reader :history
+
+ set_callback :save, :before, :nope, :if => :no
+ set_callback :save, :before, :nope, :unless => :yes
+ set_callback :save, :after, :tweedle
+ set_callback :save, :before, "tweedle_dee"
+ set_callback :save, :before, proc {|m| m.history << "yup" }
+ set_callback :save, :before, :nope, :if => proc { false }
+ set_callback :save, :before, :nope, :unless => proc { true }
+ set_callback :save, :before, :yup, :if => proc { true }
+ set_callback :save, :before, :yup, :unless => proc { false }
+ set_callback :save, :around, :tweedle_dum
+ set_callback :save, :around, :w0tyes, :if => :yes
+ set_callback :save, :around, :w0tno, :if => :no
+ set_callback :save, :around, :tweedle_deedle
+
+ def no; false; end
+ def yes; true; end
+
+ def nope
+ @history << "boom"
+ end
+
+ def yup
+ @history << "yup"
+ end
+
+ def w0tyes
+ @history << "w0tyes before"
+ yield
+ @history << "w0tyes after"
+ end
+
+ def w0tno
+ @history << "boom"
+ yield
+ end
+
+ def tweedle_dee
+ @history << "tweedle dee"
+ end
+
+ def tweedle_dum
+ @history << "tweedle dum pre"
+ yield
+ @history << "tweedle dum post"
+ end
+
+ def tweedle
+ @history << "tweedle"
+ end
+
+ def tweedle_deedle
+ @history << "tweedle deedle pre"
+ yield
+ @history << "tweedle deedle post"
+ end
+
+ def initialize
+ @history = []
+ end
- def test_eql
- callback = Callback.new(:before, :save, :identifier => :lifesaver)
- assert callback.eql?(Callback.new(:before, :save, :identifier => :lifesaver))
- assert callback.eql?(Callback.new(:before, :save))
- assert callback.eql?(:lifesaver)
- assert callback.eql?(:save)
- assert !callback.eql?(Callback.new(:before, :destroy))
- assert !callback.eql?(:destroy)
+ def save
+ run_callbacks :save do
+ @history << "running"
+ end
+ end
end
- def test_dup
- a = Callback.new(:before, :save)
- assert_equal({}, a.options)
- b = a.dup
- b.options[:unless] = :pigs_fly
- assert_equal({:unless => :pigs_fly}, b.options)
- assert_equal({}, a.options)
+ class HyphenatedCallbacks
+ include ActiveSupport::Callbacks
+ define_callbacks :save
+ attr_reader :stuff
+
+ set_callback :save, :before, :omg, :per_key => {:if => :yes}
+
+ def yes() true end
+
+ def omg
+ @stuff = "OMG"
+ end
+
+ def save
+ run_callbacks :save, "hyphen-ated" do
+ @stuff
+ end
+ end
+ end
+
+ class AroundCallbacksTest < Test::Unit::TestCase
+ def test_save_around
+ around = AroundPerson.new
+ around.save
+ assert_equal [
+ "tweedle dee",
+ "yup", "yup",
+ "tweedle dum pre",
+ "w0tyes before",
+ "tweedle deedle pre",
+ "running",
+ "tweedle deedle post",
+ "w0tyes after",
+ "tweedle dum post",
+ "tweedle"
+ ], around.history
+ end
+ end
+
+ class SkipCallbacksTest < Test::Unit::TestCase
+ def test_skip_person
+ person = PersonSkipper.new
+ assert_equal [], person.history
+ person.save
+ assert_equal [
+ [:before_save, :string],
+ [:before_save, :proc],
+ [:before_save, :object],
+ [:before_save, :block],
+ [:after_save, :block],
+ [:after_save, :object],
+ [:after_save, :proc],
+ [:after_save, :string],
+ [:after_save, :symbol]
+ ], person.history
+ end
+ end
+
+ class CallbacksTest < Test::Unit::TestCase
+ def test_save_person
+ person = Person.new
+ assert_equal [], person.history
+ person.save
+ assert_equal [
+ [:before_save, :symbol],
+ [:before_save, :string],
+ [:before_save, :proc],
+ [:before_save, :object],
+ [:before_save, :block],
+ [:after_save, :block],
+ [:after_save, :object],
+ [:after_save, :proc],
+ [:after_save, :string],
+ [:after_save, :symbol]
+ ], person.history
+ end
+ end
+
+ class ConditionalCallbackTest < Test::Unit::TestCase
+ def test_save_conditional_person
+ person = ConditionalPerson.new
+ person.save
+ assert_equal [
+ [:before_save, :proc],
+ [:before_save, :proc],
+ [:before_save, :symbol],
+ [:before_save, :symbol],
+ [:before_save, :string],
+ [:before_save, :string],
+ [:before_save, :combined_symbol],
+ ], person.history
+ end
+ end
+
+ class ResetCallbackTest < Test::Unit::TestCase
+ def test_save_conditional_person
+ person = CleanPerson.new
+ person.save
+ assert_equal [], person.history
+ end
+ end
+
+ class CallbackTerminator
+ include ActiveSupport::Callbacks
+
+ define_callbacks :save, :terminator => "result == :halt"
+
+ set_callback :save, :before, :first
+ set_callback :save, :before, :second
+ set_callback :save, :around, :around_it
+ set_callback :save, :before, :third
+ set_callback :save, :after, :first
+ set_callback :save, :around, :around_it
+ set_callback :save, :after, :second
+ set_callback :save, :around, :around_it
+ set_callback :save, :after, :third
+
+
+ attr_reader :history, :saved
+ def initialize
+ @history = []
+ end
+
+ def around_it
+ @history << "around1"
+ yield
+ @history << "around2"
+ end
+
+ def first
+ @history << "first"
+ end
+
+ def second
+ @history << "second"
+ :halt
+ end
+
+ def third
+ @history << "third"
+ end
+
+ def save
+ run_callbacks :save do
+ @saved = true
+ end
+ end
+ end
+
+ class CallbackObject
+ def before(caller)
+ caller.record << "before"
+ end
+
+ def before_save(caller)
+ caller.record << "before save"
+ end
+
+ def around(caller)
+ caller.record << "around before"
+ yield
+ caller.record << "around after"
+ end
+ end
+
+ class UsingObjectBefore
+ include ActiveSupport::Callbacks
+
+ define_callbacks :save
+ set_callback :save, :before, CallbackObject.new
+
+ attr_accessor :record
+ def initialize
+ @record = []
+ end
+
+ def save
+ run_callbacks :save do
+ @record << "yielded"
+ end
+ end
end
-end
-class CallbackChainTest < Test::Unit::TestCase
- include ActiveSupport::Callbacks
+ class UsingObjectAround
+ include ActiveSupport::Callbacks
- def setup
- @chain = CallbackChain.build(:make, :bacon, :lettuce, :tomato)
+ define_callbacks :save
+ set_callback :save, :around, CallbackObject.new
+
+ attr_accessor :record
+ def initialize
+ @record = []
+ end
+
+ def save
+ run_callbacks :save do
+ @record << "yielded"
+ end
+ end
end
- def test_build
- assert_equal 3, @chain.size
- assert_equal [:bacon, :lettuce, :tomato], @chain.map(&:method)
+ class CustomScopeObject
+ include ActiveSupport::Callbacks
+
+ define_callbacks :save, :scope => [:kind, :name]
+ set_callback :save, :before, CallbackObject.new
+
+ attr_accessor :record
+ def initialize
+ @record = []
+ end
+
+ def save
+ run_callbacks :save do
+ @record << "yielded"
+ "CallbackResult"
+ end
+ end
end
- def test_find
- assert_equal :bacon, @chain.find(:bacon).method
+ class UsingObjectTest < Test::Unit::TestCase
+ def test_before_object
+ u = UsingObjectBefore.new
+ u.save
+ assert_equal ["before", "yielded"], u.record
+ end
+
+ def test_around_object
+ u = UsingObjectAround.new
+ u.save
+ assert_equal ["around before", "yielded", "around after"], u.record
+ end
+
+ def test_customized_object
+ u = CustomScopeObject.new
+ u.save
+ assert_equal ["before save", "yielded"], u.record
+ end
+
+ def test_block_result_is_returned
+ u = CustomScopeObject.new
+ assert_equal "CallbackResult", u.save
+ end
end
- def test_replace_or_append
- assert_equal [:bacon, :lettuce, :tomato], (@chain.replace_or_append!(Callback.new(:make, :bacon))).map(&:method)
- assert_equal [:bacon, :lettuce, :tomato, :turkey], (@chain.replace_or_append!(Callback.new(:make, :turkey))).map(&:method)
- assert_equal [:bacon, :lettuce, :tomato, :turkey, :mayo], (@chain.replace_or_append!(Callback.new(:make, :mayo))).map(&:method)
+ class CallbackTerminatorTest < Test::Unit::TestCase
+ def test_termination
+ terminator = CallbackTerminator.new
+ terminator.save
+ assert_equal ["first", "second", "third", "second", "first"], terminator.history
+ end
+
+ def test_block_never_called_if_terminated
+ obj = CallbackTerminator.new
+ obj.save
+ assert !obj.saved
+ end
end
- def test_delete
- assert_equal [:bacon, :lettuce, :tomato], @chain.map(&:method)
- @chain.delete(:bacon)
- assert_equal [:lettuce, :tomato], @chain.map(&:method)
+ class HyphenatedKeyTest < Test::Unit::TestCase
+ def test_save
+ obj = HyphenatedCallbacks.new
+ obj.save
+ assert_equal obj.stuff, "OMG"
+ end
end
end
diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb
index e6370bc3db..ef300e4e26 100644
--- a/activesupport/test/message_verifier_test.rb
+++ b/activesupport/test/message_verifier_test.rb
@@ -27,6 +27,7 @@ class MessageVerifierTest < Test::Unit::TestCase
data, hash = @verifier.generate(@data).split("--")
assert_not_verified("#{data.reverse}--#{hash}")
assert_not_verified("#{data}--#{hash.reverse}")
+ assert_not_verified("purejunk")
end
def assert_not_verified(message)
diff --git a/activesupport/test/new_callbacks_test.rb b/activesupport/test/new_callbacks_test.rb
deleted file mode 100644
index 04db376fc6..0000000000
--- a/activesupport/test/new_callbacks_test.rb
+++ /dev/null
@@ -1,528 +0,0 @@
-# require 'abstract_unit'
-require 'test/unit'
-$:.unshift "#{File.dirname(__FILE__)}/../lib"
-require 'active_support'
-
-module NewCallbacksTest
- class Record
- include ActiveSupport::NewCallbacks
-
- define_callbacks :save
-
- def self.before_save(*filters, &blk)
- set_callback(:save, :before, *filters, &blk)
- end
-
- def self.after_save(*filters, &blk)
- set_callback(:save, :after, *filters, &blk)
- end
-
- class << self
- def callback_symbol(callback_method)
- method_name = :"#{callback_method}_method"
- define_method(method_name) do
- history << [callback_method, :symbol]
- end
- method_name
- end
-
- def callback_string(callback_method)
- "history << [#{callback_method.to_sym.inspect}, :string]"
- end
-
- def callback_proc(callback_method)
- Proc.new { |model| model.history << [callback_method, :proc] }
- end
-
- def callback_object(callback_method)
- klass = Class.new
- klass.send(:define_method, callback_method) do |model|
- model.history << [:"#{callback_method}_save", :object]
- end
- klass.new
- end
- end
-
- def history
- @history ||= []
- end
- end
-
- class Person < Record
- [:before_save, :after_save].each do |callback_method|
- callback_method_sym = callback_method.to_sym
- send(callback_method, callback_symbol(callback_method_sym))
- send(callback_method, callback_string(callback_method_sym))
- send(callback_method, callback_proc(callback_method_sym))
- send(callback_method, callback_object(callback_method_sym.to_s.gsub(/_save/, '')))
- send(callback_method) { |model| model.history << [callback_method_sym, :block] }
- end
-
- def save
- _run_save_callbacks {}
- end
- end
-
- class PersonSkipper < Person
- skip_callback :save, :before, :before_save_method, :if => :yes
- skip_callback :save, :after, :before_save_method, :unless => :yes
- skip_callback :save, :after, :before_save_method, :if => :no
- skip_callback :save, :before, :before_save_method, :unless => :no
- def yes; true; end
- def no; false; end
- end
-
- class ParentController
- include ActiveSupport::NewCallbacks
-
- define_callbacks :dispatch
-
- set_callback :dispatch, :before, :log, :per_key => {:unless => proc {|c| c.action_name == :index || c.action_name == :show }}
- set_callback :dispatch, :after, :log2
-
- attr_reader :action_name, :logger
- def initialize(action_name)
- @action_name, @logger = action_name, []
- end
-
- def log
- @logger << action_name
- end
-
- def log2
- @logger << action_name
- end
-
- def dispatch
- _run_dispatch_callbacks(action_name) {
- @logger << "Done"
- }
- self
- end
- end
-
- class Child < ParentController
- skip_callback :dispatch, :before, :log, :per_key => {:if => proc {|c| c.action_name == :update} }
- skip_callback :dispatch, :after, :log2
- end
-
- class OneTimeCompile < Record
- @@starts_true, @@starts_false = true, false
-
- def initialize
- super
- end
-
- before_save Proc.new {|r| r.history << [:before_save, :starts_true, :if] }, :per_key => {:if => :starts_true}
- before_save Proc.new {|r| r.history << [:before_save, :starts_false, :if] }, :per_key => {:if => :starts_false}
- before_save Proc.new {|r| r.history << [:before_save, :starts_true, :unless] }, :per_key => {:unless => :starts_true}
- before_save Proc.new {|r| r.history << [:before_save, :starts_false, :unless] }, :per_key => {:unless => :starts_false}
-
- def starts_true
- if @@starts_true
- @@starts_true = false
- return true
- end
- @@starts_true
- end
-
- def starts_false
- unless @@starts_false
- @@starts_false = true
- return false
- end
- @@starts_false
- end
-
- def save
- _run_save_callbacks(:action) {}
- end
- end
-
- class OneTimeCompileTest < Test::Unit::TestCase
- def test_optimized_first_compile
- around = OneTimeCompile.new
- around.save
- assert_equal [
- [:before_save, :starts_true, :if],
- [:before_save, :starts_true, :unless]
- ], around.history
- end
- end
-
- class ConditionalPerson < Record
- # proc
- before_save Proc.new { |r| r.history << [:before_save, :proc] }, :if => Proc.new { |r| true }
- before_save Proc.new { |r| r.history << "b00m" }, :if => Proc.new { |r| false }
- before_save Proc.new { |r| r.history << [:before_save, :proc] }, :unless => Proc.new { |r| false }
- before_save Proc.new { |r| r.history << "b00m" }, :unless => Proc.new { |r| true }
- # symbol
- before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :if => :yes
- before_save Proc.new { |r| r.history << "b00m" }, :if => :no
- before_save Proc.new { |r| r.history << [:before_save, :symbol] }, :unless => :no
- before_save Proc.new { |r| r.history << "b00m" }, :unless => :yes
- # string
- before_save Proc.new { |r| r.history << [:before_save, :string] }, :if => 'yes'
- before_save Proc.new { |r| r.history << "b00m" }, :if => 'no'
- before_save Proc.new { |r| r.history << [:before_save, :string] }, :unless => 'no'
- before_save Proc.new { |r| r.history << "b00m" }, :unless => 'yes'
- # Combined if and unless
- before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, :if => :yes, :unless => :no
- before_save Proc.new { |r| r.history << "b00m" }, :if => :yes, :unless => :yes
-
- def yes; true; end
- def other_yes; true; end
- def no; false; end
- def other_no; false; end
-
- def save
- _run_save_callbacks {}
- end
- end
-
- class CleanPerson < ConditionalPerson
- reset_callbacks :save
- end
-
- class MySuper
- include ActiveSupport::NewCallbacks
- define_callbacks :save
- end
-
- class AroundPerson < MySuper
- attr_reader :history
-
- set_callback :save, :before, :nope, :if => :no
- set_callback :save, :before, :nope, :unless => :yes
- set_callback :save, :after, :tweedle
- set_callback :save, :before, "tweedle_dee"
- set_callback :save, :before, proc {|m| m.history << "yup" }
- set_callback :save, :before, :nope, :if => proc { false }
- set_callback :save, :before, :nope, :unless => proc { true }
- set_callback :save, :before, :yup, :if => proc { true }
- set_callback :save, :before, :yup, :unless => proc { false }
- set_callback :save, :around, :tweedle_dum
- set_callback :save, :around, :w0tyes, :if => :yes
- set_callback :save, :around, :w0tno, :if => :no
- set_callback :save, :around, :tweedle_deedle
-
- def no; false; end
- def yes; true; end
-
- def nope
- @history << "boom"
- end
-
- def yup
- @history << "yup"
- end
-
- def w0tyes
- @history << "w0tyes before"
- yield
- @history << "w0tyes after"
- end
-
- def w0tno
- @history << "boom"
- yield
- end
-
- def tweedle_dee
- @history << "tweedle dee"
- end
-
- def tweedle_dum
- @history << "tweedle dum pre"
- yield
- @history << "tweedle dum post"
- end
-
- def tweedle
- @history << "tweedle"
- end
-
- def tweedle_deedle
- @history << "tweedle deedle pre"
- yield
- @history << "tweedle deedle post"
- end
-
- def initialize
- @history = []
- end
-
- def save
- _run_save_callbacks do
- @history << "running"
- end
- end
- end
-
- class HyphenatedCallbacks
- include ActiveSupport::NewCallbacks
- define_callbacks :save
- attr_reader :stuff
-
- set_callback :save, :before, :omg, :per_key => {:if => :yes}
-
- def yes() true end
-
- def omg
- @stuff = "OMG"
- end
-
- def save
- _run_save_callbacks("hyphen-ated") do
- @stuff
- end
- end
- end
-
- class AroundCallbacksTest < Test::Unit::TestCase
- def test_save_around
- around = AroundPerson.new
- around.save
- assert_equal [
- "tweedle dee",
- "yup", "yup",
- "tweedle dum pre",
- "w0tyes before",
- "tweedle deedle pre",
- "running",
- "tweedle deedle post",
- "w0tyes after",
- "tweedle dum post",
- "tweedle"
- ], around.history
- end
- end
-
- class SkipCallbacksTest < Test::Unit::TestCase
- def test_skip_person
- person = PersonSkipper.new
- assert_equal [], person.history
- person.save
- assert_equal [
- [:before_save, :string],
- [:before_save, :proc],
- [:before_save, :object],
- [:before_save, :block],
- [:after_save, :block],
- [:after_save, :object],
- [:after_save, :proc],
- [:after_save, :string],
- [:after_save, :symbol]
- ], person.history
- end
- end
-
- class CallbacksTest < Test::Unit::TestCase
- def test_save_person
- person = Person.new
- assert_equal [], person.history
- person.save
- assert_equal [
- [:before_save, :symbol],
- [:before_save, :string],
- [:before_save, :proc],
- [:before_save, :object],
- [:before_save, :block],
- [:after_save, :block],
- [:after_save, :object],
- [:after_save, :proc],
- [:after_save, :string],
- [:after_save, :symbol]
- ], person.history
- end
- end
-
- class ConditionalCallbackTest < Test::Unit::TestCase
- def test_save_conditional_person
- person = ConditionalPerson.new
- person.save
- assert_equal [
- [:before_save, :proc],
- [:before_save, :proc],
- [:before_save, :symbol],
- [:before_save, :symbol],
- [:before_save, :string],
- [:before_save, :string],
- [:before_save, :combined_symbol],
- ], person.history
- end
- end
-
- class ResetCallbackTest < Test::Unit::TestCase
- def test_save_conditional_person
- person = CleanPerson.new
- person.save
- assert_equal [], person.history
- end
- end
-
- class CallbackTerminator
- include ActiveSupport::NewCallbacks
-
- define_callbacks :save, :terminator => "result == :halt"
-
- set_callback :save, :before, :first
- set_callback :save, :before, :second
- set_callback :save, :around, :around_it
- set_callback :save, :before, :third
- set_callback :save, :after, :first
- set_callback :save, :around, :around_it
- set_callback :save, :after, :second
- set_callback :save, :around, :around_it
- set_callback :save, :after, :third
-
-
- attr_reader :history, :saved
- def initialize
- @history = []
- end
-
- def around_it
- @history << "around1"
- yield
- @history << "around2"
- end
-
- def first
- @history << "first"
- end
-
- def second
- @history << "second"
- :halt
- end
-
- def third
- @history << "third"
- end
-
- def save
- _run_save_callbacks do
- @saved = true
- end
- end
- end
-
- class CallbackObject
- def before(caller)
- caller.record << "before"
- end
-
- def before_save(caller)
- caller.record << "before save"
- end
-
- def around(caller)
- caller.record << "around before"
- yield
- caller.record << "around after"
- end
- end
-
- class UsingObjectBefore
- include ActiveSupport::NewCallbacks
-
- define_callbacks :save
- set_callback :save, :before, CallbackObject.new
-
- attr_accessor :record
- def initialize
- @record = []
- end
-
- def save
- _run_save_callbacks do
- @record << "yielded"
- end
- end
- end
-
- class UsingObjectAround
- include ActiveSupport::NewCallbacks
-
- define_callbacks :save
- set_callback :save, :around, CallbackObject.new
-
- attr_accessor :record
- def initialize
- @record = []
- end
-
- def save
- _run_save_callbacks do
- @record << "yielded"
- end
- end
- end
-
- class CustomScopeObject
- include ActiveSupport::NewCallbacks
-
- define_callbacks :save, :scope => [:kind, :name]
- set_callback :save, :before, CallbackObject.new
-
- attr_accessor :record
- def initialize
- @record = []
- end
-
- def save
- _run_save_callbacks do
- @record << "yielded"
- "CallbackResult"
- end
- end
- end
-
- class UsingObjectTest < Test::Unit::TestCase
- def test_before_object
- u = UsingObjectBefore.new
- u.save
- assert_equal ["before", "yielded"], u.record
- end
-
- def test_around_object
- u = UsingObjectAround.new
- u.save
- assert_equal ["around before", "yielded", "around after"], u.record
- end
-
- def test_customized_object
- u = CustomScopeObject.new
- u.save
- assert_equal ["before save", "yielded"], u.record
- end
-
- def test_block_result_is_returned
- u = CustomScopeObject.new
- assert_equal "CallbackResult", u.save
- end
- end
-
- class CallbackTerminatorTest < Test::Unit::TestCase
- def test_termination
- terminator = CallbackTerminator.new
- terminator.save
- assert_equal ["first", "second", "third", "second", "first"], terminator.history
- end
-
- def test_block_never_called_if_terminated
- obj = CallbackTerminator.new
- obj.save
- assert !obj.saved
- end
- end
-
- class HyphenatedKeyTest < Test::Unit::TestCase
- def test_save
- obj = HyphenatedCallbacks.new
- obj.save
- assert_equal obj.stuff, "OMG"
- end
- end
-end
diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_test.rb
index 40d3d612e7..7a45dab60b 100644
--- a/activesupport/test/test_test.rb
+++ b/activesupport/test/test_test.rb
@@ -4,7 +4,7 @@ require 'active_support/core_ext/kernel/reporting'
class AssertDifferenceTest < ActiveSupport::TestCase
def setup
@object = Class.new do
- attr_accessor :num
+ attr_accessor :num
def increment
self.num += 1
end
@@ -12,7 +12,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase
def decrement
self.num -= 1
end
- end.new
+ end.new
@object.num = 0
end
@@ -95,55 +95,3 @@ end
class AlsoDoingNothingTest < ActiveSupport::TestCase
end
-
-# Setup and teardown callbacks.
-class SetupAndTeardownTest < ActiveSupport::TestCase
- setup :reset_callback_record, :foo
- teardown :foo, :sentinel, :foo
-
- def test_inherited_setup_callbacks
- assert_equal [:reset_callback_record, :foo], self.class.setup_callback_chain.map(&:method)
- assert_equal [:foo], @called_back
- assert_equal [:foo, :sentinel, :foo], self.class.teardown_callback_chain.map(&:method)
- end
-
- def setup
- end
-
- def teardown
- end
-
- protected
- def reset_callback_record
- @called_back = []
- end
-
- def foo
- @called_back << :foo
- end
-
- def sentinel
- assert_equal [:foo, :foo], @called_back
- end
-end
-
-
-class SubclassSetupAndTeardownTest < SetupAndTeardownTest
- setup :bar
- teardown :bar
-
- def test_inherited_setup_callbacks
- assert_equal [:reset_callback_record, :foo, :bar], self.class.setup_callback_chain.map(&:method)
- assert_equal [:foo, :bar], @called_back
- assert_equal [:foo, :sentinel, :foo, :bar], self.class.teardown_callback_chain.map(&:method)
- end
-
- protected
- def bar
- @called_back << :bar
- end
-
- def sentinel
- assert_equal [:foo, :bar, :bar, :foo], @called_back
- end
-end
diff --git a/ci/geminstaller.yml b/ci/geminstaller.yml
index 8dde704e79..70729ea34a 100644
--- a/ci/geminstaller.yml
+++ b/ci/geminstaller.yml
@@ -1,5 +1,7 @@
---
gems:
+- name: erubis
+ version: >= 2.6.5
- name: geminstaller
version: >= 0.4.3
- name: fcgi
diff --git a/railties/Rakefile b/railties/Rakefile
index e36930af4f..23f9603b65 100644
--- a/railties/Rakefile
+++ b/railties/Rakefile
@@ -80,7 +80,8 @@ end
# Run application generator -------------------------------------------------------------
task :create_rails do
- require File.join(File.dirname(__FILE__), 'lib', 'generators')
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/lib"
+ require 'rails/generators'
require 'rails/generators/rails/app/app_generator'
Rails::Generators::AppGenerator.start [ File.basename(PKG_DESTINATION), "--quiet" ],
:destination_root => File.expand_path(File.dirname(PKG_DESTINATION))
diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb
index 6139e20e95..d54120f850 100644
--- a/railties/lib/rails/application.rb
+++ b/railties/lib/rails/application.rb
@@ -1,29 +1,487 @@
module Rails
class Application
+ extend Initializable
- def self.config
- @config ||= Configuration.new
+ class << self
+ def config
+ @config ||= Configuration.new
+ end
+
+ # TODO: change the plugin loader to use config
+ alias configuration config
+
+ def config=(config)
+ @config = config
+ end
+
+ def plugin_loader
+ @plugin_loader ||= config.plugin_loader.new(self)
+ end
+
+ def routes
+ ActionController::Routing::Routes
+ end
+
+ def middleware
+ config.middleware
+ end
+
+ def call(env)
+ @app ||= middleware.build(routes)
+ @app.call(env)
+ end
+
+ def new
+ initializers.run
+ self
+ end
+ end
+
+ initializer :initialize_rails do
+ Rails.initializers.run
+ end
+
+ # Set the <tt>$LOAD_PATH</tt> based on the value of
+ # Configuration#load_paths. Duplicates are removed.
+ initializer :set_load_path do
+ config.paths.add_to_load_path
+ $LOAD_PATH.uniq!
+ end
+
+ # Bail if boot.rb is outdated
+ initializer :freak_out_if_boot_rb_is_outdated do
+ unless defined?(Rails::BOOTSTRAP_VERSION)
+ abort %{Your config/boot.rb is outdated: Run "rake rails:update".}
+ end
+ end
+
+ # Requires all frameworks specified by the Configuration#frameworks
+ # list. By default, all frameworks (Active Record, Active Support,
+ # Action Pack, Action Mailer, and Active Resource) are loaded.
+ initializer :require_frameworks do
+ begin
+ require 'active_support'
+ require 'active_support/core_ext/kernel/reporting'
+ require 'active_support/core_ext/logger'
+
+ # TODO: This is here to make Sam Ruby's tests pass. Needs discussion.
+ require 'active_support/core_ext/numeric/bytes'
+ config.frameworks.each { |framework| require(framework.to_s) }
+ rescue LoadError => e
+ # Re-raise as RuntimeError because Mongrel would swallow LoadError.
+ raise e.to_s
+ end
+ end
+
+ # Set the paths from which Rails will automatically load source files, and
+ # the load_once paths.
+ initializer :set_autoload_paths do
+ require 'active_support/dependencies'
+ ActiveSupport::Dependencies.load_paths = config.load_paths.uniq
+ ActiveSupport::Dependencies.load_once_paths = config.load_once_paths.uniq
+
+ extra = ActiveSupport::Dependencies.load_once_paths - ActiveSupport::Dependencies.load_paths
+ unless extra.empty?
+ abort <<-end_error
+ load_once_paths must be a subset of the load_paths.
+ Extra items in load_once_paths: #{extra * ','}
+ end_error
+ end
+
+ # Freeze the arrays so future modifications will fail rather than do nothing mysteriously
+ config.load_once_paths.freeze
+ end
+
+ # Adds all load paths from plugins to the global set of load paths, so that
+ # code from plugins can be required (explicitly or automatically via ActiveSupport::Dependencies).
+ initializer :add_plugin_load_paths do
+ require 'active_support/dependencies'
+ plugin_loader.add_plugin_load_paths
+ end
+
+ # Create tmp directories
+ initializer :ensure_tmp_directories_exist do
+ %w(cache pids sessions sockets).each do |dir_to_make|
+ FileUtils.mkdir_p(File.join(config.root_path, 'tmp', dir_to_make))
+ end
+ end
+
+ # Loads the environment specified by Configuration#environment_path, which
+ # is typically one of development, test, or production.
+ initializer :load_environment do
+ silence_warnings do
+ next if @environment_loaded
+ next unless File.file?(config.environment_path)
+
+ @environment_loaded = true
+ constants = self.class.constants
+
+ eval(IO.read(config.environment_path), binding, config.environment_path)
+
+ (self.class.constants - constants).each do |const|
+ Object.const_set(const, self.class.const_get(const))
+ end
+ end
+ end
+
+ initializer :add_gem_load_paths do
+ require 'rails/gem_dependency'
+ Rails::GemDependency.add_frozen_gem_path
+ unless config.gems.empty?
+ require "rubygems"
+ config.gems.each { |gem| gem.add_load_paths }
+ end
+ end
+
+ # Preload all frameworks specified by the Configuration#frameworks.
+ # Used by Passenger to ensure everything's loaded before forking and
+ # to avoid autoload race conditions in JRuby.
+ initializer :preload_frameworks do
+ if config.preload_frameworks
+ config.frameworks.each do |framework|
+ # String#classify and #constantize aren't available yet.
+ toplevel = Object.const_get(framework.to_s.gsub(/(?:^|_)(.)/) { $1.upcase })
+ toplevel.load_all! if toplevel.respond_to?(:load_all!)
+ end
+ end
+ end
+
+ # This initialization routine does nothing unless <tt>:active_record</tt>
+ # is one of the frameworks to load (Configuration#frameworks). If it is,
+ # this sets the database configuration from Configuration#database_configuration
+ # and then establishes the connection.
+ initializer :initialize_database do
+ if config.frameworks.include?(:active_record)
+ ActiveRecord::Base.configurations = config.database_configuration
+ ActiveRecord::Base.establish_connection
+ end
+ end
+
+ # Include middleware to serve up static assets
+ initializer :initialize_static_server do
+ if config.frameworks.include?(:action_controller) && config.serve_static_assets
+ config.middleware.use(ActionDispatch::Static, Rails.public_path)
+ end
+ end
+
+ initializer :initialize_middleware_stack do
+ if config.frameworks.include?(:action_controller)
+ config.middleware.use(::Rack::Lock) unless ActionController::Base.allow_concurrency
+ config.middleware.use(ActionDispatch::ShowExceptions, ActionController::Base.consider_all_requests_local)
+ config.middleware.use(ActionDispatch::Callbacks, ActionController::Dispatcher.prepare_each_request)
+ config.middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options })
+ config.middleware.use(ActionDispatch::ParamsParser)
+ config.middleware.use(::Rack::MethodOverride)
+ config.middleware.use(::Rack::Head)
+ config.middleware.use(ActionDispatch::StringCoercion)
+ end
+ end
+
+ initializer :initialize_cache do
+ unless defined?(RAILS_CACHE)
+ silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(config.cache_store) }
+
+ if RAILS_CACHE.respond_to?(:middleware)
+ # Insert middleware to setup and teardown local cache for each request
+ config.middleware.insert_after(:"Rack::Lock", RAILS_CACHE.middleware)
+ end
+ end
+ end
+
+ initializer :initialize_framework_caches do
+ if config.frameworks.include?(:action_controller)
+ ActionController::Base.cache_store ||= RAILS_CACHE
+ end
+ end
+
+ initializer :initialize_logger do
+ # if the environment has explicitly defined a logger, use it
+ next if Rails.logger
+
+ unless logger = config.logger
+ begin
+ logger = ActiveSupport::BufferedLogger.new(config.log_path)
+ logger.level = ActiveSupport::BufferedLogger.const_get(config.log_level.to_s.upcase)
+ if RAILS_ENV == "production"
+ logger.auto_flushing = false
+ end
+ rescue StandardError => e
+ logger = ActiveSupport::BufferedLogger.new(STDERR)
+ logger.level = ActiveSupport::BufferedLogger::WARN
+ logger.warn(
+ "Rails Error: Unable to access log file. Please ensure that #{config.log_path} exists and is chmod 0666. " +
+ "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
+ )
+ end
+ end
+
+ # TODO: Why are we silencing warning here?
+ silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
+ end
+
+ # Sets the logger for Active Record, Action Controller, and Action Mailer
+ # (but only for those frameworks that are to be loaded). If the framework's
+ # logger is already set, it is not changed, otherwise it is set to use
+ # RAILS_DEFAULT_LOGGER.
+ initializer :initialize_framework_logging do
+ for framework in ([ :active_record, :action_controller, :action_mailer ] & config.frameworks)
+ framework.to_s.camelize.constantize.const_get("Base").logger ||= Rails.logger
+ end
+
+ ActiveSupport::Dependencies.logger ||= Rails.logger
+ Rails.cache.logger ||= Rails.logger
+ end
+
+ # Sets the dependency loading mechanism based on the value of
+ # Configuration#cache_classes.
+ initializer :initialize_dependency_mechanism do
+ # TODO: Remove files from the $" and always use require
+ ActiveSupport::Dependencies.mechanism = config.cache_classes ? :require : :load
+ end
+
+ # Loads support for "whiny nil" (noisy warnings when methods are invoked
+ # on +nil+ values) if Configuration#whiny_nils is true.
+ initializer :initialize_whiny_nils do
+ require('active_support/whiny_nil') if config.whiny_nils
+ end
+
+ # Sets the default value for Time.zone, and turns on ActiveRecord::Base#time_zone_aware_attributes.
+ # If assigned value cannot be matched to a TimeZone, an exception will be raised.
+ initializer :initialize_time_zone do
+ if config.time_zone
+ zone_default = Time.__send__(:get_zone, config.time_zone)
+
+ unless zone_default
+ raise \
+ 'Value assigned to config.time_zone not recognized.' +
+ 'Run "rake -D time" for a list of tasks for finding appropriate time zone names.'
+ end
+
+ Time.zone_default = zone_default
+
+ if config.frameworks.include?(:active_record)
+ ActiveRecord::Base.time_zone_aware_attributes = true
+ ActiveRecord::Base.default_timezone = :utc
+ end
+ end
+ end
+
+ # Set the i18n configuration from config.i18n but special-case for the load_path which should be
+ # appended to what's already set instead of overwritten.
+ initializer :initialize_i18n do
+ config.i18n.each do |setting, value|
+ if setting == :load_path
+ I18n.load_path += value
+ else
+ I18n.send("#{setting}=", value)
+ end
+ end
+ end
+
+ # Initializes framework-specific settings for each of the loaded frameworks
+ # (Configuration#frameworks). The available settings map to the accessors
+ # on each of the corresponding Base classes.
+ initializer :initialize_framework_settings do
+ config.frameworks.each do |framework|
+ base_class = framework.to_s.camelize.constantize.const_get("Base")
+
+ config.send(framework).each do |setting, value|
+ base_class.send("#{setting}=", value)
+ end
+ end
+ config.active_support.each do |setting, value|
+ ActiveSupport.send("#{setting}=", value)
+ end
end
- def self.config=(config)
- @config = config
+ # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
+ # (but only for those frameworks that are to be loaded). If the framework's
+ # paths have already been set, it is not changed, otherwise it is
+ # set to use Configuration#view_path.
+ initializer :initialize_framework_views do
+ if config.frameworks.include?(:action_view)
+ view_path = ActionView::PathSet.type_cast(config.view_path, config.cache_classes)
+ ActionMailer::Base.template_root = view_path if config.frameworks.include?(:action_mailer) && ActionMailer::Base.view_paths.blank?
+ ActionController::Base.view_paths = view_path if config.frameworks.include?(:action_controller) && ActionController::Base.view_paths.blank?
+ end
end
- def config
- self.class.config
+ initializer :initialize_metal do
+ # TODO: Make Rails and metal work without ActionController
+ if config.frameworks.include?(:action_controller)
+ Rails::Rack::Metal.requested_metals = config.metals
+ Rails::Rack::Metal.metal_paths += plugin_loader.engine_metal_paths
+
+ config.middleware.insert_before(
+ :"ActionDispatch::ParamsParser",
+ Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?)
+ end
+ end
+
+ initializer :check_for_unbuilt_gems do
+ unbuilt_gems = config.gems.select {|gem| gem.frozen? && !gem.built? }
+ if unbuilt_gems.size > 0
+ # don't print if the gems:build rake tasks are being run
+ unless $gems_build_rake_task
+ abort <<-end_error
+ The following gems have native components that need to be built
+ #{unbuilt_gems.map { |gemm| "#{gemm.name} #{gemm.requirement}" } * "\n "}
+
+ You're running:
+ ruby #{Gem.ruby_version} at #{Gem.ruby}
+ rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
+
+ Run `rake gems:build` to build the unbuilt gems.
+ end_error
+ end
+ end
end
- def routes
- ActionController::Routing::Routes
+ initializer :load_gems do
+ unless $gems_rake_task
+ config.gems.each { |gem| gem.load }
+ end
+ end
+
+ # Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt>
+ # defaults to <tt>vendor/plugins</tt> but may also be set to a list of
+ # paths, such as
+ # config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]
+ #
+ # In the default implementation, as each plugin discovered in <tt>plugin_paths</tt> is initialized:
+ # * its +lib+ directory, if present, is added to the load path (immediately after the applications lib directory)
+ # * <tt>init.rb</tt> is evaluated, if present
+ #
+ # After all plugins are loaded, duplicates are removed from the load path.
+ # If an array of plugin names is specified in config.plugins, only those plugins will be loaded
+ # and they plugins will be loaded in that order. Otherwise, plugins are loaded in alphabetical
+ # order.
+ #
+ # if config.plugins ends contains :all then the named plugins will be loaded in the given order and all other
+ # plugins will be loaded in alphabetical order
+ initializer :load_plugins do
+ plugin_loader.load_plugins
+ end
+
+ # TODO: Figure out if this needs to run a second time
+ # load_gems
+
+ initializer :check_gem_dependencies do
+ unloaded_gems = config.gems.reject { |g| g.loaded? }
+ if unloaded_gems.size > 0
+ configuration.gems_dependencies_loaded = false
+ # don't print if the gems rake tasks are being run
+ unless $gems_rake_task
+ abort <<-end_error
+ Missing these required gems:
+ #{unloaded_gems.map { |gemm| "#{gemm.name} #{gemm.requirement}" } * "\n "}
+
+ You're running:
+ ruby #{Gem.ruby_version} at #{Gem.ruby}
+ rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
+
+ Run `rake gems:install` to install the missing gems.
+ end_error
+ end
+ else
+ configuration.gems_dependencies_loaded = true
+ end
+ end
+
+ # # bail out if gems are missing - note that check_gem_dependencies will have
+ # # already called abort() unless $gems_rake_task is set
+ # return unless gems_dependencies_loaded
+
+ initializer :load_application_initializers do
+ if config.gems_dependencies_loaded
+ Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
+ load(initializer)
+ end
+ end
+ end
+
+ # Fires the user-supplied after_initialize block (Configuration#after_initialize)
+ initializer :after_initialize do
+ if config.gems_dependencies_loaded
+ configuration.after_initialize_blocks.each do |block|
+ block.call
+ end
+ end
+ end
+
+ # # Setup database middleware after initializers have run
+ initializer :initialize_database_middleware do
+ if configuration.frameworks.include?(:active_record)
+ if configuration.frameworks.include?(:action_controller) && ActionController::Base.session_store &&
+ ActionController::Base.session_store.name == 'ActiveRecord::SessionStore'
+ configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement
+ configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::QueryCache
+ else
+ configuration.middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement
+ configuration.middleware.use ActiveRecord::QueryCache
+ end
+ end
+ end
+
+ # TODO: Make a DSL way to limit an initializer to a particular framework
+
+ # # Prepare dispatcher callbacks and run 'prepare' callbacks
+ initializer :prepare_dispatcher do
+ next unless configuration.frameworks.include?(:action_controller)
+ require 'rails/dispatcher' unless defined?(::Dispatcher)
+ Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
+ end
+
+ # Routing must be initialized after plugins to allow the former to extend the routes
+ # ---
+ # If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
+ # this does nothing. Otherwise, it loads the routing definitions and sets up
+ # loading module used to lazily load controllers (Configuration#controller_paths).
+ initializer :initialize_routing do
+ next unless configuration.frameworks.include?(:action_controller)
+
+ ActionController::Routing.controller_paths += configuration.controller_paths
+ ActionController::Routing::Routes.add_configuration_file(configuration.routes_configuration_file)
+ ActionController::Routing::Routes.reload!
+ end
+ #
+ # # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
+ initializer :load_observers do
+ if config.gems_dependencies_loaded && configuration.frameworks.include?(:active_record)
+ ActiveRecord::Base.instantiate_observers
+ end
+ end
+
+ # Eager load application classes
+ initializer :load_application_classes do
+ next if $rails_rake_task
+
+ if configuration.cache_classes
+ configuration.eager_load_paths.each do |load_path|
+ matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
+ Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
+ require_dependency file.sub(matcher, '\1')
+ end
+ end
+ end
end
- def middleware
- config.middleware
+ # Disable dependency loading during request cycle
+ initializer :disable_dependency_loading do
+ if configuration.cache_classes && !configuration.dependency_loading
+ ActiveSupport::Dependencies.unhook!
+ end
end
- def call(env)
- @app ||= middleware.build(routes)
- @app.call(env)
+ # Configure generators if they were already loaded
+ # ===
+ # TODO: Does this need to be an initializer here?
+ initializer :initialize_generators do
+ if defined?(Rails::Generators)
+ Rails::Generators.no_color! unless config.generators.colorize_logging
+ Rails::Generators.aliases.deep_merge! config.generators.aliases
+ Rails::Generators.options.deep_merge! config.generators.options
+ end
end
end
end
diff --git a/railties/lib/rails/core.rb b/railties/lib/rails/core.rb
index 4be90de792..929c38bd22 100644
--- a/railties/lib/rails/core.rb
+++ b/railties/lib/rails/core.rb
@@ -15,11 +15,7 @@ module Rails
# The Configuration instance used to configure the Rails environment
def configuration
- @@configuration
- end
-
- def configuration=(configuration)
- @@configuration = configuration
+ application.configuration
end
def initialized?
diff --git a/railties/lib/rails/generators.rb b/railties/lib/rails/generators.rb
index 0419a4e36c..471eb45ee6 100644
--- a/railties/lib/rails/generators.rb
+++ b/railties/lib/rails/generators.rb
@@ -1,4 +1,4 @@
-activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
+activesupport_path = "#{File.dirname(__FILE__)}/../../../activesupport/lib"
$LOAD_PATH.unshift(activesupport_path) if File.directory?(activesupport_path)
require 'active_support'
require 'active_support/core_ext/object/blank'
diff --git a/railties/lib/rails/generators/rails/app/templates/config/boot.rb b/railties/lib/rails/generators/rails/app/templates/config/boot.rb
index 52086fbc7d..6e0e2279cd 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/boot.rb
+++ b/railties/lib/rails/generators/rails/app/templates/config/boot.rb
@@ -40,20 +40,20 @@ module Rails
class Boot
def run
- load_initializer
set_load_paths
+ load_initializer
end
def set_load_paths
%w(
- railties
- railties/lib
- activesupport/lib
+ actionmailer/lib
actionpack/lib
+ activemodel/lib
activerecord/lib
- actionmailer/lib
activeresource/lib
- actionwebservice/lib
+ activesupport/lib
+ railties/lib
+ railties
).reverse_each do |path|
path = "#{framework_root_path}/#{path}"
$LOAD_PATH.unshift(path) if File.directory?(path)
@@ -68,7 +68,6 @@ module Rails
class VendorBoot < Boot
def load_initializer
- $:.unshift("#{framework_root_path}/railties/lib")
require "rails"
install_gem_spec_stubs
Rails::GemDependency.add_frozen_gem_path
diff --git a/railties/lib/rails/initializable.rb b/railties/lib/rails/initializable.rb
new file mode 100644
index 0000000000..4bd5088207
--- /dev/null
+++ b/railties/lib/rails/initializable.rb
@@ -0,0 +1,99 @@
+module Rails
+ module Initializable
+
+ # A collection of initializers
+ class Collection
+ def initialize(context)
+ @context = context
+ @keys = []
+ @values = {}
+ @ran = false
+ end
+
+ def run
+ return self if @ran
+ each do |key, initializer|
+ @context.class_eval(&initializer.block)
+ end
+ @ran = true
+ self
+ end
+
+ def [](key)
+ keys, values = merge_with_parent
+ values[key.to_sym]
+ end
+
+ def []=(key, value)
+ key = key.to_sym
+ @keys |= [key]
+ @values[key] = value
+ end
+
+ def each
+ keys, values = merge_with_parent
+ keys.each { |k| yield k, values[k] }
+ self
+ end
+
+ protected
+
+ attr_reader :keys, :values
+
+ private
+
+ def merge_with_parent
+ keys, values = [], {}
+
+ if @context.is_a?(Class) && @context.superclass.is_a?(Initializable)
+ parent = @context.superclass.initializers
+ keys, values = parent.keys, parent.values
+ end
+
+ values = values.merge(@values)
+ return keys | @keys, values
+ end
+
+ end
+
+ class Initializer
+ attr_reader :name, :options, :block
+
+ def initialize(name, options = {}, &block)
+ @name, @options, @block = name, options, block
+ end
+ end
+
+ def initializer(name, options = {}, &block)
+ @initializers ||= Collection.new(self)
+ @initializers[name] = Initializer.new(name, options, &block)
+ end
+
+ def initializers
+ @initializers ||= Collection.new(self)
+ end
+
+ end
+
+ extend Initializable
+
+ # Check for valid Ruby version (1.8.2 or 1.8.4 or higher). This is done in an
+ # external file, so we can use it from the `rails` program as well without duplication.
+ initializer :check_ruby_version do
+ require 'rails/ruby_version_check'
+ end
+
+ # For Ruby 1.8, this initialization sets $KCODE to 'u' to enable the
+ # multibyte safe operations. Plugin authors supporting other encodings
+ # should override this behaviour and set the relevant +default_charset+
+ # on ActionController::Base.
+ #
+ # For Ruby 1.9, UTF-8 is the default internal and external encoding.
+ initializer :initialize_encoding do
+ if RUBY_VERSION < '1.9'
+ $KCODE='u'
+ else
+ Encoding.default_external = Encoding::UTF_8
+ end
+ end
+end \ No newline at end of file
diff --git a/railties/lib/rails/initializer.rb b/railties/lib/rails/initializer.rb
index c2d6e1609f..f7c3774450 100644
--- a/railties/lib/rails/initializer.rb
+++ b/railties/lib/rails/initializer.rb
@@ -1,5 +1,6 @@
require "pathname"
+require 'rails/initializable'
require 'rails/application'
require 'rails/railties_path'
require 'rails/version'
@@ -12,572 +13,16 @@ require 'rails/configuration'
RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
module Rails
- # Sanity check to make sure this file is only loaded once
- # TODO: Get to the point where this can be removed.
- raise "It looks like initializer.rb was required twice" if defined?(Initializer)
-
class Initializer
class Error < StandardError ; end
-
- class Base
- class << self
- def run(&blk)
- define_method(:run, &blk)
- end
-
- def config=(config)
- @@config = config
- end
-
- def config
- @@config || Configuration.new
- end
- alias configuration config
-
- def gems_dependencies_loaded
- config.gems_dependencies_loaded
- end
-
- def plugin_loader
- @plugin_loader ||= configuration.plugin_loader.new(self)
- end
- end
-
- def gems_dependencies_loaded
- self.class.gems_dependencies_loaded
- end
-
- def plugin_loader
- self.class.plugin_loader
- end
- end
-
- class Runner
-
- attr_reader :names, :initializers
- attr_accessor :config
- alias configuration config
-
- def initialize(parent = nil)
- @names = parent ? parent.names.dup : {}
- @initializers = parent ? parent.initializers.dup : []
- end
-
- def add(name, options = {}, &block)
- # If :before or :after is specified, set the index to the right spot
- if other = options[:before] || options[:after]
- raise Error, "The #{other.inspect} initializer does not exist" unless @names[other]
- index = @initializers.index(@names[other])
- index += 1 if options[:after]
- end
-
- @initializers.insert(index || -1, block)
- @names[name] = block
- end
-
- def delete(name)
- @names[name].tap do |initializer|
- @initializers.delete(initializer)
- @names.delete(name)
- end
- end
-
- def run_initializer(initializer)
- init_block = initializer.is_a?(Proc) ? initializer : @names[initializer]
- container = Class.new(Base, &init_block).new
- container.run if container.respond_to?(:run)
- end
-
- def run(initializer = nil)
- Rails.configuration = Base.config = @config
-
- if initializer
- run_initializer(initializer)
- else
- @initializers.each {|block| run_initializer(block) }
- end
- end
- end
-
- def self.default
- @default ||= Runner.new
- end
-
def self.run(initializer = nil, config = nil)
- # TODO: Clean this all up
if initializer
- default.config = config
- default.run(initializer)
+ # Deprecated
else
Rails.application = Class.new(Application)
yield Rails.application.config if block_given?
- default.config = Rails.application.config
- default.run
- end
- end
- end
-
- # Check for valid Ruby version (1.8.2 or 1.8.4 or higher). This is done in an
- # external file, so we can use it from the `rails` program as well without duplication.
- Initializer.default.add :check_ruby_version do
- require 'rails/ruby_version_check'
- end
-
- # Bail if boot.rb is outdated
- Initializer.default.add :freak_out_if_boot_rb_is_outdated do
- unless defined?(Rails::BOOTSTRAP_VERSION)
- abort %{Your config/boot.rb is outdated: Run "rake rails:update".}
- end
- end
-
- # Set the <tt>$LOAD_PATH</tt> based on the value of
- # Configuration#load_paths. Duplicates are removed.
- Initializer.default.add :set_load_path do
- configuration.paths.add_to_load_path
- $LOAD_PATH.uniq!
- end
-
- # Requires all frameworks specified by the Configuration#frameworks
- # list. By default, all frameworks (Active Record, Active Support,
- # Action Pack, Action Mailer, and Active Resource) are loaded.
- Initializer.default.add :require_frameworks do
- begin
- require 'active_support'
- require 'active_support/core_ext/kernel/reporting'
- require 'active_support/core_ext/logger'
-
- # TODO: This is here to make Sam Ruby's tests pass. Needs discussion.
- require 'active_support/core_ext/numeric/bytes'
- configuration.frameworks.each { |framework| require(framework.to_s) }
- rescue LoadError => e
- # Re-raise as RuntimeError because Mongrel would swallow LoadError.
- raise e.to_s
- end
- end
-
- # Set the paths from which Rails will automatically load source files, and
- # the load_once paths.
- Initializer.default.add :set_autoload_paths do
- require 'active_support/dependencies'
- ActiveSupport::Dependencies.load_paths = configuration.load_paths.uniq
- ActiveSupport::Dependencies.load_once_paths = configuration.load_once_paths.uniq
-
- extra = ActiveSupport::Dependencies.load_once_paths - ActiveSupport::Dependencies.load_paths
- unless extra.empty?
- abort <<-end_error
- load_once_paths must be a subset of the load_paths.
- Extra items in load_once_paths: #{extra * ','}
- end_error
- end
-
- # Freeze the arrays so future modifications will fail rather than do nothing mysteriously
- configuration.load_once_paths.freeze
- end
-
- # Adds all load paths from plugins to the global set of load paths, so that
- # code from plugins can be required (explicitly or automatically via ActiveSupport::Dependencies).
- Initializer.default.add :add_plugin_load_paths do
- require 'active_support/dependencies'
- plugin_loader.add_plugin_load_paths
- end
-
- # Create tmp directories
- Initializer.default.add :ensure_tmp_directories_exist do
- %w(cache pids sessions sockets).each do |dir_to_make|
- FileUtils.mkdir_p(File.join(configuration.root_path, 'tmp', dir_to_make))
- end
- end
-
- # Loads the environment specified by Configuration#environment_path, which
- # is typically one of development, test, or production.
- Initializer.default.add :load_environment do
- silence_warnings do
- next if @environment_loaded
- next unless File.file?(configuration.environment_path)
-
- @environment_loaded = true
-
- config = configuration
- constants = self.class.constants
-
- eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
-
- (self.class.constants - constants).each do |const|
- Object.const_set(const, self.class.const_get(const))
- end
- end
- end
-
- Initializer.default.add :add_gem_load_paths do
- require 'rails/gem_dependency'
- Rails::GemDependency.add_frozen_gem_path
- unless config.gems.empty?
- require "rubygems"
- config.gems.each { |gem| gem.add_load_paths }
- end
- end
-
- # Preload all frameworks specified by the Configuration#frameworks.
- # Used by Passenger to ensure everything's loaded before forking and
- # to avoid autoload race conditions in JRuby.
- Initializer.default.add :preload_frameworks do
- if configuration.preload_frameworks
- configuration.frameworks.each do |framework|
- # String#classify and #constantize aren't available yet.
- toplevel = Object.const_get(framework.to_s.gsub(/(?:^|_)(.)/) { $1.upcase })
- toplevel.load_all! if toplevel.respond_to?(:load_all!)
- end
- end
- end
-
- # For Ruby 1.8, this initialization sets $KCODE to 'u' to enable the
- # multibyte safe operations. Plugin authors supporting other encodings
- # should override this behaviour and set the relevant +default_charset+
- # on ActionController::Base.
- #
- # For Ruby 1.9, UTF-8 is the default internal and external encoding.
- Initializer.default.add :initialize_encoding do
- if RUBY_VERSION < '1.9'
- $KCODE='u'
- else
- Encoding.default_external = Encoding::UTF_8
- end
- end
-
- # This initialization routine does nothing unless <tt>:active_record</tt>
- # is one of the frameworks to load (Configuration#frameworks). If it is,
- # this sets the database configuration from Configuration#database_configuration
- # and then establishes the connection.
- Initializer.default.add :initialize_database do
- if configuration.frameworks.include?(:active_record)
- ActiveRecord::Base.configurations = configuration.database_configuration
- ActiveRecord::Base.establish_connection
- end
- end
-
- # Include middleware to serve up static assets
- Initializer.default.add :initialize_static_server do
- if configuration.frameworks.include?(:action_controller) && configuration.serve_static_assets
- configuration.middleware.use(ActionDispatch::Static, Rails.public_path)
- end
- end
-
- Initializer.default.add :initialize_middleware_stack do
- if configuration.frameworks.include?(:action_controller)
- configuration.middleware.use(::Rack::Lock) unless ActionController::Base.allow_concurrency
- configuration.middleware.use(ActionDispatch::ShowExceptions, ActionController::Base.consider_all_requests_local)
- configuration.middleware.use(ActionDispatch::Callbacks, ActionController::Dispatcher.prepare_each_request)
- configuration.middleware.use(lambda { ActionController::Base.session_store }, lambda { ActionController::Base.session_options })
- configuration.middleware.use(ActionDispatch::ParamsParser)
- configuration.middleware.use(::Rack::MethodOverride)
- configuration.middleware.use(::Rack::Head)
- configuration.middleware.use(ActionDispatch::StringCoercion)
- end
- end
-
- Initializer.default.add :initialize_cache do
- unless defined?(RAILS_CACHE)
- silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(configuration.cache_store) }
-
- if RAILS_CACHE.respond_to?(:middleware)
- # Insert middleware to setup and teardown local cache for each request
- configuration.middleware.insert_after(:"Rack::Lock", RAILS_CACHE.middleware)
- end
- end
- end
-
- Initializer.default.add :initialize_framework_caches do
- if configuration.frameworks.include?(:action_controller)
- ActionController::Base.cache_store ||= RAILS_CACHE
- end
- end
-
- Initializer.default.add :initialize_logger do
- # if the environment has explicitly defined a logger, use it
- next if Rails.logger
-
- unless logger = configuration.logger
- begin
- logger = ActiveSupport::BufferedLogger.new(configuration.log_path)
- logger.level = ActiveSupport::BufferedLogger.const_get(configuration.log_level.to_s.upcase)
- if RAILS_ENV == "production"
- logger.auto_flushing = false
- end
- rescue StandardError => e
- logger = ActiveSupport::BufferedLogger.new(STDERR)
- logger.level = ActiveSupport::BufferedLogger::WARN
- logger.warn(
- "Rails Error: Unable to access log file. Please ensure that #{configuration.log_path} exists and is chmod 0666. " +
- "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
- )
+ Rails.application.new
end
end
-
- # TODO: Why are we silencing warning here?
- silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
- end
-
- # Sets the logger for Active Record, Action Controller, and Action Mailer
- # (but only for those frameworks that are to be loaded). If the framework's
- # logger is already set, it is not changed, otherwise it is set to use
- # RAILS_DEFAULT_LOGGER.
- Initializer.default.add :initialize_framework_logging do
- for framework in ([ :active_record, :action_controller, :action_mailer ] & configuration.frameworks)
- framework.to_s.camelize.constantize.const_get("Base").logger ||= Rails.logger
- end
-
- ActiveSupport::Dependencies.logger ||= Rails.logger
- Rails.cache.logger ||= Rails.logger
- end
-
- # Sets the dependency loading mechanism based on the value of
- # Configuration#cache_classes.
- Initializer.default.add :initialize_dependency_mechanism do
- # TODO: Remove files from the $" and always use require
- ActiveSupport::Dependencies.mechanism = configuration.cache_classes ? :require : :load
- end
-
- # Loads support for "whiny nil" (noisy warnings when methods are invoked
- # on +nil+ values) if Configuration#whiny_nils is true.
- Initializer.default.add :initialize_whiny_nils do
- require('active_support/whiny_nil') if configuration.whiny_nils
- end
-
-
- # Sets the default value for Time.zone, and turns on ActiveRecord::Base#time_zone_aware_attributes.
- # If assigned value cannot be matched to a TimeZone, an exception will be raised.
- Initializer.default.add :initialize_time_zone do
- if configuration.time_zone
- zone_default = Time.__send__(:get_zone, configuration.time_zone)
-
- unless zone_default
- raise \
- 'Value assigned to config.time_zone not recognized.' +
- 'Run "rake -D time" for a list of tasks for finding appropriate time zone names.'
- end
-
- Time.zone_default = zone_default
-
- if configuration.frameworks.include?(:active_record)
- ActiveRecord::Base.time_zone_aware_attributes = true
- ActiveRecord::Base.default_timezone = :utc
- end
- end
- end
-
- # Set the i18n configuration from config.i18n but special-case for the load_path which should be
- # appended to what's already set instead of overwritten.
- Initializer.default.add :initialize_i18n do
- configuration.i18n.each do |setting, value|
- if setting == :load_path
- I18n.load_path += value
- else
- I18n.send("#{setting}=", value)
- end
- end
- end
-
- # Initializes framework-specific settings for each of the loaded frameworks
- # (Configuration#frameworks). The available settings map to the accessors
- # on each of the corresponding Base classes.
- Initializer.default.add :initialize_framework_settings do
- configuration.frameworks.each do |framework|
- base_class = framework.to_s.camelize.constantize.const_get("Base")
-
- configuration.send(framework).each do |setting, value|
- base_class.send("#{setting}=", value)
- end
- end
- configuration.active_support.each do |setting, value|
- ActiveSupport.send("#{setting}=", value)
- end
- end
-
- # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
- # (but only for those frameworks that are to be loaded). If the framework's
- # paths have already been set, it is not changed, otherwise it is
- # set to use Configuration#view_path.
- Initializer.default.add :initialize_framework_views do
- if configuration.frameworks.include?(:action_view)
- view_path = ActionView::PathSet.type_cast(configuration.view_path)
- ActionMailer::Base.template_root = view_path if configuration.frameworks.include?(:action_mailer) && ActionMailer::Base.view_paths.blank?
- ActionController::Base.view_paths = view_path if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.blank?
- end
- end
-
- Initializer.default.add :initialize_metal do
- # TODO: Make Rails and metal work without ActionController
- if defined?(ActionController)
- Rails::Rack::Metal.requested_metals = configuration.metals
- Rails::Rack::Metal.metal_paths += plugin_loader.engine_metal_paths
-
- configuration.middleware.insert_before(
- :"ActionDispatch::ParamsParser",
- Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?)
- end
- end
-
- Initializer.default.add :check_for_unbuilt_gems do
- unbuilt_gems = config.gems.select {|gem| gem.frozen? && !gem.built? }
- if unbuilt_gems.size > 0
- # don't print if the gems:build rake tasks are being run
- unless $gems_build_rake_task
- abort <<-end_error
-The following gems have native components that need to be built
-#{unbuilt_gems.map { |gemm| "#{gemm.name} #{gemm.requirement}" } * "\n "}
-
-You're running:
-ruby #{Gem.ruby_version} at #{Gem.ruby}
-rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
-
-Run `rake gems:build` to build the unbuilt gems.
- end_error
- end
- end
- end
-
- Initializer.default.add :load_gems do
- unless $gems_rake_task
- config.gems.each { |gem| gem.load }
- end
- end
-
- # Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt>
- # defaults to <tt>vendor/plugins</tt> but may also be set to a list of
- # paths, such as
- # config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]
- #
- # In the default implementation, as each plugin discovered in <tt>plugin_paths</tt> is initialized:
- # * its +lib+ directory, if present, is added to the load path (immediately after the applications lib directory)
- # * <tt>init.rb</tt> is evaluated, if present
- #
- # After all plugins are loaded, duplicates are removed from the load path.
- # If an array of plugin names is specified in config.plugins, only those plugins will be loaded
- # and they plugins will be loaded in that order. Otherwise, plugins are loaded in alphabetical
- # order.
- #
- # if config.plugins ends contains :all then the named plugins will be loaded in the given order and all other
- # plugins will be loaded in alphabetical order
- Initializer.default.add :load_plugins do
- plugin_loader.load_plugins
- end
-
- # TODO: Figure out if this needs to run a second time
- # load_gems
-
- Initializer.default.add :check_gem_dependencies do
- unloaded_gems = config.gems.reject { |g| g.loaded? }
- if unloaded_gems.size > 0
- configuration.gems_dependencies_loaded = false
- # don't print if the gems rake tasks are being run
- unless $gems_rake_task
- abort <<-end_error
-Missing these required gems:
-#{unloaded_gems.map { |gemm| "#{gemm.name} #{gemm.requirement}" } * "\n "}
-
-You're running:
-ruby #{Gem.ruby_version} at #{Gem.ruby}
-rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
-
-Run `rake gems:install` to install the missing gems.
- end_error
- end
- else
- configuration.gems_dependencies_loaded = true
- end
- end
-
- # # bail out if gems are missing - note that check_gem_dependencies will have
- # # already called abort() unless $gems_rake_task is set
- # return unless gems_dependencies_loaded
-
- Initializer.default.add :load_application_initializers do
- if gems_dependencies_loaded
- Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
- load(initializer)
- end
- end
- end
-
- # Fires the user-supplied after_initialize block (Configuration#after_initialize)
- Initializer.default.add :after_initialize do
- if gems_dependencies_loaded
- configuration.after_initialize_blocks.each do |block|
- block.call
- end
- end
- end
-
- # # Setup database middleware after initializers have run
- Initializer.default.add :initialize_database_middleware do
- if configuration.frameworks.include?(:active_record)
- if configuration.frameworks.include?(:action_controller) && ActionController::Base.session_store &&
- ActionController::Base.session_store.name == 'ActiveRecord::SessionStore'
- configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement
- configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::QueryCache
- else
- configuration.middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement
- configuration.middleware.use ActiveRecord::QueryCache
- end
- end
- end
-
- # TODO: Make a DSL way to limit an initializer to a particular framework
-
- # # Prepare dispatcher callbacks and run 'prepare' callbacks
- Initializer.default.add :prepare_dispatcher do
- next unless configuration.frameworks.include?(:action_controller)
- require 'rails/dispatcher' unless defined?(::Dispatcher)
- Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
- end
-
- # Routing must be initialized after plugins to allow the former to extend the routes
- # ---
- # If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
- # this does nothing. Otherwise, it loads the routing definitions and sets up
- # loading module used to lazily load controllers (Configuration#controller_paths).
- Initializer.default.add :initialize_routing do
- next unless configuration.frameworks.include?(:action_controller)
-
- ActionController::Routing.controller_paths += configuration.controller_paths
- ActionController::Routing::Routes.add_configuration_file(configuration.routes_configuration_file)
- ActionController::Routing::Routes.reload!
- end
- #
- # # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
- Initializer.default.add :load_observers do
- if gems_dependencies_loaded && configuration.frameworks.include?(:active_record)
- ActiveRecord::Base.instantiate_observers
- end
- end
-
- # Eager load application classes
- Initializer.default.add :load_application_classes do
- next if $rails_rake_task
-
- if configuration.cache_classes
- configuration.eager_load_paths.each do |load_path|
- matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
- Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
- require_dependency file.sub(matcher, '\1')
- end
- end
- end
- end
-
- # Disable dependency loading during request cycle
- Initializer.default.add :disable_dependency_loading do
- if configuration.cache_classes && !configuration.dependency_loading
- ActiveSupport::Dependencies.unhook!
- end
- end
-
- # Configure generators if they were already loaded
- Initializer.default.add :initialize_generators do
- if defined?(Rails::Generators)
- Rails::Generators.no_color! unless config.generators.colorize_logging
- Rails::Generators.aliases.deep_merge! config.generators.aliases
- Rails::Generators.options.deep_merge! config.generators.options
- end
end
end
diff --git a/railties/lib/rails/initializer_old.rb b/railties/lib/rails/initializer_old.rb
deleted file mode 100644
index cee5c7bcb6..0000000000
--- a/railties/lib/rails/initializer_old.rb
+++ /dev/null
@@ -1,1137 +0,0 @@
-require 'logger'
-require 'set'
-require 'pathname'
-
-$LOAD_PATH.unshift File.dirname(__FILE__)
-require 'railties_path'
-require 'rails/version'
-require 'rails/gem_dependency'
-require 'rails/rack'
-
-RAILS_ENV = (ENV['RAILS_ENV'] || 'development').dup unless defined?(RAILS_ENV)
-
-module Rails
- class << self
- # The Configuration instance used to configure the Rails environment
- def configuration
- @@configuration
- end
-
- def configuration=(configuration)
- @@configuration = configuration
- end
-
- def initialized?
- @initialized || false
- end
-
- def initialized=(initialized)
- @initialized ||= initialized
- end
-
- def logger
- if defined?(RAILS_DEFAULT_LOGGER)
- RAILS_DEFAULT_LOGGER
- else
- nil
- end
- end
-
- def backtrace_cleaner
- @@backtrace_cleaner ||= begin
- # Relies on ActiveSupport, so we have to lazy load to postpone definition until AS has been loaded
- require 'rails/backtrace_cleaner'
- Rails::BacktraceCleaner.new
- end
- end
-
- def root
- Pathname.new(RAILS_ROOT) if defined?(RAILS_ROOT)
- end
-
- def env
- @_env ||= ActiveSupport::StringInquirer.new(RAILS_ENV)
- end
-
- def cache
- RAILS_CACHE
- end
-
- def version
- VERSION::STRING
- end
-
- def public_path
- @@public_path ||= self.root ? File.join(self.root, "public") : "public"
- end
-
- def public_path=(path)
- @@public_path = path
- end
- end
-
- # The Initializer is responsible for processing the Rails configuration, such
- # as setting the $LOAD_PATH, requiring the right frameworks, initializing
- # logging, and more. It can be run either as a single command that'll just
- # use the default configuration, like this:
- #
- # Rails::Initializer.run
- #
- # But normally it's more interesting to pass in a custom configuration
- # through the block running:
- #
- # Rails::Initializer.run do |config|
- # config.frameworks -= [ :action_mailer ]
- # end
- #
- # This will use the default configuration options from Rails::Configuration,
- # but allow for overwriting on select areas.
- class Initializer
- # The Configuration instance used by this Initializer instance.
- attr_reader :configuration
-
- # The set of loaded plugins.
- attr_reader :loaded_plugins
-
- # Whether or not all the gem dependencies have been met
- attr_reader :gems_dependencies_loaded
-
- # Runs the initializer. By default, this will invoke the #process method,
- # which simply executes all of the initialization routines. Alternately,
- # you can specify explicitly which initialization routine you want:
- #
- # Rails::Initializer.run(:set_load_path)
- #
- # This is useful if you only want the load path initialized, without
- # incurring the overhead of completely loading the entire environment.
- def self.run(command = :process, configuration = Configuration.new)
- yield configuration if block_given?
- initializer = new configuration
- initializer.send(command)
- initializer
- end
-
- # Create a new Initializer instance that references the given Configuration
- # instance.
- def initialize(configuration)
- @configuration = configuration
- @loaded_plugins = []
- end
-
- # Sequentially step through all of the available initialization routines,
- # in order (view execution order in source).
- def process
- Rails.configuration = configuration
-
- check_ruby_version
- install_gem_spec_stubs
- set_load_path
- add_gem_load_paths
-
- require_frameworks
- set_autoload_paths
- add_plugin_load_paths
- load_environment
- preload_frameworks
-
- initialize_encoding
- initialize_database
-
- initialize_cache
- initialize_framework_caches
-
- initialize_logger
- initialize_framework_logging
-
- initialize_dependency_mechanism
- initialize_whiny_nils
-
- initialize_time_zone
- initialize_i18n
-
- initialize_framework_settings
- initialize_framework_views
-
- initialize_metal
-
- add_support_load_paths
-
- check_for_unbuilt_gems
-
- load_gems
- load_plugins
-
- # pick up any gems that plugins depend on
- add_gem_load_paths
- load_gems
- check_gem_dependencies
-
- # bail out if gems are missing - note that check_gem_dependencies will have
- # already called abort() unless $gems_rake_task is set
- return unless gems_dependencies_loaded
-
- load_application_initializers
-
- # the framework is now fully initialized
- after_initialize
-
- # Setup database middleware after initializers have run
- initialize_database_middleware
-
- # Prepare dispatcher callbacks and run 'prepare' callbacks
- prepare_dispatcher
-
- # Routing must be initialized after plugins to allow the former to extend the routes
- initialize_routing
-
- # Observers are loaded after plugins in case Observers or observed models are modified by plugins.
- load_observers
-
- # Load view path cache
- load_view_paths
-
- # Load application classes
- load_application_classes
-
- # Disable dependency loading during request cycle
- disable_dependency_loading
-
- # Flag initialized
- Rails.initialized = true
- end
-
- # Check for valid Ruby version
- # This is done in an external file, so we can use it
- # from the `rails` program as well without duplication.
- def check_ruby_version
- require 'ruby_version_check'
- end
-
- # If Rails is vendored and RubyGems is available, install stub GemSpecs
- # for Rails, Active Support, Active Record, Action Pack, Action Mailer, and
- # Active Resource. This allows Gem plugins to depend on Rails even when
- # the Gem version of Rails shouldn't be loaded.
- def install_gem_spec_stubs
- unless Rails.respond_to?(:vendor_rails?)
- abort %{Your config/boot.rb is outdated: Run "rake rails:update".}
- end
-
- if Rails.vendor_rails?
- begin; require "rubygems"; rescue LoadError; return; end
-
- stubs = %w(rails activesupport activerecord actionpack actionmailer activeresource)
- stubs.reject! { |s| Gem.loaded_specs.key?(s) }
-
- stubs.each do |stub|
- Gem.loaded_specs[stub] = Gem::Specification.new do |s|
- s.name = stub
- s.version = Rails::VERSION::STRING
- s.loaded_from = ""
- end
- end
- end
- end
-
- # Set the <tt>$LOAD_PATH</tt> based on the value of
- # Configuration#load_paths. Duplicates are removed.
- def set_load_path
- load_paths = configuration.load_paths + configuration.framework_paths
- load_paths.reverse_each { |dir| $LOAD_PATH.unshift(dir) if File.directory?(dir) }
- $LOAD_PATH.uniq!
- end
-
- # Set the paths from which Rails will automatically load source files, and
- # the load_once paths.
- def set_autoload_paths
- require 'active_support/dependencies'
- ActiveSupport::Dependencies.load_paths = configuration.load_paths.uniq
- ActiveSupport::Dependencies.load_once_paths = configuration.load_once_paths.uniq
-
- extra = ActiveSupport::Dependencies.load_once_paths - ActiveSupport::Dependencies.load_paths
- unless extra.empty?
- abort <<-end_error
- load_once_paths must be a subset of the load_paths.
- Extra items in load_once_paths: #{extra * ','}
- end_error
- end
-
- # Freeze the arrays so future modifications will fail rather than do nothing mysteriously
- configuration.load_once_paths.freeze
- end
-
- # Requires all frameworks specified by the Configuration#frameworks
- # list. By default, all frameworks (Active Record, Active Support,
- # Action Pack, Action Mailer, and Active Resource) are loaded.
- def require_frameworks
- require 'active_support/all'
- configuration.frameworks.each { |framework| require(framework.to_s) }
- rescue LoadError => e
- # Re-raise as RuntimeError because Mongrel would swallow LoadError.
- raise e.to_s
- end
-
- # Preload all frameworks specified by the Configuration#frameworks.
- # Used by Passenger to ensure everything's loaded before forking and
- # to avoid autoload race conditions in JRuby.
- def preload_frameworks
- if configuration.preload_frameworks
- configuration.frameworks.each do |framework|
- # String#classify and #constantize aren't available yet.
- toplevel = Object.const_get(framework.to_s.gsub(/(?:^|_)(.)/) { $1.upcase })
- toplevel.load_all! if toplevel.respond_to?(:load_all!)
- end
- end
- end
-
- # Add the load paths used by support functions such as the info controller
- def add_support_load_paths
- end
-
- # Adds all load paths from plugins to the global set of load paths, so that
- # code from plugins can be required (explicitly or automatically via ActiveSupport::Dependencies).
- def add_plugin_load_paths
- require 'active_support/dependencies'
- plugin_loader.add_plugin_load_paths
- end
-
- def add_gem_load_paths
- require 'rails/gem_dependency'
- Rails::GemDependency.add_frozen_gem_path
- unless @configuration.gems.empty?
- require "rubygems"
- @configuration.gems.each { |gem| gem.add_load_paths }
- end
- end
-
- def load_gems
- unless $gems_rake_task
- @configuration.gems.each { |gem| gem.load }
- end
- end
-
- def check_for_unbuilt_gems
- unbuilt_gems = @configuration.gems.select {|gem| gem.frozen? && !gem.built? }
- if unbuilt_gems.size > 0
- # don't print if the gems:build rake tasks are being run
- unless $gems_build_rake_task
- abort <<-end_error
-The following gems have native components that need to be built
- #{unbuilt_gems.map { |gemm| "#{gemm.name} #{gemm.requirement}" } * "\n "}
-
-You're running:
- ruby #{Gem.ruby_version} at #{Gem.ruby}
- rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
-
-Run `rake gems:build` to build the unbuilt gems.
- end_error
- end
- end
- end
-
- def check_gem_dependencies
- unloaded_gems = @configuration.gems.reject { |g| g.loaded? }
- if unloaded_gems.size > 0
- @gems_dependencies_loaded = false
- # don't print if the gems rake tasks are being run
- unless $gems_rake_task
- abort <<-end_error
-Missing these required gems:
- #{unloaded_gems.map { |gemm| "#{gemm.name} #{gemm.requirement}" } * "\n "}
-
-You're running:
- ruby #{Gem.ruby_version} at #{Gem.ruby}
- rubygems #{Gem::RubyGemsVersion} at #{Gem.path * ', '}
-
-Run `rake gems:install` to install the missing gems.
- end_error
- end
- else
- @gems_dependencies_loaded = true
- end
- end
-
- # Loads all plugins in <tt>config.plugin_paths</tt>. <tt>plugin_paths</tt>
- # defaults to <tt>vendor/plugins</tt> but may also be set to a list of
- # paths, such as
- # config.plugin_paths = ["#{RAILS_ROOT}/lib/plugins", "#{RAILS_ROOT}/vendor/plugins"]
- #
- # In the default implementation, as each plugin discovered in <tt>plugin_paths</tt> is initialized:
- # * its +lib+ directory, if present, is added to the load path (immediately after the applications lib directory)
- # * <tt>init.rb</tt> is evaluated, if present
- #
- # After all plugins are loaded, duplicates are removed from the load path.
- # If an array of plugin names is specified in config.plugins, only those plugins will be loaded
- # and they plugins will be loaded in that order. Otherwise, plugins are loaded in alphabetical
- # order.
- #
- # if config.plugins ends contains :all then the named plugins will be loaded in the given order and all other
- # plugins will be loaded in alphabetical order
- def load_plugins
- plugin_loader.load_plugins
- end
-
- def plugin_loader
- @plugin_loader ||= configuration.plugin_loader.new(self)
- end
-
- # Loads the environment specified by Configuration#environment_path, which
- # is typically one of development, test, or production.
- def load_environment
- silence_warnings do
- return if @environment_loaded
- @environment_loaded = true
-
- config = configuration
- constants = self.class.constants
-
- eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
-
- (self.class.constants - constants).each do |const|
- Object.const_set(const, self.class.const_get(const))
- end
- end
- end
-
- def load_observers
- if gems_dependencies_loaded && configuration.frameworks.include?(:active_record)
- ActiveRecord::Base.instantiate_observers
- end
- end
-
- def load_view_paths
- if configuration.frameworks.include?(:action_view)
- if configuration.cache_classes
- view_path = ActionView::FileSystemResolverWithFallback.new(configuration.view_path)
- ActionController::Base.view_paths = view_path if configuration.frameworks.include?(:action_controller)
- ActionMailer::Base.template_root = view_path if configuration.frameworks.include?(:action_mailer)
- end
- end
- end
-
- # Eager load application classes
- def load_application_classes
- return if $rails_rake_task
- if configuration.cache_classes
- configuration.eager_load_paths.each do |load_path|
- matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
- Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
- require_dependency file.sub(matcher, '\1')
- end
- end
- end
- end
-
- # For Ruby 1.8, this initialization sets $KCODE to 'u' to enable the
- # multibyte safe operations. Plugin authors supporting other encodings
- # should override this behaviour and set the relevant +default_charset+
- # on ActionController::Base.
- #
- # For Ruby 1.9, UTF-8 is the default internal and external encoding.
- def initialize_encoding
- if RUBY_VERSION < '1.9'
- $KCODE='u'
- else
- Encoding.default_internal = Encoding::UTF_8
- Encoding.default_external = Encoding::UTF_8
- end
- end
-
- # This initialization routine does nothing unless <tt>:active_record</tt>
- # is one of the frameworks to load (Configuration#frameworks). If it is,
- # this sets the database configuration from Configuration#database_configuration
- # and then establishes the connection.
- def initialize_database
- if configuration.frameworks.include?(:active_record)
- ActiveRecord::Base.configurations = configuration.database_configuration
- ActiveRecord::Base.establish_connection
- end
- end
-
- def initialize_database_middleware
- if configuration.frameworks.include?(:active_record)
- if configuration.frameworks.include?(:action_controller) &&
- ActionController::Base.session_store.name == 'ActiveRecord::SessionStore'
- configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement
- configuration.middleware.insert_before :"ActiveRecord::SessionStore", ActiveRecord::QueryCache
- else
- configuration.middleware.use ActiveRecord::ConnectionAdapters::ConnectionManagement
- configuration.middleware.use ActiveRecord::QueryCache
- end
- end
- end
-
- def initialize_cache
- unless defined?(RAILS_CACHE)
- silence_warnings { Object.const_set "RAILS_CACHE", ActiveSupport::Cache.lookup_store(configuration.cache_store) }
-
- if RAILS_CACHE.respond_to?(:middleware)
- # Insert middleware to setup and teardown local cache for each request
- configuration.middleware.insert_after(:"Rack::Lock", RAILS_CACHE.middleware)
- end
- end
- end
-
- def initialize_framework_caches
- if configuration.frameworks.include?(:action_controller)
- ActionController::Base.cache_store ||= RAILS_CACHE
- end
- end
-
- # If the RAILS_DEFAULT_LOGGER constant is already set, this initialization
- # routine does nothing. If the constant is not set, and Configuration#logger
- # is not +nil+, this also does nothing. Otherwise, a new logger instance
- # is created at Configuration#log_path, with a default log level of
- # Configuration#log_level.
- #
- # If the log could not be created, the log will be set to output to
- # +STDERR+, with a log level of +WARN+.
- def initialize_logger
- # if the environment has explicitly defined a logger, use it
- return if Rails.logger
-
- unless logger = configuration.logger
- begin
- logger = ActiveSupport::BufferedLogger.new(configuration.log_path)
- logger.level = ActiveSupport::BufferedLogger.const_get(configuration.log_level.to_s.upcase)
- if configuration.environment == "production"
- logger.auto_flushing = false
- end
- rescue StandardError => e
- logger = ActiveSupport::BufferedLogger.new(STDERR)
- logger.level = ActiveSupport::BufferedLogger::WARN
- logger.warn(
- "Rails Error: Unable to access log file. Please ensure that #{configuration.log_path} exists and is chmod 0666. " +
- "The log level has been raised to WARN and the output directed to STDERR until the problem is fixed."
- )
- end
- end
-
- silence_warnings { Object.const_set "RAILS_DEFAULT_LOGGER", logger }
- end
-
- # Sets the logger for Active Record, Action Controller, and Action Mailer
- # (but only for those frameworks that are to be loaded). If the framework's
- # logger is already set, it is not changed, otherwise it is set to use
- # RAILS_DEFAULT_LOGGER.
- def initialize_framework_logging
- for framework in ([ :active_record, :action_controller, :action_mailer ] & configuration.frameworks)
- framework.to_s.camelize.constantize.const_get("Base").logger ||= Rails.logger
- end
-
- ActiveSupport::Dependencies.logger ||= Rails.logger
- Rails.cache.logger ||= Rails.logger
- end
-
- # Sets +ActionController::Base#view_paths+ and +ActionMailer::Base#template_root+
- # (but only for those frameworks that are to be loaded). If the framework's
- # paths have already been set, it is not changed, otherwise it is
- # set to use Configuration#view_path.
- def initialize_framework_views
- if configuration.frameworks.include?(:action_view)
- view_path = ActionView::PathSet.type_cast(configuration.view_path)
- ActionMailer::Base.template_root = view_path if configuration.frameworks.include?(:action_mailer) && ActionMailer::Base.view_paths.blank?
- ActionController::Base.view_paths = view_path if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.blank?
- end
- end
-
- # If Action Controller is not one of the loaded frameworks (Configuration#frameworks)
- # this does nothing. Otherwise, it loads the routing definitions and sets up
- # loading module used to lazily load controllers (Configuration#controller_paths).
- def initialize_routing
- return unless configuration.frameworks.include?(:action_controller)
-
- ActionController::Routing.controller_paths += configuration.controller_paths
- ActionController::Routing::Routes.add_configuration_file(configuration.routes_configuration_file)
- ActionController::Routing::Routes.reload!
- end
-
- # Sets the dependency loading mechanism based on the value of
- # Configuration#cache_classes.
- def initialize_dependency_mechanism
- ActiveSupport::Dependencies.mechanism = configuration.cache_classes ? :require : :load
- end
-
- # Loads support for "whiny nil" (noisy warnings when methods are invoked
- # on +nil+ values) if Configuration#whiny_nils is true.
- def initialize_whiny_nils
- require('active_support/whiny_nil') if configuration.whiny_nils
- end
-
- # Sets the default value for Time.zone, and turns on ActiveRecord::Base#time_zone_aware_attributes.
- # If assigned value cannot be matched to a TimeZone, an exception will be raised.
- def initialize_time_zone
- if configuration.time_zone
- zone_default = Time.__send__(:get_zone, configuration.time_zone)
-
- unless zone_default
- raise \
- 'Value assigned to config.time_zone not recognized.' +
- 'Run "rake -D time" for a list of tasks for finding appropriate time zone names.'
- end
-
- Time.zone_default = zone_default
-
- if configuration.frameworks.include?(:active_record)
- ActiveRecord::Base.time_zone_aware_attributes = true
- ActiveRecord::Base.default_timezone = :utc
- end
- end
- end
-
- # Set the i18n configuration from config.i18n but special-case for the load_path which should be
- # appended to what's already set instead of overwritten.
- def initialize_i18n
- configuration.i18n.each do |setting, value|
- if setting == :load_path
- I18n.load_path += value
- else
- I18n.send("#{setting}=", value)
- end
- end
- end
-
- def initialize_metal
- Rails::Rack::Metal.requested_metals = configuration.metals
- Rails::Rack::Metal.metal_paths += plugin_loader.engine_metal_paths
-
- configuration.middleware.insert_before(
- :"ActionDispatch::ParamsParser",
- Rails::Rack::Metal, :if => Rails::Rack::Metal.metals.any?)
- end
-
- # Initializes framework-specific settings for each of the loaded frameworks
- # (Configuration#frameworks). The available settings map to the accessors
- # on each of the corresponding Base classes.
- def initialize_framework_settings
- configuration.frameworks.each do |framework|
- base_class = framework.to_s.camelize.constantize.const_get("Base")
-
- configuration.send(framework).each do |setting, value|
- base_class.send("#{setting}=", value)
- end
- end
- configuration.active_support.each do |setting, value|
- ActiveSupport.send("#{setting}=", value)
- end
- end
-
- # Fires the user-supplied after_initialize block (Configuration#after_initialize)
- def after_initialize
- if gems_dependencies_loaded
- configuration.after_initialize_blocks.each do |block|
- block.call
- end
- end
- end
-
- def load_application_initializers
- if gems_dependencies_loaded
- Dir["#{configuration.root_path}/config/initializers/**/*.rb"].sort.each do |initializer|
- load(initializer)
- end
- end
- end
-
- def prepare_dispatcher
- return unless configuration.frameworks.include?(:action_controller)
- require 'dispatcher' unless defined?(::Dispatcher)
- Dispatcher.define_dispatcher_callbacks(configuration.cache_classes)
- end
-
- def disable_dependency_loading
- if configuration.cache_classes && !configuration.dependency_loading
- ActiveSupport::Dependencies.unhook!
- end
- end
- end
-
- # The Configuration class holds all the parameters for the Initializer and
- # ships with defaults that suites most Rails applications. But it's possible
- # to overwrite everything. Usually, you'll create an Configuration file
- # implicitly through the block running on the Initializer, but it's also
- # possible to create the Configuration instance in advance and pass it in
- # like this:
- #
- # config = Rails::Configuration.new
- # Rails::Initializer.run(:process, config)
- class Configuration
- # The application's base directory.
- attr_reader :root_path
-
- # A stub for setting options on ActionController::Base.
- attr_accessor :action_controller
-
- # A stub for setting options on ActionMailer::Base.
- attr_accessor :action_mailer
-
- # A stub for setting options on ActionView::Base.
- attr_accessor :action_view
-
- # A stub for setting options on ActiveRecord::Base.
- attr_accessor :active_record
-
- # A stub for setting options on ActiveResource::Base.
- attr_accessor :active_resource
-
- # A stub for setting options on ActiveSupport.
- attr_accessor :active_support
-
- # Whether to preload all frameworks at startup.
- attr_accessor :preload_frameworks
-
- # Whether or not classes should be cached (set to false if you want
- # application classes to be reloaded on each request)
- attr_accessor :cache_classes
-
- # The list of paths that should be searched for controllers. (Defaults
- # to <tt>app/controllers</tt>.)
- attr_accessor :controller_paths
-
- # The path to the database configuration file to use. (Defaults to
- # <tt>config/database.yml</tt>.)
- attr_accessor :database_configuration_file
-
- # The path to the routes configuration file to use. (Defaults to
- # <tt>config/routes.rb</tt>.)
- attr_accessor :routes_configuration_file
-
- # The list of rails framework components that should be loaded. (Defaults
- # to <tt>:active_record</tt>, <tt>:action_controller</tt>,
- # <tt>:action_view</tt>, <tt>:action_mailer</tt>, and
- # <tt>:active_resource</tt>).
- attr_accessor :frameworks
-
- # An array of additional paths to prepend to the load path. By default,
- # all +app+, +lib+, +vendor+ and mock paths are included in this list.
- attr_accessor :load_paths
-
- # An array of paths from which Rails will automatically load from only once.
- # All elements of this array must also be in +load_paths+.
- attr_accessor :load_once_paths
-
- # An array of paths from which Rails will eager load on boot if cache
- # classes is enabled. All elements of this array must also be in
- # +load_paths+.
- attr_accessor :eager_load_paths
-
- # The log level to use for the default Rails logger. In production mode,
- # this defaults to <tt>:info</tt>. In development mode, it defaults to
- # <tt>:debug</tt>.
- attr_accessor :log_level
-
- # The path to the log file to use. Defaults to log/#{environment}.log
- # (e.g. log/development.log or log/production.log).
- attr_accessor :log_path
-
- # The specific logger to use. By default, a logger will be created and
- # initialized using #log_path and #log_level, but a programmer may
- # specifically set the logger to use via this accessor and it will be
- # used directly.
- attr_accessor :logger
-
- # The specific cache store to use. By default, the ActiveSupport::Cache::Store will be used.
- attr_accessor :cache_store
-
- # The root of the application's views. (Defaults to <tt>app/views</tt>.)
- attr_accessor :view_path
-
- # Set to +true+ if you want to be warned (noisily) when you try to invoke
- # any method of +nil+. Set to +false+ for the standard Ruby behavior.
- attr_accessor :whiny_nils
-
- # The list of plugins to load. If this is set to <tt>nil</tt>, all plugins will
- # be loaded. If this is set to <tt>[]</tt>, no plugins will be loaded. Otherwise,
- # plugins will be loaded in the order specified.
- attr_reader :plugins
- def plugins=(plugins)
- @plugins = plugins.nil? ? nil : plugins.map { |p| p.to_sym }
- end
-
- # The list of metals to load. If this is set to <tt>nil</tt>, all metals will
- # be loaded in alphabetical order. If this is set to <tt>[]</tt>, no metals will
- # be loaded. Otherwise metals will be loaded in the order specified
- attr_accessor :metals
-
- # The path to the root of the plugins directory. By default, it is in
- # <tt>vendor/plugins</tt>.
- attr_accessor :plugin_paths
-
- # The classes that handle finding the desired plugins that you'd like to load for
- # your application. By default it is the Rails::Plugin::FileSystemLocator which finds
- # plugins to load in <tt>vendor/plugins</tt>. You can hook into gem location by subclassing
- # Rails::Plugin::Locator and adding it onto the list of <tt>plugin_locators</tt>.
- attr_accessor :plugin_locators
-
- # The class that handles loading each plugin. Defaults to Rails::Plugin::Loader, but
- # a sub class would have access to fine grained modification of the loading behavior. See
- # the implementation of Rails::Plugin::Loader for more details.
- attr_accessor :plugin_loader
-
- # Enables or disables plugin reloading. You can get around this setting per plugin.
- # If <tt>reload_plugins?</tt> is false, add this to your plugin's <tt>init.rb</tt>
- # to make it reloadable:
- #
- # ActiveSupport::Dependencies.load_once_paths.delete lib_path
- #
- # If <tt>reload_plugins?</tt> is true, add this to your plugin's <tt>init.rb</tt>
- # to only load it once:
- #
- # ActiveSupport::Dependencies.load_once_paths << lib_path
- #
- attr_accessor :reload_plugins
-
- # Returns true if plugin reloading is enabled.
- def reload_plugins?
- !!@reload_plugins
- end
-
- # Enables or disables dependency loading during the request cycle. Setting
- # <tt>dependency_loading</tt> to true will allow new classes to be loaded
- # during a request. Setting it to false will disable this behavior.
- #
- # Those who want to run in a threaded environment should disable this
- # option and eager load or require all there classes on initialization.
- #
- # If <tt>cache_classes</tt> is disabled, dependency loaded will always be
- # on.
- attr_accessor :dependency_loading
-
- # An array of gems that this rails application depends on. Rails will automatically load
- # these gems during installation, and allow you to install any missing gems with:
- #
- # rake gems:install
- #
- # You can add gems with the #gem method.
- attr_accessor :gems
-
- # Adds a single Gem dependency to the rails application. By default, it will require
- # the library with the same name as the gem. Use :lib to specify a different name.
- #
- # # gem 'aws-s3', '>= 0.4.0'
- # # require 'aws/s3'
- # config.gem 'aws-s3', :lib => 'aws/s3', :version => '>= 0.4.0', \
- # :source => "http://code.whytheluckystiff.net"
- #
- # To require a library be installed, but not attempt to load it, pass :lib => false
- #
- # config.gem 'qrp', :version => '0.4.1', :lib => false
- def gem(name, options = {})
- @gems << Rails::GemDependency.new(name, options)
- end
-
- # Deprecated options:
- def breakpoint_server(_ = nil)
- $stderr.puts %(
- *******************************************************************
- * config.breakpoint_server has been deprecated and has no effect. *
- *******************************************************************
- )
- end
- alias_method :breakpoint_server=, :breakpoint_server
-
- # Sets the default +time_zone+. Setting this will enable +time_zone+
- # awareness for Active Record models and set the Active Record default
- # timezone to <tt>:utc</tt>.
- attr_accessor :time_zone
-
- # Accessor for i18n settings.
- attr_accessor :i18n
-
- # Create a new Configuration instance, initialized with the default
- # values.
- def initialize
- set_root_path!
-
- self.frameworks = default_frameworks
- self.load_paths = default_load_paths
- self.load_once_paths = default_load_once_paths
- self.eager_load_paths = default_eager_load_paths
- self.log_path = default_log_path
- self.log_level = default_log_level
- self.view_path = default_view_path
- self.controller_paths = default_controller_paths
- self.preload_frameworks = default_preload_frameworks
- self.cache_classes = default_cache_classes
- self.dependency_loading = default_dependency_loading
- self.whiny_nils = default_whiny_nils
- self.plugins = default_plugins
- self.plugin_paths = default_plugin_paths
- self.plugin_locators = default_plugin_locators
- self.plugin_loader = default_plugin_loader
- self.database_configuration_file = default_database_configuration_file
- self.routes_configuration_file = default_routes_configuration_file
- self.gems = default_gems
- self.i18n = default_i18n
-
- for framework in default_frameworks
- self.send("#{framework}=", Rails::OrderedOptions.new)
- end
- self.active_support = Rails::OrderedOptions.new
- end
-
- # Set the root_path to RAILS_ROOT and canonicalize it.
- def set_root_path!
- raise 'RAILS_ROOT is not set' unless defined?(::RAILS_ROOT)
- raise 'RAILS_ROOT is not a directory' unless File.directory?(::RAILS_ROOT)
-
- @root_path =
- # Pathname is incompatible with Windows, but Windows doesn't have
- # real symlinks so File.expand_path is safe.
- if RUBY_PLATFORM =~ /(:?mswin|mingw)/
- File.expand_path(::RAILS_ROOT)
-
- # Otherwise use Pathname#realpath which respects symlinks.
- else
- Pathname.new(::RAILS_ROOT).realpath.to_s
- end
-
- Object.const_set(:RELATIVE_RAILS_ROOT, ::RAILS_ROOT.dup) unless defined?(::RELATIVE_RAILS_ROOT)
- ::RAILS_ROOT.replace @root_path
- end
-
- # Enable threaded mode. Allows concurrent requests to controller actions and
- # multiple database connections. Also disables automatic dependency loading
- # after boot, and disables reloading code on every request, as these are
- # fundamentally incompatible with thread safety.
- def threadsafe!
- self.preload_frameworks = true
- self.cache_classes = true
- self.dependency_loading = false
- self.action_controller.allow_concurrency = true
- self
- end
-
- # Loads and returns the contents of the #database_configuration_file. The
- # contents of the file are processed via ERB before being sent through
- # YAML::load.
- def database_configuration
- require 'erb'
- YAML::load(ERB.new(IO.read(database_configuration_file)).result)
- end
-
- # The path to the current environment's file (<tt>development.rb</tt>, etc.). By
- # default the file is at <tt>config/environments/#{environment}.rb</tt>.
- def environment_path
- "#{root_path}/config/environments/#{environment}.rb"
- end
-
- # Return the currently selected environment. By default, it returns the
- # value of the RAILS_ENV constant.
- def environment
- ::RAILS_ENV
- end
-
- # Adds a block which will be executed after rails has been fully initialized.
- # Useful for per-environment configuration which depends on the framework being
- # fully initialized.
- def after_initialize(&after_initialize_block)
- after_initialize_blocks << after_initialize_block if after_initialize_block
- end
-
- # Returns the blocks added with Configuration#after_initialize
- def after_initialize_blocks
- @after_initialize_blocks ||= []
- end
-
- # Add a preparation callback that will run before every request in development
- # mode, or before the first request in production.
- #
- # See Dispatcher#to_prepare.
- def to_prepare(&callback)
- after_initialize do
- require 'dispatcher' unless defined?(::Dispatcher)
- Dispatcher.to_prepare(&callback)
- end
- end
-
- def middleware
- require 'action_controller'
- ActionController::Dispatcher.middleware
- end
-
- def builtin_directories
- # Include builtins only in the development environment.
- (environment == 'development') ? Dir["#{RAILTIES_PATH}/builtin/*/"] : []
- end
-
- def framework_paths
- paths = %w(railties railties/lib activesupport/lib)
- paths << 'actionpack/lib' if frameworks.include?(:action_controller) || frameworks.include?(:action_view)
-
- [:active_record, :action_mailer, :active_resource, :action_web_service].each do |framework|
- paths << "#{framework.to_s.gsub('_', '')}/lib" if frameworks.include?(framework)
- end
-
- paths.map { |dir| "#{framework_root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
- end
-
- private
- def framework_root_path
- defined?(::RAILS_FRAMEWORK_ROOT) ? ::RAILS_FRAMEWORK_ROOT : "#{root_path}/vendor/rails"
- end
-
- def default_frameworks
- [ :active_record, :action_controller, :action_view, :action_mailer, :active_resource ]
- end
-
- def default_load_paths
- paths = []
-
- # Add the old mock paths only if the directories exists
- paths.concat(Dir["#{root_path}/test/mocks/#{environment}"]) if File.exists?("#{root_path}/test/mocks/#{environment}")
-
- # Add the app's controller directory
- paths.concat(Dir["#{root_path}/app/controllers/"])
-
- # Followed by the standard includes.
- paths.concat %w(
- app
- app/metal
- app/models
- app/controllers
- app/helpers
- app/services
- lib
- vendor
- ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
-
- paths.concat builtin_directories
- end
-
- # Doesn't matter since plugins aren't in load_paths yet.
- def default_load_once_paths
- []
- end
-
- def default_eager_load_paths
- %w(
- app/metal
- app/models
- app/controllers
- app/helpers
- ).map { |dir| "#{root_path}/#{dir}" }.select { |dir| File.directory?(dir) }
- end
-
- def default_log_path
- File.join(root_path, 'log', "#{environment}.log")
- end
-
- def default_log_level
- environment == 'production' ? :info : :debug
- end
-
- def default_database_configuration_file
- File.join(root_path, 'config', 'database.yml')
- end
-
- def default_routes_configuration_file
- File.join(root_path, 'config', 'routes.rb')
- end
-
- def default_view_path
- File.join(root_path, 'app', 'views')
- end
-
- def default_controller_paths
- paths = [File.join(root_path, 'app', 'controllers')]
- paths.concat builtin_directories
- paths
- end
-
- def default_dependency_loading
- true
- end
-
- def default_preload_frameworks
- false
- end
-
- def default_cache_classes
- true
- end
-
- def default_whiny_nils
- false
- end
-
- def default_plugins
- nil
- end
-
- def default_plugin_paths
- ["#{root_path}/vendor/plugins"]
- end
-
- def default_plugin_locators
- require 'rails/plugin/locator'
- locators = []
- locators << Plugin::GemLocator if defined? Gem
- locators << Plugin::FileSystemLocator
- end
-
- def default_plugin_loader
- require 'rails/plugin/loader'
- Plugin::Loader
- end
-
- def default_cache_store
- if File.exist?("#{root_path}/tmp/cache/")
- [ :file_store, "#{root_path}/tmp/cache/" ]
- else
- :memory_store
- end
- end
-
- def default_gems
- []
- end
-
- def default_i18n
- i18n = Rails::OrderedOptions.new
- i18n.load_path = []
-
- if File.exist?(File.join(RAILS_ROOT, 'config', 'locales'))
- i18n.load_path << Dir[File.join(RAILS_ROOT, 'config', 'locales', '*.{rb,yml}')]
- i18n.load_path.flatten!
- end
-
- i18n
- end
- end
-end
-
-# Needs to be duplicated from Active Support since its needed before Active
-# Support is available. Here both Options and Hash are namespaced to prevent
-# conflicts with other implementations AND with the classes residing in Active Support.
-class Rails::OrderedOptions < Array #:nodoc:
- def []=(key, value)
- key = key.to_sym
-
- if pair = find_pair(key)
- pair.pop
- pair << value
- else
- self << [key, value]
- end
- end
-
- def [](key)
- pair = find_pair(key.to_sym)
- pair ? pair.last : nil
- end
-
- def method_missing(name, *args)
- if name.to_s =~ /(.*)=$/
- self[$1.to_sym] = args.first
- else
- self[name]
- end
- end
-
- private
- def find_pair(key)
- self.each { |i| return i if i.first == key }
- return false
- end
-end
-
diff --git a/railties/test/application/generators_test.rb b/railties/test/application/generators_test.rb
new file mode 100644
index 0000000000..0d6eb4147a
--- /dev/null
+++ b/railties/test/application/generators_test.rb
@@ -0,0 +1,89 @@
+require "isolation/abstract_unit"
+
+module ApplicationTests
+ class GeneratorsTest < Test::Unit::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ require "rails/generators"
+ build_app
+ boot_rails
+ end
+
+ test "generators default values" do
+ Rails::Initializer.run do |c|
+ assert_equal(true, c.generators.colorize_logging)
+ assert_equal({}, c.generators.aliases)
+ assert_equal({}, c.generators.options)
+ end
+ end
+
+ test "generators set rails options" do
+ Rails::Initializer.run do |c|
+ c.generators.orm = :datamapper
+ c.generators.test_framework = :rspec
+ expected = { :rails => { :orm => :datamapper, :test_framework => :rspec } }
+ assert_equal(expected, c.generators.options)
+ end
+ end
+
+ test "generators set rails aliases" do
+ Rails::Initializer.run do |c|
+ c.generators.aliases = { :rails => { :test_framework => "-w" } }
+ expected = { :rails => { :test_framework => "-w" } }
+ assert_equal expected, c.generators.aliases
+ end
+ end
+
+ test "generators aliases and options on initialization" do
+ Rails::Initializer.run do |c|
+ c.generators.rails :aliases => { :test_framework => "-w" }
+ c.generators.orm :datamapper
+ c.generators.test_framework :rspec
+ end
+
+ assert_equal :rspec, Rails::Generators.options[:rails][:test_framework]
+ assert_equal "-w", Rails::Generators.aliases[:rails][:test_framework]
+ end
+
+ test "generators no color on initialization" do
+ Rails::Initializer.run do |c|
+ c.generators.colorize_logging = false
+ end
+
+ assert_equal Thor::Base.shell, Thor::Shell::Basic
+ end
+
+ test "generators with hashes for options and aliases" do
+ Rails::Initializer.run do |c|
+ c.generators do |g|
+ g.orm :datamapper, :migration => false
+ g.plugin :aliases => { :generator => "-g" },
+ :generator => true
+ end
+
+ expected = {
+ :rails => { :orm => :datamapper },
+ :plugin => { :generator => true },
+ :datamapper => { :migration => false }
+ }
+
+ assert_equal expected, c.generators.options
+ assert_equal({ :plugin => { :generator => "-g" } }, c.generators.aliases)
+ end
+ end
+
+ test "generators with hashes are deep merged" do
+ Rails::Initializer.run do |c|
+ c.generators do |g|
+ g.orm :datamapper, :migration => false
+ g.plugin :aliases => { :generator => "-g" },
+ :generator => true
+ end
+ end
+
+ assert Rails::Generators.aliases.size >= 1
+ assert Rails::Generators.options.size >= 1
+ end
+ end
+end \ No newline at end of file
diff --git a/railties/test/application/initializer_test.rb b/railties/test/application/initializer_test.rb
new file mode 100644
index 0000000000..f46bf2b656
--- /dev/null
+++ b/railties/test/application/initializer_test.rb
@@ -0,0 +1,194 @@
+require "isolation/abstract_unit"
+
+module ApplicationTests
+ class InitializerTest < Test::Unit::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+ boot_rails
+ end
+
+ test "initializing an application initializes rails" do
+ class MyApp < Rails::Application ; end
+
+ if RUBY_VERSION < '1.9'
+ $KCODE = ''
+ MyApp.new
+ assert_equal 'UTF8', $KCODE
+ else
+ Encoding.default_external = Encoding::US_ASCII
+ MyApp.new
+ assert_equal Encoding::UTF_8, Encoding.default_external
+ end
+ end
+
+ test "initializing an application adds the application paths to the load path" do
+ class MyApp < Rails::Application ; end
+
+ MyApp.new
+ assert $:.include?("#{app_path}/app/models")
+ end
+
+ test "adding an unknown framework raises an error" do
+ class MyApp < Rails::Application
+ config.frameworks << :action_foo
+ end
+
+ assert_raises RuntimeError do
+ MyApp.new
+ end
+ end
+
+ test "eager loading loads parent classes before children" do
+ app_file "lib/zoo.rb", <<-ZOO
+ class Zoo ; include ReptileHouse ; end
+ ZOO
+ app_file "lib/zoo/reptile_house.rb", <<-ZOO
+ module Zoo::ReptileHouse ; end
+ ZOO
+
+ Rails::Initializer.run do |config|
+ config.eager_load_paths = "#{app_path}/lib"
+ end
+
+ assert Zoo
+ end
+
+ test "load environment with global" do
+ app_file "config/environments/development.rb", "$initialize_test_set_from_env = 'success'"
+ assert_nil $initialize_test_set_from_env
+ Rails::Initializer.run { }
+ assert_equal "success", $initialize_test_set_from_env
+ end
+
+ test "action_controller load paths set only if action controller in use" do
+ assert_nothing_raised NameError do
+ Rails::Initializer.run do |config|
+ config.frameworks = []
+ end
+ end
+ end
+
+ test "action_pack is added to the load path if action_controller is required" do
+ Rails::Initializer.run do |config|
+ config.frameworks = [:action_controller]
+ end
+
+ assert $:.include?("#{framework_path}/actionpack/lib")
+ end
+
+ test "action_pack is added to the load path if action_view is required" do
+ Rails::Initializer.run do |config|
+ config.frameworks = [:action_view]
+ end
+
+ assert $:.include?("#{framework_path}/actionpack/lib")
+ end
+
+ test "after_initialize block works correctly" do
+ Rails::Initializer.run do |config|
+ config.after_initialize { $test_after_initialize_block1 = "success" }
+ config.after_initialize { $test_after_initialize_block2 = "congratulations" }
+ end
+
+ assert_equal "success", $test_after_initialize_block1
+ assert_equal "congratulations", $test_after_initialize_block2
+ end
+
+ test "after_initialize block works correctly when no block is passed" do
+ Rails::Initializer.run do |config|
+ config.after_initialize { $test_after_initialize_block1 = "success" }
+ config.after_initialize # don't pass a block, this is what we're testing!
+ config.after_initialize { $test_after_initialize_block2 = "congratulations" }
+ end
+
+ assert_equal "success", $test_after_initialize_block1
+ assert_equal "congratulations", $test_after_initialize_block2
+ end
+
+ # i18n
+ test "setting another default locale" do
+ Rails::Initializer.run do |config|
+ config.i18n.default_locale = :de
+ end
+ assert_equal :de, I18n.default_locale
+ end
+
+ test "no config locales dir present should return empty load path" do
+ FileUtils.rm_rf "#{app_path}/config/locales"
+ Rails::Initializer.run do |c|
+ assert_equal [], c.i18n.load_path
+ end
+ end
+
+ test "config locales dir present should be added to load path" do
+ Rails::Initializer.run do |c|
+ assert_equal ["#{app_path}/config/locales/en.yml"], c.i18n.load_path
+ end
+ end
+
+ test "config defaults should be added with config settings" do
+ Rails::Initializer.run do |c|
+ c.i18n.load_path << "my/other/locale.yml"
+ end
+
+ assert_equal [
+ "#{app_path}/config/locales/en.yml", "my/other/locale.yml"
+ ], Rails.application.config.i18n.load_path
+ end
+
+ # DB middleware
+ test "database middleware doesn't initialize when session store is not active_record" do
+ Rails::Initializer.run do |config|
+ config.action_controller.session_store = :cookie_store
+ end
+
+ assert !Rails.application.config.middleware.include?(ActiveRecord::SessionStore)
+ end
+
+ test "database middleware doesn't initialize when activerecord is not in frameworks" do
+ Rails::Initializer.run do |c|
+ c.frameworks = []
+ end
+ assert_equal [], Rails.application.config.middleware
+ end
+
+ test "database middleware initializes when session store is active record" do
+ Rails::Initializer.run do |c|
+ c.action_controller.session_store = :active_record_store
+ end
+
+ expects = [ActiveRecord::ConnectionAdapters::ConnectionManagement, ActiveRecord::QueryCache, ActiveRecord::SessionStore]
+ middleware = Rails.application.config.middleware.map { |m| m.klass }
+ assert_equal expects, middleware & expects
+ end
+
+ test "ensure database middleware doesn't use action_controller on initializing" do
+ Rails::Initializer.run do |c|
+ c.frameworks -= [:action_controller]
+ c.action_controller.session_store = :active_record_store
+ end
+
+ assert !Rails.application.config.middleware.include?(ActiveRecord::SessionStore)
+ end
+
+ # Pathview test
+ test "load view paths doesn't perform anything when action_view not in frameworks" do
+ Rails::Initializer.run do |c|
+ c.frameworks -= [:action_view]
+ end
+ assert_equal nil, ActionMailer::Base.template_root
+ assert_equal [], ActionController::Base.view_paths
+ end
+
+ # Rails root test
+ test "Rails.root == RAILS_ROOT" do
+ assert_equal RAILS_ROOT, Rails.root.to_s
+ end
+
+ test "Rails.root should be a Pathname" do
+ assert_instance_of Pathname, Rails.root
+ end
+ end
+end \ No newline at end of file
diff --git a/railties/test/application/load_test.rb b/railties/test/application/load_test.rb
index 305cd7f273..5c3d35fb16 100644
--- a/railties/test/application/load_test.rb
+++ b/railties/test/application/load_test.rb
@@ -40,14 +40,14 @@ module ApplicationTests
test "Rails.application is available after config.ru has been racked up" do
rackup
- assert Rails.application.new.is_a?(Rails::Application)
+ assert Rails.application.new < Rails::Application
end
# Passenger still uses AC::Dispatcher, so we need to
# keep it working for now
test "deprecated ActionController::Dispatcher still works" do
rackup
- assert ActionController::Dispatcher.new.is_a?(Rails::Application)
+ assert ActionController::Dispatcher.new < Rails::Application
end
test "the config object is available on the application object" do
diff --git a/railties/test/application/plugins_test.rb b/railties/test/application/plugins_test.rb
new file mode 100644
index 0000000000..81e7f4d88c
--- /dev/null
+++ b/railties/test/application/plugins_test.rb
@@ -0,0 +1,101 @@
+require "isolation/abstract_unit"
+
+module ApplicationTests
+ class PluginTest < Test::Unit::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def assert_plugins(list_of_names, array_of_plugins, message=nil)
+ assert_equal list_of_names.map { |n| n.to_s }, array_of_plugins.map { |p| p.name }, message
+ end
+
+ def setup
+ build_app
+ boot_rails
+ @failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
+ # Tmp hax to get tests working
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../fixtures/plugins", "#{app_path}/vendor"
+ end
+
+ test "all plugins are loaded when registered plugin list is untouched" do
+ Rails::Initializer.run { }
+ assert_plugins [
+ :a, :acts_as_chunky_bacon, :engine, :gemlike, :plugin_with_no_lib_dir, :stubby
+ ], Rails.application.config.loaded_plugins, @failure_tip
+ end
+
+ test "no plugins are loaded if the configuration has an empty plugin list" do
+ Rails::Initializer.run { |c| c.plugins = [] }
+ assert_plugins [], Rails.application.config.loaded_plugins
+ end
+
+ test "only the specified plugins are located in the order listed" do
+ plugin_names = [:plugin_with_no_lib_dir, :acts_as_chunky_bacon]
+ Rails::Initializer.run { |c| c.plugins = plugin_names }
+ assert_plugins plugin_names, Rails.application.config.loaded_plugins
+ end
+
+ test "all plugins loaded after all" do
+ Rails::Initializer.run do |config|
+ config.plugins = [:stubby, :all, :acts_as_chunky_bacon]
+ end
+ assert_plugins [:stubby, :a, :engine, :gemlike, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], Rails.application.config.loaded_plugins, @failure_tip
+ end
+
+ test "plugin names may be strings" do
+ plugin_names = ['stubby', 'acts_as_chunky_bacon', :a, :plugin_with_no_lib_dir]
+ Rails::Initializer.run do |config|
+ config.plugins = ['stubby', 'acts_as_chunky_bacon', :a, :plugin_with_no_lib_dir]
+ end
+
+ assert_plugins plugin_names, Rails.application.config.loaded_plugins, @failure_tip
+ end
+
+ test "all plugins loaded when all is used" do
+ Rails::Initializer.run do |config|
+ config.plugins = [:stubby, :acts_as_chunky_bacon, :all]
+ end
+
+ assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :engine, :gemlike, :plugin_with_no_lib_dir], Rails.application.config.loaded_plugins, @failure_tip
+ end
+
+ test "all loaded plugins are added to the load paths" do
+ Rails::Initializer.run do |config|
+ config.plugins = [:stubby, :acts_as_chunky_bacon]
+ end
+
+ assert $LOAD_PATH.include?("#{app_path}/vendor/plugins/default/stubby/lib")
+ assert $LOAD_PATH.include?("#{app_path}/vendor/plugins/default/acts/acts_as_chunky_bacon/lib")
+ end
+
+ test "registering a plugin name that does not exist raises a load error" do
+ assert_raise(LoadError) do
+ Rails::Initializer.run do |config|
+ config.plugins = [:stubby, :acts_as_a_non_existant_plugin]
+ end
+ end
+ end
+
+ test "load error messages mention missing plugins and no others" do
+ valid_plugins = [:stubby, :acts_as_chunky_bacon]
+ invalid_plugins = [:non_existant_plugin1, :non_existant_plugin2]
+
+ begin
+ Rails::Initializer.run do |config|
+ config.plugins = [:stubby, :acts_as_chunky_bacon, :non_existant_plugin1, :non_existant_plugin2]
+ end
+ flunk "Expected a LoadError but did not get one"
+ rescue LoadError => e
+ assert_plugins valid_plugins, Rails.application.config.loaded_plugins, @failure_tip
+
+ invalid_plugins.each do |plugin|
+ assert_match(/#{plugin.to_s}/, e.message, "LoadError message should mention plugin '#{plugin}'")
+ end
+
+ valid_plugins.each do |plugin|
+ assert_no_match(/#{plugin.to_s}/, e.message, "LoadError message should not mention '#{plugin}'")
+ end
+ end
+ end
+
+ end
+end \ No newline at end of file
diff --git a/railties/test/initializable_test.rb b/railties/test/initializable_test.rb
new file mode 100644
index 0000000000..7c8aed00c9
--- /dev/null
+++ b/railties/test/initializable_test.rb
@@ -0,0 +1,68 @@
+require 'abstract_unit'
+require 'rails/initializable'
+
+module InitializableTests
+
+ class Foo
+ extend Rails::Initializable
+
+ class << self
+ attr_accessor :foo, :bar
+ end
+
+ initializer :omg do
+ @foo ||= 0
+ @foo += 1
+ end
+ end
+
+ class Bar < Foo
+ initializer :bar do
+ @bar ||= 0
+ @bar += 1
+ end
+ end
+
+ module Word
+ extend Rails::Initializable
+
+ initializer :word do
+ $word = "bird"
+ end
+ end
+
+ class Basic < ActiveSupport::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ test "initializers run" do
+ Foo.initializers.run
+ assert_equal 1, Foo.foo
+ end
+
+ test "initializers are inherited" do
+ Bar.initializers.run
+ assert_equal [1, 1], [Bar.foo, Bar.bar]
+ end
+
+ test "initializers only get run once" do
+ Foo.initializers.run
+ Foo.initializers.run
+ assert_equal 1, Foo.foo
+ end
+
+ test "running initializers on children does not effect the parent" do
+ Bar.initializers.run
+ assert_nil Foo.foo
+ assert_nil Foo.bar
+ end
+
+ test "inherited initializers are the same objects" do
+ assert Foo.initializers[:foo].eql?(Bar.initializers[:foo])
+ end
+
+ test "initializing with modules" do
+ Word.initializers.run
+ assert_equal "bird", $word
+ end
+ end
+end \ No newline at end of file
diff --git a/railties/test/initializer/initialize_i18n_test.rb b/railties/test/initializer/initialize_i18n_test.rb
new file mode 100644
index 0000000000..e909688817
--- /dev/null
+++ b/railties/test/initializer/initialize_i18n_test.rb
@@ -0,0 +1,51 @@
+require "isolation/abstract_unit"
+
+module InitializerTests
+ class InitializeI18nTest < Test::Unit::TestCase
+ include ActiveSupport::Testing::Isolation
+
+ def setup
+ build_app
+ boot_rails
+ end
+
+ # test_config_defaults_and_settings_should_be_added_to_i18n_defaults
+ test "i18n config defaults and settings should be added to i18n defaults" do
+ Rails::Initializer.run do |c|
+ c.i18n.load_path << "my/other/locale.yml"
+ end
+
+ #{RAILS_FRAMEWORK_ROOT}/railties/test/fixtures/plugins/engines/engine/config/locales/en.yml
+ assert_equal %W(
+ #{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/locale/en.yml
+ #{RAILS_FRAMEWORK_ROOT}/activemodel/lib/active_model/locale/en.yml
+ #{RAILS_FRAMEWORK_ROOT}/activerecord/lib/active_record/locale/en.yml
+ #{RAILS_FRAMEWORK_ROOT}/actionpack/lib/action_view/locale/en.yml
+ #{RAILS_FRAMEWORK_ROOT}/railties/tmp/app/config/locales/en.yml
+ my/other/locale.yml
+ ), I18n.load_path
+ end
+
+ test "i18n finds locale files in engines" do
+ app_file "vendor/plugins/engine/init.rb", ""
+ app_file "vendor/plugins/engine/app/models/hellos.rb", "class Hello ; end"
+ app_file "vendor/plugins/engine/lib/omg.rb", "puts 'omg'"
+ app_file "vendor/plugins/engine/config/locales/en.yml", "hello:"
+
+ Rails::Initializer.run do |c|
+ c.i18n.load_path << "my/other/locale.yml"
+ end
+
+ #{RAILS_FRAMEWORK_ROOT}/railties/test/fixtures/plugins/engines/engine/config/locales/en.yml
+ assert_equal %W(
+ #{RAILS_FRAMEWORK_ROOT}/activesupport/lib/active_support/locale/en.yml
+ #{RAILS_FRAMEWORK_ROOT}/activemodel/lib/active_model/locale/en.yml
+ #{RAILS_FRAMEWORK_ROOT}/activerecord/lib/active_record/locale/en.yml
+ #{RAILS_FRAMEWORK_ROOT}/actionpack/lib/action_view/locale/en.yml
+ #{app_path}/config/locales/en.yml
+ my/other/locale.yml
+ #{app_path}/vendor/plugins/engine/config/locales/en.yml
+ ), I18n.load_path
+ end
+ end
+end \ No newline at end of file
diff --git a/railties/test/initializer/path_test.rb b/railties/test/initializer/path_test.rb
index a4264bc31c..72ff8d88e0 100644
--- a/railties/test/initializer/path_test.rb
+++ b/railties/test/initializer/path_test.rb
@@ -12,7 +12,7 @@ class PathsTest < Test::Unit::TestCase
ActionController::Base.session_store = nil
end
end
- @paths = Rails::Initializer.default.config.paths
+ @paths = Rails.application.config.paths
end
def root(*path)
diff --git a/railties/test/initializer_test.rb b/railties/test/initializer_test.rb
index b67db9c835..80e774b7b7 100644
--- a/railties/test/initializer_test.rb
+++ b/railties/test/initializer_test.rb
@@ -6,490 +6,8 @@ require 'action_view'
require 'action_mailer'
require 'active_record'
-# Mocks out the configuration
-module Rails
- def self.configuration
- Rails::Configuration.new
- end
-
- module Generators
- def self.clear_aliases!
- @aliases = nil
- end
-
- def self.clear_options!
- @@options = nil
- end
- end
-end
-
-
-class ConfigurationMock < Rails::Configuration
- attr_reader :environment_path
-
- def initialize(envpath)
- super()
- @environment_path = envpath
- end
-end
-
-class Initializer_load_environment_Test < Test::Unit::TestCase
- def test_load_environment_with_constant
- config = ConfigurationMock.new("#{File.dirname(__FILE__)}/fixtures/environment_with_constant.rb")
- assert_nil $initialize_test_set_from_env
- Rails::Initializer.run(:load_environment, config)
- assert_equal "success", $initialize_test_set_from_env
- ensure
- $initialize_test_set_from_env = nil
- end
-end
-
-class Initializer_eager_loading_Test < Test::Unit::TestCase
- def setup
- @config = ConfigurationMock.new("")
- @config.cache_classes = true
- @config.load_paths = [File.expand_path(File.dirname(__FILE__) + "/fixtures/eager")]
- @config.eager_load_paths = [File.expand_path(File.dirname(__FILE__) + "/fixtures/eager")]
- @initializer = Rails::Initializer.default
- @initializer.config = @config
- @initializer.run(:set_load_path)
- @initializer.run(:set_autoload_paths)
- end
-
- def test_eager_loading_loads_parent_classes_before_children
- assert_nothing_raised do
- @initializer.run(:load_application_classes)
- end
- end
-end
-
-class Initializer_after_initialize_with_blocks_environment_Test < Test::Unit::TestCase
- def setup
- config = ConfigurationMock.new("")
- config.after_initialize do
- $test_after_initialize_block1 = "success"
- end
- config.after_initialize do
- $test_after_initialize_block2 = "congratulations"
- end
- assert_nil $test_after_initialize_block1
- assert_nil $test_after_initialize_block2
-
- config.expects(:gems_dependencies_loaded).returns(true)
- Rails::Initializer.run(:after_initialize, config)
- end
-
- def teardown
- $test_after_initialize_block1 = nil
- $test_after_initialize_block2 = nil
- end
-
- def test_should_have_called_the_first_after_initialize_block
- assert_equal "success", $test_after_initialize_block1
- end
-
- def test_should_have_called_the_second_after_initialize_block
- assert_equal "congratulations", $test_after_initialize_block2
- end
-end
-
-class Initializer_after_initialize_with_no_block_environment_Test < Test::Unit::TestCase
- def setup
- config = ConfigurationMock.new("")
- config.after_initialize do
- $test_after_initialize_block1 = "success"
- end
- config.after_initialize # don't pass a block, this is what we're testing!
- config.after_initialize do
- $test_after_initialize_block2 = "congratulations"
- end
- assert_nil $test_after_initialize_block1
-
- config.expects(:gems_dependencies_loaded).returns(true)
- Rails::Initializer.run(:after_initialize, config)
- end
-
- def teardown
- $test_after_initialize_block1 = nil
- $test_after_initialize_block2 = nil
- end
-
- def test_should_have_called_the_first_after_initialize_block
- assert_equal "success", $test_after_initialize_block1, "should still get set"
- end
-
- def test_should_have_called_the_second_after_initialize_block
- assert_equal "congratulations", $test_after_initialize_block2
- end
-end
-
-class ConfigurationFrameworkPathsTests < Test::Unit::TestCase
- def setup
- @config = Rails::Configuration.new
- @config.frameworks.clear
- @initializer = Rails::Initializer.default
- @initializer.config = @config
-
- File.stubs(:directory?).returns(true)
- Rails::Initializer.run(:set_root_path, @config)
- end
-
- def test_minimal
- expected = %w(railties railties/lib activesupport/lib)
- assert_equal expected.map {|e| "#{@config.framework_root_path}/#{e}"}, @config.framework_paths
- end
-
- def test_actioncontroller_or_actionview_add_actionpack
- @config.frameworks << :action_controller
- assert_framework_path "actionpack/lib"
-
- @config.frameworks = [:action_view]
- assert_framework_path 'actionpack/lib'
- end
-
- def test_paths_for_ar_ares_and_mailer
- [:active_record, :action_mailer, :active_resource, :action_web_service].each do |framework|
- @config.frameworks = [framework]
- assert_framework_path "#{framework.to_s.gsub('_', '')}/lib"
- end
- end
-
- def test_unknown_framework_raises_error
- @config.frameworks << :action_foo
-
- Class.any_instance.expects(:require).raises(LoadError)
-
- assert_raise RuntimeError do
- @initializer.run(:require_frameworks)
- end
- end
-
- def test_action_mailer_load_paths_set_only_if_action_mailer_in_use
- @config.frameworks = [:action_controller]
- @initializer.config = @config
- @initializer.run :require_frameworks
-
- assert_nothing_raised NameError do
- @initializer.run :load_view_paths
- end
- end
-
- def test_action_controller_load_paths_set_only_if_action_controller_in_use
- @config.frameworks = []
- @initializer.run :require_frameworks
-
- assert_nothing_raised NameError do
- @initializer.run :load_view_paths
- end
- end
-
- protected
- def assert_framework_path(path)
- assert @config.framework_paths.include?("#{@config.framework_root_path}/#{path}"),
- "<#{path.inspect}> not found among <#{@config.framework_paths.inspect}>"
- end
-end
-
require 'plugin_test_helper'
-class InitializerPluginLoadingTests < Test::Unit::TestCase
- def setup
- @configuration = Rails::Configuration.new
- @configuration.frameworks -= [:action_mailer]
- @configuration.plugin_paths << plugin_fixture_root_path
- @initializer = Rails::Initializer.default
- @initializer.config = @configuration
- @valid_plugin_path = plugin_fixture_path('default/stubby')
- @empty_plugin_path = plugin_fixture_path('default/empty')
- end
-
- def test_no_plugins_are_loaded_if_the_configuration_has_an_empty_plugin_list
- only_load_the_following_plugins! []
- @initializer.run :load_plugins
- assert_equal [], @configuration.loaded_plugins
- end
-
- def test_only_the_specified_plugins_are_located_in_the_order_listed
- plugin_names = [:plugin_with_no_lib_dir, :acts_as_chunky_bacon]
- only_load_the_following_plugins! plugin_names
- load_plugins!
- assert_plugins plugin_names, @configuration.loaded_plugins
- end
-
- def test_all_plugins_are_loaded_when_registered_plugin_list_is_untouched
- failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
- load_plugins!
- assert_plugins [:a, :acts_as_chunky_bacon, :engine, :gemlike, :plugin_with_no_lib_dir, :stubby], @configuration.loaded_plugins, failure_tip
- end
-
- def test_all_plugins_loaded_when_all_is_used
- plugin_names = [:stubby, :acts_as_chunky_bacon, :all]
- only_load_the_following_plugins! plugin_names
- load_plugins!
- failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
- assert_plugins [:stubby, :acts_as_chunky_bacon, :a, :engine, :gemlike, :plugin_with_no_lib_dir], @configuration.loaded_plugins, failure_tip
- end
-
- def test_all_plugins_loaded_after_all
- plugin_names = [:stubby, :all, :acts_as_chunky_bacon]
- only_load_the_following_plugins! plugin_names
- load_plugins!
- failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
- assert_plugins [:stubby, :a, :engine, :gemlike, :plugin_with_no_lib_dir, :acts_as_chunky_bacon], @configuration.loaded_plugins, failure_tip
- end
-
- def test_plugin_names_may_be_strings
- plugin_names = ['stubby', 'acts_as_chunky_bacon', :a, :plugin_with_no_lib_dir]
- only_load_the_following_plugins! plugin_names
- load_plugins!
- failure_tip = "It's likely someone has added a new plugin fixture without updating this list"
- assert_plugins plugin_names, @configuration.loaded_plugins, failure_tip
- end
-
- def test_registering_a_plugin_name_that_does_not_exist_raises_a_load_error
- only_load_the_following_plugins! [:stubby, :acts_as_a_non_existant_plugin]
- assert_raise(LoadError) do
- load_plugins!
- end
- end
-
- def test_load_error_messages_mention_missing_plugins_and_no_others
- valid_plugin_names = [:stubby, :acts_as_chunky_bacon]
- invalid_plugin_names = [:non_existant_plugin1, :non_existant_plugin2]
- only_load_the_following_plugins!( valid_plugin_names + invalid_plugin_names )
- begin
- load_plugins!
- flunk "Expected a LoadError but did not get one"
- rescue LoadError => e
- failure_tip = "It's likely someone renamed or deleted plugin fixtures without updating this test"
- assert_plugins valid_plugin_names, @configuration.loaded_plugins, failure_tip
- invalid_plugin_names.each do |plugin|
- assert_match(/#{plugin.to_s}/, e.message, "LoadError message should mention plugin '#{plugin}'")
- end
- valid_plugin_names.each do |plugin|
- assert_no_match(/#{plugin.to_s}/, e.message, "LoadError message should not mention '#{plugin}'")
- end
-
- end
- end
-
- def test_should_ensure_all_loaded_plugins_load_paths_are_added_to_the_load_path
- only_load_the_following_plugins! [:stubby, :acts_as_chunky_bacon]
-
- @initializer.run(:add_plugin_load_paths)
-
- assert $LOAD_PATH.include?(File.join(plugin_fixture_path('default/stubby'), 'lib'))
- assert $LOAD_PATH.include?(File.join(plugin_fixture_path('default/acts/acts_as_chunky_bacon'), 'lib'))
- end
-
- private
-
- def load_plugins!
- @initializer.run(:add_plugin_load_paths)
- @initializer.run(:load_plugins)
- end
-end
-
-class InitializerGeneratorsTests < Test::Unit::TestCase
-
- def setup
- @configuration = Rails::Configuration.new
- @initializer = Rails::Initializer.default
- @initializer.config = @configuration
- end
-
- def test_generators_default_values
- assert_equal(true, @configuration.generators.colorize_logging)
- assert_equal({}, @configuration.generators.aliases)
- assert_equal({}, @configuration.generators.options)
- end
-
- def test_generators_set_rails_options
- @configuration.generators.orm = :datamapper
- @configuration.generators.test_framework = :rspec
- expected = { :rails => { :orm => :datamapper, :test_framework => :rspec } }
- assert_equal expected, @configuration.generators.options
- end
-
- def test_generators_set_rails_aliases
- @configuration.generators.aliases = { :rails => { :test_framework => "-w" } }
- expected = { :rails => { :test_framework => "-w" } }
- assert_equal expected, @configuration.generators.aliases
- end
-
- def test_generators_aliases_and_options_on_initialization
- @configuration.generators.rails :aliases => { :test_framework => "-w" }
- @configuration.generators.orm :datamapper
- @configuration.generators.test_framework :rspec
-
- @initializer.run(:initialize_generators)
-
- assert_equal :rspec, Rails::Generators.options[:rails][:test_framework]
- assert_equal "-w", Rails::Generators.aliases[:rails][:test_framework]
- end
-
- def test_generators_no_color_on_initialization
- @configuration.generators.colorize_logging = false
- @initializer.run(:initialize_generators)
- assert_equal Thor::Base.shell, Thor::Shell::Basic
- end
-
- def test_generators_with_hashes_for_options_and_aliases
- @configuration.generators do |g|
- g.orm :datamapper, :migration => false
- g.plugin :aliases => { :generator => "-g" },
- :generator => true
- end
-
- expected = {
- :rails => { :orm => :datamapper },
- :plugin => { :generator => true },
- :datamapper => { :migration => false }
- }
-
- assert_equal expected, @configuration.generators.options
- assert_equal({ :plugin => { :generator => "-g" } }, @configuration.generators.aliases)
- end
-
- def test_generators_with_hashes_are_deep_merged
- @configuration.generators do |g|
- g.orm :datamapper, :migration => false
- g.plugin :aliases => { :generator => "-g" },
- :generator => true
- end
- @initializer.run(:initialize_generators)
-
- assert Rails::Generators.aliases.size >= 1
- assert Rails::Generators.options.size >= 1
- end
-
- protected
-
- def teardown
- Rails::Generators.clear_aliases!
- Rails::Generators.clear_options!
- end
-end
-
-class InitializerSetupI18nTests < Test::Unit::TestCase
- def test_no_config_locales_dir_present_should_return_empty_load_path
- File.stubs(:exist?).returns(false)
- assert_equal [], Rails::Configuration.new.i18n.load_path
- end
-
- def test_config_locales_dir_present_should_be_added_to_load_path
- File.stubs(:exist?).returns(true)
- Dir.stubs(:[]).returns([ "my/test/locale.yml" ])
- assert_equal [ "my/test/locale.yml" ], Rails::Configuration.new.i18n.load_path
- end
-
- def test_config_defaults_should_be_added_with_config_settings
- File.stubs(:exist?).returns(true)
- Dir.stubs(:[]).returns([ "my/test/locale.yml" ])
-
- config = Rails::Configuration.new
- config.i18n.load_path << "my/other/locale.yml"
-
- assert_equal [ "my/test/locale.yml", "my/other/locale.yml" ], config.i18n.load_path
- end
-
- def test_config_defaults_and_settings_should_be_added_to_i18n_defaults
- File.stubs(:exist?).returns(true)
- Dir.stubs(:[]).returns([ "my/test/locale.yml" ])
-
- config = Rails::Configuration.new
- config.i18n.load_path << "my/other/locale.yml"
-
- Rails::Initializer.run(:initialize_i18n, config)
- assert_equal [
- File.expand_path(File.dirname(__FILE__) + "/../../activesupport/lib/active_support/locale/en.yml"),
- File.expand_path(File.dirname(__FILE__) + "/../../actionpack/lib/action_view/locale/en.yml"),
- File.expand_path(File.dirname(__FILE__) + "/../../activemodel/lib/active_model/locale/en.yml"),
- File.expand_path(File.dirname(__FILE__) + "/../../activerecord/lib/active_record/locale/en.yml"),
- File.expand_path(File.dirname(__FILE__) + "/../../railties/test/fixtures/plugins/engines/engine/config/locales/en.yml"),
- "my/test/locale.yml",
- "my/other/locale.yml" ], I18n.load_path.collect { |path| path =~ /\.\./ ? File.expand_path(path) : path }
- end
-
- def test_setting_another_default_locale
- config = Rails::Configuration.new
- config.i18n.default_locale = :de
- Rails::Initializer.run(:initialize_i18n, config)
- assert_equal :de, I18n.default_locale
- end
-end
-
-class InitializerDatabaseMiddlewareTest < Test::Unit::TestCase
- def setup
- @config = Rails::Configuration.new
- @config.frameworks = [:active_record, :action_controller, :action_view]
- end
-
- def test_initialize_database_middleware_doesnt_perform_anything_when_active_record_not_in_frameworks
- @config.frameworks.clear
- @config.expects(:middleware).never
- Rails::Initializer.run(:initialize_database_middleware, @config)
- end
-
- def test_database_middleware_initializes_when_session_store_is_active_record
- store = ActionController::Base.session_store
- ActionController::Base.session_store = ActiveRecord::SessionStore
-
- @config.middleware.expects(:insert_before).with(:"ActiveRecord::SessionStore", ActiveRecord::ConnectionAdapters::ConnectionManagement)
- @config.middleware.expects(:insert_before).with(:"ActiveRecord::SessionStore", ActiveRecord::QueryCache)
-
- Rails::Initializer.run(:initialize_database_middleware, @config)
- ensure
- ActionController::Base.session_store = store
- end
-
- def test_database_middleware_doesnt_initialize_when_session_store_is_not_active_record
- store = ActionController::Base.session_store
- ActionController::Base.session_store = ActionDispatch::Session::CookieStore
-
- # Define the class, so we don't have to actually make it load
- eval("class ActiveRecord::ConnectionAdapters::ConnectionManagement; end")
-
- @config.middleware.expects(:use).with(ActiveRecord::ConnectionAdapters::ConnectionManagement)
- @config.middleware.expects(:use).with(ActiveRecord::QueryCache)
-
- Rails::Initializer.run(:initialize_database_middleware, @config)
- ensure
- ActionController::Base.session_store = store
- end
-
- def test_ensure_database_middleware_doesnt_use_action_controller_on_initializing
- @config.frameworks -= [:action_controller]
- store = ActionController::Base.session_store
- ActionController::Base.session_store = ActiveRecord::SessionStore
-
- @config.middleware.expects(:use).with(ActiveRecord::ConnectionAdapters::ConnectionManagement)
- @config.middleware.expects(:use).with(ActiveRecord::QueryCache)
-
- Rails::Initializer.run(:initialize_database_middleware, @config)
- ensure
- ActionController::Base.session_store = store
- @config.frameworks += [:action_controller]
- end
-end
-
-class InitializerViewPathsTest < Test::Unit::TestCase
- def setup
- @config = Rails::Configuration.new
- @config.frameworks = [:action_view, :action_controller, :action_mailer]
-
- ActionController::Base.stubs(:view_paths).returns(stub)
- ActionMailer::Base.stubs(:view_paths).returns(stub)
- end
-
- def test_load_view_paths_doesnt_perform_anything_when_action_view_not_in_frameworks
- @config.frameworks -= [:action_view]
- ActionController::Base.view_paths.expects(:load!).never
- ActionMailer::Base.view_paths.expects(:load!).never
- Rails::Initializer.run(:load_view_paths, @config)
- end
-end
-
class RailsRootTest < Test::Unit::TestCase
def test_rails_dot_root_equals_rails_root
assert_equal RAILS_ROOT, Rails.root.to_s
diff --git a/railties/test/isolation/abstract_unit.rb b/railties/test/isolation/abstract_unit.rb
index a55ee6c01d..f83e0151a4 100644
--- a/railties/test/isolation/abstract_unit.rb
+++ b/railties/test/isolation/abstract_unit.rb
@@ -7,6 +7,8 @@
# It is also good to know what is the bare minimum to get
# Rails booted up.
+require 'fileutils'
+
# TODO: Remove rubygems when possible
require 'rubygems'
require 'test/unit'
@@ -31,6 +33,10 @@ module TestHelpers
tmp_path(*%w[app] + args)
end
+ def framework_path
+ RAILS_FRAMEWORK_ROOT
+ end
+
def rails_root
app_path
end
@@ -91,7 +97,8 @@ module TestHelpers
end
def app_file(path, contents)
- File.open(app_path(path), 'w') do |f|
+ FileUtils.mkdir_p File.dirname("#{app_path}/#{path}")
+ File.open("#{app_path}/#{path}", 'w') do |f|
f.puts contents
end
end
diff --git a/railties/test/new_initializer_test.rb b/railties/test/new_initializer_test.rb
deleted file mode 100644
index 67b66fb088..0000000000
--- a/railties/test/new_initializer_test.rb
+++ /dev/null
@@ -1,165 +0,0 @@
-require 'abstract_unit'
-require 'active_support/ruby/shim'
-require 'rails/initializer'
-
-class InitializerRunnerTest < ActiveSupport::TestCase
-
- def setup
- @runner = Rails::Initializer::Runner.new
- end
-
- test "A new runner can be created" do
- assert @runner
- end
-
- test "The initializers actually get run when the runner is run" do
- state = nil
-
- @runner.add :foo do
- run { state = true }
- end
-
- @runner.run
- assert state
- end
-
- test "By default, initializers get run in the order that they are added" do
- state = []
-
- @runner.add :first do
- run { state << :first }
- end
-
- @runner.add :second do
- run { state << :second }
- end
-
- @runner.run
- assert_equal [:first, :second], state
- end
-
- test "Raises an exception if :before or :after are specified, but don't exist" do
- assert_raise(Rails::Initializer::Error) do
- @runner.add(:fail, :before => :whale) { 1 }
- end
-
- assert_raise(Rails::Initializer::Error) do
- @runner.add(:fail, :after => :whale) { 1 }
- end
- end
-
- test "When adding an initializer, specifying :after allows you to move an initializer after another" do
- state = []
-
- @runner.add :first do
- run { state << :first }
- end
-
- @runner.add :second do
- run { state << :second }
- end
-
- @runner.add :third, :after => :first do
- run { state << :third }
- end
-
- @runner.run
- assert_equal [:first, :third, :second], state
- end
-
- test "An initializer can be deleted" do
- state = []
-
- @runner.add :first do
- run { state << :first }
- end
-
- @runner.add :second do
- run { state << :second }
- end
-
- @runner.delete(:second)
-
- @runner.run
- assert_equal [:first], state
- end
-
- test "A runner can be initialized with an existing runner, which it copies" do
- state = []
-
- @runner.add :first do
- run { state << :first }
- end
-
- @runner.add :second do
- run { state << :second }
- end
-
- Rails::Initializer::Runner.new(@runner).run
- assert_equal [:first, :second], state
- end
-
- test "A child runner can be still be modified without modifying the parent" do
- state = []
-
- @runner.add :first do
- run { state << :first }
- end
-
- @runner.add :second do
- run { state << :second }
- end
-
- new_runner = Rails::Initializer::Runner.new(@runner)
- new_runner.add :trois do
- run { state << :trois }
- end
- new_runner.delete(:second)
-
- new_runner.run
- assert_equal [:first, :trois], state
- state.clear
- @runner.run
- assert_equal [:first, :second], state
- end
-
- test "A child runner that is modified does not modify any other children of the same parent" do
- state = []
-
- @runner.add :first do
- run { state << :first }
- end
-
- @runner.add :second do
- run { state << :second }
- end
-
- child_one = Rails::Initializer::Runner.new(@runner)
- child_two = Rails::Initializer::Runner.new(@runner)
-
- child_one.delete(:second)
- child_two.run
-
- assert_equal [:first, :second], state
- end
-
- test "It does not run the initializer block immediately" do
- state = []
- @runner.add :first do
- state << :first
- end
-
- assert_equal [], state
- end
-
- test "It runs the block when the runner is run" do
- state = []
- @runner.add :first do
- state << :first
- end
-
- @runner.run
- assert_equal [:first], state
- end
-
-end \ No newline at end of file
diff --git a/railties/test/plugin_loader_test.rb b/railties/test/plugin_loader_test.rb
index 99301347b6..0b43c49bb2 100644
--- a/railties/test/plugin_loader_test.rb
+++ b/railties/test/plugin_loader_test.rb
@@ -5,10 +5,13 @@ $:.unshift File.dirname(__FILE__) + "/../../actionmailer/lib"
require 'action_controller'
require 'action_mailer'
-# Mocks out the configuration
-module Rails
- def self.configuration
- Rails::Configuration.new
+# TODO: Rewrite all these tests
+class FakeInitializerSlashApplication
+ attr_reader :config
+ alias configuration config
+
+ def initialize
+ @config = Rails::Configuration.new
end
end
@@ -18,10 +21,10 @@ class TestPluginLoader < Test::Unit::TestCase
def setup
reset_load_path!
- @configuration = Rails::Configuration.new
+ @initializer = FakeInitializerSlashApplication.new
+ @configuration = @initializer.config
+ Rails.application = @initializer
@configuration.plugin_paths << plugin_fixture_root_path
- @initializer = Rails::Initializer.default
- @initializer.config = @configuration
@valid_plugin_path = plugin_fixture_path('default/stubby')
@empty_plugin_path = plugin_fixture_path('default/empty')
diff --git a/railties/test/plugin_locator_test.rb b/railties/test/plugin_locator_test.rb
index da1548dee1..ef57e7ed4c 100644
--- a/railties/test/plugin_locator_test.rb
+++ b/railties/test/plugin_locator_test.rb
@@ -1,5 +1,15 @@
require 'plugin_test_helper'
+# TODO: Rewrite all these tests
+class FakeInitializerSlashApplication
+ attr_reader :config
+ alias configuration config
+
+ def initialize
+ @config = Rails::Configuration.new
+ end
+end
+
class PluginLocatorTest < Test::Unit::TestCase
def test_should_require_subclasses_to_implement_the_plugins_method
assert_raise(RuntimeError) do
@@ -23,12 +33,12 @@ end
class PluginFileSystemLocatorTest < Test::Unit::TestCase
def setup
- @configuration = Rails::Configuration.new
+ @initializer = FakeInitializerSlashApplication.new
+ @configuration = @initializer.config
+ Rails.application = @initializer
# We need to add our testing plugin directory to the plugin paths so
# the locator knows where to look for our plugins
@configuration.plugin_paths << plugin_fixture_root_path
- @initializer = Rails::Initializer.default
- @initializer.config = @configuration
@locator = Rails::Plugin::FileSystemLocator.new(@initializer)
@valid_plugin_path = plugin_fixture_path('default/stubby')
@empty_plugin_path = plugin_fixture_path('default/empty')
diff --git a/railties/test/plugin_test.rb b/railties/test/plugin_test.rb
index ae03ea4662..199adcfe39 100644
--- a/railties/test/plugin_test.rb
+++ b/railties/test/plugin_test.rb
@@ -1,9 +1,20 @@
require 'plugin_test_helper'
+# TODO: Rewrite all these tests
+class FakeInitializerSlashApplication
+ attr_reader :config
+ alias configuration config
+
+ def initialize
+ @config = Rails::Configuration.new
+ end
+end
+
class PluginTest < Test::Unit::TestCase
def setup
- @initializer = Rails::Initializer.default
- @initializer.config = Rails::Configuration.new
+ @initializer = FakeInitializerSlashApplication.new
+ @configuration = @initializer.config
+ Rails.application = @initializer
@valid_plugin_path = plugin_fixture_path('default/stubby')
@empty_plugin_path = plugin_fixture_path('default/empty')
@gemlike_plugin_path = plugin_fixture_path('default/gemlike')