aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG2
-rw-r--r--actionpack/lib/action_dispatch.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/callbacks.rb31
-rw-r--r--actionpack/lib/action_dispatch/middleware/reloader.rb65
-rw-r--r--actionpack/lib/action_dispatch/routing/polymorphic_routes.rb8
-rw-r--r--actionpack/lib/action_view/base.rb8
-rw-r--r--actionpack/lib/action_view/helpers/number_helper.rb5
-rw-r--r--actionpack/lib/action_view/railtie.rb10
-rw-r--r--actionpack/lib/action_view/template/resolver.rb11
-rw-r--r--actionpack/test/activerecord/render_partial_with_record_identification_test.rb6
-rw-r--r--actionpack/test/dispatch/callbacks_test.rb72
-rw-r--r--actionpack/test/dispatch/reloader_test.rb124
-rw-r--r--actionpack/test/template/number_helper_test.rb5
13 files changed, 250 insertions, 98 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG
index acd9bd5b63..93b29bcc3a 100644
--- a/actionpack/CHANGELOG
+++ b/actionpack/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.1.0 (unreleased)*
+* brought back config.action_view.cache_template_loading, which allows to decide whether templates should be cached or not [Piotr Sarnacki]
+
* url_for and named url helpers now accept :subdomain and :domain as options [Josh Kalderimis]
* The redirect route method now also accepts a hash of options which will only change the parts of the url in question, or an object which responds to call, allowing for redirects to be reused (check the documentation for examples). [Josh Kalderimis]
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index 50faf666e6..50d0d191c1 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -53,6 +53,7 @@ module ActionDispatch
autoload :Flash
autoload :Head
autoload :ParamsParser
+ autoload :Reloader
autoload :RemoteIp
autoload :Rescue
autoload :ShowExceptions
diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb
index 0bb950d1cc..5776a7bb27 100644
--- a/actionpack/lib/action_dispatch/middleware/callbacks.rb
+++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb
@@ -1,32 +1,14 @@
module ActionDispatch
# Provide callbacks to be executed before and after the request dispatch.
- #
- # It also provides a to_prepare callback, which is performed in all requests
- # in development by only once in production and notification callback for async
- # operations.
- #
class Callbacks
include ActiveSupport::Callbacks
define_callbacks :call, :rescuable => true
- define_callbacks :prepare, :scope => :name
- # Add a preparation callback. Preparation callbacks are run before every
- # request in development mode, and before the first request in production mode.
- #
- # If a symbol with a block is given, the symbol is used as an identifier.
- # That allows to_prepare to be called again with the same identifier to
- # replace the existing callback. Passing an identifier is a suggested
- # practice if the code adding a preparation block may be reloaded.
def self.to_prepare(*args, &block)
- first_arg = args.first
- if first_arg.is_a?(Symbol) && block_given?
- remove_method :"__#{first_arg}" if method_defined?(:"__#{first_arg}")
- define_method :"__#{first_arg}", &block
- set_callback(:prepare, :"__#{first_arg}")
- else
- set_callback(:prepare, *args, &block)
- end
+ ActiveSupport::Deprecation.warn "ActionDispatch::Callbacks.to_prepare is deprecated. " <<
+ "Please use ActionDispatch::Reloader.to_prepare instead."
+ ActionDispatch::Reloader.to_prepare(*args, &block)
end
def self.before(*args, &block)
@@ -37,14 +19,13 @@ module ActionDispatch
set_callback(:call, :after, *args, &block)
end
- def initialize(app, prepare_each_request = false)
- @app, @prepare_each_request = app, prepare_each_request
- _run_prepare_callbacks
+ def initialize(app, unused = nil)
+ ActiveSupport::Deprecation.warn "Passing a second argument to ActionDispatch::Callbacks.new is deprecated." unless unused.nil?
+ @app = app
end
def call(env)
_run_call_callbacks do
- _run_prepare_callbacks if @prepare_each_request
@app.call(env)
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb
new file mode 100644
index 0000000000..579b5d8a02
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/reloader.rb
@@ -0,0 +1,65 @@
+module ActionDispatch
+ # ActionDispatch::Reloader provides to_prepare and to_cleanup callbacks.
+ # These are analogs of ActionDispatch::Callback's before and after
+ # callbacks, with the difference that to_cleanup is not called until the
+ # request is fully complete -- that is, after #close has been called on
+ # the request body. This is important for streaming responses such as the
+ # following:
+ #
+ # self.response_body = lambda { |response, output|
+ # # code here which refers to application models
+ # }
+ #
+ # Cleanup callbacks will not be called until after the response_body lambda
+ # is evaluated, ensuring that it can refer to application models and other
+ # classes before they are unloaded.
+ #
+ # By default, ActionDispatch::Reloader is included in the middleware stack
+ # only in the development environment.
+ #
+ class Reloader
+ include ActiveSupport::Callbacks
+
+ define_callbacks :prepare, :scope => :name
+ define_callbacks :cleanup, :scope => :name
+
+ # Add a preparation callback. Preparation callbacks are run before each
+ # request.
+ def self.to_prepare(*args, &block)
+ set_callback(:prepare, *args, &block)
+ end
+
+ # Add a cleanup callback. Cleanup callbacks are run after each request is
+ # complete (after #close is called on the response body).
+ def self.to_cleanup(*args, &block)
+ set_callback(:cleanup, *args, &block)
+ end
+
+ def self.prepare!
+ new(nil).send(:_run_prepare_callbacks)
+ end
+
+ def self.cleanup!
+ new(nil).send(:_run_cleanup_callbacks)
+ end
+
+ def initialize(app)
+ @app = app
+ end
+
+ module CleanupOnClose
+ def close
+ super if defined?(super)
+ ensure
+ ActionDispatch::Reloader.cleanup!
+ end
+ end
+
+ def call(env)
+ _run_prepare_callbacks
+ response = @app.call(env)
+ response[2].extend(CleanupOnClose)
+ response
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
index 49e237f8db..82c4fadb50 100644
--- a/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
+++ b/actionpack/lib/action_dispatch/routing/polymorphic_routes.rb
@@ -99,11 +99,9 @@ module ActionDispatch
record = extract_record(record_or_hash_or_array)
record = record.to_model if record.respond_to?(:to_model)
- args = case record_or_hash_or_array
- when Hash; [ record_or_hash_or_array ]
- when Array; record_or_hash_or_array.dup
- else [ record_or_hash_or_array ]
- end
+ args = Array === record_or_hash_or_array ?
+ record_or_hash_or_array.dup :
+ [ record_or_hash_or_array ]
inflection = if options[:action] && options[:action].to_s == "new"
args.pop
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index 15944138f7..92ff3380b0 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -172,6 +172,14 @@ module ActionView #:nodoc:
class << self
delegate :erb_trim_mode=, :to => 'ActionView::Template::Handlers::ERB'
delegate :logger, :to => 'ActionController::Base', :allow_nil => true
+
+ def cache_template_loading
+ ActionView::Resolver.caching?
+ end
+
+ def cache_template_loading=(value)
+ ActionView::Resolver.caching = value
+ end
end
attr_accessor :_template
diff --git a/actionpack/lib/action_view/helpers/number_helper.rb b/actionpack/lib/action_view/helpers/number_helper.rb
index a9400c347f..26f8dce3c3 100644
--- a/actionpack/lib/action_view/helpers/number_helper.rb
+++ b/actionpack/lib/action_view/helpers/number_helper.rb
@@ -270,12 +270,13 @@ module ActionView
digits, rounded_number = 1, 0
else
digits = (Math.log10(number.abs) + 1).floor
- rounded_number = BigDecimal.new((number / 10 ** (digits - precision)).to_s).round.to_f * 10 ** (digits - precision)
+ rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new((10 ** (digits - precision)).to_f.to_s)).round.to_f * 10 ** (digits - precision)
+ digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed
end
precision -= digits
precision = precision > 0 ? precision : 0 #don't let it be negative
else
- rounded_number = BigDecimal.new((number * (10 ** precision)).to_s).round.to_f / 10 ** precision
+ rounded_number = BigDecimal.new(number.to_s).round(precision).to_f
end
formatted_number = number_with_delimiter("%01.#{precision}f" % rounded_number, options)
if strip_insignificant_zeros
diff --git a/actionpack/lib/action_view/railtie.rb b/actionpack/lib/action_view/railtie.rb
index 71cd1a788a..501ec07b09 100644
--- a/actionpack/lib/action_view/railtie.rb
+++ b/actionpack/lib/action_view/railtie.rb
@@ -35,5 +35,13 @@ module ActionView
end
end
end
+
+ initializer "action_view.caching" do |app|
+ ActiveSupport.on_load(:action_view) do
+ if app.config.action_view.cache_template_loading.nil?
+ ActionView::Resolver.caching = app.config.cache_classes
+ end
+ end
+ end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb
index a17454da28..0dccc99d14 100644
--- a/actionpack/lib/action_view/template/resolver.rb
+++ b/actionpack/lib/action_view/template/resolver.rb
@@ -5,6 +5,13 @@ require "action_view/template"
module ActionView
# = Action View Resolver
class Resolver
+ cattr_accessor :caching
+ self.caching = true
+
+ class << self
+ alias :caching? :caching
+ end
+
def initialize
@cached = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2|
h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } }
@@ -23,9 +30,7 @@ module ActionView
private
- def caching?
- @caching ||= !defined?(Rails.application) || Rails.application.config.cache_classes
- end
+ delegate :caching?, :to => "self.class"
# This is what child classes implement. No defaults are needed
# because Resolver guarantees that the arguments are present and
diff --git a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
index 43c534c111..99f09286ff 100644
--- a/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
+++ b/actionpack/test/activerecord/render_partial_with_record_identification_test.rb
@@ -11,7 +11,7 @@ class RenderPartialWithRecordIdentificationController < ActionController::Base
render :partial => @topic.replies
end
- def render_with_named_scope
+ def render_with_scope
render :partial => Reply.base
end
@@ -62,8 +62,8 @@ class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase
assert_equal 'Birdman is better!', @response.body
end
- def test_rendering_partial_with_named_scope
- get :render_with_named_scope
+ def test_rendering_partial_with_scope
+ get :render_with_scope
assert_template 'replies/_reply'
assert_equal 'Birdman is better!Nuh uh!', @response.body
end
diff --git a/actionpack/test/dispatch/callbacks_test.rb b/actionpack/test/dispatch/callbacks_test.rb
index d3aa55a1ba..5becb621de 100644
--- a/actionpack/test/dispatch/callbacks_test.rb
+++ b/actionpack/test/dispatch/callbacks_test.rb
@@ -1,6 +1,6 @@
require 'abstract_unit'
-class DispatcherTest < Test::Unit::TestCase
+class DispatcherTest < ActiveSupport::TestCase
class Foo
cattr_accessor :a, :b
end
@@ -13,65 +13,9 @@ class DispatcherTest < Test::Unit::TestCase
def setup
Foo.a, Foo.b = 0, 0
- ActionDispatch::Callbacks.reset_callbacks(:prepare)
ActionDispatch::Callbacks.reset_callbacks(:call)
end
- def test_prepare_callbacks_with_cache_classes
- a = b = c = nil
- ActionDispatch::Callbacks.to_prepare { |*args| a = b = c = 1 }
- ActionDispatch::Callbacks.to_prepare { |*args| b = c = 2 }
- ActionDispatch::Callbacks.to_prepare { |*args| c = 3 }
-
- # Ensure to_prepare callbacks are not run when defined
- assert_nil a || b || c
-
- # Run callbacks
- dispatch
-
- assert_equal 1, a
- assert_equal 2, b
- assert_equal 3, c
-
- # Make sure they are only run once
- a = b = c = nil
- dispatch
- assert_nil a || b || c
- end
-
- def test_prepare_callbacks_without_cache_classes
- a = b = c = nil
- ActionDispatch::Callbacks.to_prepare { |*args| a = b = c = 1 }
- ActionDispatch::Callbacks.to_prepare { |*args| b = c = 2 }
- ActionDispatch::Callbacks.to_prepare { |*args| c = 3 }
-
- # Ensure to_prepare callbacks are not run when defined
- assert_nil a || b || c
-
- # Run callbacks
- dispatch(false)
-
- assert_equal 1, a
- assert_equal 2, b
- assert_equal 3, c
-
- # Make sure they are run again
- a = b = c = nil
- dispatch(false)
- assert_equal 1, a
- assert_equal 2, b
- assert_equal 3, c
- end
-
- def test_to_prepare_with_identifier_replaces
- ActionDispatch::Callbacks.to_prepare(:unique_id) { |*args| Foo.a, Foo.b = 1, 1 }
- ActionDispatch::Callbacks.to_prepare(:unique_id) { |*args| Foo.a = 2 }
-
- dispatch
- assert_equal 2, Foo.a
- assert_equal 0, Foo.b
- end
-
def test_before_and_after_callbacks
ActionDispatch::Callbacks.before { |*args| Foo.a += 1; Foo.b += 1 }
ActionDispatch::Callbacks.after { |*args| Foo.a += 1; Foo.b += 1 }
@@ -85,10 +29,20 @@ class DispatcherTest < Test::Unit::TestCase
assert_equal 4, Foo.b
end
+ def test_to_prepare_deprecation
+ prepared = false
+ assert_deprecated do
+ ActionDispatch::Callbacks.to_prepare { prepared = true }
+ end
+
+ ActionDispatch::Reloader.prepare!
+ assert prepared
+ end
+
private
- def dispatch(cache_classes = true, &block)
- @dispatcher ||= ActionDispatch::Callbacks.new(block || DummyApp.new, !cache_classes)
+ def dispatch(&block)
+ @dispatcher ||= ActionDispatch::Callbacks.new(block || DummyApp.new)
@dispatcher.call({'rack.input' => StringIO.new('')})
end
diff --git a/actionpack/test/dispatch/reloader_test.rb b/actionpack/test/dispatch/reloader_test.rb
new file mode 100644
index 0000000000..995b19030c
--- /dev/null
+++ b/actionpack/test/dispatch/reloader_test.rb
@@ -0,0 +1,124 @@
+require 'abstract_unit'
+
+class ReloaderTest < Test::Unit::TestCase
+ Reloader = ActionDispatch::Reloader
+
+ def test_prepare_callbacks
+ a = b = c = nil
+ Reloader.to_prepare { |*args| a = b = c = 1 }
+ Reloader.to_prepare { |*args| b = c = 2 }
+ Reloader.to_prepare { |*args| c = 3 }
+
+ # Ensure to_prepare callbacks are not run when defined
+ assert_nil a || b || c
+
+ # Run callbacks
+ call_and_return_body
+
+ assert_equal 1, a
+ assert_equal 2, b
+ assert_equal 3, c
+ end
+
+ class MyBody < Array
+ def initialize(&block)
+ @on_close = block
+ end
+
+ def foo
+ "foo"
+ end
+
+ def bar
+ "bar"
+ end
+
+ def close
+ @on_close.call if @on_close
+ end
+ end
+
+ def test_returned_body_object_always_responds_to_close
+ body = call_and_return_body
+ assert_respond_to body, :close
+ end
+
+ def test_returned_body_object_behaves_like_underlying_object
+ body = call_and_return_body do
+ b = MyBody.new
+ b << "hello"
+ b << "world"
+ [200, { "Content-Type" => "text/html" }, b]
+ end
+ assert_equal 2, body.size
+ assert_equal "hello", body[0]
+ assert_equal "world", body[1]
+ assert_equal "foo", body.foo
+ assert_equal "bar", body.bar
+ end
+
+ def test_it_calls_close_on_underlying_object_when_close_is_called_on_body
+ close_called = false
+ body = call_and_return_body do
+ b = MyBody.new do
+ close_called = true
+ end
+ [200, { "Content-Type" => "text/html" }, b]
+ end
+ body.close
+ assert close_called
+ end
+
+ def test_returned_body_object_responds_to_all_methods_supported_by_underlying_object
+ body = call_and_return_body do
+ [200, { "Content-Type" => "text/html" }, MyBody.new]
+ end
+ assert_respond_to body, :size
+ assert_respond_to body, :each
+ assert_respond_to body, :foo
+ assert_respond_to body, :bar
+ end
+
+ def test_cleanup_callbacks_are_called_when_body_is_closed
+ cleaned = false
+ Reloader.to_cleanup { cleaned = true }
+
+ body = call_and_return_body
+ assert !cleaned
+
+ body.close
+ assert cleaned
+ end
+
+ def test_prepare_callbacks_arent_called_when_body_is_closed
+ prepared = false
+ Reloader.to_prepare { prepared = true }
+
+ body = call_and_return_body
+ prepared = false
+
+ body.close
+ assert !prepared
+ end
+
+ def test_manual_reloading
+ prepared = cleaned = false
+ Reloader.to_prepare { prepared = true }
+ Reloader.to_cleanup { cleaned = true }
+
+ Reloader.prepare!
+ assert prepared
+ assert !cleaned
+
+ prepared = cleaned = false
+ Reloader.cleanup!
+ assert !prepared
+ assert cleaned
+ end
+
+ private
+ def call_and_return_body(&block)
+ @reloader ||= Reloader.new(block || proc {[200, {}, 'response']})
+ @reloader.call({'rack.input' => StringIO.new('')})[2]
+ end
+end
diff --git a/actionpack/test/template/number_helper_test.rb b/actionpack/test/template/number_helper_test.rb
index ab127521ad..156b7cb5ff 100644
--- a/actionpack/test/template/number_helper_test.rb
+++ b/actionpack/test/template/number_helper_test.rb
@@ -100,6 +100,8 @@ class NumberHelperTest < ActionView::TestCase
assert_equal("0", number_with_precision(0, :precision => 0))
assert_equal("0.00100", number_with_precision(0.001, :precision => 5))
assert_equal("0.001", number_with_precision(0.00111, :precision => 3))
+ assert_equal("10.00", number_with_precision(9.995, :precision => 2))
+ assert_equal("11.00", number_with_precision(10.995, :precision => 2))
end
def test_number_with_precision_with_custom_delimiter_and_separator
@@ -125,6 +127,9 @@ class NumberHelperTest < ActionView::TestCase
assert_equal "0.0001", number_with_precision(0.0001, :precision => 1, :significant => true )
assert_equal "0.000100", number_with_precision(0.0001, :precision => 3, :significant => true )
assert_equal "0.0001", number_with_precision(0.0001111, :precision => 1, :significant => true )
+ assert_equal "10.0", number_with_precision(9.995, :precision => 3, :significant => true)
+ assert_equal "9.99", number_with_precision(9.994, :precision => 3, :significant => true)
+ assert_equal "11.0", number_with_precision(10.995, :precision => 3, :significant => true)
end
def test_number_with_precision_with_strip_insignificant_zeros