From: Robert Evans Date: 2007-04-07T09:53:45+09:00 Subject: Ad-hoc debugging module Hi, I recently found myself playing with a bunch of objects, iterating their behavior in irb, and I wanted to see just some of the fields each time I did something instead of the whole object that you would get with pp or y . So, I wrote a little module that I could include in interesting classes, so that I could ask objects things like obj.debug (:field1, :field5, :field6) instead of printing out all the methods. Then I got bored doing that and extended it so I could create ad hoc watch methods, e.g., obj.show_those3(:field1, :field5, :field6). I thought others might find it useful too. Also, if anyone has any improvements on it, I am of course interested. Thanks, Bob Evans http://www.junitfactory.com/ module Debuggable def method_missing(method_name, *args) method_name = method_name.to_s if method_name.eql?('debug') _debug(args) elsif method_name =~ /^show_/ new_method_name = create_new_watch_method(method_name, args) self.method(new_method_name).call elsif method_name =~ /^unshow_/ self.class.class_eval do watch_name = method_name.slice(method_name.index(/unshow_/) + 7, method_name.length) undef_method "show_#{watch_name}" end end end def _debug(args) puts "=====" if args.empty? || args[0].eql?(:all) puts self.instance_variables.map { |a| "#{a} = # {self.instance_variable_get(a)}"}.join(", ") else strs = args.map do |a| var = self.instance_variable_get("@#{a}") if var.nil? "@#{a} is not an instance variable" else "@#{a} = #{var.inspect}" end end puts strs.join(", ") end end def create_new_watch_method(method_name, args) watch_name = method_name.slice(method_name.index(/show_/) + 5, method_name.length) new_method_name = "show_#{watch_name}" if args.empty? args = [:all] end self.class.class_eval do define_method(new_method_name) do _debug(args) end end puts "created permanent watch method: #{new_method_name}" new_method_name end end =================== given a class =================== class MyClass attr_reader :name, :date def initialize(name, date) @name = name @date = date end end =================== loaded in an irb prompt, we can do the following: =================== %>m = MyClass.new("Bob", Time.now) %> class MyClass include Debuggable end %>m.debug(:date) ===== @date = Fri Apr 06 17:15:25 -0700 2007 %> m.debug(:all) ===== @name = Bob, @date = Fri Apr 06 17:15:25 -0700 2007 %> m.debug ===== @name = Bob, @date = Fri Apr 06 17:15:25 -0700 2007 %>m.show_date(:date) created permanent watch method: show_date ===== @date = Fri Apr 06 17:15:25 -0700 2007 %>m.methods.grep /show/ ["show_date"] %>m.show_date ===== @date = Fri Apr 06 17:15:25 -0700 2007 %>m.unshow_date %>m.methods.grep /show/ [] %>m.show_all created permanent watch method: show_all ===== @name = Bob, @date = Fri Apr 06 17:15:25 -0700 2007 %>m.methods.grep /show/ ["show_all"] %>m.show_all ===== @name = Bob, @date = Fri Apr 06 17:15:25 -0700 2007 %>m.unshow_all %>m.methods.grep /show/ [] %>m.show_bazooka created permanent watch method: show_bazooka ===== @name = Bob, @date = Fri Apr 06 17:15:25 -0700 2007