1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Backport Object#public_send to 1.8 so that we can implement Module#delegate such that non-public methods raise

This commit is contained in:
Jon Leighton 2011-07-18 15:50:02 +01:00
parent 652ab436db
commit 6f4b405250
3 changed files with 143 additions and 0 deletions

View file

@ -3,6 +3,7 @@ require 'active_support/core_ext/object/blank'
require 'active_support/core_ext/object/duplicable'
require 'active_support/core_ext/object/try'
require 'active_support/core_ext/object/inclusion'
require 'active_support/core_ext/object/public_send'
require 'active_support/core_ext/object/conversions'
require 'active_support/core_ext/object/instance_variables'

View file

@ -0,0 +1,25 @@
require 'active_support/core_ext/kernel/singleton_class'
class Object
unless Object.public_method_defined?(:public_send)
# Backports Object#public_send from 1.9
def public_send(method, *args, &block) # :nodoc:
# Don't create a singleton class for the object if it doesn't already have one
# (This also protects us from classes like Fixnum and Symbol, which cannot have a
# singleton class.)
klass = singleton_methods.any? ? self.singleton_class : self.class
if klass.public_method_defined?(method)
send(method, *args, &block)
else
if klass.private_method_defined?(method)
raise NoMethodError, "private method `#{method}' called for #{inspect}"
elsif klass.protected_method_defined?(method)
raise NoMethodError, "protected method `#{method}' called for #{inspect}"
else
raise NoMethodError, "undefined method `#{method}' for #{inspect}"
end
end
end
end
end

View file

@ -0,0 +1,117 @@
require 'abstract_unit'
require 'active_support/core_ext/object/public_send'
module PublicSendReceiver
def receive_public_method(*args)
return args + [yield]
end
protected
def receive_protected_method(*args)
return args + [yield]
end
private
def receive_private_method(*args)
return args + [yield]
end
end
# Note, running this on 1.9 will be testing the Ruby core implementation, but it is good to
# do this to ensure that our backport functions the same as Ruby core in 1.9
class PublicSendTest < Test::Unit::TestCase
def instance
@instance ||= begin
klass = Class.new do
include PublicSendReceiver
end
klass.new
end
end
def singleton_instance
@singleton_instance ||= begin
object = Object.new
object.singleton_class.send(:include, PublicSendReceiver)
object
end
end
def test_should_receive_public_method
assert_equal(
[:foo, :bar, :baz],
instance.public_send(:receive_public_method, :foo, :bar) { :baz }
)
end
def test_should_receive_public_singleton_method
assert_equal(
[:foo, :bar, :baz],
singleton_instance.public_send(:receive_public_method, :foo, :bar) { :baz }
)
end
def test_should_raise_on_protected_method
assert_raises(NoMethodError) do
instance.public_send(:receive_protected_method, :foo, :bar) { :baz }
end
end
def test_should_raise_on_protected_singleton_method
assert_raises(NoMethodError) do
singleton_instance.public_send(:receive_protected_method, :foo, :bar) { :baz }
end
end
def test_should_raise_on_private_method
assert_raises(NoMethodError) do
instance.public_send(:receive_private_method, :foo, :bar) { :baz }
end
end
def test_should_raise_on_singleton_private_method
assert_raises(NoMethodError) do
singleton_instance.public_send(:receive_private_method, :foo, :bar) { :baz }
end
end
def test_should_raise_on_undefined_method
assert_raises(NoMethodError) do
instance.public_send(:receive_undefined_method, :foo, :bar) { :baz }
end
end
def test_protected_method_message
instance.public_send(:receive_protected_method, :foo, :bar) { :baz }
rescue NoMethodError => exception
assert_equal(
"protected method `receive_protected_method' called for #{instance.inspect}",
exception.message
)
end
def test_private_method_message
instance.public_send(:receive_private_method, :foo, :bar) { :baz }
rescue NoMethodError => exception
assert_equal(
"private method `receive_private_method' called for #{instance.inspect}",
exception.message
)
end
def test_undefined_method_message
instance.public_send(:receive_undefined_method, :foo, :bar) { :baz }
rescue NoMethodError => exception
assert_equal(
"undefined method `receive_undefined_method' for #{instance.inspect}",
exception.message
)
end
def test_receiver_with_no_singleton
assert_equal "5", 5.public_send(:to_s)
assert_equal "foo", :foo.public_send(:to_s)
end
end