aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile11
-rw-r--r--actionmailer/actionmailer.gemspec2
-rw-r--r--actionmailer/lib/action_mailer/mail_helper.rb3
-rw-r--r--actionpack/lib/abstract_controller/callbacks.rb4
-rw-r--r--actionpack/lib/action_controller/log_subscriber.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb6
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb14
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb1
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb8
-rw-r--r--actionpack/lib/action_view/helpers/asset_url_helper.rb3
-rw-r--r--actionpack/lib/action_view/test_case.rb4
-rw-r--r--actionpack/test/controller/filters_test.rb15
-rw-r--r--actionpack/test/controller/integration_test.rb18
-rw-r--r--actionpack/test/controller/test_case_test.rb5
-rw-r--r--actionpack/test/dispatch/routing/route_set_test.rb11
-rw-r--r--actionpack/test/template/asset_tag_helper_test.rb11
-rw-r--r--activemodel/lib/active_model/callbacks.rb2
-rw-r--r--activemodel/lib/active_model/lint.rb2
-rw-r--r--activemodel/lib/active_model/validations/callbacks.rb5
-rw-r--r--activemodel/test/cases/railtie_test.rb1
-rw-r--r--activemodel/test/cases/validations_test.rb2
-rw-r--r--activerecord/CHANGELOG.md9
-rw-r--r--activerecord/RUNNING_UNIT_TESTS.rdoc42
-rw-r--r--activerecord/Rakefile2
-rw-r--r--activerecord/lib/active_record/associations.rb46
-rw-r--r--activerecord/lib/active_record/associations/join_dependency/join_association.rb8
-rw-r--r--activerecord/lib/active_record/attribute_assignment.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb3
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb12
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/cast.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb8
-rw-r--r--activerecord/lib/active_record/errors.rb9
-rw-r--r--activerecord/lib/active_record/inheritance.rb7
-rw-r--r--activerecord/lib/active_record/railtie.rb2
-rw-r--r--activerecord/lib/active_record/reflection.rb8
-rw-r--r--activerecord/lib/active_record/relation.rb6
-rw-r--r--activerecord/lib/active_record/test_case.rb4
-rw-r--r--activerecord/lib/active_record/transactions.rb4
-rw-r--r--activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb19
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb14
-rw-r--r--activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb36
-rw-r--r--activerecord/test/cases/attribute_methods_test.rb9
-rw-r--r--activerecord/test/cases/base_test.rb2
-rw-r--r--activerecord/test/cases/callbacks_test.rb2
-rw-r--r--activerecord/test/cases/counter_cache_test.rb12
-rw-r--r--activerecord/test/cases/migration/change_schema_test.rb2
-rw-r--r--activerecord/test/cases/persistence_test.rb2
-rw-r--r--activerecord/test/cases/primary_keys_test.rb2
-rw-r--r--activerecord/test/cases/reflection_test.rb6
-rw-r--r--activerecord/test/cases/relation_test.rb5
-rw-r--r--activerecord/test/models/reply.rb1
-rw-r--r--activerecord/test/schema/schema.rb1
-rw-r--r--activesupport/CHANGELOG.md13
-rw-r--r--activesupport/activesupport.gemspec2
-rw-r--r--activesupport/lib/active_support/callbacks.rb650
-rw-r--r--activesupport/lib/active_support/concern.rb8
-rw-r--r--activesupport/lib/active_support/core_ext/class/attribute.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/marshal.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/range/include_range.rb2
-rw-r--r--activesupport/lib/active_support/hash_with_indifferent_access.rb12
-rw-r--r--activesupport/lib/active_support/notifications/fanout.rb7
-rw-r--r--activesupport/lib/active_support/test_case.rb24
-rw-r--r--activesupport/lib/active_support/testing/autorun.rb4
-rw-r--r--activesupport/lib/active_support/testing/isolation.rb17
-rw-r--r--activesupport/lib/active_support/testing/tagged_logging.rb2
-rw-r--r--activesupport/test/callbacks_test.rb103
-rw-r--r--activesupport/test/concern_test.rb14
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb9
-rw-r--r--activesupport/test/notifications_test.rb22
-rw-r--r--activesupport/test/test_case_test.rb110
-rw-r--r--activesupport/test/test_test.rb2
-rw-r--r--guides/code/getting_started/app/assets/javascripts/application.js3
-rw-r--r--guides/source/upgrading_ruby_on_rails.md55
-rw-r--r--railties/CHANGELOG.md2
-rw-r--r--railties/lib/rails/commands/console.rb4
-rw-r--r--railties/lib/rails/generators/app_base.rb2
-rw-r--r--railties/lib/rails/generators/rails/app/app_generator.rb10
-rw-r--r--railties/lib/rails/generators/rails/app/templates/Gemfile2
-rw-r--r--railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt3
-rw-r--r--railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt2
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec1
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/bin/rails.tt2
-rw-r--r--railties/lib/rails/generators/rails/plugin_new/templates/rails/javascripts.js3
-rw-r--r--railties/lib/rails/rack/debugger.rb4
-rw-r--r--railties/lib/rails/tasks.rb2
-rw-r--r--railties/test/application/rake_test.rb4
-rw-r--r--railties/test/application/test_runner_test.rb20
-rw-r--r--railties/test/generators/app_generator_test.rb3
-rw-r--r--railties/test/generators/plugin_new_generator_test.rb4
90 files changed, 940 insertions, 611 deletions
diff --git a/Gemfile b/Gemfile
index 661ef25a57..b0f91c6dac 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,7 +2,11 @@ source 'https://rubygems.org'
gemspec
-gem 'mocha', '~> 0.13.0', require: false
+# This needs to be with require false as it is
+# loaded after loading the test library to
+# ensure correct loading order
+gem 'mocha', '~> 0.14', require: false
+
gem 'rack-cache', '~> 1.2'
gem 'bcrypt-ruby', '~> 3.0.0'
gem 'jquery-rails', '~> 2.2.0'
@@ -60,11 +64,6 @@ platforms :jruby do
gem 'json'
gem 'activerecord-jdbcsqlite3-adapter', '>= 1.2.7'
- # This is needed by now to let tests work on JRuby
- # TODO: When the JRuby guys merge jruby-openssl in
- # jruby this will be removed
- gem 'jruby-openssl'
-
group :db do
gem 'activerecord-jdbcmysql-adapter', '>= 1.2.7'
gem 'activerecord-jdbcpostgresql-adapter', '>= 1.2.7'
diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec
index 67ec0d1097..c56b6979ef 100644
--- a/actionmailer/actionmailer.gemspec
+++ b/actionmailer/actionmailer.gemspec
@@ -21,5 +21,5 @@ Gem::Specification.new do |s|
s.add_dependency 'actionpack', version
- s.add_dependency 'mail', '~> 2.5.3'
+ s.add_dependency 'mail', '~> 2.5.4'
end
diff --git a/actionmailer/lib/action_mailer/mail_helper.rb b/actionmailer/lib/action_mailer/mail_helper.rb
index 892eb2472f..8d6e082d02 100644
--- a/actionmailer/lib/action_mailer/mail_helper.rb
+++ b/actionmailer/lib/action_mailer/mail_helper.rb
@@ -49,8 +49,9 @@ module ActionMailer
end
end
+ indentation = " " * indent
sentences.map { |sentence|
- "#{" " * indent}#{sentence.join(' ')}"
+ "#{indentation}#{sentence.join(' ')}"
}.join "\n"
end
end
diff --git a/actionpack/lib/abstract_controller/callbacks.rb b/actionpack/lib/abstract_controller/callbacks.rb
index 599fff81c2..19cfd7dae1 100644
--- a/actionpack/lib/abstract_controller/callbacks.rb
+++ b/actionpack/lib/abstract_controller/callbacks.rb
@@ -8,7 +8,9 @@ module AbstractController
include ActiveSupport::Callbacks
included do
- define_callbacks :process_action, :terminator => "response_body", :skip_after_callbacks_if_terminated => true
+ define_callbacks :process_action,
+ terminator: ->(controller,_) { controller.response_body },
+ skip_after_callbacks_if_terminated: true
end
# Override AbstractController::Base's process_action to run the
diff --git a/actionpack/lib/action_controller/log_subscriber.rb b/actionpack/lib/action_controller/log_subscriber.rb
index 7318c8b7ec..9279d8bcea 100644
--- a/actionpack/lib/action_controller/log_subscriber.rb
+++ b/actionpack/lib/action_controller/log_subscriber.rb
@@ -33,7 +33,7 @@ module ActionController
end
def halted_callback(event)
- info("Filter chain halted as #{event.payload[:filter]} rendered or redirected")
+ info("Filter chain halted as #{event.payload[:filter].inspect} rendered or redirected")
end
def send_file(event)
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index e5f1ad63c2..0cbbbbe1fd 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -499,12 +499,6 @@ module ActionController
process(action, "HEAD", *args)
end
- # Simulate a OPTIONS request with the given parameters and set/volley the response.
- # See +get+ for more details.
- def options(action, *args)
- process(action, "OPTIONS", *args)
- end
-
def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
@request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
@request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index 7e56feb90a..89003e7a5e 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -243,19 +243,13 @@ module ActionDispatch
session = Request::Session.find(env) || {}
flash_hash = env[KEY]
- if flash_hash
- if !flash_hash.empty? || session.key?('flash')
- session["flash"] = flash_hash.to_session_value
- new_hash = flash_hash.dup
- else
- new_hash = flash_hash
- end
-
- env[KEY] = new_hash
+ if flash_hash && (flash_hash.present? || session.key?('flash'))
+ session["flash"] = flash_hash.to_session_value
+ env[KEY] = flash_hash.dup
end
if (!session.respond_to?(:loaded?) || session.loaded?) && # (reset_session uses {}, which doesn't implement #loaded?)
- session.key?('flash') && session['flash'].nil?
+ session.key?('flash') && session['flash'].nil?
session.delete('flash')
end
end
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 342b6ec23d..3ae9f92c0b 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -218,6 +218,7 @@ module ActionDispatch
keys -= t.url_options.keys if t.respond_to?(:url_options)
keys -= options.keys
end
+ keys -= inner_options.keys
result.merge!(Hash[keys.zip(args)])
end
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index 56c31255f3..70b42ccd1b 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -62,12 +62,6 @@ module ActionDispatch
process :head, path, parameters, headers_or_env
end
- # Performs a OPTIONS request with the given parameters. See +#get+ for
- # more details.
- def options(path, parameters = nil, headers_or_env = nil)
- process :options, path, parameters, headers_or_env
- end
-
# Performs an XMLHttpRequest request with the given parameters, mirroring
# a request from the Prototype library.
#
@@ -342,7 +336,7 @@ module ActionDispatch
@integration_session = Integration::Session.new(app)
end
- %w(get post patch put head delete options cookies assigns
+ %w(get post patch put head delete cookies assigns
xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
define_method(method) do |*args|
reset! unless integration_session
diff --git a/actionpack/lib/action_view/helpers/asset_url_helper.rb b/actionpack/lib/action_view/helpers/asset_url_helper.rb
index 71b78cf0b5..b5f2df76ab 100644
--- a/actionpack/lib/action_view/helpers/asset_url_helper.rb
+++ b/actionpack/lib/action_view/helpers/asset_url_helper.rb
@@ -193,7 +193,6 @@ module ActionView
request = self.request if respond_to?(:request)
host = config.asset_host if defined? config.asset_host
host ||= request.base_url if request && options[:protocol] == :request
- return unless host
if host.respond_to?(:call)
arity = host.respond_to?(:arity) ? host.arity : host.method(:call).arity
@@ -204,6 +203,8 @@ module ActionView
host = host % (Zlib.crc32(source) % 4)
end
+ return unless host
+
if host =~ URI_REGEXP
host
else
diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb
index 10b487f37a..3145446114 100644
--- a/actionpack/lib/action_view/test_case.rb
+++ b/actionpack/lib/action_view/test_case.rb
@@ -211,7 +211,9 @@ module ActionView
alias_method :_view, :view
INTERNAL_IVARS = [
- :@__name__,
+ :@NAME,
+ :@failures,
+ :@assertions,
:@__io__,
:@_assertion_wrapped,
:@_assertions,
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index 3b79161ad3..4c82625e8e 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -10,7 +10,7 @@ class ActionController::Base
def before_filters
filters = _process_action_callbacks.select { |c| c.kind == :before }
- filters.map! { |c| c.instance_variable_get(:@raw_filter) }
+ filters.map! { |c| c.raw_filter }
end
end
@@ -213,6 +213,14 @@ class FilterTest < ActionController::TestCase
before_filter :clean_up_tmp, :if => Proc.new { |c| false }
end
+ class ConditionalOptionsSkipFilter < ConditionalFilterController
+ before_filter :ensure_login
+ before_filter :clean_up_tmp
+
+ skip_before_filter :ensure_login, if: -> { false }
+ skip_before_filter :clean_up_tmp, if: -> { true }
+ end
+
class PrependingController < TestController
prepend_before_filter :wonderful_life
# skip_before_filter :fire_flash
@@ -593,6 +601,11 @@ class FilterTest < ActionController::TestCase
assert_equal %w( ensure_login ), assigns["ran_filter"]
end
+ def test_running_conditional_skip_options
+ test_process(ConditionalOptionsSkipFilter)
+ assert_equal %w( ensure_login ), assigns["ran_filter"]
+ end
+
def test_running_collection_condition_filters
test_process(ConditionalCollectionFilterController)
assert_equal %w( ensure_login ), assigns["ran_filter"]
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index c3bdf74d93..f7ec6d71b3 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -117,12 +117,6 @@ class SessionTest < ActiveSupport::TestCase
@session.head(path,params,headers)
end
- def test_options
- path = "/index"; params = "blah"; headers = {:location => 'blah'}
- @session.expects(:process).with(:options,path,params,headers)
- @session.options(path,params,headers)
- end
-
def test_xml_http_request_get
path = "/index"; params = "blah"; headers = {:location => 'blah'}
headers_after_xhr = headers.merge(
@@ -183,16 +177,6 @@ class SessionTest < ActiveSupport::TestCase
@session.xml_http_request(:head,path,params,headers)
end
- def test_xml_http_request_options
- path = "/index"; params = "blah"; headers = {:location => 'blah'}
- headers_after_xhr = headers.merge(
- "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest",
- "HTTP_ACCEPT" => "text/javascript, text/html, application/xml, text/xml, */*"
- )
- @session.expects(:process).with(:options,path,params,headers_after_xhr)
- @session.xml_http_request(:options,path,params,headers)
- end
-
def test_xml_http_request_override_accept
path = "/index"; params = "blah"; headers = {:location => 'blah', "HTTP_ACCEPT" => "application/xml"}
headers_after_xhr = headers.merge(
@@ -250,7 +234,7 @@ class IntegrationTestUsesCorrectClass < ActionDispatch::IntegrationTest
@integration_session.stubs(:generic_url_rewriter)
@integration_session.stubs(:process)
- %w( get post head patch put delete options ).each do |verb|
+ %w( get post head patch put delete ).each do |verb|
assert_nothing_raised("'#{verb}' should use integration test methods") { __send__(verb, '/') }
end
end
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 38b9794b4d..7c27458f46 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -201,11 +201,6 @@ XML
assert_raise(NoMethodError) { head :test_params, "document body", :id => 10 }
end
- def test_options
- options :test_params
- assert_equal 200, @response.status
- end
-
def test_process_without_flash
process :set_flash
assert_equal '><', flash['test']
diff --git a/actionpack/test/dispatch/routing/route_set_test.rb b/actionpack/test/dispatch/routing/route_set_test.rb
index d57b1a5637..0e488d2b88 100644
--- a/actionpack/test/dispatch/routing/route_set_test.rb
+++ b/actionpack/test/dispatch/routing/route_set_test.rb
@@ -69,6 +69,17 @@ module ActionDispatch
end
end
+ test "explicit keys win over implicit keys" do
+ draw do
+ resources :foo do
+ resources :bar, to: SimpleApp.new('foo#show')
+ end
+ end
+
+ assert_equal '/foo/1/bar/2', url_helpers.foo_bar_path(1, 2)
+ assert_equal '/foo/1/bar/2', url_helpers.foo_bar_path(2, foo_id: 1)
+ end
+
private
def clear!
@set.clear!
diff --git a/actionpack/test/template/asset_tag_helper_test.rb b/actionpack/test/template/asset_tag_helper_test.rb
index 11614a45dc..67f593c22f 100644
--- a/actionpack/test/template/asset_tag_helper_test.rb
+++ b/actionpack/test/template/asset_tag_helper_test.rb
@@ -530,6 +530,17 @@ class AssetTagHelperTest < ActionView::TestCase
assert_equal copy, source
end
+ def test_image_path_with_asset_host_proc_returning_nil
+ @controller.config.asset_host = Proc.new do |source|
+ unless source.end_with?("tiff")
+ "cdn.example.com"
+ end
+ end
+
+ assert_equal "/images/file.tiff", image_path("file.tiff")
+ assert_equal "http://cdn.example.com/images/file.png", image_path("file.png")
+ end
+
def test_caching_image_path_with_caching_and_proc_asset_host_using_request
@controller.config.asset_host = Proc.new do |source, request|
if request.ssl?
diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb
index 94d2181e4d..8b09f8b203 100644
--- a/activemodel/lib/active_model/callbacks.rb
+++ b/activemodel/lib/active_model/callbacks.rb
@@ -100,7 +100,7 @@ module ActiveModel
def define_model_callbacks(*callbacks)
options = callbacks.extract_options!
options = {
- terminator: "result == false",
+ terminator: ->(_,result) { result == false },
skip_after_callbacks_if_terminated: true,
scope: [:kind, :name],
only: [:before, :around, :after]
diff --git a/activemodel/lib/active_model/lint.rb b/activemodel/lib/active_model/lint.rb
index 1be2913f0b..46b446dc08 100644
--- a/activemodel/lib/active_model/lint.rb
+++ b/activemodel/lib/active_model/lint.rb
@@ -98,7 +98,7 @@ module ActiveModel
private
def model
- assert @model.respond_to?(:to_model), "The object should respond_to to_model"
+ assert @model.respond_to?(:to_model), "The object should respond to to_model"
@model.to_model
end
diff --git a/activemodel/lib/active_model/validations/callbacks.rb b/activemodel/lib/active_model/validations/callbacks.rb
index 8de36b4f8b..cabb9482f2 100644
--- a/activemodel/lib/active_model/validations/callbacks.rb
+++ b/activemodel/lib/active_model/validations/callbacks.rb
@@ -22,7 +22,10 @@ module ActiveModel
included do
include ActiveSupport::Callbacks
- define_callbacks :validation, terminator: "result == false", skip_after_callbacks_if_terminated: true, scope: [:kind, :name]
+ define_callbacks :validation,
+ terminator: ->(_,result) { result == false },
+ skip_after_callbacks_if_terminated: true,
+ scope: [:kind, :name]
end
module ClassMethods
diff --git a/activemodel/test/cases/railtie_test.rb b/activemodel/test/cases/railtie_test.rb
index a0cd1402b1..d44a3448df 100644
--- a/activemodel/test/cases/railtie_test.rb
+++ b/activemodel/test/cases/railtie_test.rb
@@ -9,7 +9,6 @@ class RailtieTest < ActiveModel::TestCase
@app ||= Class.new(::Rails::Application) do
config.eager_load = false
- config.logger = Logger.new(STDOUT)
end
end
diff --git a/activemodel/test/cases/validations_test.rb b/activemodel/test/cases/validations_test.rb
index 3241a03b53..3e84297cc2 100644
--- a/activemodel/test/cases/validations_test.rb
+++ b/activemodel/test/cases/validations_test.rb
@@ -166,7 +166,7 @@ class ValidationsTest < ActiveModel::TestCase
def test_invalid_validator
Topic.validate :i_dont_exist
- assert_raise(NameError) do
+ assert_raises(NoMethodError) do
t = Topic.new
t.valid?
end
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 789e7f41f9..19d2195bca 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,12 @@
+* Also support extensions in PostgreSQL 9.1. This feature has been supported since 9.1.
+
+ *kennyj*
+
+* Deprecate `ConnectionAdapters::SchemaStatements#distinct`,
+ as it is no longer used by internals.
+
+ *Ben Woosley#
+
* Fix pending migrations error when loading schema and `ActiveRecord::Base.table_name_prefix`
is not blank.
diff --git a/activerecord/RUNNING_UNIT_TESTS.rdoc b/activerecord/RUNNING_UNIT_TESTS.rdoc
index 2f3d516c43..c3ee34da55 100644
--- a/activerecord/RUNNING_UNIT_TESTS.rdoc
+++ b/activerecord/RUNNING_UNIT_TESTS.rdoc
@@ -1,31 +1,43 @@
== Setup
-If you don't have the environment set make sure to read
-
- http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#testing-active-record
+If you don't have an environment for running tests, read
+http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#setting-up-a-development-environment
== Running the Tests
-You can run a particular test file from the command line, e.g.
+To run a specific test:
+
+ $ ruby -Itest test/cases/base_test.rb -n method_name
+
+To run a set of tests:
$ ruby -Itest test/cases/base_test.rb
-To run a specific test:
+You can also run tests that depend upon a specific database backend. For
+example:
- $ ruby -Itest test/cases/base_test.rb -n test_something_works
+ $ bundle exec rake test_sqlite3
-You can run with a database other than the default you set in test/config.yml, using the ARCONN
-environment variable:
+Simply executing <tt>bundle exec rake test</tt> is equivalent to the following:
- $ ARCONN=postgresql ruby -Itest test/cases/base_test.rb
+ $ bundle exec rake test_mysql
+ $ bundle exec rake test_mysql2
+ $ bundle exec rake test_postgresql
+ $ bundle exec rake test_sqlite3
-You can run all the tests for a given database via rake:
+There should be tests available for each database backend listed in the {Config
+File}[rdoc-label:label-Config+File]. (the exact set of available tests is
+defined in +Rakefile+)
- $ rake test_mysql
+== Config File
-The 'rake test' task will run all the tests for mysql, mysql2, sqlite3 and postgresql.
+If +test/config.yml+ is present, it's parameters are obeyed. Otherwise, the
+parameters in +test/config.example.yml+ are obeyed.
-== Custom Config file
+You can override the +connections:+ parameter in either file using the +ARCONN+
+(Active Record CONNection) environment variable:
+
+ $ ARCONN=postgresql ruby -Itest test/cases/base_test.rb
-By default, the config file is expected to be at the path test/config.yml. You can specify a
-custom location with the ARCONFIG environment variable.
+You can specify a custom location for the config file using the +ARCONFIG+
+environment variable.
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index 0523314128..cd73489cbe 100644
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -125,8 +125,6 @@ namespace :postgresql do
%w(arunit arunit2).each do |db|
if version < "9.1.0"
puts "Please prepare hstore data type. See http://www.postgresql.org/docs/9.0/static/hstore.html"
- else
- %x( psql #{config[db]['database']} -c "CREATE EXTENSION hstore;" )
end
end
end
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index b71200cd2a..3490057298 100644
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -172,7 +172,7 @@ module ActiveRecord
@association_cache[name] = association
end
- # Associations are a set of macro-like class methods for tying objects together through
+ # \Associations are a set of macro-like class methods for tying objects together through
# foreign keys. They express relationships like "Project has one Project Manager"
# or "Project belongs to a Portfolio". Each macro adds a number of methods to the
# class which are specialized according to the collection or association symbol and the
@@ -365,11 +365,11 @@ module ActiveRecord
# there is some special behavior you should be aware of, mostly involving the saving of
# associated objects.
#
- # You can set the :autosave option on a <tt>has_one</tt>, <tt>belongs_to</tt>,
+ # You can set the <tt>:autosave</tt> option on a <tt>has_one</tt>, <tt>belongs_to</tt>,
# <tt>has_many</tt>, or <tt>has_and_belongs_to_many</tt> association. Setting it
# to +true+ will _always_ save the members, whereas setting it to +false+ will
- # _never_ save the members. More details about :autosave option is available at
- # autosave_association.rb .
+ # _never_ save the members. More details about <tt>:autosave</tt> option is available at
+ # AutosaveAssociation.
#
# === One-to-one associations
#
@@ -402,7 +402,7 @@ module ActiveRecord
#
# == Customizing the query
#
- # Associations are built from <tt>Relation</tt>s, and you can use the <tt>Relation</tt> syntax
+ # \Associations are built from <tt>Relation</tt>s, and you can use the <tt>Relation</tt> syntax
# to customize them. For example, to add a condition:
#
# class Blog < ActiveRecord::Base
@@ -588,10 +588,10 @@ module ActiveRecord
#
# If you do not set the +:inverse_of+ record, the association will do its
# best to match itself up with the correct inverse. Automatic +:inverse_of+
- # detection only works on :has_many, :has_one, and :belongs_to associations.
+ # detection only works on +has_many+, +has_one+, and +belongs_to+ associations.
#
# Extra options on the associations, as defined in the
- # +AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS+ constant, will
+ # <tt>AssociationReflection::INVALID_AUTOMATIC_INVERSE_OPTIONS</tt> constant, will
# also prevent the association's inverse from being found automatically.
#
# The automatic guessing of the inverse association uses a heuristic based
@@ -605,7 +605,7 @@ module ActiveRecord
# belongs_to :tag, automatic_inverse_of: false
# end
#
- # == Nested Associations
+ # == Nested \Associations
#
# You can actually specify *any* association with the <tt>:through</tt> option, including an
# association which has a <tt>:through</tt> option itself. For example:
@@ -648,7 +648,7 @@ module ActiveRecord
# add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
# intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
#
- # == Polymorphic Associations
+ # == Polymorphic \Associations
#
# Polymorphic associations on models are not restricted on what types of models they
# can be associated with. Rather, they specify an interface that a +has_many+ association
@@ -810,7 +810,7 @@ module ActiveRecord
# For example if all the addressables are either of class Person or Company then a total
# of 3 queries will be executed. The list of addressable types to load is determined on
# the back of the addresses loaded. This is not supported if Active Record has to fallback
- # to the previous implementation of eager loading and will raise ActiveRecord::EagerLoadPolymorphicError.
+ # to the previous implementation of eager loading and will raise <tt>ActiveRecord::EagerLoadPolymorphicError</tt>.
# The reason is that the parent model's type is a column value so its corresponding table
# name cannot be put in the +FROM+/+JOIN+ clauses of that query.
#
@@ -1045,7 +1045,7 @@ module ActiveRecord
# An empty array is returned if none are found.
# [collection<<(object, ...)]
# Adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
- # Note that this operation instantly fires update sql without waiting for the save or update call on the
+ # Note that this operation instantly fires update SQL without waiting for the save or update call on the
# parent object, unless the parent object is a new record.
# [collection.delete(object, ...)]
# Removes one or more objects from the collection by setting their foreign keys to +NULL+.
@@ -1081,10 +1081,10 @@ module ActiveRecord
# [collection.size]
# Returns the number of associated objects.
# [collection.find(...)]
- # Finds an associated object according to the same rules as ActiveRecord::Base.find.
+ # Finds an associated object according to the same rules as <tt>ActiveRecord::Base.find</tt>.
# [collection.exists?(...)]
# Checks whether an associated object with the given conditions exists.
- # Uses the same rules as ActiveRecord::Base.exists?.
+ # Uses the same rules as <tt>ActiveRecord::Base.exists?</tt>.
# [collection.build(attributes = {}, ...)]
# Returns one or more new objects of the collection type that have been instantiated
# with +attributes+ and linked to this object through a foreign key, but have not yet
@@ -1103,7 +1103,7 @@ module ActiveRecord
#
# === Example
#
- # Example: A Firm class declares <tt>has_many :clients</tt>, which will add:
+ # A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add:
# * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>)
# * <tt>Firm#clients<<</tt>
# * <tt>Firm#clients.delete</tt>
@@ -1137,8 +1137,8 @@ module ActiveRecord
# Controls what happens to the associated objects when
# their owner is destroyed. Note that these are implemented as
# callbacks, and Rails executes callbacks in order. Therefore, other
- # similar callbacks may affect the :dependent behavior, and the
- # :dependent behavior may affect other callbacks.
+ # similar callbacks may affect the <tt>:dependent</tt> behavior, and the
+ # <tt>:dependent</tt> behavior may affect other callbacks.
#
# * <tt>:destroy</tt> causes all the associated objects to also be destroyed.
# * <tt>:delete_all</tt> causes all the associated objects to be deleted directly from the database (so callbacks will not be executed).
@@ -1184,8 +1184,8 @@ module ActiveRecord
# If true, always save the associated objects or destroy them if marked for destruction,
# when saving the parent object. If false, never save or destroy the associated objects.
# By default, only save associated objects that are new records. This option is implemented as a
- # before_save callback. Because callbacks are run in the order they are defined, associated objects
- # may need to be explicitly saved in any user-defined before_save callbacks.
+ # +before_save+ callback. Because callbacks are run in the order they are defined, associated objects
+ # may need to be explicitly saved in any user-defined +before_save+ callbacks.
#
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
# [:inverse_of]
@@ -1210,7 +1210,7 @@ module ActiveRecord
# Specifies a one-to-one association with another class. This method should only be used
# if the other class contains the foreign key. If the current class contains the foreign key,
# then you should use +belongs_to+ instead. See also ActiveRecord::Associations::ClassMethods's overview
- # on when to use has_one and when to use belongs_to.
+ # on when to use +has_one+ and when to use +belongs_to+.
#
# The following methods for retrieval and query of a single associated object will be added:
#
@@ -1378,7 +1378,7 @@ module ActiveRecord
# class is created and decremented when it's destroyed. This requires that a column
# named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
# is used on the associate class (such as a Post class) - that is the migration for
- # <tt>#{table_name}_count</tt> is created on the associate class (such that Post.comments_count will
+ # <tt>#{table_name}_count</tt> is created on the associate class (such that <tt>Post.comments_count</tt> will
# return the count cached, see note below). You can also specify a custom counter
# cache column by providing a column name instead of a +true+/+false+ value to this
# option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
@@ -1460,7 +1460,7 @@ module ActiveRecord
# [collection<<(object, ...)]
# Adds one or more objects to the collection by creating associations in the join table
# (<tt>collection.push</tt> and <tt>collection.concat</tt> are aliases to this method).
- # Note that this operation instantly fires update sql without waiting for the save or update call on the
+ # Note that this operation instantly fires update SQL without waiting for the save or update call on the
# parent object, unless the parent object is a new record.
# [collection.delete(object, ...)]
# Removes one or more objects from the collection by removing their associations from the join table.
@@ -1483,10 +1483,10 @@ module ActiveRecord
# [collection.find(id)]
# Finds an associated object responding to the +id+ and that
# meets the condition that it has to be associated with this object.
- # Uses the same rules as ActiveRecord::Base.find.
+ # Uses the same rules as <tt>ActiveRecord::Base.find</tt>.
# [collection.exists?(...)]
# Checks whether an associated object with the given conditions exists.
- # Uses the same rules as ActiveRecord::Base.exists?.
+ # Uses the same rules as <tt>ActiveRecord::Base.exists?</tt>.
# [collection.build(attributes = {})]
# Returns a new object of the collection type that has been instantiated
# with +attributes+ and linked to this object through the join table, but has not yet been saved.
diff --git a/activerecord/lib/active_record/associations/join_dependency/join_association.rb b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
index e4d17451dc..b81aecb4e5 100644
--- a/activerecord/lib/active_record/associations/join_dependency/join_association.rb
+++ b/activerecord/lib/active_record/associations/join_dependency/join_association.rb
@@ -106,12 +106,16 @@ module ActiveRecord
]
end
- scope_chain_items.each do |item|
+ constraint = scope_chain_items.inject(constraint) do |chain, item|
unless item.is_a?(Relation)
item = ActiveRecord::Relation.new(reflection.klass, table).instance_exec(self, &item)
end
- constraint = constraint.and(item.arel.constraints) unless item.arel.constraints.empty?
+ if item.arel.constraints.empty?
+ chain
+ else
+ chain.and(item.arel.constraints)
+ end
end
manager.from(join(table, constraint))
diff --git a/activerecord/lib/active_record/attribute_assignment.rb b/activerecord/lib/active_record/attribute_assignment.rb
index e536f5ebcc..75377bba57 100644
--- a/activerecord/lib/active_record/attribute_assignment.rb
+++ b/activerecord/lib/active_record/attribute_assignment.rb
@@ -1,3 +1,4 @@
+require 'active_model/forbidden_attributes_protection'
module ActiveRecord
module AttributeAssignment
@@ -44,7 +45,7 @@ module ActiveRecord
if respond_to?("#{k}=")
raise
else
- raise UnknownAttributeError, "unknown attribute: #{k}"
+ raise UnknownAttributeError.new(self, k)
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
index 6e1f43cce6..8ffe150de6 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
@@ -710,6 +710,7 @@ module ActiveRecord
# distinct("posts.id", ["posts.created_at desc"])
#
def distinct(columns, order_by)
+ ActiveSupport::Deprecation.warn("#distinct is deprecated and shall be removed from future releases.")
"DISTINCT #{columns_for_distinct(columns, order_by)}"
end
@@ -718,7 +719,7 @@ module ActiveRecord
# require the order columns appear in the SELECT.
#
# columns_for_distinct("posts.id", ["posts.created_at desc"])
- def columns_for_distinct(columns, orders)
+ def columns_for_distinct(columns, orders) # :nodoc:
columns
end
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index f23521430d..1826d88500 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -393,6 +393,14 @@ module ActiveRecord
TYPES[new] = TYPES[old]
end
+ def self.find_type(field)
+ if field.type == Mysql::Field::TYPE_TINY && field.length > 1
+ TYPES[Mysql::Field::TYPE_LONG]
+ else
+ TYPES.fetch(field.type) { Fields::Identity.new }
+ end
+ end
+
register_type Mysql::Field::TYPE_TINY, Fields::Boolean.new
register_type Mysql::Field::TYPE_LONG, Fields::Integer.new
alias_type Mysql::Field::TYPE_LONGLONG, Mysql::Field::TYPE_LONG
@@ -425,9 +433,7 @@ module ActiveRecord
if field.decimals > 0
types[field.name] = Fields::Decimal.new
else
- types[field.name] = Fields::TYPES.fetch(field.type) {
- Fields::Identity.new
- }
+ types[field.name] = Fields.find_type field
end
}
result_set = ActiveRecord::Result.new(types.keys, result.to_a, types)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
index a9ef11aa83..a73f0ac57f 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/cast.rb
@@ -60,7 +60,7 @@ module ActiveRecord
end
def json_to_string(object)
- if Hash === object
+ if Hash === object || Array === object
ActiveSupport::JSON.encode(object)
else
object
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index 40a3b82839..e9daa5d7ff 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -30,6 +30,7 @@ module ActiveRecord
when Array
case sql_type
when 'point' then super(PostgreSQLColumn.point_to_string(value))
+ when 'json' then super(PostgreSQLColumn.json_to_string(value))
else
if column.array
"'#{PostgreSQLColumn.array_to_string(value, column, self).gsub(/'/, "''")}'"
@@ -98,6 +99,7 @@ module ActiveRecord
when Array
case column.sql_type
when 'point' then PostgreSQLColumn.point_to_string(value)
+ when 'json' then PostgreSQLColumn.json_to_string(value)
else
return super(value, column) unless column.array
PostgreSQLColumn.array_to_string(value, column, self)
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
index 88b09e7999..d5a603cadc 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -622,9 +622,9 @@ module ActiveRecord
true
end
- # Returns true if pg > 9.2
+ # Returns true if pg > 9.1
def supports_extensions?
- postgresql_version >= 90200
+ postgresql_version >= 90100
end
# Range datatypes weren't introduced until PostgreSQL 9.2
@@ -646,9 +646,9 @@ module ActiveRecord
def extension_enabled?(name)
if supports_extensions?
- res = exec_query "SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL)",
+ res = exec_query "SELECT EXISTS(SELECT * FROM pg_available_extensions WHERE name = '#{name}' AND installed_version IS NOT NULL) as enabled",
'SCHEMA'
- res.column_types['exists'].type_cast res.rows.first.first
+ res.column_types['enabled'].type_cast res.rows.first.first
end
end
diff --git a/activerecord/lib/active_record/errors.rb b/activerecord/lib/active_record/errors.rb
index cd31147414..017b8bace6 100644
--- a/activerecord/lib/active_record/errors.rb
+++ b/activerecord/lib/active_record/errors.rb
@@ -159,6 +159,15 @@ module ActiveRecord
# Raised when unknown attributes are supplied via mass assignment.
class UnknownAttributeError < NoMethodError
+
+ attr_reader :record, :attribute
+
+ def initialize(record, attribute)
+ @record = record
+ @attribute = attribute.to_s
+ super("unknown attribute: #{attribute}")
+ end
+
end
# Raised when an error occurred while doing a mass assignment to an attribute through the
diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index 8df76c7f5f..40976bc29e 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -116,9 +116,10 @@ module ActiveRecord
begin
constant = ActiveSupport::Dependencies.constantize(candidate)
return constant if candidate == constant.to_s
- rescue NameError => e
- # We don't want to swallow NoMethodError < NameError errors
- raise e unless e.instance_of?(NameError)
+ # We don't want to swallow NoMethodError < NameError errors
+ rescue NoMethodError
+ raise
+ rescue NameError
end
end
diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb
index e36888d4a8..31a0ace864 100644
--- a/activerecord/lib/active_record/railtie.rb
+++ b/activerecord/lib/active_record/railtie.rb
@@ -44,7 +44,7 @@ module ActiveRecord
ActiveRecord::Tasks::DatabaseTasks.migrations_paths = Rails.application.paths['db/migrate'].to_a
ActiveRecord::Tasks::DatabaseTasks.fixtures_path = File.join Rails.root, 'test', 'fixtures'
- if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH)
+ if defined?(APP_RAKEFILE) && engine = Rails::Engine.find(find_engine_path(APP_RAKEFILE))
if engine.paths['db/migrate'].existent
ActiveRecord::Tasks::DatabaseTasks.migrations_paths += engine.paths['db/migrate'].to_a
end
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index dc082b96f4..1f76adb367 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -8,7 +8,7 @@ module ActiveRecord
self.reflections = {}
end
- # Reflection enables to interrogate Active Record classes and objects
+ # \Reflection enables to interrogate Active Record classes and objects
# about their associations and aggregations. This information can,
# for example, be used in a form builder that takes an Active Record object
# and creates input fields for all of the attributes depending on their type
@@ -100,7 +100,7 @@ module ActiveRecord
# Returns the hash of options used for the macro.
#
# <tt>composed_of :balance, class_name: 'Money'</tt> returns <tt>{ class_name: "Money" }</tt>
- # <tt>has_many :clients</tt> returns +{}+
+ # <tt>has_many :clients</tt> returns <tt>{}</tt>
attr_reader :options
attr_reader :active_record
@@ -449,8 +449,8 @@ module ActiveRecord
# Checks to see if the reflection doesn't have any options that prevent
# us from being able to guess the inverse automatically. First, the
# +automatic_inverse_of+ option cannot be set to false. Second, we must
- # have :has_many, :has_one, :belongs_to associations. Third, we must
- # not have options such as :polymorphic or :foreign_key which prevent us
+ # have +has_many+, +has_one+, +belongs_to+ associations. Third, we must
+ # not have options such as +:polymorphic+ or +:foreign_key+ which prevent us
# from correctly guessing the inverse association.
#
# Anything with a scope can additionally ruin our attempt at finding an
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
index ae3fa85da9..94ab465cc1 100644
--- a/activerecord/lib/active_record/relation.rb
+++ b/activerecord/lib/active_record/relation.rb
@@ -489,11 +489,13 @@ module ActiveRecord
# User.where(name: 'Oscar').where_values_hash
# # => {name: "Oscar"}
def where_values_hash
- equalities = with_default_scope.where_values.grep(Arel::Nodes::Equality).find_all { |node|
+ scope = with_default_scope
+ equalities = scope.where_values.grep(Arel::Nodes::Equality).find_all { |node|
node.left.relation.name == table_name
}
- binds = Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
+ binds = Hash[scope.bind_values.find_all(&:first).map { |column, v| [column.name, v] }]
+ binds.merge!(Hash[bind_values.find_all(&:first).map { |column, v| [column.name, v] }])
Hash[equalities.map { |where|
name = where.left.name
diff --git a/activerecord/lib/active_record/test_case.rb b/activerecord/lib/active_record/test_case.rb
index e9142481a3..1b4c473bfc 100644
--- a/activerecord/lib/active_record/test_case.rb
+++ b/activerecord/lib/active_record/test_case.rb
@@ -35,8 +35,7 @@ module ActiveRecord
def assert_queries(num = 1, options = {})
ignore_none = options.fetch(:ignore_none) { num == :any }
SQLCounter.clear_log
- yield
- ensure
+ x = yield
the_log = ignore_none ? SQLCounter.log_all : SQLCounter.log
if num == :any
assert_operator the_log.size, :>=, 1, "1 or more queries expected, but none were executed."
@@ -44,6 +43,7 @@ module ActiveRecord
mesg = "#{the_log.size} instead of #{num} queries were executed.#{the_log.size == 0 ? '' : "\nQueries:\n#{the_log.join("\n")}"}"
assert_equal num, the_log.size, mesg
end
+ x
end
def assert_no_queries(&block)
diff --git a/activerecord/lib/active_record/transactions.rb b/activerecord/lib/active_record/transactions.rb
index a5955ccba4..77634b40bb 100644
--- a/activerecord/lib/active_record/transactions.rb
+++ b/activerecord/lib/active_record/transactions.rb
@@ -10,7 +10,9 @@ module ActiveRecord
end
included do
- define_callbacks :commit, :rollback, :terminator => "result == false", :scope => [:kind, :name]
+ define_callbacks :commit, :rollback,
+ terminator: ->(_, result) { result == false },
+ scope: [:kind, :name]
end
# = Active Record Transactions
diff --git a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
index a75883cd3a..4a23287448 100644
--- a/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/mysql/mysql_adapter_test.rb
@@ -95,14 +95,27 @@ module ActiveRecord
assert_equal @conn.default_sequence_name('ex_with_custom_index_type_pk', 'id'), seq
end
+ def test_tinyint_integer_typecasting
+ @conn.exec_query('drop table if exists ex_with_non_boolean_tinyint_column')
+ @conn.exec_query(<<-eosql)
+ CREATE TABLE `ex_with_non_boolean_tinyint_column` (
+ `status` TINYINT(4))
+ eosql
+ insert(@conn, { 'status' => 2 }, 'ex_with_non_boolean_tinyint_column')
+
+ result = @conn.exec_query('SELECT status FROM ex_with_non_boolean_tinyint_column')
+
+ assert_equal 2, result.column_types['status'].type_cast(result.last['status'])
+ end
+
private
- def insert(ctx, data)
+ def insert(ctx, data, table='ex')
binds = data.map { |name, value|
- [ctx.columns('ex').find { |x| x.name == name }, value]
+ [ctx.columns(table).find { |x| x.name == name }, value]
}
columns = binds.map(&:first).map(&:name)
- sql = "INSERT INTO ex (#{columns.join(", ")})
+ sql = "INSERT INTO #{table} (#{columns.join(", ")})
VALUES (#{(['?'] * columns.length).join(', ')})"
ctx.exec_insert(sql, 'SQL', binds)
diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb
index 6fc08ae4f0..f45c7afcc0 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -83,4 +83,18 @@ class PostgresqlJSONTest < ActiveRecord::TestCase
x = JsonDataType.first
assert_equal(nil, x.payload)
end
+
+ def test_select_array_json_value
+ @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')|
+ x = JsonDataType.first
+ assert_equal(['v0', {'k1' => 'v1'}], x.payload)
+ end
+
+ def test_rewrite_array_json_value
+ @connection.execute %q|insert into json_data_type (payload) VALUES ('["v0",{"k1":"v1"}]')|
+ x = JsonDataType.first
+ x.payload = ['v1', {'k2' => 'v2'}, 'v3']
+ assert x.save!
+ end
+
end
diff --git a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
index ff7eb86969..fb88ab7c09 100644
--- a/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/postgresql_adapter_test.rb
@@ -226,8 +226,10 @@ module ActiveRecord
end
def test_distinct_zero_orders
- assert_equal "DISTINCT posts.id",
- @connection.distinct("posts.id", [])
+ assert_deprecated do
+ assert_equal "DISTINCT posts.id",
+ @connection.distinct("posts.id", [])
+ end
end
def test_columns_for_distinct_zero_orders
@@ -236,8 +238,10 @@ module ActiveRecord
end
def test_distinct_one_order
- assert_equal "DISTINCT posts.id, posts.created_at AS alias_0",
- @connection.distinct("posts.id", ["posts.created_at desc"])
+ assert_deprecated do
+ assert_equal "DISTINCT posts.id, posts.created_at AS alias_0",
+ @connection.distinct("posts.id", ["posts.created_at desc"])
+ end
end
def test_columns_for_distinct_one_order
@@ -246,8 +250,10 @@ module ActiveRecord
end
def test_distinct_few_orders
- assert_equal "DISTINCT posts.id, posts.created_at AS alias_0, posts.position AS alias_1",
- @connection.distinct("posts.id", ["posts.created_at desc", "posts.position asc"])
+ assert_deprecated do
+ assert_equal "DISTINCT posts.id, posts.created_at AS alias_0, posts.position AS alias_1",
+ @connection.distinct("posts.id", ["posts.created_at desc", "posts.position asc"])
+ end
end
def test_columns_for_distinct_few_orders
@@ -256,8 +262,10 @@ module ActiveRecord
end
def test_distinct_blank_not_nil_orders
- assert_equal "DISTINCT posts.id, posts.created_at AS alias_0",
- @connection.distinct("posts.id", ["posts.created_at desc", "", " "])
+ assert_deprecated do
+ assert_equal "DISTINCT posts.id, posts.created_at AS alias_0",
+ @connection.distinct("posts.id", ["posts.created_at desc", "", " "])
+ end
end
def test_columns_for_distinct_blank_not_nil_orders
@@ -270,8 +278,10 @@ module ActiveRecord
def order.to_sql
"posts.created_at desc"
end
- assert_equal "DISTINCT posts.id, posts.created_at AS alias_0",
- @connection.distinct("posts.id", [order])
+ assert_deprecated do
+ assert_equal "DISTINCT posts.id, posts.created_at AS alias_0",
+ @connection.distinct("posts.id", [order])
+ end
end
def test_columns_for_distinct_with_arel_order
@@ -284,8 +294,10 @@ module ActiveRecord
end
def test_distinct_with_nulls
- assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls first"])
- assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls last"])
+ assert_deprecated do
+ assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls first"])
+ assert_equal "DISTINCT posts.title, posts.updater_id AS alias_0", @connection.distinct("posts.title", ["posts.updater_id desc nulls last"])
+ end
end
def test_columns_for_distinct_with_nulls
diff --git a/activerecord/test/cases/attribute_methods_test.rb b/activerecord/test/cases/attribute_methods_test.rb
index a181c513ae..f10732ddda 100644
--- a/activerecord/test/cases/attribute_methods_test.rb
+++ b/activerecord/test/cases/attribute_methods_test.rb
@@ -711,6 +711,15 @@ class AttributeMethodsTest < ActiveRecord::TestCase
assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
end
+ def test_bulk_update_raise_unknown_attribute_errro
+ error = assert_raises(ActiveRecord::UnknownAttributeError) {
+ @target.new(:hello => "world")
+ }
+ assert @target, error.record
+ assert "hello", error.attribute
+ assert "unknown attribute: hello", error.message
+ end
+
def test_read_attribute_overwrites_private_method_not_considered_implemented
# simulate a model with a db column that shares its name an inherited
# private method (e.g. Object#system)
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index d20ccaa5ca..15d536daf5 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1236,7 +1236,7 @@ class BasicsTest < ActiveRecord::TestCase
def test_inspect_instance
topic = topics(:first)
- assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", important: nil, approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil, created_at: "#{topic.created_at.to_s(:db)}", updated_at: "#{topic.updated_at.to_s(:db)}">), topic.inspect
+ assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", important: nil, approved: false, replies_count: 1, unique_replies_count: 0, parent_id: nil, parent_title: nil, type: nil, group: nil, created_at: "#{topic.created_at.to_s(:db)}", updated_at: "#{topic.updated_at.to_s(:db)}">), topic.inspect
end
def test_inspect_new_instance
diff --git a/activerecord/test/cases/callbacks_test.rb b/activerecord/test/cases/callbacks_test.rb
index 187cad9599..c8f56e3c73 100644
--- a/activerecord/test/cases/callbacks_test.rb
+++ b/activerecord/test/cases/callbacks_test.rb
@@ -43,7 +43,7 @@ class CallbackDeveloper < ActiveRecord::Base
end
class CallbackDeveloperWithFalseValidation < CallbackDeveloper
- before_validation proc { |model| model.history << [:before_validation, :returning_false]; return false }
+ before_validation proc { |model| model.history << [:before_validation, :returning_false]; false }
before_validation proc { |model| model.history << [:before_validation, :should_never_get_here] }
end
diff --git a/activerecord/test/cases/counter_cache_test.rb b/activerecord/test/cases/counter_cache_test.rb
index ac093251a5..61f9d4cdae 100644
--- a/activerecord/test/cases/counter_cache_test.rb
+++ b/activerecord/test/cases/counter_cache_test.rb
@@ -51,6 +51,18 @@ class CounterCacheTest < ActiveRecord::TestCase
end
end
+ test 'reset multiple association counters' do
+ Topic.increment_counter(:replies_count, @topic.id)
+ assert_difference '@topic.reload.replies_count', -1 do
+ Topic.reset_counters(@topic.id, :replies, :unique_replies)
+ end
+
+ Topic.increment_counter(:unique_replies_count, @topic.id)
+ assert_difference '@topic.reload.unique_replies_count', -1 do
+ Topic.reset_counters(@topic.id, :replies, :unique_replies)
+ end
+ end
+
test "reset counters with string argument" do
Topic.increment_counter('replies_count', @topic.id)
diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb
index cad759bba9..54fff8a0f5 100644
--- a/activerecord/test/cases/migration/change_schema_test.rb
+++ b/activerecord/test/cases/migration/change_schema_test.rb
@@ -235,7 +235,7 @@ module ActiveRecord
end
end
- def test_keeping_default_and_notnull_constaint_on_change
+ def test_keeping_default_and_notnull_constraints_on_change
connection.create_table :testings do |t|
t.column :title, :string
end
diff --git a/activerecord/test/cases/persistence_test.rb b/activerecord/test/cases/persistence_test.rb
index db3bb56f1f..c4a72ed3bc 100644
--- a/activerecord/test/cases/persistence_test.rb
+++ b/activerecord/test/cases/persistence_test.rb
@@ -18,7 +18,7 @@ require 'models/pet'
require 'models/toy'
require 'rexml/document'
-class PersistencesTest < ActiveRecord::TestCase
+class PersistenceTest < ActiveRecord::TestCase
fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts, :minivans, :pets, :toys
# Oracle UPDATE does not support ORDER BY
diff --git a/activerecord/test/cases/primary_keys_test.rb b/activerecord/test/cases/primary_keys_test.rb
index 8e5379cb1f..aa125c70c5 100644
--- a/activerecord/test/cases/primary_keys_test.rb
+++ b/activerecord/test/cases/primary_keys_test.rb
@@ -205,7 +205,7 @@ if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
class PrimaryKeyWithAnsiQuotesTest < ActiveRecord::TestCase
self.use_transactional_fixtures = false
- def test_primaery_key_method_with_ansi_quotes
+ def test_primary_key_method_with_ansi_quotes
con = ActiveRecord::Base.connection
con.execute("SET SESSION sql_mode='ANSI_QUOTES'")
assert_equal "id", con.primary_key("topics")
diff --git a/activerecord/test/cases/reflection_test.rb b/activerecord/test/cases/reflection_test.rb
index a9d46f4fba..b5314bc9be 100644
--- a/activerecord/test/cases/reflection_test.rb
+++ b/activerecord/test/cases/reflection_test.rb
@@ -35,18 +35,18 @@ class ReflectionTest < ActiveRecord::TestCase
def test_read_attribute_names
assert_equal(
- %w( id title author_name author_email_address bonus_time written_on last_read content important group approved replies_count parent_id parent_title type created_at updated_at ).sort,
+ %w( id title author_name author_email_address bonus_time written_on last_read content important group approved replies_count unique_replies_count parent_id parent_title type created_at updated_at ).sort,
@first.attribute_names.sort
)
end
def test_columns
- assert_equal 17, Topic.columns.length
+ assert_equal 18, Topic.columns.length
end
def test_columns_are_returned_in_the_order_they_were_declared
column_names = Topic.columns.map { |column| column.name }
- assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content important approved replies_count parent_id parent_title type group created_at updated_at), column_names
+ assert_equal %w(id title author_name author_email_address written_on bonus_time last_read content important approved replies_count unique_replies_count parent_id parent_title type group created_at updated_at), column_names
end
def test_content_columns
diff --git a/activerecord/test/cases/relation_test.rb b/activerecord/test/cases/relation_test.rb
index 482c1b3d48..03c7009568 100644
--- a/activerecord/test/cases/relation_test.rb
+++ b/activerecord/test/cases/relation_test.rb
@@ -12,10 +12,7 @@ module ActiveRecord
end
def test_construction
- relation = nil
- assert_nothing_raised do
- relation = Relation.new FakeKlass, :b
- end
+ relation = Relation.new FakeKlass, :b
assert_equal FakeKlass, relation.klass
assert_equal :b, relation.table
assert !relation.loaded, 'relation is not loaded'
diff --git a/activerecord/test/models/reply.rb b/activerecord/test/models/reply.rb
index c88262580e..3e82e55d89 100644
--- a/activerecord/test/models/reply.rb
+++ b/activerecord/test/models/reply.rb
@@ -7,6 +7,7 @@ class Reply < Topic
end
class UniqueReply < Reply
+ belongs_to :topic, :foreign_key => 'parent_id', :counter_cache => true
validates_uniqueness_of :content, :scope => 'parent_id'
end
diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb
index 8beb58f3fc..188a3f0164 100644
--- a/activerecord/test/schema/schema.rb
+++ b/activerecord/test/schema/schema.rb
@@ -675,6 +675,7 @@ ActiveRecord::Schema.define do
end
t.boolean :approved, :default => true
t.integer :replies_count, :default => 0
+ t.integer :unique_replies_count, :default => 0
t.integer :parent_id
t.string :parent_title
t.string :type
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 7c666a9b83..1982811500 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,16 @@
+* Raise an error when multiple `included` blocks are defined for a Concern.
+ The old behavior would silently discard previously defined blocks, running
+ only the last one.
+
+ *Mike Dillon*
+
+* Replace `multi_json` with `json`.
+
+ Since Rails requires Ruby 1.9 and since Ruby 1.9 includes `json` in the standard library,
+ `multi_json` is no longer necessary.
+
+ *Erik Michaels-Ober*
+
* Added escaping of U+2028 and U+2029 inside the json encoder.
These characters are legal in JSON but break the Javascript interpreter.
After escaping them, the JSON is still legal and can be parsed by Javascript.
diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec
index 08d503ae30..ffc2c2074e 100644
--- a/activesupport/activesupport.gemspec
+++ b/activesupport/activesupport.gemspec
@@ -23,6 +23,6 @@ Gem::Specification.new do |s|
s.add_dependency('i18n', '~> 0.6', '>= 0.6.4')
s.add_dependency 'json', '~> 1.7'
s.add_dependency 'tzinfo', '~> 0.3.37'
- s.add_dependency 'minitest', '~> 4.2'
+ s.add_dependency 'minitest', '~> 5.0'
s.add_dependency 'thread_safe','~> 0.1'
end
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index a151aa03b5..bbfa74f98d 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -1,9 +1,9 @@
-require 'thread_safe'
require 'active_support/concern'
require 'active_support/descendants_tracker'
require 'active_support/core_ext/class/attribute'
require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/kernel/singleton_class'
+require 'thread'
module ActiveSupport
# Callbacks are code hooks that are run at key points in an object's lifecycle.
@@ -76,8 +76,14 @@ module ActiveSupport
# save
# end
def run_callbacks(kind, &block)
- runner_name = self.class.__define_callbacks(kind, self)
- send(runner_name, &block)
+ cbs = send("_#{kind}_callbacks")
+ if cbs.empty?
+ yield if block_given?
+ else
+ runner = cbs.compile
+ e = Filters::Environment.new(self, false, nil, block)
+ runner.call(e).value
+ end
end
private
@@ -88,204 +94,306 @@ module ActiveSupport
def halted_callback_hook(filter)
end
- class Callback #:nodoc:#
- @@_callback_sequence = 0
+ module Filters
+ Environment = Struct.new(:target, :halted, :value, :run_block)
- class Basic < Callback
+ class End
+ def call(env)
+ block = env.run_block
+ env.value = !env.halted && (!block || block.call)
+ env
+ end
end
+ ENDING = End.new
- class Object < Callback
- def duplicates?(other)
- false
+ class Before
+ def self.build(next_callback, user_callback, user_conditions, chain_config, filter)
+ halted_lambda = chain_config[:terminator]
+
+ if chain_config.key?(:terminator) && user_conditions.any?
+ halting_and_conditional(next_callback, user_callback, user_conditions, halted_lambda, filter)
+ elsif chain_config.key? :terminator
+ halting(next_callback, user_callback, halted_lambda, filter)
+ elsif user_conditions.any?
+ conditional(next_callback, user_callback, user_conditions)
+ else
+ simple next_callback, user_callback
+ end
end
- end
- def self.build(chain, filter, kind, options, _klass)
- klass = case filter
- when Array, Symbol, String
- Callback::Basic
- else
- Callback::Object
- end
- klass.new chain, filter, kind, options, _klass
- end
+ private
- attr_accessor :chain, :kind, :options, :klass, :raw_filter
+ def self.halting_and_conditional(next_callback, user_callback, user_conditions, halted_lambda, filter)
+ lambda { |env|
+ target = env.target
+ value = env.value
+ halted = env.halted
- def initialize(chain, filter, kind, options, klass)
- @chain, @kind, @klass = chain, kind, klass
- deprecate_per_key_option(options)
- normalize_options!(options)
+ if !halted && user_conditions.all? { |c| c.call(target, value) }
+ result = user_callback.call target, value
+ env.halted = halted_lambda.call(target, result)
+ if env.halted
+ target.send :halted_callback_hook, filter
+ end
+ end
+ next_callback.call env
+ }
+ end
- @raw_filter, @options = filter, options
- @key = compute_identifier filter
- @source = _compile_source(filter)
- recompile_options!
- end
+ def self.halting(next_callback, user_callback, halted_lambda, filter)
+ lambda { |env|
+ target = env.target
+ value = env.value
+ halted = env.halted
+
+ unless halted
+ result = user_callback.call target, value
+ env.halted = halted_lambda.call(target, result)
+ if env.halted
+ target.send :halted_callback_hook, filter
+ end
+ end
+ next_callback.call env
+ }
+ end
- def filter
- @key
- end
+ def self.conditional(next_callback, user_callback, user_conditions)
+ lambda { |env|
+ target = env.target
+ value = env.value
- def deprecate_per_key_option(options)
- if options[:per_key]
- raise NotImplementedError, ":per_key option is no longer supported. Use generic :if and :unless options instead."
+ if user_conditions.all? { |c| c.call(target, value) }
+ user_callback.call target, value
+ end
+ next_callback.call env
+ }
end
- end
- def clone(chain, klass)
- obj = super()
- obj.chain = chain
- obj.klass = klass
- obj.options = @options.dup
- obj.options[:if] = @options[:if].dup
- obj.options[:unless] = @options[:unless].dup
- obj
+ def self.simple(next_callback, user_callback)
+ lambda { |env|
+ user_callback.call env.target, env.value
+ next_callback.call env
+ }
+ end
end
- def normalize_options!(options)
- options[:if] = Array(options[:if])
- options[:unless] = Array(options[:unless])
- end
+ class After
+ def self.build(next_callback, user_callback, user_conditions, chain_config)
+ if chain_config[:skip_after_callbacks_if_terminated]
+ if chain_config.key?(:terminator) && user_conditions.any?
+ halting_and_conditional(next_callback, user_callback, user_conditions)
+ elsif chain_config.key?(:terminator)
+ halting(next_callback, user_callback)
+ elsif user_conditions.any?
+ conditional next_callback, user_callback, user_conditions
+ else
+ simple next_callback, user_callback
+ end
+ else
+ if user_conditions.any?
+ conditional next_callback, user_callback, user_conditions
+ else
+ simple next_callback, user_callback
+ end
+ end
+ end
- def name
- chain.name
- end
+ private
- def next_id
- @@_callback_sequence += 1
- end
+ def self.halting_and_conditional(next_callback, user_callback, user_conditions)
+ lambda { |env|
+ env = next_callback.call env
+ target = env.target
+ value = env.value
+ halted = env.halted
- def matches?(_kind, _filter)
- @kind == _kind && filter == _filter
+ if !halted && user_conditions.all? { |c| c.call(target, value) }
+ user_callback.call target, value
+ end
+ env
+ }
+ end
+
+ def self.halting(next_callback, user_callback)
+ lambda { |env|
+ env = next_callback.call env
+ unless env.halted
+ user_callback.call env.target, env.value
+ end
+ env
+ }
+ end
+
+ def self.conditional(next_callback, user_callback, user_conditions)
+ lambda { |env|
+ env = next_callback.call env
+ target = env.target
+ value = env.value
+
+ if user_conditions.all? { |c| c.call(target, value) }
+ user_callback.call target, value
+ end
+ env
+ }
+ end
+
+ def self.simple(next_callback, user_callback)
+ lambda { |env|
+ env = next_callback.call env
+ user_callback.call env.target, env.value
+ env
+ }
+ end
end
- def duplicates?(other)
- return false unless self.class == other.class
+ class Around
+ def self.build(next_callback, user_callback, user_conditions, chain_config)
+ if chain_config.key?(:terminator) && user_conditions.any?
+ halting_and_conditional(next_callback, user_callback, user_conditions)
+ elsif chain_config.key? :terminator
+ halting(next_callback, user_callback)
+ elsif user_conditions.any?
+ conditional(next_callback, user_callback, user_conditions)
+ else
+ simple(next_callback, user_callback)
+ end
+ end
+
+ private
+
+ def self.halting_and_conditional(next_callback, user_callback, user_conditions)
+ lambda { |env|
+ target = env.target
+ value = env.value
+ halted = env.halted
+
+ if !halted && user_conditions.all? { |c| c.call(target, value) }
+ user_callback.call(target, value) {
+ env = next_callback.call env
+ env.value
+ }
+ env
+ else
+ next_callback.call env
+ end
+ }
+ end
+
+ def self.halting(next_callback, user_callback)
+ lambda { |env|
+ target = env.target
+ value = env.value
+
+ unless env.halted
+ user_callback.call(target, value) {
+ env = next_callback.call env
+ env.value
+ }
+ env
+ else
+ next_callback.call env
+ end
+ }
+ end
+
+ def self.conditional(next_callback, user_callback, user_conditions)
+ lambda { |env|
+ target = env.target
+ value = env.value
+
+ if user_conditions.all? { |c| c.call(target, value) }
+ user_callback.call(target, value) {
+ env = next_callback.call env
+ env.value
+ }
+ env
+ else
+ next_callback.call env
+ end
+ }
+ end
- matches?(other.kind, other.filter)
+ def self.simple(next_callback, user_callback)
+ lambda { |env|
+ user_callback.call(env.target, env.value) {
+ env = next_callback.call env
+ env.value
+ }
+ env
+ }
+ end
end
+ end
- def _update_filter(filter_options, new_options)
- filter_options[:if].concat(Array(new_options[:unless])) if new_options.key?(:unless)
- filter_options[:unless].concat(Array(new_options[:if])) if new_options.key?(:if)
+ class Callback #:nodoc:#
+ def self.build(chain, filter, kind, options)
+ new chain.name, filter, kind, options, chain.config
end
- def recompile!(_options)
- deprecate_per_key_option(_options)
- _update_filter(self.options, _options)
+ attr_accessor :kind, :name
+ attr_reader :chain_config
- recompile_options!
+ def initialize(name, filter, kind, options, chain_config)
+ @chain_config = chain_config
+ @name = name
+ @kind = kind
+ @filter = filter
+ @key = compute_identifier filter
+ @if = Array(options[:if])
+ @unless = Array(options[:unless])
end
- # Wraps code with filter
- def apply(code)
- case @kind
- when :before
- <<-RUBY_EVAL
- if !halted && #{@compiled_options}
- # This double assignment is to prevent warnings in 1.9.3 as
- # the `result` variable is not always used except if the
- # terminator code refers to it.
- result = result = #{@source}
- halted = (#{chain.config[:terminator]})
- if halted
- halted_callback_hook(#{@raw_filter.inspect.inspect})
- end
- end
- #{code}
- RUBY_EVAL
- when :after
- <<-RUBY_EVAL
- #{code}
- if #{!chain.config[:skip_after_callbacks_if_terminated] || "!halted"} && #{@compiled_options}
- #{@source}
- end
- RUBY_EVAL
- when :around
- name = define_conditional_callback
- <<-RUBY_EVAL
- #{name}(halted) do
- #{code}
- value
- end
- RUBY_EVAL
- end
+ def filter; @key; end
+ def raw_filter; @filter; end
+
+ def merge(chain, new_options)
+ options = {
+ :if => @if.dup,
+ :unless => @unless.dup
+ }
+
+ options[:if].concat Array(new_options.fetch(:unless, []))
+ options[:unless].concat Array(new_options.fetch(:if, []))
+
+ self.class.build chain, @filter, @kind, options
end
- private
+ def matches?(_kind, _filter)
+ @kind == _kind && filter == _filter
+ end
- def compute_identifier(filter)
- case filter
- when String, ::Proc
- filter.object_id
+ def duplicates?(other)
+ case @filter
+ when Symbol, String
+ matches?(other.kind, other.filter)
else
- filter
+ false
end
end
- # Compile around filters with conditions into proxy methods
- # that contain the conditions.
- #
- # For `set_callback :save, :around, :filter_name, if: :condition`:
- #
- # def _conditional_callback_save_17
- # if condition
- # filter_name do
- # yield self
- # end
- # else
- # yield self
- # end
- # end
- def define_conditional_callback
- name = "_conditional_callback_#{@kind}_#{next_id}"
- @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def #{name}(halted)
- if #{@compiled_options} && !halted
- #{@source} do
- yield self
- end
- else
- yield self
- end
- end
- RUBY_EVAL
- name
- end
-
- # Options support the same options as filters themselves (and support
- # symbols, string, procs, and objects), so compile a conditional
- # expression based on the options.
- def recompile_options!
- conditions = ["true"]
-
- unless options[:if].empty?
- conditions << Array(_compile_source(options[:if]))
- end
+ # Wraps code with filter
+ def apply(next_callback)
+ user_conditions = conditions_lambdas
+ user_callback = make_lambda @filter
- unless options[:unless].empty?
- conditions << Array(_compile_source(options[:unless])).map {|f| "!#{f}"}
+ case kind
+ when :before
+ Filters::Before.build(next_callback, user_callback, user_conditions, chain_config, @filter)
+ when :after
+ Filters::After.build(next_callback, user_callback, user_conditions, chain_config)
+ when :around
+ Filters::Around.build(next_callback, user_callback, user_conditions, chain_config)
end
-
- @compiled_options = conditions.flatten.join(" && ")
end
- def _method_name_for_object_filter(kind, filter, append_next_id = true)
- class_name = filter.kind_of?(Class) ? filter.to_s : filter.class.to_s
- class_name.gsub!(/<|>|#/, '')
- class_name.gsub!(/\/|:/, "_")
+ private
- method_name = "_callback_#{kind}_#{class_name}"
- method_name << "_#{next_id}" if append_next_id
- method_name
+ def invert_lambda(l)
+ lambda { |*args, &blk| !l.call(*args, &blk) }
end
# Filters support:
#
- # Arrays:: Used in conditions. This is used to specify
- # multiple conditions. Used internally to
- # merge conditions from skip_* filters.
# Symbols:: A method to call.
# Strings:: Some content to evaluate.
# Procs:: A proc to call with the object.
@@ -294,87 +402,105 @@ module ActiveSupport
# All of these objects are compiled into methods and handled
# the same after this point:
#
- # Arrays:: Merged together into a single filter.
# Symbols:: Already methods.
# Strings:: class_eval'ed into methods.
# Procs:: define_method'ed into methods.
# Objects::
# a method is created that calls the before_foo method
# on the object.
- def _compile_source(filter)
+ def make_lambda(filter)
case filter
- when Array
- filter.map {|f| _compile_source(f)}
when Symbol
- filter
+ lambda { |target, _, &blk| target.send filter, &blk }
when String
- "(#{filter})"
+ l = eval "lambda { |value| #{filter} }"
+ lambda { |target, value| target.instance_exec(value, &l) }
when ::Proc
- method_name = "_callback_#{@kind}_#{next_id}"
- @klass.send(:define_method, method_name, &filter)
- return method_name if filter.arity <= 0
+ if filter.arity > 1
+ return lambda { |target, _, &block|
+ raise ArgumentError unless block
+ target.instance_exec(target, block, &filter)
+ }
+ end
- method_name << (filter.arity == 1 ? "(self)" : "(self, ::Proc.new)")
+ if filter.arity <= 0
+ lambda { |target, _| target.instance_exec(&filter) }
+ else
+ lambda { |target, _| target.instance_exec(target, &filter) }
+ end
else
- method_name = _method_name_for_object_filter(kind, filter)
- @klass.send(:define_method, "#{method_name}_object") { filter }
-
- _normalize_legacy_filter(kind, filter)
- scopes = Array(chain.config[:scope])
+ scopes = Array(chain_config[:scope])
method_to_call = scopes.map{ |s| public_send(s) }.join("_")
- @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def #{method_name}(&blk)
- #{method_name}_object.send(:#{method_to_call}, self, &blk)
- end
- RUBY_EVAL
-
- method_name
+ lambda { |target, _, &blk|
+ filter.public_send method_to_call, target, &blk
+ }
end
end
- def _normalize_legacy_filter(kind, filter)
- if !filter.respond_to?(kind) && filter.respond_to?(:filter)
- message = "Filter object with #filter method is deprecated. Define method corresponding " \
- "to filter type (#before, #after or #around)."
- ActiveSupport::Deprecation.warn message
- filter.singleton_class.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def #{kind}(context, &block) filter(context, &block) end
- RUBY_EVAL
- elsif filter.respond_to?(:before) && filter.respond_to?(:after) && kind == :around && !filter.respond_to?(:around)
- message = "Filter object with #before and #after methods is deprecated. Define #around method instead."
- ActiveSupport::Deprecation.warn message
- def filter.around(context)
- should_continue = before(context)
- yield if should_continue
- after(context)
- end
+ def compute_identifier(filter)
+ case filter
+ when String, ::Proc
+ filter.object_id
+ else
+ filter
end
end
+
+ def conditions_lambdas
+ @if.map { |c| make_lambda c } +
+ @unless.map { |c| invert_lambda make_lambda c }
+ end
end
# An Array with a compile method.
- class CallbackChain < Array #:nodoc:#
+ class CallbackChain #:nodoc:#
+ include Enumerable
+
attr_reader :name, :config
def initialize(name, config)
@name = name
@config = {
- :terminator => "false",
:scope => [ :kind ]
}.merge!(config)
+ @chain = []
+ @callbacks = nil
+ @mutex = Mutex.new
+ end
+
+ def each(&block); @chain.each(&block); end
+ def index(o); @chain.index(o); end
+ def empty?; @chain.empty?; end
+
+ def insert(index, o)
+ @callbacks = nil
+ @chain.insert(index, o)
+ end
+
+ def delete(o)
+ @callbacks = nil
+ @chain.delete(o)
+ end
+
+ def clear
+ @callbacks = nil
+ @chain.clear
+ self
+ end
+
+ def initialize_copy(other)
+ @callbacks = nil
+ @chain = other.chain.dup
+ @mutex = Mutex.new
end
def compile
- method = ["value = nil", "halted = false"]
- callbacks = "value = !halted && (!block_given? || yield)"
- reverse_each do |callback|
- callbacks = callback.apply(callbacks)
+ @callbacks || @mutex.synchronize do
+ @callbacks ||= @chain.reverse.inject(Filters::ENDING) do |chain, callback|
+ callback.apply chain
+ end
end
- method << callbacks
-
- method << "value"
- method.join("\n")
end
def append(*callbacks)
@@ -385,69 +511,45 @@ module ActiveSupport
callbacks.each { |c| prepend_one(c) }
end
+ protected
+ def chain; @chain; end
+
private
def append_one(callback)
+ @callbacks = nil
remove_duplicates(callback)
- push(callback)
+ @chain.push(callback)
end
def prepend_one(callback)
+ @callbacks = nil
remove_duplicates(callback)
- unshift(callback)
+ @chain.unshift(callback)
end
def remove_duplicates(callback)
- delete_if { |c| callback.duplicates?(c) }
+ @callbacks = nil
+ @chain.delete_if { |c| callback.duplicates?(c) }
end
end
module ClassMethods
- # This method defines callback chain method for the given kind
- # if it was not yet defined.
- # This generated method plays caching role.
- def __define_callbacks(kind, object) #:nodoc:
- name = __callback_runner_name(kind)
- unless object.respond_to?(name, true)
- str = object.send("_#{kind}_callbacks").compile
- class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
- def #{name}() #{str} end
- protected :#{name}
- RUBY_EVAL
- end
- name
- end
-
- def __reset_runner(symbol)
- name = __callback_runner_name(symbol)
- undef_method(name) if method_defined?(name)
- end
-
- def __callback_runner_name_cache
- @__callback_runner_name_cache ||= ThreadSafe::Cache.new {|cache, kind| cache[kind] = __generate_callback_runner_name(kind) }
- end
-
- def __generate_callback_runner_name(kind)
- "_run__#{self.name.hash.abs}__#{kind}__callbacks"
- end
-
- def __callback_runner_name(kind)
- __callback_runner_name_cache[kind]
- end
-
- # This is used internally to append, prepend and skip callbacks to the
- # CallbackChain.
- def __update_callbacks(name, filters = [], block = nil) #:nodoc:
+ def normalize_callback_params(name, filters, block) # :nodoc:
type = CALLBACK_FILTER_TYPES.include?(filters.first) ? filters.shift : :before
options = filters.last.is_a?(Hash) ? filters.pop : {}
filters.unshift(block) if block
+ [type, filters, options.dup]
+ end
+ # This is used internally to append, prepend and skip callbacks to the
+ # CallbackChain.
+ def __update_callbacks(name) #:nodoc:
([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse.each do |target|
- chain = target.send("_#{name}_callbacks")
- yield target, chain.dup, type, filters, options
- target.__reset_runner(name)
+ chain = target.get_callbacks name
+ yield target, chain.dup
end
end
@@ -487,16 +589,15 @@ module ActiveSupport
# * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
# existing chain rather than appended.
def set_callback(name, *filter_list, &block)
- mapped = nil
-
- __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
- mapped ||= filters.map do |filter|
- Callback.build(chain, filter, type, options.dup, self)
- end
+ type, filters, options = normalize_callback_params(name, filter_list, block)
+ self_chain = get_callbacks name
+ mapped = filters.map do |filter|
+ Callback.build(self_chain, filter, type, options)
+ end
+ __update_callbacks(name) do |target, chain|
options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped)
-
- target.send("_#{name}_callbacks=", chain)
+ target.set_callbacks name, chain
end
end
@@ -508,36 +609,34 @@ module ActiveSupport
# skip_callback :validate, :before, :check_membership, if: -> { self.age > 18 }
# end
def skip_callback(name, *filter_list, &block)
- __update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
+ type, filters, options = normalize_callback_params(name, filter_list, block)
+
+ __update_callbacks(name) do |target, chain|
filters.each do |filter|
filter = chain.find {|c| c.matches?(type, filter) }
if filter && options.any?
- new_filter = filter.clone(chain, self)
+ new_filter = filter.merge(chain, options)
chain.insert(chain.index(filter), new_filter)
- new_filter.recompile!(options)
end
chain.delete(filter)
end
- target.send("_#{name}_callbacks=", chain)
+ target.set_callbacks name, chain
end
end
# Remove all set callbacks for the given event.
def reset_callbacks(symbol)
- callbacks = send("_#{symbol}_callbacks")
+ callbacks = get_callbacks symbol
ActiveSupport::DescendantsTracker.descendants(self).each do |target|
- chain = target.send("_#{symbol}_callbacks").dup
+ chain = target.get_callbacks(symbol).dup
callbacks.each { |c| chain.delete(c) }
- target.send("_#{symbol}_callbacks=", chain)
- target.__reset_runner(symbol)
+ target.set_callbacks symbol, chain
end
- self.send("_#{symbol}_callbacks=", callbacks.dup.clear)
-
- __reset_runner(symbol)
+ self.set_callbacks symbol, callbacks.dup.clear
end
# Define sets of events in the object lifecycle that support callbacks.
@@ -609,11 +708,28 @@ module ActiveSupport
# would call <tt>Audit#save</tt>.
def define_callbacks(*callbacks)
config = callbacks.last.is_a?(Hash) ? callbacks.pop : {}
+ if config.key?(:terminator) && String === config[:terminator]
+ ActiveSupport::Deprecation.warn "String based terminators are deprecated, please use a lambda"
+ value = config[:terminator]
+ l = class_eval "lambda { |result| #{value} }", __FILE__, __LINE__
+ config[:terminator] = lambda { |target, result| target.instance_exec(result, &l) }
+ end
+
callbacks.each do |callback|
class_attribute "_#{callback}_callbacks"
- send("_#{callback}_callbacks=", CallbackChain.new(callback, config))
+ set_callbacks callback, CallbackChain.new(callback, config)
end
end
+
+ protected
+
+ def get_callbacks(name)
+ send "_#{name}_callbacks"
+ end
+
+ def set_callbacks(name, callbacks)
+ send "_#{name}_callbacks=", callbacks
+ end
end
end
end
diff --git a/activesupport/lib/active_support/concern.rb b/activesupport/lib/active_support/concern.rb
index eeeba60839..b6ae86b583 100644
--- a/activesupport/lib/active_support/concern.rb
+++ b/activesupport/lib/active_support/concern.rb
@@ -98,6 +98,12 @@ module ActiveSupport
# include Bar # works, Bar takes care now of its dependencies
# end
module Concern
+ class MultipleIncludedBlocks < StandardError #:nodoc:
+ def initialize
+ super "Cannot define multiple 'included' blocks for a Concern"
+ end
+ end
+
def self.extended(base) #:nodoc:
base.instance_variable_set("@_dependencies", [])
end
@@ -117,6 +123,8 @@ module ActiveSupport
def included(base = nil, &block)
if base.nil?
+ raise MultipleIncludedBlocks if instance_variable_defined?("@_included_block")
+
@_included_block = block
else
super
diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb
index 6d49b7b6e1..6fa9967a28 100644
--- a/activesupport/lib/active_support/core_ext/class/attribute.rb
+++ b/activesupport/lib/active_support/core_ext/class/attribute.rb
@@ -71,7 +71,7 @@ class Class
def class_attribute(*attrs)
options = attrs.extract_options!
# double assignment is used to avoid "assigned but unused variable" warning
- instance_reader = instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
+ instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
instance_predicate = options.fetch(:instance_predicate, true)
diff --git a/activesupport/lib/active_support/core_ext/marshal.rb b/activesupport/lib/active_support/core_ext/marshal.rb
index c7a8348b1d..56c79c04bd 100644
--- a/activesupport/lib/active_support/core_ext/marshal.rb
+++ b/activesupport/lib/active_support/core_ext/marshal.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/module/aliasing'
+
module Marshal
class << self
def load_with_autoloading(source)
diff --git a/activesupport/lib/active_support/core_ext/range/include_range.rb b/activesupport/lib/active_support/core_ext/range/include_range.rb
index 3af66aaf2f..3a07401c8a 100644
--- a/activesupport/lib/active_support/core_ext/range/include_range.rb
+++ b/activesupport/lib/active_support/core_ext/range/include_range.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/module/aliasing'
+
class Range
# Extends the default Range#include? to support range comparisons.
# (1..5).include?(1..5) # => true
diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb
index 1b20592e4c..bdb8877f55 100644
--- a/activesupport/lib/active_support/hash_with_indifferent_access.rb
+++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb
@@ -229,7 +229,11 @@ module ActiveSupport
# Convert to a regular hash with string keys.
def to_hash
- Hash.new(default).merge!(self)
+ _new_hash= {}
+ each do |key, value|
+ _new_hash[convert_key(key)] = convert_value(value, true)
+ end
+ Hash.new(default).merge!(_new_hash)
end
protected
@@ -237,12 +241,12 @@ module ActiveSupport
key.kind_of?(Symbol) ? key.to_s : key
end
- def convert_value(value)
+ def convert_value(value, _convert_for_to_hash = false)
if value.is_a? Hash
- value.nested_under_indifferent_access
+ _convert_for_to_hash ? value.to_hash : value.nested_under_indifferent_access
elsif value.is_a?(Array)
value = value.dup if value.frozen?
- value.map! { |e| convert_value(e) }
+ value.map! { |e| convert_value(e, _convert_for_to_hash) }
else
value
end
diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb
index 7588fdb67c..99fe03e6d0 100644
--- a/activesupport/lib/active_support/notifications/fanout.rb
+++ b/activesupport/lib/active_support/notifications/fanout.rb
@@ -79,6 +79,13 @@ module ActiveSupport
def initialize(pattern, delegate)
@pattern = pattern
@delegate = delegate
+ @can_publish = delegate.respond_to?(:publish)
+ end
+
+ def publish(name, *args)
+ if @can_publish
+ @delegate.publish name, *args
+ end
end
def start(name, id, payload)
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index 8b392c36d0..f0962998a0 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -16,10 +16,28 @@ begin
rescue LoadError
end
+module Minitest # :nodoc:
+ class << self
+ remove_method :__run
+ end
+
+ def self.__run reporter, options # :nodoc:
+ # FIXME: MT5's runnables is not ordered. This is needed because
+ # we have have tests have cross-class order-dependent bugs.
+ suites = Runnable.runnables.sort_by { |ts| ts.name.to_s }
+
+ parallel, serial = suites.partition { |s| s.test_order == :parallel }
+
+ ParallelEach.new(parallel).map { |suite| suite.run reporter, options } +
+ serial.map { |suite| suite.run reporter, options }
+ end
+end
+
module ActiveSupport
- class TestCase < ::MiniTest::Unit::TestCase
- Assertion = MiniTest::Assertion
- alias_method :method_name, :__name__
+ class TestCase < ::Minitest::Test
+ Assertion = Minitest::Assertion
+
+ alias_method :method_name, :name
$tags = {}
def self.for_tag(tag)
diff --git a/activesupport/lib/active_support/testing/autorun.rb b/activesupport/lib/active_support/testing/autorun.rb
index c446adc16d..5aa5f46310 100644
--- a/activesupport/lib/active_support/testing/autorun.rb
+++ b/activesupport/lib/active_support/testing/autorun.rb
@@ -1,5 +1,5 @@
gem 'minitest'
-require 'minitest/unit'
+require 'minitest'
-MiniTest::Unit.autorun
+Minitest.autorun
diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb
index e16b73a036..9c52ae7768 100644
--- a/activesupport/lib/active_support/testing/isolation.rb
+++ b/activesupport/lib/active_support/testing/isolation.rb
@@ -72,16 +72,12 @@ module ActiveSupport
end
end
- def run(runner)
- _run_class_setup
-
- serialized = run_in_isolation do |isolated_runner|
- super(isolated_runner)
+ def run
+ serialized = run_in_isolation do
+ super
end
- retval, proxy = Marshal.load(serialized)
- proxy.__replay__(runner)
- retval
+ Marshal.load(serialized)
end
module Forking
@@ -90,9 +86,8 @@ module ActiveSupport
pid = fork do
read.close
- proxy = ProxyTestResult.new
- retval = yield proxy
- write.puts [Marshal.dump([retval, proxy])].pack("m")
+ yield
+ write.puts [Marshal.dump(self.dup)].pack("m")
exit!
end
diff --git a/activesupport/lib/active_support/testing/tagged_logging.rb b/activesupport/lib/active_support/testing/tagged_logging.rb
index 9d43eb179f..f4cee64091 100644
--- a/activesupport/lib/active_support/testing/tagged_logging.rb
+++ b/activesupport/lib/active_support/testing/tagged_logging.rb
@@ -7,7 +7,7 @@ module ActiveSupport
def before_setup
if tagged_logger
- heading = "#{self.class}: #{__name__}"
+ heading = "#{self.class}: #{name}"
divider = '-' * heading.size
tagged_logger.info divider
tagged_logger.info heading
diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb
index 9659f141cb..f8e2ce22fa 100644
--- a/activesupport/test/callbacks_test.rb
+++ b/activesupport/test/callbacks_test.rb
@@ -525,7 +525,7 @@ module CallbacksTest
class CallbackTerminator
include ActiveSupport::Callbacks
- define_callbacks :save, :terminator => "result == :halt"
+ define_callbacks :save, :terminator => ->(_,result) { result == :halt }
set_callback :save, :before, :first
set_callback :save, :before, :second
@@ -718,7 +718,7 @@ module CallbacksTest
def test_termination_invokes_hook
terminator = CallbackTerminator.new
terminator.save
- assert_equal ":second", terminator.halted
+ assert_equal :second, terminator.halted
end
def test_block_never_called_if_terminated
@@ -772,22 +772,6 @@ module CallbacksTest
end
end
- class PerKeyOptionDeprecationTest < ActiveSupport::TestCase
-
- def test_per_key_option_deprecation
- assert_raise NotImplementedError do
- Phone.class_eval do
- set_callback :save, :before, :before_save1, :per_key => {:if => "true"}
- end
- end
- assert_raise NotImplementedError do
- Phone.class_eval do
- skip_callback :save, :before, :before_save1, :per_key => {:if => "true"}
- end
- end
- end
- end
-
class ExcludingDuplicatesCallbackTest < ActiveSupport::TestCase
def test_excludes_duplicates_in_separate_calls
model = DuplicatingCallbacks.new
@@ -802,6 +786,46 @@ module CallbacksTest
end
end
+ class CallbackProcTest < ActiveSupport::TestCase
+ def build_class(callback)
+ Class.new {
+ include ActiveSupport::Callbacks
+ define_callbacks :foo
+ set_callback :foo, :before, callback
+ def run; run_callbacks :foo; end
+ }
+ end
+
+ def test_proc_arity_0
+ calls = []
+ klass = build_class(->() { calls << :foo })
+ klass.new.run
+ assert_equal [:foo], calls
+ end
+
+ def test_proc_arity_1
+ calls = []
+ klass = build_class(->(o) { calls << o })
+ instance = klass.new
+ instance.run
+ assert_equal [instance], calls
+ end
+
+ def test_proc_arity_2
+ assert_raises(ArgumentError) do
+ klass = build_class(->(x,y) { })
+ klass.new.run
+ end
+ end
+
+ def test_proc_negative_called_with_empty_list
+ calls = []
+ klass = build_class(->(*args) { calls << args })
+ klass.new.run
+ assert_equal [[]], calls
+ end
+ end
+
class ConditionalTests < ActiveSupport::TestCase
def build_class(callback)
Class.new {
@@ -824,8 +848,9 @@ module CallbacksTest
include ActiveSupport::Callbacks
define_callbacks :foo, :scope => [:name]
set_callback :foo, :before, :foo, :if => callback
- def foo; end
def run; run_callbacks :foo; end
+ private
+ def foo; end
}
object = klass.new
object.run
@@ -873,6 +898,46 @@ module CallbacksTest
end
end
+ class ResetCallbackTest < ActiveSupport::TestCase
+ def build_class(memo)
+ klass = Class.new {
+ include ActiveSupport::Callbacks
+ define_callbacks :foo
+ set_callback :foo, :before, :hello
+ def run; run_callbacks :foo; end
+ }
+ klass.class_eval {
+ define_method(:hello) { memo << :hi }
+ }
+ klass
+ end
+
+ def test_reset_callbacks
+ events = []
+ klass = build_class events
+ klass.new.run
+ assert_equal 1, events.length
+
+ klass.reset_callbacks :foo
+ klass.new.run
+ assert_equal 1, events.length
+ end
+
+ def test_reset_impacts_subclasses
+ events = []
+ klass = build_class events
+ subclass = Class.new(klass) { set_callback :foo, :before, :world }
+ subclass.class_eval { define_method(:world) { events << :world } }
+
+ subclass.new.run
+ assert_equal 2, events.length
+
+ klass.reset_callbacks :foo
+ subclass.new.run
+ assert_equal 3, events.length
+ end
+ end
+
class CallbackTypeTest < ActiveSupport::TestCase
def build_class(callback, n = 10)
Class.new {
diff --git a/activesupport/test/concern_test.rb b/activesupport/test/concern_test.rb
index 912ce30c29..8e2c298fc6 100644
--- a/activesupport/test/concern_test.rb
+++ b/activesupport/test/concern_test.rb
@@ -91,4 +91,18 @@ class ConcernTest < ActiveSupport::TestCase
@klass.send(:include, Foo)
assert_equal [ConcernTest::Foo, ConcernTest::Bar, ConcernTest::Baz], @klass.included_modules[0..2]
end
+
+ def test_raise_on_multiple_included_calls
+ assert_raises(ActiveSupport::Concern::MultipleIncludedBlocks) do
+ Module.new do
+ extend ActiveSupport::Concern
+
+ included do
+ end
+
+ included do
+ end
+ end
+ end
+ end
end
diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index 30d95b75bc..dfcc6cd12a 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -490,6 +490,10 @@ class HashExtTest < ActiveSupport::TestCase
roundtrip = mixed_with_default.with_indifferent_access.to_hash
assert_equal @strings, roundtrip
assert_equal '1234', roundtrip.default
+ new_to_hash = @nested_mixed.with_indifferent_access.to_hash
+ assert_not new_to_hash.instance_of?(HashWithIndifferentAccess)
+ assert_not new_to_hash["a"].instance_of?(HashWithIndifferentAccess)
+ assert_not new_to_hash["a"]["b"].instance_of?(HashWithIndifferentAccess)
end
def test_lookup_returns_the_same_object_that_is_stored_in_hash_indifferent_access
@@ -502,6 +506,11 @@ class HashExtTest < ActiveSupport::TestCase
def test_indifferent_hash_with_array_of_hashes
hash = { "urls" => { "url" => [ { "address" => "1" }, { "address" => "2" } ] }}.with_indifferent_access
assert_equal "1", hash[:urls][:url].first[:address]
+
+ hash = hash.to_hash
+ assert_not hash.instance_of?(HashWithIndifferentAccess)
+ assert_not hash["urls"].instance_of?(HashWithIndifferentAccess)
+ assert_not hash["urls"]["url"].first.instance_of?(HashWithIndifferentAccess)
end
def test_should_preserve_array_subclass_when_value_is_array
diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb
index 33627a4e74..f729f0a95b 100644
--- a/activesupport/test/notifications_test.rb
+++ b/activesupport/test/notifications_test.rb
@@ -81,6 +81,20 @@ module Notifications
end
end
+ class TestSubscriber
+ attr_reader :starts, :finishes, :publishes
+
+ def initialize
+ @starts = []
+ @finishes = []
+ @publishes = []
+ end
+
+ def start(*args); @starts << args; end
+ def finish(*args); @finishes << args; end
+ def publish(*args); @publishes << args; end
+ end
+
class SyncPubSubTest < TestCase
def test_events_are_published_to_a_listener
@notifier.publish :foo
@@ -144,6 +158,14 @@ module Notifications
assert_equal [[:foo]], @another
end
+ def test_publish_with_subscriber
+ subscriber = TestSubscriber.new
+ @notifier.subscribe nil, subscriber
+ @notifier.publish :foo
+
+ assert_equal [[:foo]], subscriber.publishes
+ end
+
private
def event(*args)
args
diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb
index a1bdcf2396..08df67827e 100644
--- a/activesupport/test/test_case_test.rb
+++ b/activesupport/test/test_case_test.rb
@@ -2,116 +2,6 @@ require 'abstract_unit'
module ActiveSupport
class TestCaseTest < ActiveSupport::TestCase
- class FakeRunner
- attr_reader :puked
-
- def initialize
- @puked = []
- end
-
- def puke(klass, name, e)
- @puked << [klass, name, e]
- end
-
- def options
- nil
- end
-
- def record(*args)
- end
-
- def info_signal
- end
- end
-
- def test_standard_error_raised_within_setup_callback_is_puked
- tc = Class.new(TestCase) do
- def self.name; nil; end
-
- setup :bad_callback
- def bad_callback; raise 'oh noes' end
- def test_true; assert true end
- end
-
- test_name = 'test_true'
- fr = FakeRunner.new
-
- test = tc.new test_name
- test.run fr
- klass, name, exception = *fr.puked.first
-
- assert_equal tc, klass
- assert_equal test_name, name
- assert_equal 'oh noes', exception.message
- end
-
- def test_standard_error_raised_within_teardown_callback_is_puked
- tc = Class.new(TestCase) do
- def self.name; nil; end
-
- teardown :bad_callback
- def bad_callback; raise 'oh noes' end
- def test_true; assert true end
- end
-
- test_name = 'test_true'
- fr = FakeRunner.new
-
- test = tc.new test_name
- test.run fr
- klass, name, exception = *fr.puked.first
-
- assert_equal tc, klass
- assert_equal test_name, name
- assert_equal 'oh noes', exception.message
- end
-
- def test_passthrough_exception_raised_within_test_method_is_not_rescued
- tc = Class.new(TestCase) do
- def self.name; nil; end
-
- def test_which_raises_interrupt; raise Interrupt; end
- end
-
- test_name = 'test_which_raises_interrupt'
- fr = FakeRunner.new
-
- test = tc.new test_name
- assert_raises(Interrupt) { test.run fr }
- end
-
- def test_passthrough_exception_raised_within_setup_callback_is_not_rescued
- tc = Class.new(TestCase) do
- def self.name; nil; end
-
- setup :callback_which_raises_interrupt
- def callback_which_raises_interrupt; raise Interrupt; end
- def test_true; assert true end
- end
-
- test_name = 'test_true'
- fr = FakeRunner.new
-
- test = tc.new test_name
- assert_raises(Interrupt) { test.run fr }
- end
-
- def test_passthrough_exception_raised_within_teardown_callback_is_not_rescued
- tc = Class.new(TestCase) do
- def self.name; nil; end
-
- teardown :callback_which_raises_interrupt
- def callback_which_raises_interrupt; raise Interrupt; end
- def test_true; assert true end
- end
-
- test_name = 'test_true'
- fr = FakeRunner.new
-
- test = tc.new test_name
- assert_raises(Interrupt) { test.run fr }
- end
-
def test_pending_deprecation
assert_deprecated do
pending "should use #skip instead"
diff --git a/activesupport/test/test_test.rb b/activesupport/test/test_test.rb
index 3e6ac811a4..68f9ec6c00 100644
--- a/activesupport/test/test_test.rb
+++ b/activesupport/test/test_test.rb
@@ -201,6 +201,6 @@ class TestCaseTaggedLoggingTest < ActiveSupport::TestCase
end
def test_logs_tagged_with_current_test_case
- assert_match "#{self.class}: #{__name__}\n", @out.string
+ assert_match "#{self.class}: #{name}\n", @out.string
end
end
diff --git a/guides/code/getting_started/app/assets/javascripts/application.js b/guides/code/getting_started/app/assets/javascripts/application.js
index 9e83eb5e7e..5a4fbaa370 100644
--- a/guides/code/getting_started/app/assets/javascripts/application.js
+++ b/guides/code/getting_started/app/assets/javascripts/application.js
@@ -7,8 +7,7 @@
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
-// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
-// GO AFTER THE REQUIRES BELOW.
+// stub path allows dependency to be excluded from the asset bundle.
//
//= require jquery
//= require jquery_ujs
diff --git a/guides/source/upgrading_ruby_on_rails.md b/guides/source/upgrading_ruby_on_rails.md
index 51d6775c3e..694592a9de 100644
--- a/guides/source/upgrading_ruby_on_rails.md
+++ b/guides/source/upgrading_ruby_on_rails.md
@@ -22,6 +22,59 @@ Rails generally stays close to the latest released Ruby version when it's releas
TIP: Ruby 1.8.7 p248 and p249 have marshaling bugs that crash Rails. Ruby Enterprise Edition has these fixed since the release of 1.8.7-2010.02. On the 1.9 front, Ruby 1.9.1 is not usable because it outright segfaults, so if you want to use 1.9.x, jump straight to 1.9.3 for smooth sailing.
+### HTTP PATCH
+
+Rails 4 now uses `PATCH` as the primary HTTP verb for updates. When a resource
+is declared in `config/routes.rb`:
+
+```ruby
+resources :users
+```
+
+the action in `UsersController` to update a user is still `update`.
+
+`PUT` requests to `/users/:id` in Rails 4 get routed to `update` as they are
+today. So, if you have an API that gets real PUT requests it is going to work.
+The router also routes `PATCH` requests to `/users/:id` to the `update` action.
+
+So, in Rails 4 both `PUT` and `PATCH` are routed to update. We recommend
+switching to `PATCH` as part of your upgrade process if possible, as it's more
+likely what you want.
+
+For more on PATCH and why this change was made, see [this post](http://weblog.rubyonrails.org/2012/2/25/edge-rails-patch-is-the-new-primary-http-method-for-updates/)
+on the Rails blog.
+
+#### A note about media types
+
+The erratta for the `PATCH` verb [specifies that a 'diff' media type should be
+used with `PATCH`](http://www.rfc-editor.org/errata_search.php?rfc=5789). One
+such format is [JSON Patch](http://tools.ietf.org/html/rfc6902). While Rails
+does not support JSON Patch natively, it's easy enough to add support:
+
+```
+# in your controller
+def update
+ respond_to do |format|
+ format.json do
+ # perform a partial update
+ @post.update params[:post]
+ end
+
+ format.json_patch do
+ # perform sophisticated change
+ end
+ end
+end
+
+# In config/initializers/json_patch.rb:
+Mime::Type.register 'application/json-patch+json', :json_patch
+```
+
+As JSON Patch was only recently made into an RFC, there aren't a lot of great
+Ruby libraries yet. Aaron Patterson's
+[hana](https://github.com/tenderlove/hana) is one such gem, but doesn't have
+full support for the last few changes in the specification.
+
Upgrading from Rails 3.2 to Rails 4.0
-------------------------------------
@@ -118,7 +171,7 @@ Please read [Pull Request #9978](https://github.com/rails/rails/pull/9978) for d
* Rails 4.0 changes the default memcached client from `memcache-client` to `dalli`. To upgrade, simply add `gem 'dalli'` to your `Gemfile`.
-* Rails 4.0 deprecates the `dom_id` and `dom_class` methods. You will need to include the `ActionView::RecordIdentifier` module in controllers requiring this feature.
+* Rails 4.0 deprecates the `dom_id` and `dom_class` methods in controllers (they are fine in views). You will need to include the `ActionView::RecordIdentifier` module in controllers requiring this feature.
* Rails 4.0 changed how `assert_generates`, `assert_recognizes`, and `assert_routing` work. Now all these assertions raise `Assertion` instead of `ActionController::RoutingError`.
diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md
index 04cdbec428..d11b0b7e85 100644
--- a/railties/CHANGELOG.md
+++ b/railties/CHANGELOG.md
@@ -4,7 +4,7 @@
*Arun Agrawal*
* Rails::Railtie no longer forces the Rails::Configurable module on everything
- that subclassess it. Instead, the methods from Rails::Configurable have been
+ that subclasses it. Instead, the methods from Rails::Configurable have been
moved to class methods in Railtie and the Railtie has been made abstract.
*John Wang*
diff --git a/railties/lib/rails/commands/console.rb b/railties/lib/rails/commands/console.rb
index 96229bb4f6..f6bdf129d6 100644
--- a/railties/lib/rails/commands/console.rb
+++ b/railties/lib/rails/commands/console.rb
@@ -94,8 +94,8 @@ module Rails
require 'debugger'
puts "=> Debugger enabled"
rescue LoadError
- puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle, and try again."
- exit
+ puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle it and try again."
+ exit(1)
end
end
end
diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb
index 853d6fa4b9..675ada7ed0 100644
--- a/railties/lib/rails/generators/app_base.rb
+++ b/railties/lib/rails/generators/app_base.rb
@@ -116,7 +116,7 @@ module Rails
def database_gemfile_entry
options[:skip_active_record] ? "" :
- <<-GEMFILE.strip_heredoc.chomp
+ <<-GEMFILE.strip_heredoc
# Use #{options[:database]} as the database for Active Record
gem '#{gem_for_database}'
GEMFILE
diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb
index 5877579fc4..d48dcf9ef3 100644
--- a/railties/lib/rails/generators/rails/app/app_generator.rb
+++ b/railties/lib/rails/generators/rails/app/app_generator.rb
@@ -151,7 +151,15 @@ module Rails
desc: "Show Rails version number and quit"
def initialize(*args)
- raise Error, "Options should be given after the application name. For details run: rails --help" if args[0].blank?
+ if args[0].blank?
+ if args[1].blank?
+ # rails new
+ raise Error, "Application name should be provided in arguments. For details run: rails --help"
+ else
+ # rails new --skip-bundle my_new_application
+ raise Error, "Options should be given after the application name. For details run: rails --help"
+ end
+ end
super
diff --git a/railties/lib/rails/generators/rails/app/templates/Gemfile b/railties/lib/rails/generators/rails/app/templates/Gemfile
index 243e7e9da8..577ff651e5 100644
--- a/railties/lib/rails/generators/rails/app/templates/Gemfile
+++ b/railties/lib/rails/generators/rails/app/templates/Gemfile
@@ -4,8 +4,6 @@ source 'https://rubygems.org'
<%= database_gemfile_entry -%>
-<%= "gem 'jruby-openssl'\n" if defined?(JRUBY_VERSION) -%>
-
<%= assets_gemfile_entry %>
<%= javascript_gemfile_entry -%>
diff --git a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
index 7342bffd9d..6899dfe9c9 100644
--- a/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
+++ b/railties/lib/rails/generators/rails/app/templates/app/assets/javascripts/application.js.tt
@@ -7,8 +7,7 @@
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
-// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
-// GO AFTER THE REQUIRES BELOW.
+// stub path allows dependency to be excluded from the asset bundle.
//
<% unless options[:skip_javascript] -%>
//= require <%= options[:javascript] %>
diff --git a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt
index 4f1d56cd2f..f2110c2c70 100644
--- a/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt
+++ b/railties/lib/rails/generators/rails/app/templates/config/initializers/wrap_parameters.rb.tt
@@ -7,8 +7,8 @@
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
end
-
<%- unless options.skip_active_record? -%>
+
# To enable root element in JSON for ActiveRecord objects.
# ActiveSupport.on_load(:active_record) do
# self.include_root_in_json = true
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec
index f7c12e67dd..5fdf0e1554 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/%name%.gemspec
@@ -12,6 +12,7 @@ Gem::Specification.new do |s|
s.homepage = "TODO"
s.summary = "TODO: Summary of <%= camelized %>."
s.description = "TODO: Description of <%= camelized %>."
+ s.license = "MIT"
s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"]
<% unless options.skip_test_unit? -%>
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/bin/rails.tt b/railties/lib/rails/generators/rails/plugin_new/templates/bin/rails.tt
index aa87d1b50c..c8de9f3e0f 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/bin/rails.tt
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/bin/rails.tt
@@ -1,4 +1,4 @@
-# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
+# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
ENGINE_ROOT = File.expand_path('../..', __FILE__)
ENGINE_PATH = File.expand_path('../../lib/<%= name -%>/engine', __FILE__)
diff --git a/railties/lib/rails/generators/rails/plugin_new/templates/rails/javascripts.js b/railties/lib/rails/generators/rails/plugin_new/templates/rails/javascripts.js
index 084d5d1c49..f84de00fd3 100644
--- a/railties/lib/rails/generators/rails/plugin_new/templates/rails/javascripts.js
+++ b/railties/lib/rails/generators/rails/plugin_new/templates/rails/javascripts.js
@@ -7,7 +7,6 @@
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
-// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
-// GO AFTER THE REQUIRES BELOW.
+// stub path allows dependency to be excluded from the asset bundle.
//
//= require_tree .
diff --git a/railties/lib/rails/rack/debugger.rb b/railties/lib/rails/rack/debugger.rb
index 902361ce77..f7b77bcb3b 100644
--- a/railties/lib/rails/rack/debugger.rb
+++ b/railties/lib/rails/rack/debugger.rb
@@ -12,8 +12,8 @@ module Rails
::Debugger.settings[:autoeval] = true if ::Debugger.respond_to?(:settings)
puts "=> Debugger enabled"
rescue LoadError
- puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle, and try again."
- exit
+ puts "You're missing the 'debugger' gem. Add it to your Gemfile, bundle it and try again."
+ exit(1)
end
def call(env)
diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb
index 9807000578..142af2d792 100644
--- a/railties/lib/rails/tasks.rb
+++ b/railties/lib/rails/tasks.rb
@@ -1,6 +1,6 @@
$VERBOSE = nil
-# Load Rails rakefile extensions
+# Load Rails Rakefile extensions
%w(
annotations
documentation
diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb
index fa3ab969ae..6703f8df51 100644
--- a/railties/test/application/rake_test.rb
+++ b/railties/test/application/rake_test.rb
@@ -214,7 +214,7 @@ module ApplicationTests
bundle exec rake db:migrate db:test:clone test`
end
- assert_match(/7 tests, 13 assertions, 0 failures, 0 errors/, output)
+ assert_match(/7 runs, 13 assertions, 0 failures, 0 errors/, output)
assert_no_match(/Errors running/, output)
end
@@ -224,7 +224,7 @@ module ApplicationTests
bundle exec rake db:migrate db:test:clone test`
end
- assert_match(/7 tests, 13 assertions, 0 failures, 0 errors/, output)
+ assert_match(/7 runs, 13 assertions, 0 failures, 0 errors/, output)
assert_no_match(/Errors running/, output)
end
diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb
index 1cf53aa4fb..118f22995e 100644
--- a/railties/test/application/test_runner_test.rb
+++ b/railties/test/application/test_runner_test.rb
@@ -32,13 +32,13 @@ module ApplicationTests
def test_run_single_file
create_test_file :models, 'foo'
create_test_file :models, 'bar'
- assert_match "1 tests, 1 assertions, 0 failures", run_test_command("test/models/foo_test.rb")
+ assert_match "1 runs, 1 assertions, 0 failures", run_test_command("test/models/foo_test.rb")
end
def test_run_multiple_files
create_test_file :models, 'foo'
create_test_file :models, 'bar'
- assert_match "2 tests, 2 assertions, 0 failures", run_test_command("test/models/foo_test.rb test/models/bar_test.rb")
+ assert_match "2 runs, 2 assertions, 0 failures", run_test_command("test/models/foo_test.rb test/models/bar_test.rb")
end
def test_run_file_with_syntax_error
@@ -59,7 +59,7 @@ module ApplicationTests
run_test_models_command.tap do |output|
assert_match "FooTest", output
assert_match "BarTest", output
- assert_match "2 tests, 2 assertions, 0 failures", output
+ assert_match "2 runs, 2 assertions, 0 failures", output
end
end
@@ -70,7 +70,7 @@ module ApplicationTests
run_test_helpers_command.tap do |output|
assert_match "FooHelperTest", output
assert_match "BarHelperTest", output
- assert_match "2 tests, 2 assertions, 0 failures", output
+ assert_match "2 runs, 2 assertions, 0 failures", output
end
end
@@ -83,7 +83,7 @@ module ApplicationTests
assert_match "FooTest", output
assert_match "BarHelperTest", output
assert_match "BazUnitTest", output
- assert_match "3 tests, 3 assertions, 0 failures", output
+ assert_match "3 runs, 3 assertions, 0 failures", output
end
end
@@ -94,7 +94,7 @@ module ApplicationTests
run_test_controllers_command.tap do |output|
assert_match "FooControllerTest", output
assert_match "BarControllerTest", output
- assert_match "2 tests, 2 assertions, 0 failures", output
+ assert_match "2 runs, 2 assertions, 0 failures", output
end
end
@@ -105,7 +105,7 @@ module ApplicationTests
run_test_mailers_command.tap do |output|
assert_match "FooMailerTest", output
assert_match "BarMailerTest", output
- assert_match "2 tests, 2 assertions, 0 failures", output
+ assert_match "2 runs, 2 assertions, 0 failures", output
end
end
@@ -118,7 +118,7 @@ module ApplicationTests
assert_match "FooMailerTest", output
assert_match "BarControllerTest", output
assert_match "BazFunctionalTest", output
- assert_match "3 tests, 3 assertions, 0 failures", output
+ assert_match "3 runs, 3 assertions, 0 failures", output
end
end
@@ -127,7 +127,7 @@ module ApplicationTests
create_test_file :models, 'foo'
run_test_integration_command.tap do |output|
assert_match "FooIntegration", output
- assert_match "1 tests, 1 assertions, 0 failures", output
+ assert_match "1 runs, 1 assertions, 0 failures", output
end
end
@@ -136,7 +136,7 @@ module ApplicationTests
suites.each { |suite| create_test_file suite, "foo_#{suite}" }
run_test_command('') .tap do |output|
suites.each { |suite| assert_match "Foo#{suite.to_s.camelize}Test", output }
- assert_match "7 tests, 7 assertions, 0 failures", output
+ assert_match "7 runs, 7 assertions, 0 failures", output
end
end
diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb
index 0ffb615764..e992534938 100644
--- a/railties/test/generators/app_generator_test.rb
+++ b/railties/test/generators/app_generator_test.rb
@@ -183,9 +183,6 @@ class AppGeneratorTest < Rails::Generators::TestCase
run_generator([destination_root, "-d", "jdbcmysql"])
assert_file "config/database.yml", /mysql/
assert_gem "activerecord-jdbcmysql-adapter"
- # TODO: When the JRuby guys merge jruby-openssl in
- # jruby this will be removed
- assert_gem "jruby-openssl" if defined?(JRUBY_VERSION)
end
def test_config_jdbcsqlite3_database
diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb
index ac71fb5884..32c7612a8f 100644
--- a/railties/test/generators/plugin_new_generator_test.rb
+++ b/railties/test/generators/plugin_new_generator_test.rb
@@ -168,14 +168,14 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase
run_generator
FileUtils.cd destination_root
quietly { system 'bundle install' }
- assert_match(/1 tests, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`)
+ assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`)
end
def test_ensure_that_tests_works_in_full_mode
run_generator [destination_root, "--full", "--skip_active_record"]
FileUtils.cd destination_root
quietly { system 'bundle install' }
- assert_match(/1 tests, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`)
+ assert_match(/1 runs, 1 assertions, 0 failures, 0 errors/, `bundle exec rake test`)
end
def test_ensure_that_migration_tasks_work_with_mountable_option