I'm new to using gems. Can you tell me the command I need to run to get 
ruby-gtk2 so I can run your code?

----- Original Message ----- 
From: "Jamis Buck" <jgb3 / email.byu.edu>
To: "ruby-talk ML" <ruby-talk / ruby-lang.org>
Sent: Sunday, November 21, 2004 6:48 PM
Subject: [SOLUTION] Object Browser (#8)


> Well, I was kind of waiting to see what other people came up with, but
> since the list seems quiet on this topic, I guess I'll go ahead and post
> first.
>
> This is a VERY rough implementation. It uses ruby-gtk2, and is one of my
> first projects using that interface, so I've doubtless done all kinds of
> things wrong. :) But it works.
>
> By default, it displays the "main" object. You can see the class,
> superclass, instance/class variables, public/private/protected methods,
> and constants (where any of them apply and are non-empty).
>
> I wanted to add the ability to modify values, but didn't quite have time
> to get that far.
>
> This was a great quiz, though. I'd love to see a more sophisticated
> version of this. I can use mine, for instance, to do a kind of
> breakpoint in my code:
>
>   ObjectBrowser.browse( @foo )
>
> And the program will stop, display the window, and wait for the window
> to close before proceeding.
>
> Anyway. Comments?
>
> - Jamis
>
> -- 
> Jamis Buck
> jgb3 / email.byu.edu
> http://www.jamisbuck.org/jamis
>


--------------------------------------------------------------------------------


