--T4IYkFBVPN84tP7K
Content-Type: multipart/mixed; boundary="YhFoJY/gx7awiIuK"
Content-Disposition: inline


--YhFoJY/gx7awiIuK
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

	Hey.  I've included a script that lets you traverse part (most?)
of the object space for ruby through mod_ruby.  Toss it onto a mod_ruby
server and you should be good to go.  The code is derivative work from
bits and pieces in ruby-session so that it can be used standalone, so
the code needs documentation, but it's here for people to comment on.  
If you'd like to tour through things w/o installing it, you can check it
out at:

http://wheel.tgd.net/debug.rbx

	I'd love feedback and any feature enhancements.  This puppie has
saved me a ton of time in mod_ruby debugging, but it's useful to use to
poke at.  If you want to debug your own module, include/require it in
the debug script and it should be available for your use.

echo "require 'mymodule'" >> debug.rbx

	-sc

-- 
Sean Chittenden

--YhFoJY/gx7awiIuK
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="debug.rbx"
Content-Transfer-Encoding: quoted-printable

#!/usr/local/bin/ruby -w

#  All of the documentation and software included in ruby-session releases is
#  copyrighted by Sean Chittenden <sean / chittenden.org>
#
#  Copyright 2001
#  	Sean Chittenden <sean / chittenden.org>.  All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions
#  are met:
#  1. Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
#  2. Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#  3. All advertising materials mentioning features or use of this software
#     must display the following acknowledgment:
#
#      This product includes software developed by Sean Chittenden
#      <sean / chittenden.org> and ruby-session's contributors.
#
#  4. Neither the name of the software nor the names of its contributors
#     may be used to endorse or promote products derived from this software
#     without specific prior written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
#  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#  ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
#  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
#  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
#  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
#  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
#  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
#  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#  SUCH DAMAGE.
#
#  If you have any questions regarding the redistribution of this software,
#  please contact the author at <sean / chittenden.org>.

include ObjectSpace

r = Apache.request

def body (r)
  params = get_params(r)

  if params.has_key?('class')
    r.puts(inspect_class(params['class'], get_classes()))
  elsif params.has_key?('module')
    r.puts(inspect_module(params['module'], get_modules()))
  else
    r.puts(format_modules(get_classes(), 'Classes', 'class'))
    r.puts(format_modules(get_modules(), 'Modules', 'module'))
  end

end



