Forum: Ruby properly extending test::unit to add logging

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Df5e7adb20adae6c120b04e7cafb15a0?d=identicon&s=25 Rob Sanheim (Guest)
on 2006-06-07 17:30
(Received via mailing list)
Hi,

I'd like to open up test::unit to add default logging to setup and
teardown.  In java I did this with a base test class that every other
test extended, but that was never very nice as you had to remember to
call super in subclasses.  The other option was adding aspects and all
that complexity.   So I thought I could do it nicer in ruby with the
following:

  alias_method :old_setup, :setup
  def setup
    logger.debug "**** Beginning setup for: #{name} ****"
    old_setup
  end

Is this the proper way to extend builtin methods, and still preserve
the old behavior?  I'm thinking the timing that the above code gets
called is important.  Right now I'm getting one test error when I
extend setup as above, as opposed to leaving it out, so I must be dong
something wrong.

Btw - this w/i a Rails app (the above code is w/i test_helper), but I
figured this is more ruby then rails specific.

thanks,
Rob
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-06-07 17:33
(Received via mailing list)
On Thu, 8 Jun 2006, Rob Sanheim wrote:

> def setup
>   logger.debug "**** Beginning setup for: #{name} ****"
>   old_setup
> end

whenever you wrap methods like this __always__, __always__, __always__
do this

   alias_method "old_method", "method"

   def method *a, &b
     # ...
     old_method *a, &b
     # ...
   end

you need to collect any args and block and pass them through.

regards.

-a
Df5e7adb20adae6c120b04e7cafb15a0?d=identicon&s=25 Rob Sanheim (Guest)
on 2006-06-08 01:16
(Received via mailing list)
On 6/7/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
> you need to collect any args and block and pass them through.
>
> regards.
>

Thanks for the tip.  Besides that, are there any other gotchas related
to redefining methods?  For instance, I'm redefining my_foo inside
module x, but y and z call my_foo before module x ever needs to get
loaded.  Does that mean that my_foo will be the old version for y and
z, then the new version for any callers after module x gets loaded?

- rob
Dd76a12d66f843de5c5f8782668e7127?d=identicon&s=25 Mauricio Fernandez (Guest)
on 2006-06-08 01:38
(Received via mailing list)
On Thu, Jun 08, 2006 at 08:15:21AM +0900, Rob Sanheim wrote:
> >   end
> >
> >you need to collect any args and block and pass them through.
> >
> >regards.
> >
>
> Thanks for the tip.  Besides that, are there any other gotchas related
> to redefining methods?

This one is at least as conspicuous as the above one, but just in
case...

Try to come up with a more imaginative name than old_method for the old
definition, or you'll get SystemStackErrors when somebody also overrides
it
using the same name...

If the method doesn't take a block (or you're running 1.9), you can also
use
the following idiom:

old_meth = instance_method(:method)
define_method(:method) do |*a|  # &b too on 1.9
  # ...
  old_meth.bind(self).call(*a)  # ditto
  # ...
end

which is safer name-clash-wise, but note that this is slower than the
alias_method mechanism.

> For instance, I'm redefining my_foo inside
> module x, but y and z call my_foo before module x ever needs to get
> loaded.  Does that mean that my_foo will be the old version for y and
> z, then the new version for any callers after module x gets loaded?

Yes (if the later calls would see the new definition at all under the
standard
method resolution rules).
This topic is locked and can not be replied to.