> require 'gtk2'
>
> DEFAULT_OBJECTBROWSER_ROOT = self
>
> class Object
>  alias :pre_objbrowser_inspect :inspect
>  def inspect
>    result = pre_objbrowser_inspect
>    result = $1 + " ...>" if result =~ /^(#<.*?:0x\w+) /
>    result
>  end
> end
>
> module ObjectBrowser
>
>  def browse( root = DEFAULT_OBJECTBROWSER_ROOT )
>    Interface.new( root ).display_and_wait
>  end
>  module_function :browse
>
>  class Interface
>    def initialize( root = DEFAULT_OBJECTBROWSER_ROOT )
>      @root = root
>      Gtk.init
>    end
>
>    def display
>      window = Window.new( @root )
>      window.show_all
>    end
>
>    def display_and_wait
>      display
>      wait
>    end
>
>    def wait
>      Gtk.main
>    end
>  end
>
>  class Window < Gtk::Window
>    OBJECT = 1
>    CLASS  = 2
>    INSTANCE_VARS = 3
>    PUBLIC_METHODS = 4
>    PROTECTED_METHODS = 5
>    PRIVATE_METHODS = 6
>    CLASS_VARS = 7
>    CONSTANTS = 8
>    SUPERCLASS = 9
>    STRING = 10
>    INSTANCE_METHODS = 11
>
>    LABEL = 0
>    TYPE  = 1
>    REF   = 2
>
>    def initialize( root )
>      super( Gtk::Window::TOPLEVEL )
>
>      signal_connect "delete_event", &method( :on_delete )
>      signal_connect "destroy", &method( :on_destroy )
>
>      vbox = Gtk::VBox.new
>      add(vbox)
>
>      pane = Gtk::VPaned.new
>      vbox.add pane
>
>      sw = Gtk::ScrolledWindow.new
>      sw.set_policy *[Gtk::POLICY_AUTOMATIC]*2
>      sw.shadow_type = Gtk::SHADOW_IN
>      pane.add sw
>
>      @model = Gtk::TreeStore.new( String, Integer, Integer )
>      add_node( nil, root )
>
>      @tree = Gtk::TreeView.new( @model )
>      @tree.set_size_request -1, 400
>
>      renderer = Gtk::CellRendererText.new
>
>      col = Gtk::TreeViewColumn.new( "Data", renderer )
>      col.set_cell_data_func renderer, &method( :on_cell_render )
>
>      @tree.append_column col
>      @tree.expand_row Gtk::TreePath.new( "0" ), false
>
>      @tree.signal_connect "row_expanded", &method( :on_row_expanded )
>
>      sw.add @tree
>
>      sw = Gtk::ScrolledWindow.new
>      sw.set_policy *[Gtk::POLICY_AUTOMATIC]*2
>      sw.shadow_type = Gtk::SHADOW_IN
>      pane.add sw
>
>      @text = Gtk::TextView.new
>      sw.add @text
>
>      set_default_size 650, 500
>    end
>
>    def on_delete( widget, event )
>      false
>    end
>
>    def on_destroy( widget )
>      Gtk.main_quit
>    end
>
>    def on_cell_render( c, r, m, i )
>      case i[TYPE]
>        when OBJECT
>          obj = ObjectSpace._id2ref( i[REF].to_i )
>          r.text = "#{i[LABEL]}#{obj.inspect}"
>        when CLASS, SUPERCLASS
>          obj = ObjectSpace._id2ref( i[REF].to_i )
>          r.text = "#{i[LABEL]} #{obj.name}"
>        else
>          r.text = i[LABEL]
>      end
>    end
>
>    def on_row_expanded( widget, iter, path )
>      unless iter.first_child[LABEL]
>        case iter[1]
>          when OBJECT, CLASS, SUPERCLASS then
>            obj = ObjectSpace._id2ref( iter[REF].to_i )
>            add_node iter, obj, iter.first_child
>          when INSTANCE_VARS then
>            obj = ObjectSpace._id2ref( iter.parent[REF].to_i )
>            initialize_vars_list( obj, iter, obj.instance_variables.sort,
>              :instance_variable_get )
>          when PUBLIC_METHODS then
>            obj = ObjectSpace._id2ref( iter.parent[REF].to_i )
>            initialize_methods_list( obj, iter, 
> obj.public_methods(false).sort )
>          when PROTECTED_METHODS then
>            obj = ObjectSpace._id2ref( iter.parent[REF].to_i )
>            initialize_methods_list( obj, iter,
>              obj.protected_methods(false).sort )
>          when PRIVATE_METHODS then
>            obj = ObjectSpace._id2ref( iter.parent[REF].to_i )
>            initialize_methods_list( obj, iter,
>              obj.private_methods(false).sort )
>          when INSTANCE_METHODS then
>            obj = ObjectSpace._id2ref( iter.parent[REF].to_i )
>            initialize_methods_list( obj, iter,
>              obj.instance_methods(false).sort, true )
>          when CLASS_VARS then
>            obj = ObjectSpace._id2ref( iter.parent[REF].to_i )
>            initialize_vars_list( obj, iter,
>              obj.class_variables.sort, :class_eval )
>          when CONSTANTS then
>            obj = ObjectSpace._id2ref( iter.parent[REF].to_i )
>            constants = obj.constants
>            if obj.respond_to?(:superclass) && obj.superclass
>              constants = constants - obj.superclass.constants
>            end
>            initialize_vars_list( obj, iter, constants.sort, :const_get )
>          else
>            raise "don't know what to do with row of type #{iter[TYPE]}"
>        end
>      end
>
>      path_str = iter.path.to_s + ":" + ( iter.n_children - 1 ).to_s
>      path = Gtk::TreePath.new( path_str )
>
>      @tree.scroll_to_cell( path, nil, true, 1.0, 0 )
>    end
>
>    def add_node( parent, object, node=nil )
>      unless node
>        node = add_row( parent, "", object, OBJECT, false )
>        add_row( node, "class", object.class, CLASS )
>      else
>        add_row( parent, "class", object.class, CLASS, true, node )
>        node = parent
>      end
>
>      if object.is_a?( Module )
>        if object.respond_to?(:superclass) && object.superclass
>          add_row( node, "extends", object.superclass, SUPERCLASS )
>        end
>        add_row_unless_empty(
>          object.class_variables, node, "Class Variables", CLASS_VARS )
>
>        constants = object.constants
>        if object.respond_to?(:superclass) && object.superclass
>          constants = constants - object.superclass.constants
>        end
>
>        add_row_unless_empty( constants, node, "Constants", CONSTANTS )
>        add_row_unless_empty( object.instance_methods(false), node,
>          "Instance Methods", INSTANCE_METHODS )
>      end
>
>      add_row_unless_empty( object.instance_variables, node,
>        "Instance Variables", INSTANCE_VARS )
>      add_row_unless_empty( object.public_methods(false), node,
>        "Public Methods", PUBLIC_METHODS )
>      add_row_unless_empty( object.protected_methods(false), node,
>        "Protected Methods", PROTECTED_METHODS )
>      add_row_unless_empty( object.private_methods(false), node,
>        "Private Methods", PRIVATE_METHODS )
>
>      node
>    end
>
>    def add_row_unless_empty( list, node, name, type, add_empty=true )
>      unless list.empty?
>        summary = list.sort.join( "," )
>        summary = summary[0,60] + "..." if summary.length > 63
>        add_row( node, "#{name} (#{summary})", nil, type )
>      end
>    end
>
>    def add_row( parent, label, value, type, add_empty=true, node=nil )
>      node = @model.append( parent ) unless node
>
>      node[ LABEL ] = label
>      node[ TYPE ] = type
>      node[ REF ] = value.object_id
>
>      @model.append( node ) if add_empty
>
>      node
>    end
>
>    def initialize_methods_list( obj, iter, list, instance=false )
>      node = iter.first_child
>      list.each do |item|
>        if instance
>          method = obj.instance_method( item.to_sym )
>        else
>          method = obj.method( item.to_sym )
>        end
>        add_row iter, item + "(#{method.arity})", obj, STRING, false, node
>        node = nil
>      end
>    end
>
>    def initialize_vars_list( obj, iter, list, message )
>      node = iter.first_child
>      list.each do |item|
>        value = obj.__send__( message, item )
>        add_row iter, "#{item}=", value, OBJECT, true, node
>        node = nil
>      end
>    end
>  end
>
> end
>
> if __FILE__ == $0
>  @obj = ObjectBrowser::Interface.new
>  @obj.display_and_wait
> end
>