Hello, I read the thread.
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/676
Matz mentioned that he does not think its “worthy” which I interpret
to mean there is either no use case or the use case is not beneficial
to satisfy.
If there was a way to intercept all incoming calls, it would make the
“blank slate” pattern obsolete. FTWDK, The “blank slate” pattern
implementation means, one would remove all methods from an object so
method_missing can be used.
It is used to implement a lightweight and transparent Proxy to another
object. ActiveRecord Association proxies make heavy use of the blank
slate pattern.
Here is an example implementation:
class Foo
instance_methods.each {|m| undef_method(m) unless m =~ /__/}
def initialize(proxy_target)
@proxy_target = proxy_target
end
def method_missing(name, *args, &block)
@proxy_target.send(name, *args, &block)
end
end
The problem with this pattern is that it is imperative. If another
library defines a method on Object after Foo is loaded, then the blank
slate for Foo breaks.
For example:
require “foo”
class Object
def bar
“I don’t want to be called”
end
end
class ProxyTarget
def bar
“I want to be called”
end
end
foo = Foo.new(“the proxy target”)
foo.bar # “I don’t want to be called”
So to solve this particular problem, you can apply the blank slate on
object instantiation:
class Foo
def initialize(proxy_target)
@proxy_target = proxy_target
class << self
instance_methods.each {|m| undef_method(m) unless(m =~ /^_/ ||
m.to_s == 'object_id')}
end
def method_missing(name, *args, &block)
@proxy_target.__send__(name, *args, &block)
end
end
end
For some reason, #method_missing also needs to be redefined on
#initialize.
Ideally, Ruby would support a way to intercept method invocation
before its sent to the real implementation. I believe Python allows
this by redefining one of the __ methods (I don’t know which one, but
I think I saw somebody do this) on the proxy class.
Something like the following would be nice:
class Foo
def initialize(proxy_target)
@proxy_target = proxy_target
end
def call(name, *args, &block)
if m =~ /^_/ || m.to_s == ‘object_id’
super
else
@proxy_target.send(name, *args, &block)
end
end
end
Anyways, removing the need for the “blank slate” pattern is a concrete
use case for this feature. I do believe that method invocation
interception would open the door for some powerful abstraction and
really cool libraries.
Also, are feature requests for Ruby officially on rubyforge.org tracker?
Thanks,
Brian