diff options
34 files changed, 211 insertions, 94 deletions
diff --git a/.travis.yml b/.travis.yml index 585791f757..88dd6b7b5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ env: matrix: - "GEM=railties" - "GEM=ap" - - "GEM=ac TESTOPTS=-vs26" + - "GEM=ac" - "GEM=ac:integration" - "GEM=am,amo,as,av,aj" - "GEM=as PRESERVE_TIMEZONES=1" @@ -66,7 +66,6 @@ matrix: allow_failures: - rvm: ruby-head - rvm: jruby-9.0.5.0 - - env: "GEM=ac:integration" fast_finish: true notifications: @@ -36,7 +36,7 @@ gem "sass", github: "sass/sass", branch: "stable", require: false gem "rb-inotify", github: "matthewd/rb-inotify", branch: "close-handling", require: false group :doc do - gem "sdoc", "~> 0.4.0" + gem "sdoc", "1.0.0.beta2" gem "redcarpet", "~> 3.2.3", platforms: :ruby gem "w3c_validators" gem "kindlerb", "0.1.1" @@ -72,7 +72,7 @@ group :cable do gem "hiredis", require: false gem "redis", require: false - gem "websocket-client-simple", require: false + gem "websocket-client-simple", github: "matthewd/websocket-client-simple", branch: "close-race", require: false gem "blade", require: false, platforms: [:ruby] gem "blade-sauce_labs_plugin", require: false, platforms: [:ruby] diff --git a/Gemfile.lock b/Gemfile.lock index 14635a8cb2..d4059c607d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -30,6 +30,15 @@ GIT ffi (>= 0.5.0) GIT + remote: https://github.com/matthewd/websocket-client-simple.git + revision: e161305f1a466b9398d86df3b1731b03362da91b + branch: close-race + specs: + websocket-client-simple (0.3.0) + event_emitter + websocket + +GIT remote: https://github.com/resque/resque.git revision: 20d885065ac19e7f7d7a982f4ed1296083db0300 specs: @@ -201,7 +210,7 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (1.8.3) + json (2.0.2) kindlerb (0.1.1) mustache nokogiri @@ -267,8 +276,7 @@ GEM loofah (~> 2.0) rake (11.3.0) rb-fsevent (0.9.7) - rdoc (4.2.2) - json (~> 1.4) + rdoc (5.0.0.beta2) redcarpet (3.2.3) redis (3.3.1) redis-namespace (1.5.2) @@ -287,9 +295,8 @@ GEM sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - sdoc (0.4.1) - json (~> 1.7, >= 1.7.7) - rdoc (~> 4.0) + sdoc (1.0.0.beta2) + rdoc (= 5.0.0.beta2) selenium-webdriver (2.53.4) childprocess (~> 0.5) rubyzip (~> 1.0) @@ -350,9 +357,6 @@ GEM nokogiri wdm (0.1.1) websocket (1.2.3) - websocket-client-simple (0.3.0) - event_emitter - websocket websocket-driver (0.6.4) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) @@ -402,7 +406,7 @@ DEPENDENCIES resque-scheduler sass! sass-rails - sdoc (~> 0.4.0) + sdoc (= 1.0.0.beta2) sequel sidekiq sneakers @@ -414,7 +418,7 @@ DEPENDENCIES uglifier (>= 1.3.0) w3c_validators wdm (>= 0.1.0) - websocket-client-simple + websocket-client-simple! BUNDLED WITH 1.13.2 diff --git a/actioncable/README.md b/actioncable/README.md index 28e2602cbf..a0b7412dd4 100644 --- a/actioncable/README.md +++ b/actioncable/README.md @@ -167,7 +167,7 @@ App.cable.subscriptions.create "AppearanceChannel", buttonSelector = "[data-behavior~=appear_away]" install: -> - $(document).on "page:change.appearance", => + $(document).on "turbolinks:load.appearance", => @appear() $(document).on "click.appearance", buttonSelector, => diff --git a/actioncable/lib/action_cable/connection/stream.rb b/actioncable/lib/action_cable/connection/stream.rb index d66e1b4e41..e620b93845 100644 --- a/actioncable/lib/action_cable/connection/stream.rb +++ b/actioncable/lib/action_cable/connection/stream.rb @@ -106,7 +106,6 @@ module ActionCable def clean_rack_hijack return unless @rack_hijack_io @event_loop.detach(@rack_hijack_io, self) - @rack_hijack_io.close @rack_hijack_io = nil end end diff --git a/actioncable/lib/action_cable/connection/stream_event_loop.rb b/actioncable/lib/action_cable/connection/stream_event_loop.rb index eec24638b6..2d1af0ff9f 100644 --- a/actioncable/lib/action_cable/connection/stream_event_loop.rb +++ b/actioncable/lib/action_cable/connection/stream_event_loop.rb @@ -36,6 +36,7 @@ module ActionCable @todo << lambda do @nio.deregister io @map.delete io + io.close end wakeup end diff --git a/actioncable/test/client_test.rb b/actioncable/test/client_test.rb index f6d4ab3202..db10a7ad16 100644 --- a/actioncable/test/client_test.rb +++ b/actioncable/test/client_test.rb @@ -21,13 +21,6 @@ WebSocket::Frame::Data.prepend Module.new { super end } - -WebSocket::Client::Simple::Client.prepend Module.new { - def initialize(*) - @socket = nil - super - end -} # #### diff --git a/actioncable/test/connection/client_socket_test.rb b/actioncable/test/connection/client_socket_test.rb index dff7fefbfb..bc3ff6a3d7 100644 --- a/actioncable/test/connection/client_socket_test.rb +++ b/actioncable/test/connection/client_socket_test.rb @@ -51,10 +51,12 @@ class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase connection = open_connection client = connection.websocket.send(:websocket) + event = Concurrent::Event.new client.instance_variable_get("@stream") .instance_variable_get("@rack_hijack_io") - .expects(:close) + .define_singleton_method(:close) { event.set } connection.close + event.wait end end @@ -63,7 +65,13 @@ class ActionCable::Connection::ClientSocketTest < ActionCable::TestCase env = Rack::MockRequest.env_for "/test", "HTTP_CONNECTION" => "upgrade", "HTTP_UPGRADE" => "websocket", "HTTP_HOST" => "localhost", "HTTP_ORIGIN" => "http://rubyonrails.com" - env["rack.hijack"] = -> { env["rack.hijack_io"] = StringIO.new } + io = \ + begin + Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM, 0).first + rescue + StringIO.new + end + env["rack.hijack"] = -> { env["rack.hijack_io"] = io } Connection.new(@server, env).tap do |connection| connection.process diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb index 720651fa1f..265459f79e 100644 --- a/actionpack/lib/action_dispatch/testing/integration.rb +++ b/actionpack/lib/action_dispatch/testing/integration.rb @@ -713,6 +713,8 @@ module ActionDispatch class IntegrationTest < ActiveSupport::TestCase include TestProcess + undef :assigns + module UrlOptions extend ActiveSupport::Concern def url_options diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index d3bc77d3ef..cf96b9b752 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -383,6 +383,14 @@ class IntegrationTestTest < ActiveSupport::TestCase mixin.__send__(:remove_method, :method_missing) end end + + def test_assigns_is_undefined_and_not_point_to_the_gem + e = assert_raises(NoMethodError) do + @test.assigns(:foo) + end + + assert_match(/undefined method/, e.message) + end end # Tests that integration tests don't call Controller test methods for processing. diff --git a/actionpack/test/controller/live_stream_test.rb b/actionpack/test/controller/live_stream_test.rb index 1361e95081..e76628b936 100644 --- a/actionpack/test/controller/live_stream_test.rb +++ b/actionpack/test/controller/live_stream_test.rb @@ -157,7 +157,9 @@ module ActionController response.headers["Content-Type"] = "text/event-stream" response.stream.write "before load" sleep 0.01 - ::LoadMe + silence_warning do + ::LoadMe + end response.stream.close latch.count_down diff --git a/actionview/lib/action_view/digestor.rb b/actionview/lib/action_view/digestor.rb index 2d6ad8f6d9..0658d8601d 100644 --- a/actionview/lib/action_view/digestor.rb +++ b/actionview/lib/action_view/digestor.rb @@ -6,6 +6,12 @@ module ActionView class Digestor @@digest_mutex = Mutex.new + module PerExecutionDigestCacheExpiry + def self.before(target) + ActionView::LookupContext::DetailsKey.clear + end + end + class << self # Supported options: # diff --git a/actionview/lib/action_view/railtie.rb b/actionview/lib/action_view/railtie.rb index dfb99f4ea9..42795ca2c7 100644 --- a/actionview/lib/action_view/railtie.rb +++ b/actionview/lib/action_view/railtie.rb @@ -40,7 +40,7 @@ module ActionView initializer "action_view.per_request_digest_cache" do |app| ActiveSupport.on_load(:action_view) do if app.config.consider_all_requests_local - app.executor.to_run { ActionView::LookupContext::DetailsKey.clear } + app.executor.to_run ActionView::Digestor::PerExecutionDigestCacheExpiry end end end diff --git a/activejob/CHANGELOG.md b/activejob/CHANGELOG.md index 9bf397af14..ef62b2136b 100644 --- a/activejob/CHANGELOG.md +++ b/activejob/CHANGELOG.md @@ -16,13 +16,13 @@ class RemoteServiceJob < ActiveJob::Base retry_on CustomAppException # defaults to 3s wait, 5 attempts retry_on AnotherCustomAppException, wait: ->(executions) { executions * 2 } - retry_on ActiveRecord::StatementInvalid, wait: 5.seconds, attempts: 3 + retry_on ActiveRecord::Deadlocked, wait: 5.seconds, attempts: 3 retry_on Net::OpenTimeout, wait: :exponentially_longer, attempts: 10 discard_on ActiveJob::DeserializationError def perform(*args) # Might raise CustomAppException or AnotherCustomAppException for something domain specific - # Might raise ActiveRecord::StatementInvalid when a local db deadlock is detected + # Might raise ActiveRecord::Deadlocked when a local db deadlock is detected # Might raise Net::OpenTimeout when the remote service is down end end diff --git a/activejob/lib/active_job/arguments.rb b/activejob/lib/active_job/arguments.rb index 41ce5f863b..23e237c1b7 100644 --- a/activejob/lib/active_job/arguments.rb +++ b/activejob/lib/active_job/arguments.rb @@ -34,8 +34,8 @@ module ActiveJob module Arguments extend self # :nodoc: - # Calls #uniq since Integer, Fixnum, and Bignum are all the same class on Ruby 2.4+ - TYPE_WHITELIST = [ NilClass, String, Integer, Fixnum, Bignum, Float, BigDecimal, TrueClass, FalseClass ].uniq + TYPE_WHITELIST = [ NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass ] + TYPE_WHITELIST.push(Fixnum, Bignum) unless 1.class == Integer # Serializes a set of arguments. Whitelisted types are returned # as-is. Arrays/Hashes are serialized element by element. diff --git a/activemodel/lib/active_model/type/float.rb b/activemodel/lib/active_model/type/float.rb index 94bb7e700c..4d0d2771a0 100644 --- a/activemodel/lib/active_model/type/float.rb +++ b/activemodel/lib/active_model/type/float.rb @@ -7,6 +7,15 @@ module ActiveModel :float end + def type_cast_for_schema(value) + return "::Float::NAN" if value.try(:nan?) + case value + when ::Float::INFINITY then "::Float::INFINITY" + when -::Float::INFINITY then "-::Float::INFINITY" + else super + end + end + alias serialize cast private diff --git a/activerecord/lib/active_record/log_subscriber.rb b/activerecord/lib/active_record/log_subscriber.rb index b27e84a5be..ad71c6cde8 100644 --- a/activerecord/lib/active_record/log_subscriber.rb +++ b/activerecord/lib/active_record/log_subscriber.rb @@ -26,9 +26,8 @@ module ActiveRecord end def sql(event) - return unless logger.debug? - self.class.runtime += event.duration + return unless logger.debug? payload = event.payload diff --git a/activerecord/lib/active_record/query_cache.rb b/activerecord/lib/active_record/query_cache.rb index 387dd8e9bd..c45c8c1697 100644 --- a/activerecord/lib/active_record/query_cache.rb +++ b/activerecord/lib/active_record/query_cache.rb @@ -34,16 +34,14 @@ module ActiveRecord def self.complete(enabled) ActiveRecord::Base.connection.clear_query_cache ActiveRecord::Base.connection.disable_query_cache! unless enabled + + unless ActiveRecord::Base.connected? && ActiveRecord::Base.connection.transaction_open? + ActiveRecord::Base.clear_active_connections! + end end def self.install_executor_hooks(executor = ActiveSupport::Executor) executor.register_hook(self) - - executor.to_complete do - unless ActiveRecord::Base.connected? && ActiveRecord::Base.connection.transaction_open? - ActiveRecord::Base.clear_active_connections! - end - end end end end diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 9b692f55d2..57020e00c9 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -282,6 +282,10 @@ module ActiveRecord end def autosave=(autosave) + # autosave and inverse_of do not get along together nowadays. They may + # for example cause double saves. Thus, we disable this flag. If in the + # future those two flags are known to work well together, this could be + # removed. @automatic_inverse_of = false @options[:autosave] = autosave parent_reflection = self.parent_reflection diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index a887be8a20..e4676f79a5 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -112,10 +112,6 @@ module ActiveRecord # ... # end def calculate(operation, column_name) - if column_name.is_a?(Symbol) && attribute_alias?(column_name) - column_name = attribute_alias(column_name) - end - if has_include?(column_name) relation = construct_relation_for_association_calculations relation = relation.distinct if operation.to_s.downcase == "count" @@ -215,8 +211,8 @@ module ActiveRecord def aggregate_column(column_name) return column_name if Arel::Expressions === column_name - if @klass.column_names.include?(column_name.to_s) - Arel::Attribute.new(@klass.unscoped.table, column_name) + if @klass.has_attribute?(column_name.to_s) || @klass.attribute_alias?(column_name.to_s) + @klass.arel_attribute(column_name) else Arel.sql(column_name == :all ? "*" : column_name.to_s) end diff --git a/activerecord/test/cases/adapters/postgresql/transaction_test.rb b/activerecord/test/cases/adapters/postgresql/transaction_test.rb index 00119f13bb..c450524de8 100644 --- a/activerecord/test/cases/adapters/postgresql/transaction_test.rb +++ b/activerecord/test/cases/adapters/postgresql/transaction_test.rb @@ -28,32 +28,29 @@ module ActiveRecord end test "raises SerializationFailure when a serialization failure occurs" do - with_warning_suppression do - assert_raises(ActiveRecord::SerializationFailure) do - thread = Thread.new do - Sample.transaction isolation: :serializable do - Sample.delete_all + assert_raises(ActiveRecord::SerializationFailure) do + before = Concurrent::CyclicBarrier.new(2) + after = Concurrent::CyclicBarrier.new(2) - 10.times do |i| - sleep 0.1 - - Sample.create value: i - end + thread = Thread.new do + with_warning_suppression do + Sample.transaction isolation: :serializable do + before.wait + Sample.create value: Sample.sum(:value) + after.wait end end + end - sleep 0.1 - - Sample.transaction isolation: :serializable do - Sample.delete_all - - 10.times do |i| - sleep 0.1 - - Sample.create value: i + begin + with_warning_suppression do + Sample.transaction isolation: :serializable do + before.wait + Sample.create value: Sample.sum(:value) + after.wait end end - + ensure thread.join end end @@ -91,10 +88,11 @@ module ActiveRecord protected def with_warning_suppression - log_level = @connection.client_min_messages - @connection.client_min_messages = "error" + log_level = ActiveRecord::Base.connection.client_min_messages + ActiveRecord::Base.connection.client_min_messages = "error" yield - @connection.client_min_messages = log_level + ensure + ActiveRecord::Base.connection.client_min_messages = log_level end end end diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb index 03d781d3d2..48df931543 100644 --- a/activerecord/test/cases/migration/column_attributes_test.rb +++ b/activerecord/test/cases/migration/column_attributes_test.rb @@ -72,9 +72,7 @@ module ActiveRecord assert_kind_of BigDecimal, row.wealth # If this assert fails, that means the SELECT is broken! - unless current_adapter?(:SQLite3Adapter) - assert_equal correct_value, row.wealth - end + assert_equal correct_value, row.wealth # Reset to old state TestModel.delete_all @@ -165,7 +163,7 @@ module ActiveRecord assert_raise(ActiveRecordError) { add_column :test_models, :integer_too_big, :integer, limit: 10 } unless current_adapter?(:PostgreSQLAdapter) - assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :integer, limit: 0xfffffffff } + assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :text, limit: 0xfffffffff } end end end diff --git a/activerecord/test/cases/query_cache_test.rb b/activerecord/test/cases/query_cache_test.rb index 7f7faca70d..16cf2bd2d0 100644 --- a/activerecord/test/cases/query_cache_test.rb +++ b/activerecord/test/cases/query_cache_test.rb @@ -138,7 +138,7 @@ class QueryCacheTest < ActiveRecord::TestCase assert_kind_of Numeric, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") elsif current_adapter?(:SQLite3Adapter, :Mysql2Adapter, :PostgreSQLAdapter) # Future versions of the sqlite3 adapter will return numeric - assert_instance_of Fixnum, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") + assert_instance_of 0.class, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") else assert_instance_of String, Task.connection.select_value("SELECT count(*) AS count_all FROM tasks") end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index dcaae5b462..2e18c43b1b 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -1522,7 +1522,7 @@ class RelationTest < ActiveRecord::TestCase assert_equal Post.where(author_id: 1).to_a, author_posts.to_a all_posts = relation.only(:limit) - assert_equal Post.limit(1).to_a.first, all_posts.first + assert_equal Post.limit(1).to_a, all_posts.to_a end def test_anonymous_extension diff --git a/activerecord/test/cases/schema_dumper_test.rb b/activerecord/test/cases/schema_dumper_test.rb index 57b1bc889a..8b604ba930 100644 --- a/activerecord/test/cases/schema_dumper_test.rb +++ b/activerecord/test/cases/schema_dumper_test.rb @@ -423,6 +423,13 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase t.datetime :datetime_with_default, default: "2014-06-05 07:17:04" t.time :time_with_default, default: "07:17:04" end + + if current_adapter?(:PostgreSQLAdapter) + @connection.create_table :infinity_defaults, force: true do |t| + t.float :float_with_inf_default, default: Float::INFINITY + t.float :float_with_nan_default, default: Float::NAN + end + end end teardown do @@ -438,4 +445,11 @@ class SchemaDumperDefaultsTest < ActiveRecord::TestCase assert_match %r{t\.datetime\s+"datetime_with_default",\s+default: '2014-06-05 07:17:04'}, output assert_match %r{t\.time\s+"time_with_default",\s+default: '2000-01-01 07:17:04'}, output end + + def test_schema_dump_with_float_column_infinity_default + skip unless current_adapter?(:PostgreSQLAdapter) + output = dump_table_schema('infinity_defaults') + assert_match %r{t\.float\s+"float_with_inf_default",\s+default: ::Float::INFINITY}, output + assert_match %r{t\.float\s+"float_with_nan_default",\s+default: ::Float::NAN}, output + end end diff --git a/activerecord/test/cases/type/date_time_test.rb b/activerecord/test/cases/type/date_time_test.rb index bc4900e1c2..6848619ece 100644 --- a/activerecord/test/cases/type/date_time_test.rb +++ b/activerecord/test/cases/type/date_time_test.rb @@ -3,7 +3,7 @@ require "models/task" module ActiveRecord module Type - class IntegerTest < ActiveRecord::TestCase + class DateTimeTest < ActiveRecord::TestCase def test_datetime_seconds_precision_applied_to_timestamp skip "This test is invalid if subsecond precision isn't supported" unless subsecond_precision_supported? p = Task.create!(starting: ::Time.now) diff --git a/activesupport/lib/active_support/core_ext/numeric/conversions.rb b/activesupport/lib/active_support/core_ext/numeric/conversions.rb index 5ac312790d..cebfda8d31 100644 --- a/activesupport/lib/active_support/core_ext/numeric/conversions.rb +++ b/activesupport/lib/active_support/core_ext/numeric/conversions.rb @@ -134,7 +134,7 @@ module ActiveSupport::NumericWithFormat end # Ruby 2.4+ unifies Fixnum & Bignum into Integer. -if Integer == Fixnum +if 0.class == Integer Integer.prepend ActiveSupport::NumericWithFormat else Fixnum.prepend ActiveSupport::NumericWithFormat diff --git a/activesupport/lib/active_support/deprecation/instance_delegator.rb b/activesupport/lib/active_support/deprecation/instance_delegator.rb index 8efa6aabdc..6d390f3b37 100644 --- a/activesupport/lib/active_support/deprecation/instance_delegator.rb +++ b/activesupport/lib/active_support/deprecation/instance_delegator.rb @@ -6,6 +6,7 @@ module ActiveSupport module InstanceDelegator # :nodoc: def self.included(base) base.extend(ClassMethods) + base.singleton_class.prepend(OverrideDelegators) base.public_class_method :new end @@ -19,6 +20,18 @@ module ActiveSupport singleton_class.delegate(method_name, to: :instance) end end + + module OverrideDelegators # :nodoc: + def warn(message = nil, callstack = nil) + callstack ||= caller_locations(2) + super + end + + def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil) + caller_backtrace ||= caller_locations(2) + super + end + end end end end diff --git a/activesupport/lib/active_support/execution_wrapper.rb b/activesupport/lib/active_support/execution_wrapper.rb index 4c8b03c9df..3384d12d5b 100644 --- a/activesupport/lib/active_support/execution_wrapper.rb +++ b/activesupport/lib/active_support/execution_wrapper.rb @@ -19,6 +19,23 @@ module ActiveSupport set_callback(:complete, *args, &block) end + class RunHook < Struct.new(:hook) # :nodoc: + def before(target) + hook_state = target.send(:hook_state) + hook_state[hook] = hook.run + end + end + + class CompleteHook < Struct.new(:hook) # :nodoc: + def before(target) + hook_state = target.send(:hook_state) + if hook_state.key?(hook) + hook.complete hook_state[hook] + end + end + alias after before + end + # Register an object to be invoked during both the +run+ and # +complete+ steps. # @@ -29,19 +46,11 @@ module ActiveSupport # invoked in that situation.) def self.register_hook(hook, outer: false) if outer - run_args = [prepend: true] - complete_args = [:after] + to_run RunHook.new(hook), prepend: true + to_complete :after, CompleteHook.new(hook) else - run_args = complete_args = [] - end - - to_run(*run_args) do - hook_state[hook] = hook.run - end - to_complete(*complete_args) do - if hook_state.key?(hook) - hook.complete hook_state[hook] - end + to_run RunHook.new(hook) + to_complete CompleteHook.new(hook) end end diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 8de8120fba..889f71c4f3 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -477,6 +477,8 @@ module ActiveSupport end def transfer_time_values_to_utc_constructor(time) + # avoid creating another Time object if possible + return time if time.instance_of?(::Time) && time.utc? ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec + time.subsec) end diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb index 46b91806f6..921a3447d0 100644 --- a/activesupport/lib/active_support/xml_mini.rb +++ b/activesupport/lib/active_support/xml_mini.rb @@ -48,8 +48,8 @@ module ActiveSupport } # No need to map these on Ruby 2.4+ - TYPE_NAMES["Fixnum"] = "integer" unless Fixnum == Integer - TYPE_NAMES["Bignum"] = "integer" unless Bignum == Integer + TYPE_NAMES["Fixnum"] = "integer" unless 0.class == Integer + TYPE_NAMES["Bignum"] = "integer" unless 0.class == Integer end FORMATTING = { diff --git a/activesupport/test/core_ext/array/grouping_test.rb b/activesupport/test/core_ext/array/grouping_test.rb index 86c9bae131..b06f87c008 100644 --- a/activesupport/test/core_ext/array/grouping_test.rb +++ b/activesupport/test/core_ext/array/grouping_test.rb @@ -4,11 +4,11 @@ require "active_support/core_ext/array" class GroupingTest < ActiveSupport::TestCase def setup # In Ruby < 2.4, test we avoid Integer#/ (redefined by mathn) - Fixnum.send :private, :/ unless Fixnum == Integer + Fixnum.send :private, :/ unless 0.class == Integer end def teardown - Fixnum.send :public, :/ unless Fixnum == Integer + Fixnum.send :public, :/ unless 0.class == Integer end def test_in_groups_of_with_perfect_fit diff --git a/activesupport/test/executor_test.rb b/activesupport/test/executor_test.rb index 0b56ea008f..d409216206 100644 --- a/activesupport/test/executor_test.rb +++ b/activesupport/test/executor_test.rb @@ -158,6 +158,61 @@ class ExecutorTest < ActiveSupport::TestCase assert_equal :some_state, supplied_state end + def test_hook_insertion_order + invoked = [] + supplied_state = [] + + hook_class = Class.new do + attr_accessor :letter + + define_method(:initialize) do |letter| + self.letter = letter + end + + define_method(:run) do + invoked << :"run_#{letter}" + :"state_#{letter}" + end + + define_method(:complete) do |state| + invoked << :"complete_#{letter}" + supplied_state << state + end + end + + executor.register_hook(hook_class.new(:a)) + executor.register_hook(hook_class.new(:b)) + executor.register_hook(hook_class.new(:c), outer: true) + executor.register_hook(hook_class.new(:d)) + + executor.wrap {} + + assert_equal [:run_c, :run_a, :run_b, :run_d, :complete_a, :complete_b, :complete_d, :complete_c], invoked + assert_equal [:state_a, :state_b, :state_d, :state_c], supplied_state + end + + def test_class_serial_is_unaffected + hook = Class.new do + define_method(:run) do + nil + end + + define_method(:complete) do |state| + nil + end + end.new + + executor.register_hook(hook) + + before = RubyVM.stat(:class_serial) + executor.wrap {} + executor.wrap {} + executor.wrap {} + after = RubyVM.stat(:class_serial) + + assert_equal before, after + end + def test_separate_classes_can_wrap other_executor = Class.new(ActiveSupport::Executor) diff --git a/guides/source/action_cable_overview.md b/guides/source/action_cable_overview.md index 4b9a22101a..a66a8ff484 100644 --- a/guides/source/action_cable_overview.md +++ b/guides/source/action_cable_overview.md @@ -422,7 +422,7 @@ App.cable.subscriptions.create "AppearanceChannel", buttonSelector = "[data-behavior~=appear_away]" install: -> - $(document).on "page:change.appearance", => + $(document).on "turbolinks:load.appearance", => @appear() $(document).on "click.appearance", buttonSelector, => |