local_method_missing possible

T

trans. (T. Onoma)

I'm wondering how feasible it might be to implement a local_method_missing
hook in core Ruby? What I mean by that is a hook like method_missing, but one
that only is concerned with the methods defined in the current class context.

E.g.

class A
def a; end
end
class B < A
def local_method_missing(sym, *args)
puts "Can't find #{sym}."
end
end

B.new.a
#=> Can't find a.

Thanks,
T.
 
M

Markus

I'm not sure I understand what you're getting at. Why would you
subclass A if you didn't want to inherit any of the methods from A?

-- Markus
 
T

trans. (T. Onoma)

I'm not sure I understand what you're getting at. Why would you
subclass A if you didn't want to inherit any of the methods from A?

Hi.

It's related to AOP. The basic idea is to be able to reroute method
invocations.

class A
def a; puts "here"; end
end
class B < A
def b(meth)
puts "before"
send(meth)
puts "after"
end
def local_method_missing(sym, *args)
if /^a/ =~ meth.to_s
b(meth)
end
end
end

T.

--
( o _ カラãƒ
// trans.
/ \ (e-mail address removed)

I don't give a damn for a man that can only spell a word one way.
-Mark Twain
 
J

jim

* trans. (T. Onoma) said:
It's related to AOP. The basic idea is to be able to reroute method
invocations.

class A
def a; puts "here"; end
end
class B < A
def b(meth)
puts "before"
send(meth)
puts "after"
end
def local_method_missing(sym, *args)
if /^a/ =~ meth.to_s
b(meth)
end
end
end

Could you just use super?

class A
def a; puts "in a"; end
end
class B < A
def a
puts "before"
super
puts "after"
end
end

B.new.a
 
T

trans. (T. Onoma)

1) Wouldn't that cause infinite recursion if you called B.new.a?
2) Is this something like CLOS (common lisp object system) around
methods? (See http://www.aiai.ed.ac.uk/~jeff/clos-guide.html). If so,
I have an partial implementation that works in 1.8.0 (and I hope will
work in 1.8.2 final)

1) Good point.

Actually, what is really needed, to make this work well, is a way to send the
method on, up to the next level of the class/module hierarchy, without
rerouting back to the bottom.

2) Thanks. I actually have many implementations of wraps already -- I take it
you are using alias?

Obviously local_method_missing is just a proto-idea, but what it intendeds to
solve is related to dynamically creating wraps that apply to collections of
methods, not just a single method. Also, it is for use in a specific context,
namely a subclass.

So the question is this: Given a class and a predefined 'wrapping' method, how
do I create a subclass and a submethod to effect multiple methods in the
class. Obviously I could just create a submethod for each class method, but
that seems rather bulky.

Hope that makes enough sense,
T.
 
T

trans. (T. Onoma)

Could you just use super?

class A
def a; puts "in a"; end
end
class B < A
def a
puts "before"
super
puts "after"
end
end

The idea is to submethod multiple methods in one fell-swoop. Hence:

if /^a/ =~ meth.to_s

If you have any ideas on other ways to do this, I would love to hear them.

Thanks,
T.
 
J

Jamis Buck

trans. (T. Onoma) said:
The idea is to submethod multiple methods in one fell-swoop. Hence:

if /^a/ =~ meth.to_s

If you have any ideas on other ways to do this, I would love to hear them.

Well, it's not very pretty, but what about:

1) aliasing all methods of the subclass to something else (mangling
them, basically),

2) Using "method_missing" to intercept and redirect calls to those methods,

3) and using "self.class.instance_methods(false).include?(...)" to
determine whether the method was defined in the subclass or a superclass...

If this isn't clear enough (and it may very well not be!) I could try
posting some pseudo-code...

- Jamis
 
M

Mauricio Fernández

The idea is to submethod multiple methods in one fell-swoop. Hence:

if /^a/ =~ meth.to_s

If you have any ideas on other ways to do this, I would love to hear them.

batsman@tux-chan:/tmp$ cat gdfgrre.rb

