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:
parent
652ab436db
commit
6f4b405250
3 changed files with 143 additions and 0 deletions
|
@ -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'
|
||||
|
|
|
@ -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
|
117
activesupport/test/core_ext/object/public_send_test.rb
Normal file
117
activesupport/test/core_ext/object/public_send_test.rb
Normal 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
|
Loading…
Reference in a new issue