[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

overriding Object::send

Joe Van Dyk

1/16/2006 8:11:00 PM

Why doesn't this work?

class Object
alias_method :old_send, :send
def send meth, *args
STDERR.puts "#{ meth } was called"
old_send meth, args
end
end


7 Answers

Ara.T.Howard

1/16/2006 8:22:00 PM

0

Caleb Tennis

1/16/2006 8:23:00 PM

0

On Monday 16 January 2006 15:11, Joe Van Dyk wrote:
> Why doesn't this work?

It works for me if I use "module Kernel" instead of "class Object".


> class Object
> alias_method :old_send, :send
> def send meth, *args
> STDERR.puts "#{ meth } was called"
> old_send meth, args
> end
> end


Jacob Fugal

1/16/2006 8:31:00 PM

0

Try:

class Object
alias_method :old_send, :send
def send meth, *args
STDERR.puts "#{ meth } was called"
old_send meth, *args
end
end

The difference is the splat in front of args in the invocation of
old_send. With the splat there, it seems to work for me.

irb> -1.send(:abs)
abs was called
=> 1

This used to give me an error about wrong number of arguments.

Note: this still doesn't work without invoking send explicitly, since
foo.bar is *actually* equivalent to foo.__send__(:bar), *not*
foo.send(:bar). It just so happens the the default implementation of
send just forwards to __send__. And overwriting __send__ is a *bad*
idea. :)

Jacob Fugal


Joe Van Dyk

1/16/2006 11:08:00 PM

0

On 1/16/06, Jacob Fugal <lukfugl@gmail.com> wrote:
> Try:
>
> class Object
> alias_method :old_send, :send
> def send meth, *args
> STDERR.puts "#{ meth } was called"
> old_send meth, *args
> end
> end
>
> The difference is the splat in front of args in the invocation of
> old_send. With the splat there, it seems to work for me.
>
> irb> -1.send(:abs)
> abs was called
> => 1
>
> This used to give me an error about wrong number of arguments.
>
> Note: this still doesn't work without invoking send explicitly, since
> foo.bar is *actually* equivalent to foo.__send__(:bar), *not*
> foo.send(:bar). It just so happens the the default implementation of
> send just forwards to __send__. And overwriting __send__ is a *bad*
> idea. :)

Hm. Well, essentially what I want to do is output print statements
every time I enter and leave a method. (having problems identifying
what's going on in my code)


Jacob Fugal

1/16/2006 11:13:00 PM

0

On 1/16/06, Joe Van Dyk <joevandyk@gmail.com> wrote:
> Hm. Well, essentially what I want to do is output print statements
> every time I enter and leave a method. (having problems identifying
> what's going on in my code)

Check out set_trace_func, may be what you need:

http://www.rubycentral.com/book/ref_m_kernel.html#Kernel.set_...

Jacob Fugal


Joe Van Dyk

1/16/2006 11:34:00 PM

0

On 1/16/06, Jacob Fugal <lukfugl@gmail.com> wrote:
> On 1/16/06, Joe Van Dyk <joevandyk@gmail.com> wrote:
> > Hm. Well, essentially what I want to do is output print statements
> > every time I enter and leave a method. (having problems identifying
> > what's going on in my code)
>
> Check out set_trace_func, may be what you need:
>
> http://www.rubycentral.com/book/ref_m_kernel.html#Kernel.set_...

Aha, I forgot about that one.

Say I want to display the arguments that each function gets. Could I
get that from a binding object?


Ross Bamford

1/17/2006 12:34:00 AM

0

On Mon, 16 Jan 2006 23:34:24 -0000, Joe Van Dyk <joevandyk@gmail.com>
wrote:

>> Check out set_trace_func, may be what you need:
>>
>> http://www.rubycentral.com/book/ref_m_kernel.html#Kernel.set_...
>
> Aha, I forgot about that one.
>
> Say I want to display the arguments that each function gets. Could I
> get that from a binding object?
>

Maybe this would do it (with the caveat noted):

class Binding
def locals
eval('local_variables',self).inject({}) do |hsh, var|
hsh[var.intern] = eval(var, self)
hsh
end
end
end

def foo(one, two = 'default')
'foo!'
end

def bar(*args)
'bar!'
end

def baz(arg = 7, &blk)
'baz!'
end

set_trace_func proc { |event, file, line, id, binding, classname|
if event == 'call'
puts "Called #{classname}.#{id} with args #{binding.locals.inspect}"
end
}

foo('arg')
foo('arg_one', 'arg_two')
bar
bar('these','are','my','args')
baz(4)

# NOTE: failure here, doesn't see the block
baz { |b| puts b }
baz(11, &proc { |b| puts b })


Output:

Called Object.foo with args {:one=>"arg", :two=>"default"}
Called Object.foo with args {:one=>"arg_one", :two=>"arg_two"}
Called Object.bar with args {:args=>[]}
Called Object.bar with args {:args=>["these", "are", "my", "args"]}
Called Object.baz with args {:arg=>4, :blk=>nil}
Called Object.baz with args {:arg=>7, :blk=>nil}
Called Object.baz with args {:arg=>11, :blk=>nil}

Also, the extensions/binding
(http://extensions.rubyforge.org/rdoc/...) adds and changes the
binding, so you can just do:

bin = <a binding>
lvs = bin.local_variables.inject({}) { |hsh, v| hsh[v.intern] = bin[v];
hsh }

instead of modifying Binding yourself if you like, but I'm a bit confused
about the status of facets, extensions, and so on - not sure which are
current and which aren't :(

Cheers,

--
Ross Bamford - rosco@roscopeco.remove.co.uk