diff options
Diffstat (limited to 'activesupport')
12 files changed, 201 insertions, 30 deletions
diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index fbc6e538d5..45181f0e16 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -13,7 +13,7 @@ class Hash # valid_keys = [:mass, :velocity, :time] # search(options.slice(*valid_keys)) def slice(*keys) - keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) + keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true) keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if has_key?(k) } end @@ -21,7 +21,7 @@ class Hash # Returns a hash contained the removed key/value pairs # {:a => 1, :b => 2, :c => 3, :d => 4}.slice!(:a, :b) # => {:c => 3, :d => 4} def slice!(*keys) - keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) + keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true) omit = slice(*self.keys - keys) hash = slice(*keys) replace(hash) diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb index 9d044eba71..9d1630bb7c 100644 --- a/activesupport/lib/active_support/core_ext/object/duplicable.rb +++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb @@ -104,3 +104,16 @@ class Module false end end + +require 'bigdecimal' +class BigDecimal + begin + BigDecimal.new('4.56').dup + + def duplicable? + true + end + rescue TypeError + # can't dup, so use superclass implementation + end +end diff --git a/activesupport/lib/active_support/core_ext/proc.rb b/activesupport/lib/active_support/core_ext/proc.rb index 94bb5fb0cb..cd63740940 100644 --- a/activesupport/lib/active_support/core_ext/proc.rb +++ b/activesupport/lib/active_support/core_ext/proc.rb @@ -1,7 +1,10 @@ require "active_support/core_ext/kernel/singleton_class" +require "active_support/deprecation" class Proc #:nodoc: def bind(object) + ActiveSupport::Deprecation.warn 'Proc#bind is deprecated and will be removed in future versions', caller + block, time = self, Time.now object.class_eval do method_name = "__bind_#{time.to_i}_#{time.usec}" diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index e4a13870d7..49aa012268 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -5,7 +5,7 @@ module ActiveSupport # people can write <tt>params[:key]</tt> instead of <tt>params['key']</tt> # and they get the same value for both keys. class HashWithIndifferentAccess < Hash - + # Always returns true, so that <tt>Array#extract_options!</tt> finds members of this class. def extractable_options? true diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb index 13f675c654..8cf7bdafda 100644 --- a/activesupport/lib/active_support/notifications.rb +++ b/activesupport/lib/active_support/notifications.rb @@ -1,3 +1,6 @@ +require 'active_support/notifications/instrumenter' +require 'active_support/notifications/fanout' + module ActiveSupport # = Notifications # @@ -105,10 +108,6 @@ module ActiveSupport # to log subscribers in a thread. You can use any queue implementation you want. # module Notifications - autoload :Instrumenter, 'active_support/notifications/instrumenter' - autoload :Event, 'active_support/notifications/instrumenter' - autoload :Fanout, 'active_support/notifications/fanout' - @instrumenters = Hash.new { |h,k| h[k] = notifier.listening?(k) } class << self diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb index 4c1b7b2784..17c99089c1 100644 --- a/activesupport/lib/active_support/notifications/fanout.rb +++ b/activesupport/lib/active_support/notifications/fanout.rb @@ -9,7 +9,7 @@ module ActiveSupport end def subscribe(pattern = nil, block = Proc.new) - subscriber = Subscriber.new(pattern, block) + subscriber = Subscribers.new pattern, block @subscribers << subscriber @listeners_for.clear subscriber @@ -20,6 +20,14 @@ module ActiveSupport @listeners_for.clear end + def start(name, id, payload) + listeners_for(name).each { |s| s.start(name, id, payload) } + end + + def finish(name, id, payload) + listeners_for(name).each { |s| s.finish(name, id, payload) } + end + def publish(name, *args) listeners_for(name).each { |s| s.publish(name, *args) } end @@ -36,23 +44,89 @@ module ActiveSupport def wait end - class Subscriber #:nodoc: - def initialize(pattern, delegate) - @pattern = pattern - @delegate = delegate + module Subscribers # :nodoc: + def self.new(pattern, listener) + if listener.respond_to?(:call) + subscriber = Timed.new pattern, listener + else + subscriber = Evented.new pattern, listener + end + + unless pattern + AllMessages.new(subscriber) + else + subscriber + end end - def publish(message, *args) - @delegate.call(message, *args) + class Evented #:nodoc: + def initialize(pattern, delegate) + @pattern = pattern + @delegate = delegate + end + + def start(name, id, payload) + @delegate.start name, id, payload + end + + def finish(name, id, payload) + @delegate.finish name, id, payload + end + + def subscribed_to?(name) + @pattern === name.to_s + end + + def matches?(subscriber_or_name) + self === subscriber_or_name || + @pattern && @pattern === subscriber_or_name + end end - def subscribed_to?(name) - !@pattern || @pattern === name.to_s + class Timed < Evented + def initialize(pattern, delegate) + @timestack = Hash.new { |h,id| + h[id] = Hash.new { |ids,name| ids[name] = [] } + } + super + end + + def publish(name, *args) + @delegate.call name, *args + end + + def start(name, id, payload) + @timestack[id][name].push Time.now + end + + def finish(name, id, payload) + started = @timestack[id][name].pop + @delegate.call(name, started, Time.now, id, payload) + end end - def matches?(subscriber_or_name) - self === subscriber_or_name || - @pattern && @pattern === subscriber_or_name + class AllMessages # :nodoc: + def initialize(delegate) + @delegate = delegate + end + + def start(name, id, payload) + @delegate.start name, id, payload + end + + def finish(name, id, payload) + @delegate.finish name, id, payload + end + + def publish(name, *args) + @delegate.publish name, *args + end + + def subscribed_to?(name) + true + end + + alias :matches? :=== end end end diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb index 547df5c731..58e292c658 100644 --- a/activesupport/lib/active_support/notifications/instrumenter.rb +++ b/activesupport/lib/active_support/notifications/instrumenter.rb @@ -1,5 +1,6 @@ module ActiveSupport module Notifications + # Instrumentors are stored in a thread local. class Instrumenter attr_reader :id @@ -12,15 +13,14 @@ module ActiveSupport # and publish it. Notice that events get sent even if an error occurs # in the passed-in block def instrument(name, payload={}) - started = Time.now - + @notifier.start(name, @id, payload) begin yield rescue Exception => e payload[:exception] = [e.class.name, e.message] raise e ensure - @notifier.publish(name, started, Time.now, @id, payload) + @notifier.finish(name, @id, payload) end end diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb index 0f4a06468a..85e84bc203 100644 --- a/activesupport/lib/active_support/rescuable.rb +++ b/activesupport/lib/active_support/rescuable.rb @@ -108,7 +108,11 @@ module ActiveSupport when Symbol method(rescuer) when Proc - rescuer.bind(self) + if rescuer.arity == 0 + Proc.new { instance_exec(&rescuer) } + else + Proc.new { |_exception| instance_exec(_exception, &rescuer) } + end end end end diff --git a/activesupport/test/core_ext/duplicable_test.rb b/activesupport/test/core_ext/duplicable_test.rb index 3e54266051..1105353e45 100644 --- a/activesupport/test/core_ext/duplicable_test.rb +++ b/activesupport/test/core_ext/duplicable_test.rb @@ -4,17 +4,25 @@ require 'active_support/core_ext/object/duplicable' require 'active_support/core_ext/numeric/time' class DuplicableTest < ActiveSupport::TestCase - RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, BigDecimal.new('4.56'), 5.seconds] + RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, 5.seconds] YES = ['1', Object.new, /foo/, [], {}, Time.now] NO = [Class.new, Module.new] + begin + bd = BigDecimal.new('4.56') + YES << bd.dup + rescue TypeError + RAISE_DUP << bd + end + + def test_duplicable (RAISE_DUP + NO).each do |v| assert !v.duplicable? end YES.each do |v| - assert v.duplicable? + assert v.duplicable?, "#{v.class} should be duplicable" end (YES + NO).each do |v| diff --git a/activesupport/test/core_ext/proc_test.rb b/activesupport/test/core_ext/proc_test.rb index 690bfd3bf8..c4d5592196 100644 --- a/activesupport/test/core_ext/proc_test.rb +++ b/activesupport/test/core_ext/proc_test.rb @@ -3,10 +3,12 @@ require 'active_support/core_ext/proc' class ProcTests < ActiveSupport::TestCase def test_bind_returns_method_with_changed_self - block = Proc.new { self } - assert_equal self, block.call - bound_block = block.bind("hello") - assert_not_equal block, bound_block - assert_equal "hello", bound_block.call + assert_deprecated do + block = Proc.new { self } + assert_equal self, block.call + bound_block = block.bind("hello") + assert_not_equal block, bound_block + assert_equal "hello", bound_block.call + end end end diff --git a/activesupport/test/notifications/evented_notification_test.rb b/activesupport/test/notifications/evented_notification_test.rb new file mode 100644 index 0000000000..f77a0eb3fa --- /dev/null +++ b/activesupport/test/notifications/evented_notification_test.rb @@ -0,0 +1,67 @@ +require 'abstract_unit' + +module ActiveSupport + module Notifications + class EventedTest < ActiveSupport::TestCase + class Listener + attr_reader :events + + def initialize + @events = [] + end + + def start(name, id, payload) + @events << [:start, name, id, payload] + end + + def finish(name, id, payload) + @events << [:finish, name, id, payload] + end + end + + def test_evented_listener + notifier = Fanout.new + listener = Listener.new + notifier.subscribe 'hi', listener + notifier.start 'hi', 1, {} + notifier.start 'hi', 2, {} + notifier.finish 'hi', 2, {} + notifier.finish 'hi', 1, {} + + assert_equal 4, listener.events.length + assert_equal [ + [:start, 'hi', 1, {}], + [:start, 'hi', 2, {}], + [:finish, 'hi', 2, {}], + [:finish, 'hi', 1, {}], + ], listener.events + end + + def test_evented_listener_no_events + notifier = Fanout.new + listener = Listener.new + notifier.subscribe 'hi', listener + notifier.start 'world', 1, {} + assert_equal 0, listener.events.length + end + + def test_listen_to_everything + notifier = Fanout.new + listener = Listener.new + notifier.subscribe nil, listener + notifier.start 'hello', 1, {} + notifier.start 'world', 1, {} + notifier.finish 'world', 1, {} + notifier.finish 'hello', 1, {} + + assert_equal 4, listener.events.length + assert_equal [ + [:start, 'hello', 1, {}], + [:start, 'world', 1, {}], + [:finish, 'world', 1, {}], + [:finish, 'hello', 1, {}], + ], listener.events + end + end + end +end diff --git a/activesupport/test/ordered_options_test.rb b/activesupport/test/ordered_options_test.rb index 0eee991e20..3526c7a366 100644 --- a/activesupport/test/ordered_options_test.rb +++ b/activesupport/test/ordered_options_test.rb @@ -1,4 +1,5 @@ require 'abstract_unit' +require 'active_support/ordered_options' class OrderedOptionsTest < ActiveSupport::TestCase def test_usage |