local_method_missing possible

Discussion in 'Ruby' started by trans. (T. Onoma), Sep 26, 2004.

  1. 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.
    trans. (T. Onoma), Sep 26, 2004
    #1
    1. Advertising

  2. trans.  (T. Onoma)

    Markus Guest

    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

    On Sat, 2004-09-25 at 18:57, trans. (T. Onoma) wrote:
    > 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.
    >
    Markus, Sep 26, 2004
    #2
    1. Advertising

  3. On Saturday 25 September 2004 10:42 pm, Markus wrote:
    > 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.
    / \

    I don't give a damn for a man that can only spell a word one way.
    -Mark Twain
    trans. (T. Onoma), Sep 26, 2004
    #3
  4. trans.  (T. Onoma)

    Markus Guest

    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)

    -- Markus



    On Sat, 2004-09-25 at 20:10, trans. (T. Onoma) wrote:
    > On Saturday 25 September 2004 10:42 pm, Markus wrote:
    > > 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.
    Markus, Sep 26, 2004
    #4
  5. trans.  (T. Onoma)

    Guest

    * trans. (T. Onoma) <> [2004-09-26 12:10:59 +0900]:

    > 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

    --
    Jim Freeze
    , Sep 27, 2004
    #5
  6. On Sunday 26 September 2004 02:01 am, Markus wrote:
    > 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.
    trans. (T. Onoma), Sep 27, 2004
    #6
  7. On Sunday 26 September 2004 10:33 pm, wrote:
    > > 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


    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.
    trans. (T. Onoma), Sep 27, 2004
    #7
  8. trans.  (T. Onoma)

    Jamis Buck Guest

    trans. (T. Onoma) wrote:
    > On Sunday 26 September 2004 10:33 pm, wrote:
    >
    >>> 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

    >
    >
    > 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

    --
    Jamis Buck

    http://www.jamisbuck.org/jamis
    Jamis Buck, Sep 27, 2004
    #8
  9. On Tue, Sep 28, 2004 at 01:28:47AM +0900, trans. (T. Onoma) wrote:
    > > 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.


    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

    --
    Running Debian GNU/Linux Sid (unstable)
    batsman dot geo at yahoo dot com
    Mauricio Fernández, Sep 27, 2004
    #9
  10. trans.  (T. Onoma)

    Markus Guest

    On Mon, 2004-09-27 at 09:53, Mauricio Fernández wrote:
    > 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
    Markus, Sep 27, 2004
    #10
  11. On Monday 27 September 2004 12:53 pm, Mauricio Fernández wrote:
    > 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.
    trans. (T. Onoma), Sep 27, 2004
    #11
  12. On Monday 27 September 2004 12:45 pm, Jamis Buck wrote:
    > 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.
    trans. (T. Onoma), Sep 27, 2004
    #12
  13. On Tue, Sep 28, 2004 at 02:35:58AM +0900, Markus wrote:
    > On Mon, 2004-09-27 at 09:53, Mauricio Fernández wrote:
    > > 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)


    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?

    --
    Running Debian GNU/Linux Sid (unstable)
    batsman dot geo at yahoo dot com
    Mauricio Fernández, Sep 27, 2004
    #13
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Michael Giagnocavo [MVP]

    Re: Is it possible....

    Michael Giagnocavo [MVP], Jun 28, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    1,194
    Michael Giagnocavo [MVP]
    Jun 28, 2003
  2. Ekkehard Kraemer

    Development on 98 possible at all?

    Ekkehard Kraemer, Sep 13, 2003, in forum: ASP .Net
    Replies:
    2
    Views:
    422
    Dino Chiesa [Microsoft]
    Sep 22, 2003
  3. Markus
    Replies:
    1
    Views:
    457
    Markus
    Nov 22, 2005
  4. Replies:
    4
    Views:
    281
    Kenny McCormack
    Feb 21, 2006
  5. Replies:
    10
    Views:
    471
    Chris Gonnerman
    Dec 14, 2007
Loading...

Share This Page