Revert all the stuff to do with disallowing non-public methods for Module#delegate

This commit is contained in:
Jon Leighton 2011-08-25 18:51:17 +01:00
parent bad6803570
commit 8ba491acc3
7 changed files with 3 additions and 194 deletions

@ -2,8 +2,6 @@
* Added Array#prepend as an alias for Array#unshift and Array#append as an alias for Array#<< [DHH]
* Removed support for using Module#delegate to delegate to non-public methods [Jon Leighton]
* The definition of blank string for Ruby 1.9 has been extended to Unicode whitespace.
Also, in 1.8 the ideographic space U+3000 is considered to be whitespace. [Akira Matsuda, Damien Mathieu]

@ -1,6 +1,3 @@
require 'active_support/core_ext/object/public_send'
require 'active_support/core_ext/string/starts_ends_with'
class Module
# Provides a delegate class method to easily expose contained objects' methods
# as your own. Pass one or more methods (specified as symbols or strings)
@ -127,13 +124,12 @@ def delegate(*methods)
methods.each do |method|
method = method.to_s
call = method.ends_with?('=') ? "public_send(:#{method}, " : "#{method}("
if allow_nil
module_eval(<<-EOS, file, line - 2)
def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block)
if #{to} || #{to}.respond_to?(:#{method}) # if client || client.respond_to?(:name)
#{to}.#{call}*args, &block) # client.name(*args, &block)
#{to}.__send__(:#{method}, *args, &block) # client.__send__(:name, *args, &block)
end # end
end # end
EOS
@ -142,7 +138,7 @@ def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &
module_eval(<<-EOS, file, line - 1)
def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block)
#{to}.#{call}*args, &block) # client.name(*args, &block)
#{to}.__send__(:#{method}, *args, &block) # client.__send__(:name, *args, &block)
rescue NoMethodError # rescue NoMethodError
if #{to}.nil? # if client.nil?
#{exception} # # add helpful message to the exception

@ -3,7 +3,6 @@
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'

@ -1,25 +0,0 @@
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)
# 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

@ -28,20 +28,10 @@ class Cd
Somewhere = Struct.new(:street, :city) do
attr_accessor :name
protected
def protected_method
end
private
def private_method
end
end
class Someone < Struct.new(:name, :place)
delegate :street, :city, :to_f, :protected_method, :private_method, :to => :place
delegate :street, :city, :to_f, :to => :place
delegate :name=, :to => :place, :prefix => true
delegate :upcase, :to => "place.city"
@ -93,14 +83,6 @@ def test_delegation_to_assignment_method
assert_equal "Fred", @david.place.name
end
def test_delegation_to_protected_method
assert_raise(NoMethodError) { @david.protected_method }
end
def test_delegation_to_private_method
assert_raise(NoMethodError) { @david.private_method }
end
def test_delegation_down_hierarchy
assert_equal "CHICAGO", @david.upcase
end

@ -1,117 +0,0 @@
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

@ -452,30 +452,6 @@ Examples of +in?+:
NOTE: Defined in +active_support/core_ext/object/inclusion.rb+.
h4. +public_send+
This method is available by default in Ruby 1.9, and is backported to Ruby 1.8 by Active Support. Like the regular +send+ method, +public_send+ allows you to call a method when the name is not known until runtime. However, if the method is not public then a +NoMethodError+ exception will be raised.
<ruby>
class Greeter
def hello(who)
"Hello " + who
end
private
def secret
"sauce"
end
end
greeter = Greeter.new
greeter.public_send(:hello, 'Jim') # => "Hello Jim"
greeter.public_send(:secret) # => NoMethodError
</ruby>
NOTE: Defined in +active_support/core_ext/object/public_send.rb+.
h3. Extensions to +Module+
h4. +alias_method_chain+