From: Josh Cheek Date: 2010-12-02T01:27:04+09:00 Subject: Re: Cutting down on logging statements --001636c596cbf2f7cc04965bc40b Content-Type: text/plain; charset=ISO-8859-1 On Wed, Dec 1, 2010 at 8:48 AM, Iain Barnett wrote: > Hi, > > As hacky ideas go, how does this sound? My code is peppered with logging > statements which I'd rather not wade through, so maybe I could define all my > methods with a leading underscore but call them without e.g. > > def _my_method... > > @n = my_method @a, @b, @c ... > > and use method missing to wrap all the calls with logging and then remove > the underscore and recall the method. > > I tried using the Aquarius lib but it didn't work for me, so this is my > crazy idea for the day. Aside from putting all my money into buying > government debt. > > Is it crazy? > > Regards, > Iain > > I'm not especially keen on method_missing, it seems difficult to diagnose when it has issues, and I always worry about it colliding with other method_missings. It would also mean you'd have to hack respond_to as well (if you want to play nice, anyway). And it means you can't override methods, for example: class MyClass def _foo(arg) end def _to_s "you will never see me" end def method_missing(meth,*args,&block) if respond_to?("_#{meth}") puts "LOGGING: '#{meth}' RECEIVED #{args.inspect} WITH#{'OUT' unless block} A BLOCK" else super end end end m = MyClass.new m.foo(:bar) { } puts m.to_s # >> LOGGING: 'foo' RECEIVED [:bar] WITH A BLOCK # >> # Here is a different way, which allows you to exert a bit more control. Note that this won't work on 1.8.6. Some other things you could do would be to have it hook into a callback so you can customize the logging for each class, or even each method that uses it; or to allow additional args to loggable method, which would then be the custom message (ie priority and message). alias :log :puts module Loggable def loggable( meth , &block ) define_actual meth , &block define_loggable meth end def define_actual( meth , &block ) define_method "_#{meth}" , &block end def define_loggable(meth) define_method meth do |*args,&block| log "LOGGING: '#{meth}' RECEIVED #{args.inspect} WITH#{'OUT' unless block} A BLOCK" send "_#{meth}" , *args , &block end end end class BreadBox extend Loggable def initialize @slices = 0 end # a logging method loggable :insert do |n| @slices += n end # a non-logging method def remove(n) @slices -= n end # can log overridden methods loggable :to_s do "" end end box = BreadBox.new BreadBox.instance_methods(false) # => [:_insert, :insert, :remove, :_to_s, :to_s] box.respond_to? :insert # => true box.insert 5 # => 5 box.remove 3 # => 2 box.insert 7 # => 9 box.to_s # => "" # >> LOGGING: 'insert' RECEIVED [5] WITHOUT A BLOCK # >> LOGGING: 'insert' RECEIVED [7] WITHOUT A BLOCK # >> LOGGING: 'to_s' RECEIVED [] WITHOUT A BLOCK --001636c596cbf2f7cc04965bc40b--