Forum: Ruby Ad-hoc debugging module

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.
Bob E. (Guest)
on 2007-04-07 04:54
(Received via mailing list)
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 E.
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
This topic is locked and can not be replied to.