I'm in the process of writing a logging package for a project. The actual
logging methods can be specified at runtime and are implemented with a class
method_missing call.
That works fine until I call the warn method using 'send'. I would have
expected the object to respond identically to both the direct invocation and
the indirect invocation via 'send'.
Is this a bug in ruby or have I missed something?
class B
def self.method_missing(sym, *args)
puts "%s: %s"%[sym, args[1]]
end
end
B.log(self, "There was a young man called McKnight,")
B.send(:log, self, "Who could travel faster than light.")
B.warn(self, "One day at about noon, he went to the moon")
B.send(:warn, self, "And arrived back the previous night.")
bash-2.05b$ ruby -v
ruby 1.8.1 (2004-01-27) [i386-mswin32]
bash-2.05b$
bash-2.05b$ tmp.rb
log: There was a young man called McKnight,
log: Who could travel faster than light.
warn: One day at about noon, he went to the moon
./tmp.rb:71:in `warn': wrong number of arguments(2 for 1) (ArgumentError)
from ./tmp.rb:71:in `send'
from ./tmp.rb:71
bash-2.05b$
I'm in the process of writing a logging package for a project. The actual
logging methods can be specified at runtime and are implemented with a class
method_missing call.
That works fine until I call the warn method using 'send'. I would have
expected the object to respond identically to both the direct invocation and
the indirect invocation via 'send'.
Is this a bug in ruby or have I missed something?
well, you have to consider that warn is already a method in ruby;
warn 'foo'
foo
=> nil
OTOH it works for me:
def warn(*args)
p args
end
=> nil
warn 't' , 't', 'y'
["t", "t", "y"]
=> nil
self.send :warn , :t,:t,:t,:t
[:t, :t, :t, :t]
=> nil
so I believe you did something wrong. But I wonder: why don'tu you use
the logger module (that comes with ruby 1.8) or log4r ?
···
il Mon, 14 Jun 2004 20:13:42 +0900, "Neil Mc Laughlin" <nml@fjserv.net> ha scritto::
Doing so is rather efficient when the said domain is disabled.
As a result you can keep traces in production code.
You can even:
def off( domain )
if domain == :trace then
alias trace noop
end
$domains[domain] = false
end
def noop( *a ); end
...
off( :trace) # turns all tracing off
Yours,
JeanHuguesRobert
···
At 20:13 14/06/2004 +0900, you wrote:
I'm in the process of writing a logging package for a project. The actual
logging methods can be specified at runtime and are implemented with a class
method_missing call.
That works fine until I call the warn method using 'send'. I would have
expected the object to respond identically to both the direct invocation and
the indirect invocation via 'send'.
Is this a bug in ruby or have I missed something?
class B
def self.method_missing(sym, *args)
puts "%s: %s"%[sym, args[1]]
end
end
B.log(self, "There was a young man called McKnight,")
B.send(:log, self, "Who could travel faster than light.")
B.warn(self, "One day at about noon, he went to the moon")
B.send(:warn, self, "And arrived back the previous night.")
bash-2.05b$ ruby -v
ruby 1.8.1 (2004-01-27) [i386-mswin32]
bash-2.05b$
bash-2.05b$ tmp.rb
log: There was a young man called McKnight,
log: Who could travel faster than light.
warn: One day at about noon, he went to the moon
../tmp.rb:71:in `warn': wrong number of arguments(2 for 1) (ArgumentError)
from ./tmp.rb:71:in `send'
from ./tmp.rb:71
bash-2.05b$
Neil.
-------------------------------------------------------------------------
Web: @jhr is virteal, virtually real
Phone: +33 (0) 4 92 27 74 17
Thanks for that. I see that send does indeed call the private method.
I'm still a bit puzzled as to why 'obj.send(:msg)' should behave differently
from 'obj.msg'. My impression was that they are different ways of expressing
the same concept - sending a message to an object. That's why I expected the
same result from either call.
Does anyone else think this odd or even in violation of the principle of
least surprise?
Regards, Neil
···
----- Original Message -----
From: "ts" <decoux@moulon.inra.fr>
To: "ruby-talk ML" <ruby-talk@ruby-lang.org>
Cc: <ruby-talk@ruby-lang.org>
Sent: Monday, June 14, 2004 12:25 PM
Subject: Re: method_missing and send
> Is this a bug in ruby or have I missed something?
#warn is a private method of Kernel
When you call it, like a public method (i.e. B.warn), ruby don't find it
and call #method_missing
With #send ruby is able to find any methods (even private) and call it.
For example
svg% cat b.rb
#!/usr/bin/ruby
class A
class << self
def method_missing(*args)
puts "method_missing : #{args}"
end
private
def tt(*args)
puts "tt : #{args}"
end
end
end
I'm still a bit puzzled as to why 'obj.send(:msg)' should behave differently
from 'obj.msg'. My impression was that they are different ways of expressing
the same concept - sending a message to an object. That's why I expected the
same result from either call.
Does anyone else think this odd or even in violation of the principle of
least surprise?
I too found it odd, but very convenient. By using obj#send, you also get to sidestep the encapsulation support. So it's possible to call protected and private methods this way. That might be considered in violation of POLS, but it's pretty darn useful in those edge cases where you really do want to, knowingly, sidestep encapsulation.
On Wed, Jun 16, 2004 at 04:48:57AM +0900, David Heinemeier Hansson wrote:
I too found it odd, but very convenient. By using obj#send, you also
get to sidestep the encapsulation support. So it's possible to call
protected and private methods this way. That might be considered in
violation of POLS, but it's pretty darn useful in those edge cases
where you really do want to, knowingly, sidestep encapsulation.