def escape_html (str)
  str.gsub(/&/, '&amp;').gsub(/\"/, '&quot;').gsub(/</, '&lt;').gsub(/>/, '&gt;')
end



def escape_uri(string)
  string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
    '%' + $1.unpack('H2' * $1.size).join('%').upcase
  end.tr(' ', '+')
end



def format_modules (module_list, title = 'Modules', uriname = 'module')
  output = ''
  ordered_modules = []
  module_list.each do |ml|
    ordered_modules.push(ml.to_s)
  end

  output <<= "<h1>#{title}:</h1>"
  output <<= '<table border="1">'
  ordered_modules.uniq.sort.each do |mn|
    output <<= "<tr><td><a href=\"#{Apache.request.uri}?#{uriname}=#{escape_uri(mn)}\">#{mn}</a></td></tr>"
  end

  output <<= '</table>'
  return(output)
end



def format_class_methods(obj = Object, method = methods, name = 'Methods')
  output = ''
  m = []
  comment = ''

  if method == 'constants'
    if obj.type == 'Class' && obj.superclass
      m = obj.send(method) - obj.superclass.send(method)
      comment = '<i>super class constants ommited</i>'
    elsif obj.type.to_s == 'Module'
      begin
	m = obj.send(method)
      rescue NameError
	comment <<= $!
      end
    else
      m.push(obj.type.to_s)
    end
  else
    m = obj.send(method)
  end

  output <<= "<h3>#{name}:</h3>"
  output <<= comment
  output <<= '<table border="1">'

  len = output.length
  m.sort.each do |m|
    output <<= "<tr><td><code>#{escape_html(m)}</code></td>"

    if method == 'constants'
      output <<= "<td>#{escape_html(obj.const_get(m).inspect)}</td>"
    else
      output <<= "</tr>"
    end
  end

  if len == output.length
    output <<= "<tr><td>No #{name}</td></tr>"
  end
  output <<= '</table>'

  return(output)
end



def get_classes()
  class_types = []
  ObjectSpace.each_object(Class) { |o|
    class_types.push(o)
  }

  return(class_types)
end



def get_modules()
  module_types = []
  ObjectSpace.each_object(Module) { |o|
    module_types.push(o)
  }

  return(module_types)
end



def get_params (r)
  params = Hash.new([])
  args = r.args

  if args
    args.split(/[&;]/n).each do |pairs|
      key, value = pairs.split('=',2).collect{|v| unescape_uri(v) }
      if params.has_key?(key)
	params[key].push(value)
      else
	params[key] = [value]
      end
    end
  end

  return(params)
end



def inspect_class(class_name, classes)
  output = ''
  class_obj = nil

  classes.each do |c|
    class_obj = c.dup if class_name.to_s == c.to_s
  end

  output <<= "<h1>Class: <code>#{class_obj.to_s}</code></h1>"

  klass = class_obj
  hier = []
  begin
    hier.unshift("<code><a href=\"#{Apache.request.uri}?class=#{escape_uri(klass.to_s)}\">" + escape_html(klass.to_s) + '</a></code>')
    klass = klass.superclass
  end while klass


  output <<= "Ancestry: " + hier.join('&nbsp;>&nbsp;') + "<br>"


  output <<= 'Included Modules: '
  im = []
  class_obj.included_modules.sort.each do |m|
    unless m
      raise RuntimeError, m.inspect
    end
      
    im.push("<code><a href=\"#{Apache.request.uri}?module=#{m}\">#{m}</a></code>")
  end
  output <<= im.sort.join(', ') + '<br>'

  output <<= "Class Variables: " + class_obj.class_variables.sort.join(',) + "<br>"


  output <<= format_class_methods(class_obj, 'public_instance_methods', 'Public Instance Methods')
  output <<= format_class_methods(class_obj, 'protected_instance_methods', 'Protected Instance Methods')
  output <<= format_class_methods(class_obj, 'private_instance_methods', 'Private Instance Methods')
  output <<= format_class_methods(class_obj, 'singleton_methods', 'Singleton Methods')
  output <<= format_class_methods(class_obj, 'constants', 'Constants')

  return(output)
end



def inspect_module(module_name, modules)
  output = ''
  module_obj = nil

  modules.each do |m|
    module_obj = m.dup if module_name.to_s == m.to_s
  end

  output <<= "<h1>Module: <code>#{module_obj.to_s}</code></h1>"

  output <<= 'Included Modules: '
  im = []
  module_obj.included_modules.sort.each do |m|
    unless m
      raise RuntimeError, m.inspect
    end
      
    im.push("<code><a href=\"#{Apache.request.uri}?module=#{m}\">#{m}</a></code>")
  end
  output <<= im.sort.join(', ') + '<br>'

  output <<= "Class Variables: " + module_obj.class_variables.sort.join(', ') + "<br>"


  output <<= format_class_methods(module_obj, 'public_instance_methods', 'Public Instance Methods')
  output <<= format_class_methods(module_obj, 'protected_instance_methods', 'Protected Instance Methods')
  output <<= format_class_methods(module_obj, 'private_instance_methods',Private Instance Methods')
  output <<= format_class_methods(module_obj, 'singleton_methods', 'Singleton Methods')
  output <<= format_class_methods(module_obj, 'constants', 'Constants')

  return(output)
end



def main (r)
  r.content_type = 'text/html'
  r.send_http_header()
  return(Apache::OK) if r.header_only?

  body(r)
end

def unescape_uri(string)
  string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do
    [$1.delete('%')].pack('H*')
  end
end



main(r)




--YhFoJY/gx7awiIuK--

--T4IYkFBVPN84tP7K
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Comment: Sean Chittenden <sean / chittenden.org>

iEYEARECAAYFAjuJs4cACgkQn09c7x7d+q2RGwCdGMl1XIyRlMTaG7Gmr79oLLl/
YusAn2U+/BxlK5/Vza355FMJVYk8a2vo
gN
-----END PGP SIGNATURE-----

--T4IYkFBVPN84tP7K--