diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb index 6fdf6d810f..505455fe54 100644 --- a/activesupport/lib/active_support/core_ext/object/duplicable.rb +++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb @@ -28,23 +28,32 @@ def duplicable? end end -class Method - # Methods are not duplicable: - # - # method(:puts).duplicable? # => false - # method(:puts).dup # => TypeError: allocator undefined for Method - def duplicable? - false - end +methods_are_duplicable = begin + Object.instance_method(:duplicable?).dup + true +rescue TypeError + false end -class UnboundMethod - # Unbound methods are not duplicable: - # - # method(:puts).unbind.duplicable? # => false - # method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod - def duplicable? - false +unless methods_are_duplicable + class Method + # Methods are not duplicable: + # + # method(:puts).duplicable? # => false + # method(:puts).dup # => TypeError: allocator undefined for Method + def duplicable? + false + end + end + + class UnboundMethod + # Unbound methods are not duplicable: + # + # method(:puts).unbind.duplicable? # => false + # method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod + def duplicable? + false + end end end diff --git a/activesupport/test/core_ext/object/duplicable_test.rb b/activesupport/test/core_ext/object/duplicable_test.rb index 07d9a3df4a..58de295719 100644 --- a/activesupport/test/core_ext/object/duplicable_test.rb +++ b/activesupport/test/core_ext/object/duplicable_test.rb @@ -6,18 +6,26 @@ require "active_support/core_ext/numeric/time" class DuplicableTest < ActiveSupport::TestCase - RAISE_DUP = [method(:puts), method(:puts).unbind, Class.new.include(Singleton).instance] - ALLOW_DUP = ["1", "symbol_from_string".to_sym, Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal("4.56"), nil, false, true, 1, 2.3, Complex(1), Rational(1)] + OBJECTS = [ + method(:puts), method(:puts).unbind, Class.new.include(Singleton).instance, + "1", "symbol_from_string".to_sym, Object.new, /foo/, [], {}, Time.now, Class.new, + Module.new, BigDecimal("4.56"), nil, false, true, 1, 2.3, Complex(1), Rational(1), + ] - def test_duplicable - RAISE_DUP.each do |v| - assert_not v.duplicable?, "#{ v.inspect } should not be duplicable" - assert_raises(TypeError, v.class.name) { v.dup } - end + OBJECTS.each do |v| + test "#{v.class}#duplicable? matches #{v.class}#dup behavior" do + duplicable = begin + v.dup + true + rescue TypeError + false + end - ALLOW_DUP.each do |v| - assert_predicate v, :duplicable?, "#{ v.class } should be duplicable" - assert_nothing_raised { v.dup } + if duplicable + assert_predicate v, :duplicable? + else + assert_not_predicate v, :duplicable? + end end end end