aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport
diff options
context:
space:
mode:
authorMatthew Draper <matthew@trebex.net>2016-10-03 01:34:27 +1030
committerMatthew Draper <matthew@trebex.net>2016-10-03 13:35:51 +1030
commite8b36e7711d44bf23a39426b3d766c08528573b3 (patch)
treeb9c6b801df7cf50c3902cb5c50dbe22089dc3837 /activesupport
parent7b63f56ce0c708f05db31de04b8cd2dc6e4ef96b (diff)
downloadrails-e8b36e7711d44bf23a39426b3d766c08528573b3.tar.gz
rails-e8b36e7711d44bf23a39426b3d766c08528573b3.tar.bz2
rails-e8b36e7711d44bf23a39426b3d766c08528573b3.zip
Avoid bumping the class serial when invoking executor
Diffstat (limited to 'activesupport')
-rw-r--r--activesupport/lib/active_support/execution_wrapper.rb33
-rw-r--r--activesupport/test/executor_test.rb55
2 files changed, 76 insertions, 12 deletions
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/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)