aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Noria <fxn@hashref.com>2010-05-04 19:36:26 +0200
committerXavier Noria <fxn@hashref.com>2010-05-04 19:36:26 +0200
commit583b60d109522907020700225f1c739737297a2d (patch)
treea36d986cbbb73c94d217cbe86c9af7ef97a89567
parent44a98967676492995d19fd4d541dbc9d52bf6b53 (diff)
parent0dd3b4630fea4bd4d4010b7096c9ee79d34c4501 (diff)
downloadrails-583b60d109522907020700225f1c739737297a2d.tar.gz
rails-583b60d109522907020700225f1c739737297a2d.tar.bz2
rails-583b60d109522907020700225f1c739737297a2d.zip
Merge remote branch 'rails/master'
-rw-r--r--actionmailer/lib/action_mailer/base.rb11
-rw-r--r--actionmailer/test/base_test.rb30
-rw-r--r--actionpack/lib/action_controller/caching/fragments.rb2
-rw-r--r--actionpack/lib/action_controller/caching/pages.rb2
-rw-r--r--actionpack/lib/action_controller/metal/instrumentation.rb10
-rw-r--r--actionpack/lib/action_controller/test_case.rb11
-rw-r--r--actionpack/lib/action_view/helpers/form_helper.rb8
-rw-r--r--actionpack/lib/action_view/helpers/translation_helper.rb10
-rw-r--r--actionpack/lib/action_view/locale/en.yml28
-rw-r--r--actionpack/lib/action_view/render/partials.rb4
-rw-r--r--actionpack/lib/action_view/render/rendering.rb2
-rw-r--r--actionpack/lib/action_view/template.rb2
-rw-r--r--actionpack/lib/action_view/template/error.rb32
-rw-r--r--actionpack/lib/action_view/testing/resolvers.rb (renamed from actionpack/test/lib/fixture_template.rb)16
-rw-r--r--actionpack/test/abstract_unit.rb2
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb66
-rw-r--r--actionpack/test/controller/layout_test.rb2
-rw-r--r--actionpack/test/template/form_helper_test.rb6
-rw-r--r--actionpack/test/template/testing/fixture_resolver_test.rb18
-rw-r--r--actionpack/test/template/testing/null_resolver_test.rb12
-rw-r--r--activemodel/lib/active_model/errors.rb2
-rw-r--r--activemodel/lib/active_model/locale/en.yml18
-rw-r--r--activemodel/lib/active_model/validations/exclusion.rb2
-rw-r--r--activemodel/lib/active_model/validations/inclusion.rb2
-rw-r--r--activemodel/lib/active_model/validations/length.rb6
-rw-r--r--activemodel/test/cases/validations/conditional_validation_test.rb24
-rw-r--r--activemodel/test/cases/validations/exclusion_validation_test.rb2
-rw-r--r--activemodel/test/cases/validations/format_validation_test.rb2
-rw-r--r--activemodel/test/cases/validations/i18n_generate_message_validation_test.rb14
-rw-r--r--activemodel/test/cases/validations/i18n_validation_test.rb2
-rw-r--r--activemodel/test/cases/validations/inclusion_validation_test.rb2
-rw-r--r--activemodel/test/cases/validations/length_validation_test.rb24
-rw-r--r--activemodel/test/cases/validations/numericality_validation_test.rb4
-rw-r--r--activerecord/lib/active_record/callbacks.rb7
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb2
-rwxr-xr-xactiverecord/lib/active_record/connection_adapters/abstract_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb8
-rw-r--r--activerecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/locale/en.yml4
-rw-r--r--activerecord/lib/active_record/transactions.rb55
-rw-r--r--activerecord/test/cases/validations/i18n_generate_message_validation_test.rb4
-rw-r--r--activeresource/lib/active_resource/connection.rb2
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/activesupport.gemspec2
-rw-r--r--activesupport/lib/active_support/cache.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/date/calculations.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/date/conversions.rb1
-rw-r--r--activesupport/lib/active_support/inflector/transliterate.rb5
-rw-r--r--activesupport/lib/active_support/json/encoding.rb9
-rw-r--r--activesupport/lib/active_support/notifications/instrumenter.rb14
-rw-r--r--activesupport/test/core_ext/date_ext_test.rb48
-rw-r--r--activesupport/test/json/encoding_test.rb4
-rw-r--r--activesupport/test/message_encryptor_test.rb10
-rw-r--r--activesupport/test/notifications_test.rb6
-rw-r--r--railties/guides/source/activerecord_validations_callbacks.textile24
-rw-r--r--railties/guides/source/i18n.textile10
-rw-r--r--railties/lib/rails/backtrace_cleaner.rb23
-rw-r--r--railties/lib/rails/log_subscriber.rb6
-rw-r--r--railties/test/application/initializers/notifications_test.rb2
-rw-r--r--railties/test/log_subscriber_test.rb18
61 files changed, 412 insertions, 248 deletions
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index efef5da6d7..88298966eb 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -354,7 +354,7 @@ module ActionMailer #:nodoc:
# end
# end
def receive(raw_mail)
- ActiveSupport::Notifications.instrument("action_mailer.receive") do |payload|
+ ActiveSupport::Notifications.instrument("receive.action_mailer") do |payload|
mail = Mail.new(raw_mail)
set_payload_for_mail(payload, mail)
new.receive(mail)
@@ -366,7 +366,7 @@ module ActionMailer #:nodoc:
# when you call <tt>:deliver</tt> on the Mail::Message, calling +deliver_mail+ directly
# and passing a Mail::Message will do nothing except tell the logger you sent the email.
def deliver_mail(mail) #:nodoc:
- ActiveSupport::Notifications.instrument("action_mailer.deliver") do |payload|
+ ActiveSupport::Notifications.instrument("deliver.action_mailer") do |payload|
self.set_payload_for_mail(payload, mail)
yield # Let Mail do the delivery actions
end
@@ -566,8 +566,13 @@ module ActionMailer #:nodoc:
content_type = headers[:content_type]
parts_order = headers[:parts_order]
+ # Call all the procs (if any)
+ default_values = self.class.default.merge(self.class.default) do |k,v|
+ v.respond_to?(:call) ? v.bind(self).call : v
+ end
+
# Handle defaults
- headers = headers.reverse_merge(self.class.default)
+ headers = headers.reverse_merge(default_values)
headers[:subject] ||= default_i18n_subject
# Apply charset at the beginning so all fields are properly quoted
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index 8e69073009..5506d62d6a 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -113,6 +113,23 @@ class BaseTest < ActiveSupport::TestCase
end
end
end
+
+ class ProcMailer < ActionMailer::Base
+ default :to => 'system@test.lindsaar.net',
+ 'X-Proc-Method' => Proc.new { Time.now.to_i.to_s },
+ :subject => Proc.new { give_a_greeting }
+
+ def welcome
+ mail
+ end
+
+ private
+
+ def give_a_greeting
+ "Thanks for signing up this afternoon"
+ end
+
+ end
test "method call to mail does not raise error" do
assert_nothing_raised { BaseMailer.welcome }
@@ -560,6 +577,19 @@ class BaseTest < ActiveSupport::TestCase
MyInterceptor.expects(:delivering_email).with(mail)
mail.deliver
end
+
+ test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do
+ mail1 = ProcMailer.welcome
+ yesterday = 1.day.ago
+ Time.stubs(:now).returns(yesterday)
+ mail2 = ProcMailer.welcome
+ assert(mail1['X-Proc-Method'].to_s.to_i > mail2['X-Proc-Method'].to_s.to_i)
+ end
+
+ test "we can call other defined methods on the class as needed" do
+ mail = ProcMailer.welcome
+ assert_equal("Thanks for signing up this afternoon", mail.subject)
+ end
protected
diff --git a/actionpack/lib/action_controller/caching/fragments.rb b/actionpack/lib/action_controller/caching/fragments.rb
index 473a2fe214..460273dac1 100644
--- a/actionpack/lib/action_controller/caching/fragments.rb
+++ b/actionpack/lib/action_controller/caching/fragments.rb
@@ -99,7 +99,7 @@ module ActionController #:nodoc:
end
def instrument_fragment_cache(name, key)
- ActiveSupport::Notifications.instrument("action_controller.#{name}", :key => key){ yield }
+ ActiveSupport::Notifications.instrument("#{name}.action_controller", :key => key){ yield }
end
end
end
diff --git a/actionpack/lib/action_controller/caching/pages.rb b/actionpack/lib/action_controller/caching/pages.rb
index cefd1f48c0..4f7a5d3f55 100644
--- a/actionpack/lib/action_controller/caching/pages.rb
+++ b/actionpack/lib/action_controller/caching/pages.rb
@@ -109,7 +109,7 @@ module ActionController #:nodoc:
end
def instrument_page_cache(name, path)
- ActiveSupport::Notifications.instrument("action_controller.#{name}", :path => path){ yield }
+ ActiveSupport::Notifications.instrument("#{name}.action_controller", :path => path){ yield }
end
end
diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb
index d69de65f28..ba38b186d6 100644
--- a/actionpack/lib/action_controller/metal/instrumentation.rb
+++ b/actionpack/lib/action_controller/metal/instrumentation.rb
@@ -23,9 +23,9 @@ module ActionController
:path => (request.fullpath rescue "unknown")
}
- ActiveSupport::Notifications.instrument("action_controller.start_processing", raw_payload.dup)
+ ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup)
- ActiveSupport::Notifications.instrument("action_controller.process_action", raw_payload) do |payload|
+ ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
result = super
payload[:status] = response.status
append_info_to_payload(payload)
@@ -42,20 +42,20 @@ module ActionController
end
def send_file(path, options={})
- ActiveSupport::Notifications.instrument("action_controller.send_file",
+ ActiveSupport::Notifications.instrument("send_file.action_controller",
options.merge(:path => path)) do
super
end
end
def send_data(data, options = {})
- ActiveSupport::Notifications.instrument("action_controller.send_data", options) do
+ ActiveSupport::Notifications.instrument("send_data.action_controller", options) do
super
end
end
def redirect_to(*args)
- ActiveSupport::Notifications.instrument("action_controller.redirect_to") do |payload|
+ ActiveSupport::Notifications.instrument("redirect_to.action_controller") do |payload|
result = super
payload[:status] = self.status
payload[:location] = self.location
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 2b9b34961e..34499fa784 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -16,12 +16,12 @@ module ActionController
@templates = Hash.new(0)
@layouts = Hash.new(0)
- ActiveSupport::Notifications.subscribe("action_view.render_template") do |name, start, finish, id, payload|
+ ActiveSupport::Notifications.subscribe("render_template.action_view") do |name, start, finish, id, payload|
path = payload[:layout]
@layouts[path] += 1
end
- ActiveSupport::Notifications.subscribe("action_view.render_template!") do |name, start, finish, id, payload|
+ ActiveSupport::Notifications.subscribe("!render_template.action_view") do |name, start, finish, id, payload|
path = payload[:virtual_path]
next unless path
partial = path =~ /^.*\/_[^\/]*$/
@@ -36,8 +36,8 @@ module ActionController
end
def teardown_subscriptions
- ActiveSupport::Notifications.unsubscribe("action_view.render_template")
- ActiveSupport::Notifications.unsubscribe("action_view.render_template!")
+ ActiveSupport::Notifications.unsubscribe("render_template.action_view")
+ ActiveSupport::Notifications.unsubscribe("!render_template.action_view")
end
# Asserts that the request was rendered with the appropriate template file or partials
@@ -57,7 +57,8 @@ module ActionController
validate_request!
case options
- when NilClass, String
+ when NilClass, String, Symbol
+ options = options.to_s if Symbol === options
rendered = @templates
msg = build_message(message,
"expecting <?> but rendering with <?>",
diff --git a/actionpack/lib/action_view/helpers/form_helper.rb b/actionpack/lib/action_view/helpers/form_helper.rb
index d3604925e8..6e26ae6c29 100644
--- a/actionpack/lib/action_view/helpers/form_helper.rb
+++ b/actionpack/lib/action_view/helpers/form_helper.rb
@@ -1165,13 +1165,13 @@ module ActionView
# submit button label, otherwise, it uses "Update Post".
#
# Those labels can be customized using I18n, under the helpers.submit key and accept
- # the {{model}} as translation interpolation:
+ # the %{model} as translation interpolation:
#
# en:
# helpers:
# submit:
- # create: "Create a {{model}}"
- # update: "Confirm changes to {{model}}"
+ # create: "Create a %{model}"
+ # update: "Confirm changes to %{model}"
#
# It also searches for a key specific for the given object:
#
@@ -1179,7 +1179,7 @@ module ActionView
# helpers:
# submit:
# post:
- # create: "Add {{model}}"
+ # create: "Add %{model}"
#
def submit(value=nil, options={})
value, options = nil, value if value.is_a?(Hash)
diff --git a/actionpack/lib/action_view/helpers/translation_helper.rb b/actionpack/lib/action_view/helpers/translation_helper.rb
index 89c1b4a275..086ad261c8 100644
--- a/actionpack/lib/action_view/helpers/translation_helper.rb
+++ b/actionpack/lib/action_view/helpers/translation_helper.rb
@@ -20,7 +20,7 @@ module ActionView
options[:raise] = true
translation = I18n.translate(scope_key_by_partial(key), options)
translation = (translation.respond_to?(:join) ? translation.join : translation)
- if html_safe_translation_key? key
+ if html_safe_translation_key?(key)
translation.html_safe
else
translation
@@ -53,12 +53,8 @@ module ActionView
end
def html_safe_translation_key?(key)
- last_key = if key.is_a? Array
- key.last
- else
- key.to_s.split('.').last
- end
- (last_key == "html") || (last_key.ends_with? "_html")
+ key = key.is_a?(Array) ? key.last : key.to_s
+ key =~ /(\b|_|\.)html$/
end
end
end
diff --git a/actionpack/lib/action_view/locale/en.yml b/actionpack/lib/action_view/locale/en.yml
index 187e010e30..9004e52c5b 100644
--- a/actionpack/lib/action_view/locale/en.yml
+++ b/actionpack/lib/action_view/locale/en.yml
@@ -102,37 +102,37 @@
half_a_minute: "half a minute"
less_than_x_seconds:
one: "less than 1 second"
- other: "less than {{count}} seconds"
+ other: "less than %{count} seconds"
x_seconds:
one: "1 second"
- other: "{{count}} seconds"
+ other: "%{count} seconds"
less_than_x_minutes:
one: "less than a minute"
- other: "less than {{count}} minutes"
+ other: "less than %{count} minutes"
x_minutes:
one: "1 minute"
- other: "{{count}} minutes"
+ other: "%{count} minutes"
about_x_hours:
one: "about 1 hour"
- other: "about {{count}} hours"
+ other: "about %{count} hours"
x_days:
one: "1 day"
- other: "{{count}} days"
+ other: "%{count} days"
about_x_months:
one: "about 1 month"
- other: "about {{count}} months"
+ other: "about %{count} months"
x_months:
one: "1 month"
- other: "{{count}} months"
+ other: "%{count} months"
about_x_years:
one: "about 1 year"
- other: "about {{count}} years"
+ other: "about %{count} years"
over_x_years:
one: "over 1 year"
- other: "over {{count}} years"
+ other: "over %{count} years"
almost_x_years:
one: "almost 1 year"
- other: "almost {{count}} years"
+ other: "almost %{count} years"
prompts:
year: "Year"
month: "Month"
@@ -148,7 +148,7 @@
# Default translation keys for submit FormHelper
submit:
- create: 'Create {{model}}'
- update: 'Update {{model}}'
- submit: 'Save {{model}}'
+ create: 'Create %{model}'
+ update: 'Update %{model}'
+ submit: 'Save %{model}'
diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb
index 4d23d55687..974345633c 100644
--- a/actionpack/lib/action_view/render/partials.rb
+++ b/actionpack/lib/action_view/render/partials.rb
@@ -211,12 +211,12 @@ module ActionView
identifier = ((@template = find_template) ? @template.identifier : @path)
if @collection
- ActiveSupport::Notifications.instrument("action_view.render_collection",
+ ActiveSupport::Notifications.instrument("render_collection.action_view",
:identifier => identifier || "collection", :count => @collection.size) do
render_collection
end
else
- content = ActiveSupport::Notifications.instrument("action_view.render_partial",
+ content = ActiveSupport::Notifications.instrument("render_partial.action_view",
:identifier => identifier) do
render_partial
end
diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb
index 492326964a..4198013f57 100644
--- a/actionpack/lib/action_view/render/rendering.rb
+++ b/actionpack/lib/action_view/render/rendering.rb
@@ -52,7 +52,7 @@ module ActionView
locals = options[:locals] || {}
layout = find_layout(layout) if layout
- ActiveSupport::Notifications.instrument("action_view.render_template",
+ ActiveSupport::Notifications.instrument("render_template.action_view",
:identifier => template.identifier, :layout => layout.try(:virtual_path)) do
content = template.render(self, locals) { |*name| _layout_for(*name) }
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb
index 3c0cd35359..a1a970e2d2 100644
--- a/actionpack/lib/action_view/template.rb
+++ b/actionpack/lib/action_view/template.rb
@@ -41,7 +41,7 @@ module ActionView
def render(view, locals, &block)
# Notice that we use a bang in this instrumentation because you don't want to
# consume this in production. This is only slow if it's being listened to.
- ActiveSupport::Notifications.instrument("action_view.render_template!", :virtual_path => @virtual_path) do
+ ActiveSupport::Notifications.instrument("!render_template.action_view", :virtual_path => @virtual_path) do
method_name = compile(locals, view)
view.send(method_name, locals, &block)
end
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb
index 5222ffa89c..a947d746e3 100644
--- a/actionpack/lib/action_view/template/error.rb
+++ b/actionpack/lib/action_view/template/error.rb
@@ -21,17 +21,18 @@ module ActionView
super("Missing #{template_type} #{path} with #{details.inspect} in view paths #{display_paths}")
end
end
+
class Template
# The Template::Error exception is raised when the compilation of the template fails. This exception then gathers a
# bunch of intimate details and uses it to report a very precise exception message.
class Error < ActionViewError #:nodoc:
SOURCE_CODE_RADIUS = 3
- attr_reader :original_exception
+ attr_reader :original_exception, :backtrace
def initialize(template, assigns, original_exception)
@template, @assigns, @original_exception = template, assigns.dup, original_exception
- @backtrace = compute_backtrace
+ @backtrace = original_exception.backtrace
end
def file_name
@@ -42,14 +43,6 @@ module ActionView
ActiveSupport::Deprecation.silence { original_exception.message }
end
- def clean_backtrace
- if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
- Rails.backtrace_cleaner.clean(original_exception.backtrace)
- else
- original_exception.backtrace
- end
- end
-
def sub_template_message
if @sub_templates
"Trace of template inclusion: " +
@@ -87,29 +80,16 @@ module ActionView
@line_number ||=
if file_name
regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/
-
- $1 if message =~ regexp or clean_backtrace.find { |line| line =~ regexp }
+ $1 if message =~ regexp || backtrace.find { |line| line =~ regexp }
end
end
def to_s
- "\n#{self.class} (#{message}) #{source_location}:\n" +
- "#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n"
- end
-
- # don't do anything nontrivial here. Any raised exception from here becomes fatal
- # (and can't be rescued).
- def backtrace
- @backtrace
+ "\n#{self.class} (#{message}) #{source_location}:\n\n" +
+ "#{source_extract(4)}\n #{backtrace.join("\n ")}\n\n"
end
private
- def compute_backtrace
- [
- "#{source_location.capitalize}\n\n#{source_extract(4)}\n " +
- clean_backtrace.join("\n ")
- ]
- end
def source_location
if line_number
diff --git a/actionpack/test/lib/fixture_template.rb b/actionpack/lib/action_view/testing/resolvers.rb
index b49ccd39ca..578c56c6c4 100644
--- a/actionpack/test/lib/fixture_template.rb
+++ b/actionpack/lib/action_view/testing/resolvers.rb
@@ -1,4 +1,10 @@
+require 'action_view/template/resolver'
+
module ActionView #:nodoc:
+ # Use FixtureResolver in your tests to simulate the presence of files on the
+ # file system. This is used internally by Rails' own test suite, and is
+ # useful for testing extensions that have no way of knowing what the file
+ # system will look like at runtime.
class FixtureResolver < PathResolver
attr_reader :hash
@@ -24,6 +30,14 @@ module ActionView #:nodoc:
templates.sort_by {|t| -t.identifier.match(/^#{query}$/).captures.reject(&:blank?).size }
end
+ end
+ class NullResolver < ActionView::PathResolver
+ def query(path, exts, formats)
+ handler, format = extract_handler_and_format(path, formats)
+ [ActionView::Template.new("Template generated by Null Resolver", path, handler, :virtual_path => path, :format => format)]
+ end
end
-end \ No newline at end of file
+
+end
+
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb
index f3ff258016..89ba0990f1 100644
--- a/actionpack/test/abstract_unit.rb
+++ b/actionpack/test/abstract_unit.rb
@@ -16,8 +16,8 @@ require 'test/unit'
require 'abstract_controller'
require 'action_controller'
require 'action_view'
+require 'action_view/testing/resolvers'
require 'action_dispatch'
-require 'fixture_template'
require 'active_support/dependencies'
require 'active_model'
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index 1741b58f72..765e111226 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -344,25 +344,6 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
end
end
- def test_assert_template_with_partial
- get :partial
- assert_template :partial => '_partial'
- end
-
- def test_assert_template_with_nil
- get :nothing
- assert_template nil
- end
-
- def test_assert_template_with_string
- get :hello_world
- assert_template 'hello_world'
- end
-
- def test_assert_template_with_symbol
- get :hello_world
- assert_template :hello_world
- end
# check if we were rendered by a file-based template?
def test_rendered_action
@@ -387,7 +368,6 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
assert_nil @response.redirect_url
end
-
# check server errors
def test_server_error_response_code
process :response500
@@ -538,6 +518,52 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
end
end
+class AssertTemplateTest < ActionController::TestCase
+ tests ActionPackAssertionsController
+
+ def test_with_partial
+ get :partial
+ assert_template :partial => '_partial'
+ end
+
+ def test_with_nil_passes_when_no_template_rendered
+ get :nothing
+ assert_template nil
+ end
+
+ def test_with_nil_fails_when_template_rendered
+ get :hello_world
+ assert_raise(ActiveSupport::TestCase::Assertion) do
+ assert_template nil
+ end
+ end
+
+ def test_passes_with_correct_string
+ get :hello_world
+ assert_template 'hello_world'
+ assert_template 'test/hello_world'
+ end
+
+ def test_passes_with_correct_symbol
+ get :hello_world
+ assert_template :hello_world
+ end
+
+ def test_fails_with_incorrect_string
+ get :hello_world
+ assert_raise(ActiveSupport::TestCase::Assertion) do
+ assert_template 'hello_planet'
+ end
+ end
+
+ def test_fails_with_incorrect_symbol
+ get :hello_world
+ assert_raise(ActiveSupport::TestCase::Assertion) do
+ assert_template :hello_planet
+ end
+ end
+end
+
class ActionPackHeaderTest < ActionController::TestCase
tests ActionPackAssertionsController
diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb
index 48be7571ea..165c61ffad 100644
--- a/actionpack/test/controller/layout_test.rb
+++ b/actionpack/test/controller/layout_test.rb
@@ -10,8 +10,6 @@ ActionView::Template::register_template_handler :mab,
ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../fixtures/layout_tests/' ]
-require "fixture_template"
-
class LayoutTest < ActionController::Base
def self.controller_path; 'views' end
def self._implied_layout_name; to_s.underscore.gsub(/_controller$/, '') ; end
diff --git a/actionpack/test/template/form_helper_test.rb b/actionpack/test/template/form_helper_test.rb
index 47ac911540..2234fbece9 100644
--- a/actionpack/test/template/form_helper_test.rb
+++ b/actionpack/test/template/form_helper_test.rb
@@ -33,11 +33,11 @@ class FormHelperTest < ActionView::TestCase
I18n.backend.store_translations 'submit', {
:helpers => {
:submit => {
- :create => 'Create {{model}}',
- :update => 'Confirm {{model}} changes',
+ :create => 'Create %{model}',
+ :update => 'Confirm %{model} changes',
:submit => 'Save changes',
:another_post => {
- :update => 'Update your {{model}}'
+ :update => 'Update your %{model}'
}
}
}
diff --git a/actionpack/test/template/testing/fixture_resolver_test.rb b/actionpack/test/template/testing/fixture_resolver_test.rb
new file mode 100644
index 0000000000..de83540468
--- /dev/null
+++ b/actionpack/test/template/testing/fixture_resolver_test.rb
@@ -0,0 +1,18 @@
+require 'abstract_unit'
+
+class FixtureResolverTest < ActiveSupport::TestCase
+ def test_should_return_empty_list_for_unknown_path
+ resolver = ActionView::FixtureResolver.new()
+ templates = resolver.find_all("path", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => []})
+ assert_equal [], templates, "expected an empty list of templates"
+ end
+
+ def test_should_return_template_for_declared_path
+ resolver = ActionView::FixtureResolver.new("arbitrary/path" => "this text")
+ templates = resolver.find_all("path", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => []})
+ assert_equal 1, templates.size, "expected one template"
+ assert_equal "this text", templates.first.source
+ assert_equal "arbitrary/path", templates.first.virtual_path
+ assert_equal [:html], templates.first.formats
+ end
+end
diff --git a/actionpack/test/template/testing/null_resolver_test.rb b/actionpack/test/template/testing/null_resolver_test.rb
new file mode 100644
index 0000000000..e142506e6a
--- /dev/null
+++ b/actionpack/test/template/testing/null_resolver_test.rb
@@ -0,0 +1,12 @@
+require 'abstract_unit'
+
+class NullResolverTest < ActiveSupport::TestCase
+ def test_should_return_template_for_any_path
+ resolver = ActionView::NullResolver.new()
+ templates = resolver.find_all("path", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => []})
+ assert_equal 1, templates.size, "expected one template"
+ assert_equal "Template generated by Null Resolver", templates.first.source
+ assert_equal "arbitrary/path", templates.first.virtual_path
+ assert_equal [:html], templates.first.formats
+ end
+end
diff --git a/activemodel/lib/active_model/errors.rb b/activemodel/lib/active_model/errors.rb
index e6c86c7843..14afc5265f 100644
--- a/activemodel/lib/active_model/errors.rb
+++ b/activemodel/lib/active_model/errors.rb
@@ -223,7 +223,7 @@ module ActiveModel
else
attr_name = attribute.to_s.gsub('.', '_').humanize
attr_name = @base.class.human_attribute_name(attribute, :default => attr_name)
- options = { :default => "{{attribute}} {{message}}", :attribute => attr_name }
+ options = { :default => "%{attribute} %{message}", :attribute => attr_name }
messages.each do |m|
full_messages << I18n.t(:"errors.format", options.merge(:message => m))
diff --git a/activemodel/lib/active_model/locale/en.yml b/activemodel/lib/active_model/locale/en.yml
index d05c04967c..602a530dc0 100644
--- a/activemodel/lib/active_model/locale/en.yml
+++ b/activemodel/lib/active_model/locale/en.yml
@@ -1,7 +1,7 @@
en:
errors:
# The default format use in full error messages.
- format: "{{attribute}} {{message}}"
+ format: "%{attribute} %{message}"
# The values :model, :attribute and :value are always available for interpolation
# The value :count is available when applicable. Can be used for pluralization.
@@ -13,15 +13,15 @@ en:
accepted: "must be accepted"
empty: "can't be empty"
blank: "can't be blank"
- too_long: "is too long (maximum is {{count}} characters)"
- too_short: "is too short (minimum is {{count}} characters)"
- wrong_length: "is the wrong length (should be {{count}} characters)"
+ too_long: "is too long (maximum is %{count} characters)"
+ too_short: "is too short (minimum is %{count} characters)"
+ wrong_length: "is the wrong length (should be %{count} characters)"
not_a_number: "is not a number"
not_an_integer: "must be an integer"
- greater_than: "must be greater than {{count}}"
- greater_than_or_equal_to: "must be greater than or equal to {{count}}"
- equal_to: "must be equal to {{count}}"
- less_than: "must be less than {{count}}"
- less_than_or_equal_to: "must be less than or equal to {{count}}"
+ greater_than: "must be greater than %{count}"
+ greater_than_or_equal_to: "must be greater than or equal to %{count}"
+ equal_to: "must be equal to %{count}"
+ less_than: "must be less than %{count}"
+ less_than_or_equal_to: "must be less than or equal to %{count}"
odd: "must be odd"
even: "must be even"
diff --git a/activemodel/lib/active_model/validations/exclusion.rb b/activemodel/lib/active_model/validations/exclusion.rb
index 7ee718cf3c..2f51edfa9a 100644
--- a/activemodel/lib/active_model/validations/exclusion.rb
+++ b/activemodel/lib/active_model/validations/exclusion.rb
@@ -18,7 +18,7 @@ module ActiveModel
# class Person < ActiveRecord::Base
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
- # validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension {{value}} is not allowed"
+ # validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
# end
#
# Configuration options:
diff --git a/activemodel/lib/active_model/validations/inclusion.rb b/activemodel/lib/active_model/validations/inclusion.rb
index c1838bb93e..96dc8b6e15 100644
--- a/activemodel/lib/active_model/validations/inclusion.rb
+++ b/activemodel/lib/active_model/validations/inclusion.rb
@@ -18,7 +18,7 @@ module ActiveModel
# class Person < ActiveRecord::Base
# validates_inclusion_of :gender, :in => %w( m f )
# validates_inclusion_of :age, :in => 0..99
- # validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension {{value}} is not included in the list"
+ # validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %{value} is not included in the list"
# end
#
# Configuration options:
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index 9ceb75487f..95da3e93ea 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -74,9 +74,9 @@ module ActiveModel
# * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
# * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
# * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
- # * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is {{count}} characters)").
- # * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is {{count}} characters)").
- # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be {{count}} characters)").
+ # * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %{count} characters)").
+ # * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %{count} characters)").
+ # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %{count} characters)").
# * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
# * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
diff --git a/activemodel/test/cases/validations/conditional_validation_test.rb b/activemodel/test/cases/validations/conditional_validation_test.rb
index 5260162a58..6866bfcf24 100644
--- a/activemodel/test/cases/validations/conditional_validation_test.rb
+++ b/activemodel/test/cases/validations/conditional_validation_test.rb
@@ -13,7 +13,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_method_true
# When the method returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true )
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -22,7 +22,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_method_true
# When the method returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true )
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert !t.errors[:title].any?
@@ -30,7 +30,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_method_false
# When the method returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => :condition_is_true_but_its_not )
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true_but_its_not )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert t.errors[:title].empty?
@@ -38,7 +38,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_method_false
# When the method returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => :condition_is_true_but_its_not )
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true_but_its_not )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -47,7 +47,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_string_true
# When the evaluated string returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "a = 1; a == 1" )
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "a = 1; a == 1" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -56,7 +56,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_string_true
# When the evaluated string returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "a = 1; a == 1" )
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "a = 1; a == 1" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert t.errors[:title].empty?
@@ -64,7 +64,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_string_false
# When the evaluated string returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :if => "false")
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "false")
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
assert t.errors[:title].empty?
@@ -72,7 +72,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_string_false
# When the evaluated string returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}", :unless => "false")
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "false")
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -81,7 +81,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_block_true
# When the block returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
:if => Proc.new { |r| r.content.size > 4 } )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
@@ -91,7 +91,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_block_true
# When the block returns true
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
:unless => Proc.new { |r| r.content.size > 4 } )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
@@ -100,7 +100,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_if_validation_using_block_false
# When the block returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
:if => Proc.new { |r| r.title != "uhohuhoh"} )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert t.valid?
@@ -109,7 +109,7 @@ class ConditionalValidationTest < ActiveModel::TestCase
def test_unless_validation_using_block_false
# When the block returns false
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}",
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
:unless => Proc.new { |r| r.title != "uhohuhoh"} )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
diff --git a/activemodel/test/cases/validations/exclusion_validation_test.rb b/activemodel/test/cases/validations/exclusion_validation_test.rb
index 7d851f546c..fffd290fa3 100644
--- a/activemodel/test/cases/validations/exclusion_validation_test.rb
+++ b/activemodel/test/cases/validations/exclusion_validation_test.rb
@@ -20,7 +20,7 @@ class ExclusionValidationTest < ActiveModel::TestCase
end
def test_validates_exclusion_of_with_formatted_message
- Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option {{value}} is restricted" )
+ Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option %{value} is restricted" )
assert Topic.create("title" => "something", "content" => "abc")
diff --git a/activemodel/test/cases/validations/format_validation_test.rb b/activemodel/test/cases/validations/format_validation_test.rb
index e10089208a..1aa6e30f6b 100644
--- a/activemodel/test/cases/validations/format_validation_test.rb
+++ b/activemodel/test/cases/validations/format_validation_test.rb
@@ -67,7 +67,7 @@ class PresenceValidationTest < ActiveModel::TestCase
end
def test_validate_format_with_formatted_message
- Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be {{value}}")
+ Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be %{value}")
t = Topic.create(:title => 'Invalid title')
assert_equal ["can't be Invalid title"], t.errors[:title]
end
diff --git a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb
index 6116ef71d4..3a644c92c9 100644
--- a/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb
+++ b/activemodel/test/cases/validations/i18n_generate_message_validation_test.rb
@@ -15,7 +15,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase
end
def test_generate_message_inclusion_with_custom_message
- assert_equal 'custom message title', @person.errors.generate_message(:title, :inclusion, :default => 'custom message {{value}}', :value => 'title')
+ assert_equal 'custom message title', @person.errors.generate_message(:title, :inclusion, :default => 'custom message %{value}', :value => 'title')
end
# validates_exclusion_of: generate_message(attr_name, :exclusion, :default => configuration[:message], :value => value)
@@ -24,7 +24,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase
end
def test_generate_message_exclusion_with_custom_message
- assert_equal 'custom message title', @person.errors.generate_message(:title, :exclusion, :default => 'custom message {{value}}', :value => 'title')
+ assert_equal 'custom message title', @person.errors.generate_message(:title, :exclusion, :default => 'custom message %{value}', :value => 'title')
end
# validates_format_of: generate_message(attr_name, :invalid, :default => configuration[:message], :value => value)
@@ -33,7 +33,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase
end
def test_generate_message_invalid_with_custom_message
- assert_equal 'custom message title', @person.errors.generate_message(:title, :invalid, :default => 'custom message {{value}}', :value => 'title')
+ assert_equal 'custom message title', @person.errors.generate_message(:title, :invalid, :default => 'custom message %{value}', :value => 'title')
end
# validates_confirmation_of: generate_message(attr_name, :confirmation, :default => configuration[:message])
@@ -78,7 +78,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase
end
def test_generate_message_too_long_with_custom_message
- assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, :default => 'custom message {{count}}', :count => 10)
+ assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_long, :default => 'custom message %{count}', :count => 10)
end
# validates_length_of: generate_message(attr, :too_short, :default => options[:too_short], :count => option_value.begin)
@@ -87,7 +87,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase
end
def test_generate_message_too_short_with_custom_message
- assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, :default => 'custom message {{count}}', :count => 10)
+ assert_equal 'custom message 10', @person.errors.generate_message(:title, :too_short, :default => 'custom message %{count}', :count => 10)
end
# validates_length_of: generate_message(attr, key, :default => custom_message, :count => option_value)
@@ -96,7 +96,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase
end
def test_generate_message_wrong_length_with_custom_message
- assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, :default => 'custom message {{count}}', :count => 10)
+ assert_equal 'custom message 10', @person.errors.generate_message(:title, :wrong_length, :default => 'custom message %{count}', :count => 10)
end
# validates_numericality_of: generate_message(attr_name, :not_a_number, :value => raw_value, :default => configuration[:message])
@@ -105,7 +105,7 @@ class I18nGenerateMessageValidationTest < ActiveModel::TestCase
end
def test_generate_message_not_a_number_with_custom_message
- assert_equal 'custom message title', @person.errors.generate_message(:title, :not_a_number, :default => 'custom message {{value}}', :value => 'title')
+ assert_equal 'custom message title', @person.errors.generate_message(:title, :not_a_number, :default => 'custom message %{value}', :value => 'title')
end
# validates_numericality_of: generate_message(attr_name, option, :value => raw_value, :default => configuration[:message])
diff --git a/activemodel/test/cases/validations/i18n_validation_test.rb b/activemodel/test/cases/validations/i18n_validation_test.rb
index 1b4c1699ae..d65d94d599 100644
--- a/activemodel/test/cases/validations/i18n_validation_test.rb
+++ b/activemodel/test/cases/validations/i18n_validation_test.rb
@@ -58,7 +58,7 @@ class I18nValidationTest < ActiveModel::TestCase
end
def test_errors_full_messages_uses_format
- I18n.backend.store_translations('en', :errors => {:format => "Field {{attribute}} {{message}}"})
+ I18n.backend.store_translations('en', :errors => {:format => "Field %{attribute} %{message}"})
@person.errors.add('name', 'empty')
assert_equal ["Field Name empty"], @person.errors.full_messages
end
diff --git a/activemodel/test/cases/validations/inclusion_validation_test.rb b/activemodel/test/cases/validations/inclusion_validation_test.rb
index 6b2bcd9c60..45ff0175d1 100644
--- a/activemodel/test/cases/validations/inclusion_validation_test.rb
+++ b/activemodel/test/cases/validations/inclusion_validation_test.rb
@@ -44,7 +44,7 @@ class InclusionValidationTest < ActiveModel::TestCase
end
def test_validates_inclusion_of_with_formatted_message
- Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option {{value}} is not in the list" )
+ Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %{value} is not in the list" )
assert Topic.create("title" => "a", "content" => "abc").valid?
diff --git a/activemodel/test/cases/validations/length_validation_test.rb b/activemodel/test/cases/validations/length_validation_test.rb
index 99d0268b67..254e823b7c 100644
--- a/activemodel/test/cases/validations/length_validation_test.rb
+++ b/activemodel/test/cases/validations/length_validation_test.rb
@@ -138,7 +138,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_optionally_validates_length_of_using_within_on_create
- Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: {{count}}"
+ Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: %{count}"
t = Topic.create("title" => "thisisnotvalid", "content" => "whatever")
assert !t.save
@@ -159,7 +159,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_optionally_validates_length_of_using_within_on_update
- Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: {{count}}"
+ Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: %{count}"
t = Topic.create("title" => "vali", "content" => "whatever")
assert !t.save
@@ -230,7 +230,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_minimum_with_message
- Topic.validates_length_of( :title, :minimum=>5, :message=>"boo {{count}}" )
+ Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %{count}" )
t = Topic.create("title" => "uhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -238,7 +238,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_minimum_with_too_short
- Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo {{count}}" )
+ Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %{count}" )
t = Topic.create("title" => "uhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -246,7 +246,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_maximum_with_message
- Topic.validates_length_of( :title, :maximum=>5, :message=>"boo {{count}}" )
+ Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %{count}" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -254,7 +254,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_in
- Topic.validates_length_of(:title, :in => 10..20, :message => "hoo {{count}}")
+ Topic.validates_length_of(:title, :in => 10..20, :message => "hoo %{count}")
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -267,7 +267,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_maximum_with_too_long
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo {{count}}" )
+ Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -275,7 +275,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_is_with_message
- Topic.validates_length_of( :title, :is=>5, :message=>"boo {{count}}" )
+ Topic.validates_length_of( :title, :is=>5, :message=>"boo %{count}" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -283,7 +283,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_custom_errors_for_is_with_wrong_length
- Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo {{count}}" )
+ Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %{count}" )
t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
assert !t.valid?
assert t.errors[:title].any?
@@ -349,7 +349,7 @@ class LengthValidationTest < ActiveModel::TestCase
def test_optionally_validates_length_of_using_within_on_create_utf8
with_kcode('UTF8') do
- Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: {{count}}"
+ Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: %{count}"
t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever")
assert !t.save
@@ -372,7 +372,7 @@ class LengthValidationTest < ActiveModel::TestCase
def test_optionally_validates_length_of_using_within_on_update_utf8
with_kcode('UTF8') do
- Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: {{count}}"
+ Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: %{count}"
t = Topic.create("title" => "一二三4", "content" => "whatever")
assert !t.save
@@ -407,7 +407,7 @@ class LengthValidationTest < ActiveModel::TestCase
end
def test_validates_length_of_with_block
- Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least {{count}} words.",
+ Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least %{count} words.",
:tokenizer => lambda {|str| str.scan(/\w+/) }
t = Topic.create!(:content => "this content should be long enough")
assert t.valid?
diff --git a/activemodel/test/cases/validations/numericality_validation_test.rb b/activemodel/test/cases/validations/numericality_validation_test.rb
index 38b3f87e93..1e73744649 100644
--- a/activemodel/test/cases/validations/numericality_validation_test.rb
+++ b/activemodel/test/cases/validations/numericality_validation_test.rb
@@ -126,13 +126,13 @@ class NumericalityValidationTest < ActiveModel::TestCase
end
def test_validates_numericality_with_numeric_message
- Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than {{count}}"
+ Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than %{count}"
topic = Topic.new("title" => "numeric test", "approved" => 10)
assert !topic.valid?
assert_equal ["smaller than 4"], topic.errors[:approved]
- Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than {{count}}"
+ Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than %{count}"
topic = Topic.new("title" => "numeric test", "approved" => 1)
assert !topic.valid?
diff --git a/activerecord/lib/active_record/callbacks.rb b/activerecord/lib/active_record/callbacks.rb
index 98c14e6eb0..7ebeb6079e 100644
--- a/activerecord/lib/active_record/callbacks.rb
+++ b/activerecord/lib/active_record/callbacks.rb
@@ -17,8 +17,13 @@ module ActiveRecord
# * (-) <tt>create</tt>
# * (5) <tt>after_create</tt>
# * (6) <tt>after_save</tt>
+ # * (7) <tt>after_commit</tt>
#
- # That's a total of eight callbacks, which gives you immense power to react and prepare for each state in the
+ # Also, an <tt>after_rollback</tt> callback can be configured to be triggered whenever a rollback is issued.
+ # Check out <tt>ActiveRecord::Transactions</tt> for more details about <tt>after_commit</tt> and
+ # <tt>after_rollback</tt>.
+ #
+ # That's a total of ten 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
# <tt>_on_create</tt> callback is replaced by the corresponding <tt>_on_update</tt> callback.
#
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
index 2f36bec764..2493095a04 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_specification.rb
@@ -10,8 +10,8 @@ module ActiveRecord
##
# :singleton-method:
# The connection handler
- cattr_accessor :connection_handler, :instance_writer => false
- @@connection_handler = ConnectionAdapters::ConnectionHandler.new
+ class_inheritable_accessor :connection_handler, :instance_writer => false
+ self.connection_handler = ConnectionAdapters::ConnectionHandler.new
# Returns the connection currently associated with the class. This can
# also be used to "borrow" the connection to do database work that isn't
@@ -54,7 +54,7 @@ module ActiveRecord
raise AdapterNotSpecified unless defined?(Rails.env)
establish_connection(Rails.env)
when ConnectionSpecification
- @@connection_handler.establish_connection(name, spec)
+ self.connection_handler.establish_connection(name, spec)
when Symbol, String
if configuration = configurations[spec.to_s]
establish_connection(configuration)
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
index 3c560903f7..533a7bb8e6 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb
@@ -76,7 +76,7 @@ module ActiveRecord
def cache_sql(sql)
result =
if @query_cache.has_key?(sql)
- ActiveSupport::Notifications.instrument("active_record.sql",
+ ActiveSupport::Notifications.instrument("sql.active_record",
:sql => sql, :name => "CACHE", :connection_id => self.object_id)
@query_cache[sql]
else
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
index 578297029b..28a59c1e62 100755
--- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb
@@ -197,7 +197,7 @@ module ActiveRecord
def log(sql, name)
name ||= "SQL"
result = nil
- ActiveSupport::Notifications.instrument("active_record.sql",
+ ActiveSupport::Notifications.instrument("sql.active_record",
:sql => sql, :name => name, :connection_id => self.object_id) do
@runtime += Benchmark.ms { result = yield }
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 74fed4ad62..6389094b8a 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -490,12 +490,8 @@ module ActiveRecord
execute "ROLLBACK"
end
- if defined?(PGconn::PQTRANS_IDLE)
- # The ruby-pg driver supports inspecting the transaction status,
- # while the ruby-postgres driver does not.
- def outside_transaction?
- @connection.transaction_status == PGconn::PQTRANS_IDLE
- end
+ def outside_transaction?
+ @connection.transaction_status == PGconn::PQTRANS_IDLE
end
def create_savepoint
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 0bc49c1daa..4bf33c3856 100644
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -516,7 +516,7 @@ class Fixtures < (RUBY_VERSION < '1.9' ? YAML::Omap : Hash)
# Cap primary key sequences to max(pk).
if connection.respond_to?(:reset_pk_sequence!)
table_names.each do |table_name|
- connection.reset_pk_sequence!(table_name)
+ connection.reset_pk_sequence!(table_name.tr('/', '_'))
end
end
end
diff --git a/activerecord/lib/active_record/locale/en.yml b/activerecord/lib/active_record/locale/en.yml
index 810359fef3..9d5cb54180 100644
--- a/activerecord/lib/active_record/locale/en.yml
+++ b/activerecord/lib/active_record/locale/en.yml
@@ -9,7 +9,7 @@ en:
errors:
messages:
taken: "has already been taken"
- record_invalid: "Validation failed: {{errors}}"
+ record_invalid: "Validation failed: %{errors}"
# Append your own errors here or at the model/attributes scope.
# You can define own errors for models or model attributes.
@@ -18,7 +18,7 @@ en:
# For example,
# models:
# user:
- # blank: "This is a custom blank message for {{model}}: {{attribute}}"
+ # blank: "This is a custom blank message for %{model}: %{attribute}"
# attributes:
# login:
# blank: "This is a custom blank message for User login"
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index 796dd99f02..1a195fbb81 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -31,10 +31,10 @@ module ActiveRecord
# mary.deposit(100)
# end
#
- # This example will only take money from David and give to Mary if neither
- # +withdrawal+ nor +deposit+ raises an exception. Exceptions will force a
- # ROLLBACK that returns the database to the state before the transaction was
- # begun. Be aware, though, that the objects will _not_ have their instance
+ # This example will only take money from David and give it to Mary if neither
+ # +withdrawal+ nor +deposit+ raise an exception. Exceptions will force a
+ # ROLLBACK that returns the database to the state before the transaction
+ # began. Be aware, though, that the objects will _not_ have their instance
# data returned to their pre-transactional state.
#
# == Different Active Record classes in a single transaction
@@ -44,16 +44,16 @@ module ActiveRecord
# that class. This is because transactions are per-database connection, not
# per-model.
#
- # In this example a <tt>Balance</tt> record is transactionally saved even
- # though <tt>transaction</tt> is called on the <tt>Account</tt> class:
+ # In this example a +balance+ record is transactionally saved even
+ # though +transaction+ is called on the +Account+ class:
#
# Account.transaction do
# balance.save!
# account.save!
# end
#
- # Note that the +transaction+ method is also available as a model instance
- # method. For example, you can also do this:
+ # The +transaction+ method is also available as a model instance method.
+ # For example, you can also do this:
#
# balance.transaction do
# balance.save!
@@ -62,9 +62,9 @@ module ActiveRecord
#
# == Transactions are not distributed across database connections
#
- # A transaction acts on a single database connection. If you have
+ # A transaction acts on a single database connection. If you have
# multiple class-specific databases, the transaction will not protect
- # interaction among them. One workaround is to begin a transaction
+ # interaction among them. One workaround is to begin a transaction
# on each class whose models you alter:
#
# Student.transaction do
@@ -74,16 +74,22 @@ module ActiveRecord
# end
# end
#
- # This is a poor solution, but full distributed transactions are beyond
+ # This is a poor solution, but fully distributed transactions are beyond
# the scope of Active Record.
#
- # == Save and destroy are automatically wrapped in a transaction
+ # == +save+ and +destroy+ are automatically wrapped in a transaction
#
- # Both Base#save and Base#destroy come wrapped in a transaction that ensures
- # that whatever you do in validations or callbacks will happen under the
- # protected cover of a transaction. So you can use validations to check for
- # values that the transaction depends on or you can raise exceptions in the
- # callbacks to rollback, including <tt>after_*</tt> callbacks.
+ # Both +save+ and +destroy+ come wrapped in a transaction that ensures
+ # that whatever you do in validations or callbacks will happen under its
+ # protected cover. So you can use validations to check for values that
+ # the transaction depends on or you can raise exceptions in the callbacks
+ # to rollback, including <tt>after_*</tt> callbacks.
+ #
+ # As a consequence changes to the database are not seen outside your connection
+ # until the operation is complete. For example, if you try to update the index
+ # of a search engine in +after_save+ the indexer won't see the updated record.
+ # The +after_commit+ callback is the only one that is triggered once the update
+ # is committed. See below.
#
# == Exception handling and rolling back
#
@@ -91,14 +97,14 @@ module ActiveRecord
# be propagated (after triggering the ROLLBACK), so you should be ready to
# catch those in your application code.
#
- # One exception is the ActiveRecord::Rollback exception, which will trigger
+ # One exception is the <tt>ActiveRecord::Rollback</tt> exception, which will trigger
# a ROLLBACK when raised, but not be re-raised by the transaction block.
#
- # *Warning*: one should not catch ActiveRecord::StatementInvalid exceptions
- # inside a transaction block. StatementInvalid exceptions indicate that an
+ # *Warning*: one should not catch <tt>ActiveRecord::StatementInvalid</tt> exceptions
+ # inside a transaction block. <tt>ActiveRecord::StatementInvalid</tt> exceptions indicate that an
# error occurred at the database level, for example when a unique constraint
# is violated. On some database systems, such as PostgreSQL, database errors
- # inside a transaction causes the entire transaction to become unusable
+ # inside a transaction cause the entire transaction to become unusable
# until it's restarted from the beginning. Here is an example which
# demonstrates the problem:
#
@@ -120,11 +126,12 @@ module ActiveRecord
# # ignored until end of transaction block"
# end
#
- # One should restart the entire transaction if a StatementError occurred.
+ # One should restart the entire transaction if an
+ # <tt>ActiveRecord::StatementInvalid</tt> occurred.
#
# == Nested transactions
#
- # #transaction calls can be nested. By default, this makes all database
+ # +transaction+ calls can be nested. By default, this makes all database
# statements in the nested transaction block become part of the parent
# transaction. For example:
#
@@ -139,7 +146,7 @@ module ActiveRecord
# User.find(:all) # => empty
#
# It is also possible to requires a sub-transaction by passing
- # <tt>:requires_new => true</tt>. If anything goes wrong, the
+ # <tt>:requires_new => true</tt>. If anything goes wrong, the
# database rolls back to the beginning of the sub-transaction
# without rolling back the parent transaction. For example:
#
diff --git a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
index 15730c2a87..8ee2a5868c 100644
--- a/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
+++ b/activerecord/test/cases/validations/i18n_generate_message_validation_test.rb
@@ -15,7 +15,7 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase
end
def test_generate_message_invalid_with_custom_message
- assert_equal 'custom message title', @topic.errors.generate_message(:title, :invalid, :default => 'custom message {{value}}', :value => 'title')
+ assert_equal 'custom message title', @topic.errors.generate_message(:title, :invalid, :default => 'custom message %{value}', :value => 'title')
end
# validates_uniqueness_of: generate_message(attr_name, :taken, :default => configuration[:message])
@@ -24,7 +24,7 @@ class I18nGenerateMessageValidationTest < ActiveRecord::TestCase
end
def test_generate_message_taken_with_custom_message
- assert_equal 'custom message title', @topic.errors.generate_message(:title, :taken, :default => 'custom message {{value}}', :value => 'title')
+ assert_equal 'custom message title', @topic.errors.generate_message(:title, :taken, :default => 'custom message %{value}', :value => 'title')
end
# ActiveRecord#RecordInvalid exception
diff --git a/activeresource/lib/active_resource/connection.rb b/activeresource/lib/active_resource/connection.rb
index 2f0ccd7dae..b7befe110d 100644
--- a/activeresource/lib/active_resource/connection.rb
+++ b/activeresource/lib/active_resource/connection.rb
@@ -106,7 +106,7 @@ module ActiveResource
private
# Makes a request to the remote service.
def request(method, path, *arguments)
- result = ActiveSupport::Notifications.instrument("active_resource.request") do |payload|
+ result = ActiveSupport::Notifications.instrument("request.active_resource") do |payload|
payload[:method] = method
payload[:request_uri] = "#{site.scheme}://#{site.host}:#{site.port}#{path}"
payload[:result] = http.send(method, path, *arguments)
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index f24a1b1c6c..0652a20035 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,7 @@
*Rails 3.0.0 [beta 4/release candidate] (unreleased)*
+* Deprecate {{}} as interpolation syntax for I18n in favor of %{} [José Valim]
+
* Array#to_xml is more powerful and able to handle the same types as Hash#to_xml #4490 [Neeraj Singh]
* Harmonize the caching API and refactor the backends. #4452 [Brian Durand]
diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec
index 0fea84a6ef..cfd85f61c9 100644
--- a/activesupport/activesupport.gemspec
+++ b/activesupport/activesupport.gemspec
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
s.has_rdoc = true
- s.add_dependency('i18n', '~> 0.4.0.beta')
+ s.add_dependency('i18n', '~> 0.4.0.beta1')
s.add_dependency('tzinfo', '~> 0.3.16')
s.add_dependency('builder', '~> 2.1.2')
s.add_dependency('memcache-client', '>= 1.7.5')
diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index ec5007c284..2605a3f2b8 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -502,7 +502,7 @@ module ActiveSupport
if self.class.instrument
payload = { :key => key }
payload.merge!(options) if options.is_a?(Hash)
- ActiveSupport::Notifications.instrument("active_support.cache_#{operation}", payload){ yield }
+ ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield }
else
yield
end
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb
index 9d2ad2bbcf..fef49e1003 100644
--- a/activesupport/lib/active_support/core_ext/date/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/date/calculations.rb
@@ -7,12 +7,12 @@ class Date
class << self
# Returns a new Date representing the date 1 day ago (i.e. yesterday's date).
def yesterday
- ::Date.today.yesterday
+ ::Date.current.yesterday
end
# Returns a new Date representing the date 1 day after today (i.e. tomorrow's date).
def tomorrow
- ::Date.today.tomorrow
+ ::Date.current.tomorrow
end
# Returns Time.zone.today when config.time_zone is set, otherwise just returns Date.today.
diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb
index 90ab1eb281..13ef703f49 100644
--- a/activesupport/lib/active_support/core_ext/date/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/date/conversions.rb
@@ -1,5 +1,6 @@
require 'date'
require 'active_support/inflector'
+require 'active_support/core_ext/time/calculations'
class Date
DATE_FORMATS = {
diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb
index 5ec87372d0..2344bb1bb3 100644
--- a/activesupport/lib/active_support/inflector/transliterate.rb
+++ b/activesupport/lib/active_support/inflector/transliterate.rb
@@ -24,8 +24,9 @@ module ActiveSupport
# # Store the transliterations in locales/de.yml
# i18n:
# transliterate:
- # ü: "ue"
- # ö: "oe"
+ # rule:
+ # ü: "ue"
+ # ö: "oe"
#
# # Or set them using Ruby
# I18n.backend.store_translations(:de, :i18n => {
diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index e692f6d142..02c233595d 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -1,6 +1,7 @@
# encoding: utf-8
require 'bigdecimal'
require 'active_support/core_ext/array/wrap'
+require 'active_support/core_ext/big_decimal/conversions' # for #to_s
require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/module/delegation'
@@ -178,6 +179,14 @@ class Numeric
end
class BigDecimal
+ # A BigDecimal would be naturally represented as a JSON number. Most libraries,
+ # however, parse non-integer JSON numbers directly as floats. Clients using
+ # those libraries would get in general a wrong number and no way to recover
+ # other than manually inspecting the string with the JSON code itself.
+ #
+ # That's why a JSON string is returned. The JSON literal is not numeric, but if
+ # the other end knows by contract that the data is supposed to be a BigDecimal,
+ # it still has the chance to post-process the string and get the real value.
def as_json(options = nil) to_s end #:nodoc:
end
diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb
index f3d877efe7..7e89402822 100644
--- a/activesupport/lib/active_support/notifications/instrumenter.rb
+++ b/activesupport/lib/active_support/notifications/instrumenter.rb
@@ -12,12 +12,18 @@ module ActiveSupport
end
# Instrument the given block by measuring the time taken to execute it
- # and publish it.
+ # and publish it. Notice that events get sent even if an error occurs
+ # in the passed-in block
def instrument(name, payload={})
time = Time.now
- result = yield(payload) if block_given?
- @notifier.publish(name, time, Time.now, @id, payload)
- result
+ begin
+ yield(payload) if block_given?
+ rescue Exception => e
+ payload[:exception] = [e.class.name, e.message]
+ raise e
+ ensure
+ @notifier.publish(name, time, Time.now, @id, payload)
+ end
end
private
diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb
index 23c9bc7fb1..c403d7fb11 100644
--- a/activesupport/test/core_ext/date_ext_test.rb
+++ b/activesupport/test/core_ext/date_ext_test.rb
@@ -176,11 +176,47 @@ class DateExtCalculationsTest < Test::Unit::TestCase
end
def test_yesterday_constructor
- assert_equal Date.today - 1, Date.yesterday
+ assert_equal Date.current - 1, Date.yesterday
+ end
+
+ def test_yesterday_constructor_when_zone_default_is_not_set
+ with_env_tz 'UTC' do
+ with_tz_default do
+ Time.stubs(:now).returns Time.local(2000, 1, 1)
+ assert_equal Date.new(1999, 12, 31), Date.yesterday
+ end
+ end
+ end
+
+ def test_yesterday_constructor_when_zone_default_is_set
+ with_env_tz 'UTC' do
+ with_tz_default ActiveSupport::TimeZone['Eastern Time (US & Canada)'] do # UTC -5
+ Time.stubs(:now).returns Time.local(2000, 1, 1)
+ assert_equal Date.new(1999, 12, 30), Date.yesterday
+ end
+ end
end
def test_tomorrow_constructor
- assert_equal Date.today + 1, Date.tomorrow
+ assert_equal Date.current + 1, Date.tomorrow
+ end
+
+ def test_tomorrow_constructor_when_zone_default_is_not_set
+ with_env_tz 'UTC' do
+ with_tz_default do
+ Time.stubs(:now).returns Time.local(1999, 12, 31)
+ assert_equal Date.new(2000, 1, 1), Date.tomorrow
+ end
+ end
+ end
+
+ def test_tomorrow_constructor_when_zone_default_is_set
+ with_env_tz 'UTC' do
+ with_tz_default ActiveSupport::TimeZone['Europe/Paris'] do # UTC +1
+ Time.stubs(:now).returns Time.local(1999, 12, 31, 23)
+ assert_equal Date.new(2000, 1, 2), Date.tomorrow
+ end
+ end
end
def test_since
@@ -264,6 +300,14 @@ class DateExtCalculationsTest < Test::Unit::TestCase
ensure
old_tz ? ENV['TZ'] = old_tz : ENV.delete('TZ')
end
+
+ def with_tz_default(tz = nil)
+ old_tz = Time.zone_default
+ Time.zone_default = tz
+ yield
+ ensure
+ Time.zone_default = old_tz
+ end
end
class DateExtBehaviorTest < Test::Unit::TestCase
diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
index ac7ca96c4d..a8ecf4e4cf 100644
--- a/activesupport/test/json/encoding_test.rb
+++ b/activesupport/test/json/encoding_test.rb
@@ -1,5 +1,7 @@
# encoding: utf-8
require 'abstract_unit'
+require 'bigdecimal'
+require 'active_support/core_ext/big_decimal/conversions'
require 'active_support/json'
class TestJSONEncoding < Test::Unit::TestCase
@@ -26,7 +28,7 @@ class TestJSONEncoding < Test::Unit::TestCase
NilTests = [[ nil, %(null) ]]
NumericTests = [[ 1, %(1) ],
[ 2.5, %(2.5) ],
- [ BigDecimal('2.5'), %("#{BigDecimal('2.5').to_s('F')}") ]]
+ [ BigDecimal('2.5'), %("#{BigDecimal('2.5').to_s}") ]]
StringTests = [[ 'this is the <string>', %("this is the \\u003Cstring\\u003E")],
[ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ],
diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb
index 2fba62bdd6..684b931176 100644
--- a/activesupport/test/message_encryptor_test.rb
+++ b/activesupport/test/message_encryptor_test.rb
@@ -1,4 +1,12 @@
require 'abstract_unit'
+
+begin
+ require 'openssl'
+ OpenSSL::Digest::SHA1
+rescue LoadError, NameError
+ $stderr.puts "Skipping MessageEncryptor test: broken OpenSSL install"
+else
+
require 'active_support/time'
class MessageEncryptorTest < Test::Unit::TestCase
@@ -45,3 +53,5 @@ class MessageEncryptorTest < Test::Unit::TestCase
ActiveSupport::Base64.encode64s(bits)
end
end
+
+end
diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb
index c2e1c588f0..e11de5f67a 100644
--- a/activesupport/test/notifications_test.rb
+++ b/activesupport/test/notifications_test.rb
@@ -168,7 +168,7 @@ module Notifications
assert_equal Hash[:payload => "notifications"], @events.last.payload
end
- def test_instrument_does_not_publish_when_exception_is_raised
+ def test_instrument_publishes_when_exception_is_raised
begin
instrument(:awesome, :payload => "notifications") do
raise "FAIL"
@@ -178,7 +178,9 @@ module Notifications
end
drain
- assert_equal 0, @events.size
+ assert_equal 1, @events.size
+ assert_equal Hash[:payload => "notifications",
+ :exception => ["RuntimeError", "FAIL"]], @events.last.payload
end
def test_event_is_pushed_even_without_block
diff --git a/railties/guides/source/activerecord_validations_callbacks.textile b/railties/guides/source/activerecord_validations_callbacks.textile
index 126a6efff5..97915d5d55 100644
--- a/railties/guides/source/activerecord_validations_callbacks.textile
+++ b/railties/guides/source/activerecord_validations_callbacks.textile
@@ -234,7 +234,7 @@ This helper validates that the attributes' values are not included in a given se
<ruby>
class Account < ActiveRecord::Base
validates_exclusion_of :subdomain, :in => %w(www),
- :message => "Subdomain {{value}} is reserved."
+ :message => "Subdomain %{value} is reserved."
end
</ruby>
@@ -262,7 +262,7 @@ This helper validates that the attributes' values are included in a given set. I
<ruby>
class Coffee < ActiveRecord::Base
validates_inclusion_of :size, :in => %w(small medium large),
- :message => "{{value}} is not a valid size"
+ :message => "%{value} is not a valid size"
end
</ruby>
@@ -290,12 +290,12 @@ The possible length constraint options are:
* +:in+ (or +:within+) - The attribute length must be included in a given interval. The value for this option must be a range.
* +:is+ - The attribute length must be equal to the given value.
-The default error messages depend on the type of length validation being performed. You can personalize these messages using the +:wrong_length+, +:too_long+, and +:too_short+ options and <tt>{{count}}</tt> as a placeholder for the number corresponding to the length constraint being used. You can still use the +:message+ option to specify an error message.
+The default error messages depend on the type of length validation being performed. You can personalize these messages using the +:wrong_length+, +:too_long+, and +:too_short+ options and <tt>%{count}</tt> as a placeholder for the number corresponding to the length constraint being used. You can still use the +:message+ option to specify an error message.
<ruby>
class Person < ActiveRecord::Base
validates_length_of :bio, :maximum => 1000,
- :too_long => "{{count}} characters is the maximum allowed"
+ :too_long => "%{count} characters is the maximum allowed"
end
</ruby>
@@ -307,8 +307,8 @@ class Essay < ActiveRecord::Base
:minimum => 300,
:maximum => 400,
:tokenizer => lambda { |str| str.scan(/\w+/) },
- :too_short => "must have at least {{count}} words",
- :too_long => "must have at most {{count}} words"
+ :too_short => "must have at least %{count} words",
+ :too_long => "must have at most %{count} words"
end
</ruby>
@@ -337,11 +337,11 @@ end
Besides +:only_integer+, the +validates_numericality_of+ helper also accepts the following options to add constraints to acceptable values:
-* +:greater_than+ - Specifies the value must be greater than the supplied value. The default error message for this option is "_must be greater than {{count}}_".
-* +:greater_than_or_equal_to+ - Specifies the value must be greater than or equal to the supplied value. The default error message for this option is "_must be greater than or equal to {{count}}_".
-* +:equal_to+ - Specifies the value must be equal to the supplied value. The default error message for this option is "_must be equal to {{count}}_".
-* +:less_than+ - Specifies the value must be less than the supplied value. The default error message for this option is "_must be less than {{count}}_".
-* +:less_than_or_equal_to+ - Specifies the value must be less than or equal the supplied value. The default error message for this option is "_must be less or equal to {{count}}_".
+* +:greater_than+ - Specifies the value must be greater than the supplied value. The default error message for this option is "_must be greater than %{count}_".
+* +:greater_than_or_equal_to+ - Specifies the value must be greater than or equal to the supplied value. The default error message for this option is "_must be greater than or equal to %{count}_".
+* +:equal_to+ - Specifies the value must be equal to the supplied value. The default error message for this option is "_must be equal to %{count}_".
+* +:less_than+ - Specifies the value must be less than the supplied value. The default error message for this option is "_must be less than %{count}_".
+* +:less_than_or_equal_to+ - Specifies the value must be less than or equal the supplied value. The default error message for this option is "_must be less or equal to %{count}_".
* +:odd+ - Specifies the value must be an odd number if set to true. The default error message for this option is "_must be odd_".
* +:even+ - Specifies the value must be an even number if set to true. The default error message for this option is "_must be even_".
@@ -469,7 +469,7 @@ The +:allow_nil+ option skips the validation when the value being validated is +
<ruby>
class Coffee < ActiveRecord::Base
validates_inclusion_of :size, :in => %w(small medium large),
- :message => "{{value}} is not a valid size", :allow_nil => true
+ :message => "%{value} is not a valid size", :allow_nil => true
end
</ruby>
diff --git a/railties/guides/source/i18n.textile b/railties/guides/source/i18n.textile
index dcad451e23..bb383d3cf9 100644
--- a/railties/guides/source/i18n.textile
+++ b/railties/guides/source/i18n.textile
@@ -531,7 +531,7 @@ In many cases you want to abstract your translations so that *variables can be i
All options besides +:default+ and +:scope+ that are passed to +#translate+ will be interpolated to the translation:
<ruby>
-I18n.backend.store_translations :en, :thanks => 'Thanks {{name}}!'
+I18n.backend.store_translations :en, :thanks => 'Thanks %{name}!'
I18n.translate :thanks, :name => 'Jeremy'
# => 'Thanks Jeremy!'
</ruby>
@@ -547,7 +547,7 @@ The +:count+ interpolation variable has a special role in that it both is interp
<ruby>
I18n.backend.store_translations :en, :inbox => {
:one => '1 message',
- :other => '{{count}} messages'
+ :other => '%{count} messages'
}
I18n.translate :inbox, :count => 2
# => '2 messages'
@@ -711,7 +711,7 @@ h5. Error Message Interpolation
The translated model name, translated attribute name, and value are always available for interpolation.
-So, for example, instead of the default error message +"can not be blank"+ you could use the attribute name like this : +"Please fill in your {{attribute}}"+.
+So, for example, instead of the default error message +"can not be blank"+ you could use the attribute name like this : +"Please fill in your %{attribute}"+.
* +count+, where available, can be used for pluralization if present:
@@ -750,8 +750,8 @@ en:
errors:
template:
header:
- one: "1 error prohibited this {{model}} from being saved"
- other: "{{count}} errors prohibited this {{model}} from being saved"
+ one: "1 error prohibited this %{model} from being saved"
+ other: "%{count} errors prohibited this %{model} from being saved"
body: "There were problems with the following fields:"
</yaml>
diff --git a/railties/lib/rails/backtrace_cleaner.rb b/railties/lib/rails/backtrace_cleaner.rb
index ee2635d4cd..bedefaa51c 100644
--- a/railties/lib/rails/backtrace_cleaner.rb
+++ b/railties/lib/rails/backtrace_cleaner.rb
@@ -2,29 +2,28 @@ require 'active_support/backtrace_cleaner'
module Rails
class BacktraceCleaner < ActiveSupport::BacktraceCleaner
- ERB_METHOD_SIG = /:in `_run_erb_.*/
- APP_DIRS = %w( app config lib test )
+ APP_DIRS_PATTERN = /^\/?(app|config|lib|test)/
+ RENDER_TEMPLATE_PATTERN = /:in `_render_template_\w*'/
def initialize
super
add_filter { |line| line.sub("#{Rails.root}/", '') }
- add_filter { |line| line.sub(ERB_METHOD_SIG, '') }
+ add_filter { |line| line.sub(RENDER_TEMPLATE_PATTERN, '') }
add_filter { |line| line.sub('./', '/') } # for tests
add_gem_filters
-
- add_silencer { |line| !APP_DIRS.any? { |dir| line =~ /^\/?#{dir}/ } }
+ add_silencer { |line| line !~ APP_DIRS_PATTERN }
end
private
def add_gem_filters
- return unless defined? Gem
- (Gem.path + [Gem.default_dir]).uniq.each do |path|
- # http://gist.github.com/30430
- add_filter { |line|
- line.sub(%r{(#{path})/gems/([^/]+)-([0-9.]+)/(.*)}, '\2 (\3) \4')
- }
- end
+ return unless defined?(Gem)
+
+ gems_paths = (Gem.path + [Gem.default_dir]).uniq.map!{ |p| Regexp.escape(p) }
+ return if gems_paths.empty?
+
+ gems_regexp = %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w\.]+)/(.*)}
+ add_filter { |line| line.sub(gems_regexp, '\2 (\3) \4') }
end
end
diff --git a/railties/lib/rails/log_subscriber.rb b/railties/lib/rails/log_subscriber.rb
index 42697d2e32..145c7e0ace 100644
--- a/railties/lib/rails/log_subscriber.rb
+++ b/railties/lib/rails/log_subscriber.rb
@@ -22,7 +22,7 @@ module Rails
#
# Rails::LogSubscriber.add :active_record, ActiveRecord::Railtie::LogSubscriber.new
#
- # So whenever a "active_record.sql" notification arrive to Rails::LogSubscriber,
+ # So whenever a "sql.active_record" notification arrive to Rails::LogSubscriber,
# it will properly dispatch the event (ActiveSupport::Notifications::Event) to
# the sql method.
#
@@ -54,7 +54,7 @@ module Rails
log_subscribers << log_subscriber
log_subscriber.public_methods(false).each do |event|
- notifier.subscribe("#{namespace}.#{event}") do |*args|
+ notifier.subscribe("#{event}.#{namespace}") do |*args|
next if log_subscriber.logger.nil?
begin
@@ -105,4 +105,4 @@ module Rails
"#{bold}#{color}#{text}#{CLEAR}"
end
end
-end \ No newline at end of file
+end
diff --git a/railties/test/application/initializers/notifications_test.rb b/railties/test/application/initializers/notifications_test.rb
index b99cf5bb4f..276950c78c 100644
--- a/railties/test/application/initializers/notifications_test.rb
+++ b/railties/test/application/initializers/notifications_test.rb
@@ -38,7 +38,7 @@ module ApplicationTests
ActiveRecord::Base.logger = logger = MockLogger.new
# Mimic ActiveRecord notifications
- instrument "active_record.sql", :name => "SQL", :sql => "SHOW tables"
+ instrument "sql.active_record", :name => "SQL", :sql => "SHOW tables"
wait
assert_equal 1, logger.logged.size
diff --git a/railties/test/log_subscriber_test.rb b/railties/test/log_subscriber_test.rb
index 49288cfaa8..a3a755ae62 100644
--- a/railties/test/log_subscriber_test.rb
+++ b/railties/test/log_subscriber_test.rb
@@ -61,21 +61,21 @@ class SyncLogSubscriberTest < ActiveSupport::TestCase
def test_event_is_sent_to_the_registered_class
Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber
- instrument "my_log_subscriber.some_event"
+ instrument "some_event.my_log_subscriber"
wait
- assert_equal %w(my_log_subscriber.some_event), @logger.logged(:info)
+ assert_equal %w(some_event.my_log_subscriber), @logger.logged(:info)
end
def test_event_is_an_active_support_notifications_event
Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber
- instrument "my_log_subscriber.some_event"
+ instrument "some_event.my_log_subscriber"
wait
assert_kind_of ActiveSupport::Notifications::Event, @log_subscriber.event
end
def test_does_not_send_the_event_if_it_doesnt_match_the_class
Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber
- instrument "my_log_subscriber.unknown_event"
+ instrument "unknown_event.my_log_subscriber"
wait
# If we get here, it means that NoMethodError was not raised.
end
@@ -84,7 +84,7 @@ class SyncLogSubscriberTest < ActiveSupport::TestCase
Rails.logger = nil
@log_subscriber.expects(:some_event).never
Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber
- instrument "my_log_subscriber.some_event"
+ instrument "some_event.my_log_subscriber"
wait
end
@@ -110,14 +110,14 @@ class SyncLogSubscriberTest < ActiveSupport::TestCase
def test_logging_does_not_die_on_failures
Rails::LogSubscriber.add :my_log_subscriber, @log_subscriber
- instrument "my_log_subscriber.puke"
- instrument "my_log_subscriber.some_event"
+ instrument "puke.my_log_subscriber"
+ instrument "some_event.my_log_subscriber"
wait
assert_equal 1, @logger.logged(:info).size
- assert_equal 'my_log_subscriber.some_event', @logger.logged(:info).last
+ assert_equal 'some_event.my_log_subscriber', @logger.logged(:info).last
assert_equal 1, @logger.logged(:error).size
- assert_equal 'Could not log "my_log_subscriber.puke" event. RuntimeError: puke', @logger.logged(:error).last
+ assert_equal 'Could not log "puke.my_log_subscriber" event. RuntimeError: puke', @logger.logged(:error).last
end
end \ No newline at end of file