T
Trans
Put together a proof of concept of Gary Wright's idea of using an
operator for send instead of a method. This also incorporates an
implementation of Ara's Pervasives. There are a couple caveats to this
implementation however that would have to be handled in any production
version.
1) It uses >> rather then ->, for obvious reasons. So as it is, it will
not work with a few classes that already use >> (unless they are
redefined).
2) You have to pass an array, since an operator normally can't handle
more that one arg. This also means unfortunately that blocks can't be
passed.
3) It doesn't provide a "pervasive send" operator.
Usage:
# send equivalent to '.'
obj >> [:method, *args]
# send as (binds to method in parent class/module)
obj >> [Ancestor, :method, *args]
The second form can also be used to bypass privacy.
obj >> [(obj>>:class), :method, *args]
Albeit this will bypass singletons (aside from this it would be nice to
have method that returns the singleton if it exists, but the regular
class otherwise).
---
module Kernel
module Pervasives
METHODS = {}
Kernel.instance_methods.each do |m|
METHODS[m] = Kernel.instance_method(m)
end
METHODS.each do |s,m|
define_method s do |o,*a|
m.bind(o).call(*a)
end
module_function s
end
end
Pervasives.freeze(Pervasives)
def >>(a)
a = [a].flatten
case a[0] when Module, Class
c, m, *a = *a
c.instance_method(m).bind(self).call(*a)
else
if respond_to?(a[0])
Pervasives.send(self,*a)
elsif respond_to?
method_missing)
method_missing(*a)
else
raise NoMethodError, "private method called for #{self}"
end
end
end
end
#=begin test
require 'test/unit'
class TestSendOP < Test::Unit::TestCase
class C
def a; "c"; end
end
class X < C
def send; "send"; end
def a; "a"; end
private
def b; "b"; end
end
def setup
@x = X.new
end
def test_send
assert_equal( "send", @x.send )
end
def test_normal
assert_equal( "a", @x >> [:a] )
end
def test_as_C
assert_equal( "c", @x >> [C,:a] )
end
def test_singleton
assert_equal( "a", @x >> [(class<<@x;self;end),:a] )
end
def test_singleton_bypass_private
assert_equal( "b", @x >> [(class<<@x;self;end),:b] )
end
def test_private
assert_raises(NoMethodError){ @x >> [:b] }
end
end
#=end
operator for send instead of a method. This also incorporates an
implementation of Ara's Pervasives. There are a couple caveats to this
implementation however that would have to be handled in any production
version.
1) It uses >> rather then ->, for obvious reasons. So as it is, it will
not work with a few classes that already use >> (unless they are
redefined).
2) You have to pass an array, since an operator normally can't handle
more that one arg. This also means unfortunately that blocks can't be
passed.
3) It doesn't provide a "pervasive send" operator.
Usage:
# send equivalent to '.'
obj >> [:method, *args]
# send as (binds to method in parent class/module)
obj >> [Ancestor, :method, *args]
The second form can also be used to bypass privacy.
obj >> [(obj>>:class), :method, *args]
Albeit this will bypass singletons (aside from this it would be nice to
have method that returns the singleton if it exists, but the regular
class otherwise).
---
module Kernel
module Pervasives
METHODS = {}
Kernel.instance_methods.each do |m|
METHODS[m] = Kernel.instance_method(m)
end
METHODS.each do |s,m|
define_method s do |o,*a|
m.bind(o).call(*a)
end
module_function s
end
end
Pervasives.freeze(Pervasives)
def >>(a)
a = [a].flatten
case a[0] when Module, Class
c, m, *a = *a
c.instance_method(m).bind(self).call(*a)
else
if respond_to?(a[0])
Pervasives.send(self,*a)
elsif respond_to?
method_missing(*a)
else
raise NoMethodError, "private method called for #{self}"
end
end
end
end
#=begin test
require 'test/unit'
class TestSendOP < Test::Unit::TestCase
class C
def a; "c"; end
end
class X < C
def send; "send"; end
def a; "a"; end
private
def b; "b"; end
end
def setup
@x = X.new
end
def test_send
assert_equal( "send", @x.send )
end
def test_normal
assert_equal( "a", @x >> [:a] )
end
def test_as_C
assert_equal( "c", @x >> [C,:a] )
end
def test_singleton
assert_equal( "a", @x >> [(class<<@x;self;end),:a] )
end
def test_singleton_bypass_private
assert_equal( "b", @x >> [(class<<@x;self;end),:b] )
end
def test_private
assert_raises(NoMethodError){ @x >> [:b] }
end
end
#=end