module Magic
def wrap_method(*names, &block)
names.each do |name|
old = instance_method(name)
define_method(name) do |*a| # |*a, &b| on 1.9
block.call(name, old.bind(self), *a) # &b on 1.9
end
end
end
end

class A
def foo; puts "A#foo" end
def bar; puts "A#bar" end
end

class B < A
extend Magic

wrap_method:)foo, :bar) do |meth, old|
puts "pre"
puts "About to call #{meth}"
if meth.to_s == "foo"
puts "special action for foo!"
end
old.call
puts "post"
end
end

b = B.new
b.foo
b.bar
batsman@tux-chan:/tmp$ ruby gdfgrre.rb
pre
About to call foo
special action for foo!
A#foo
post
pre
About to call bar
A#bar
post
 
M

Markus

module Magic
def wrap_method(*names, &block)
names.each do |name|
old = instance_method(name)
define_method(name) do |*a| # |*a, &b| on 1.9
block.call(name, old.bind(self), *a) # &b on 1.9
end
end
end
end

Note, though, that this will fail under 1.8.1 & 1.8.2Pre (but not, I
hope, under later versions) because of the change in block/proc
semantics. See:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/113629

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/113697

(and of course the follow-ons), if you haven't been following that
thread already.

-- Markus
 
T

trans. (T. Onoma)

module Magic
    def wrap_method(*names, &block)
        names.each do |name|
            old = instance_method(name)
            define_method(name) do |*a|  # |*a, &b|  on 1.9
                block.call(name, old.bind(self), *a) # &b on 1.9
            end
        end
    end
end

Well done, albeit this the "bulky" solution I referred to. It does seem bulky
doesn't it --defining all those new methods? Or is it just me?

Nonetheless you get the idea. I'm wondering if there's a way to implement
without the bulkiness (even if it is in Ruby core, hence why I was wondering
about the fiesability of local_method_missing)

T.
 
T

trans. (T. Onoma)

Well, it's not very pretty, but what about:

1) aliasing all methods of the subclass to something else (mangling
them, basically),

You're right. And it's this first step that's just too ugly to be acceptable
to me.
2) Using "method_missing" to intercept and redirect calls to those methods,

3) and using "self.class.instance_methods(false).include?(...)" to
determine whether the method was defined in the subclass or a superclass...

If this isn't clear enough (and it may very well not be!) I could try
posting some pseudo-code...

It's clear and it's certainly a solution --but not the "less filling" one I'm
really after.

T.
 
M

Mauricio Fernández

Note, though, that this will fail under 1.8.1 & 1.8.2Pre (but not, I
hope, under later versions)

batsman@tux-chan:/tmp$ ruby -v gdfgrre.rb
ruby 1.8.2 (2004-09-22) [i686-linux]
#<ArgumentError: wrong number of arguments (1 for 2)>
A#foo a: 1 b: 2
#<ArgumentError: wrong number of arguments (3 for 2)>
A#foobar a: [1, 2]
#<ArgumentError: wrong number of arguments (2 for 1)>
A#bar a: [[1, 2, 3]]
A#bar a: [1, 2, 3]
batsman@tux-chan:/tmp$ cat gdfgrre.rb

module Magic
def wrap_method(*names, &block)
names.each do |name|
old = instance_method(name)
define_method(name) do |*a| # |*a, &b| on 1.9
block.call(name, old.bind(self), *a)
end
end
end
end

class A
def foo(a,b); puts "A#foo a: #{a.inspect} b: #{b.inspect}" end
def foobar(a); puts "A#foobar a: #{a.inspect}" end
def bar(*a); puts "A#bar a: #{a.inspect}" end
end

class B < A
extend Magic

wrap_method:)foo, :bar, :foobar) do |meth, old, *args|
old.call(*args)
end
end

b = B.new
b.foo [1,2] rescue p $!
b.foo 1, 2
b.foo 1, 2, 3 rescue p $!
b.foobar [1,2]
b.foobar(1, 2) rescue p $!
b.bar [1,2,3]
b.bar 1, 2, 3

propagation in 1.9 maybe?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top