[ANN] DrX, an object inspector

Caleb C. wrote:

The size and style drop-down boxes don’t work for me if I
close and then re-open drx a second time from within irb.

Thanks for reminding me of this Ruby/Tk bug. I think I’ll have a
workaround soon. It only happens for Tk 8.4, not for Tk 8.5.

Tip for Ubuntu users:

Here’s how to compile Ruby/Tk against the new Tk 8.5:

http://drx.rubyforge.org/ubuntu-new-tk.html

Is there any chance you’ll extend this to show an object’s
contents instead of or in addition to it’s class/type?

Yes, there’s a chance. I haven’t yet an idea how this feature will
look/behave.

You ought to provide a drx command so I can launch it directly
instead of invoking it via irb.

Yes, that’s a good idea.

You should consider using the EDITOR or VISUAL environment
variables instead of DRX_EDITOR_COMMAND.

There are several reasons for not doing this. Jakub has explained. I
certainly don’t want to use my EDITOR: mine works only in the console,
and gedit starts up faster.

(Besides, I don’t recommend people to use this environment variable
anyway. They should put all their configuration in ~/.drxrc: it’s much
better because they can backup it, copy to other systems, etc. This
DRX_EDITOR_COMMAND exists only because DrX didn’t have ~/.drxrc when I
wrote that section in the user manual.)

Brian C. wrote:

Only suggestion: a “back” button would be nice. I had to go to
the docs to find out that right-click = back.

Thanks, I’ve added this to my Issue Tracker.

Mooffie n/a schrieb:

doxygen generates a similar […]
parallel/perpendicular). That’s what DrX does. Doxygen is good for
diagram. Static tools like ‘rdoc’ can’t tell us in which classes the
if you have more ideas on this and similar subjects.

Note that I’m not using Tk’s canvas to draw the graph. I show the bitmap
GraphViz produces.

Send a medium to large compressed svg via email to me, then I take a
look at it.
I suspect the graphviz/svg issue can be solved inside the DOM-tree after
graphviz generated
the svg.

-roger

Mooffie wrote:

Note that I’m not using Tk’s canvas to draw the graph. I show the bitmap
GraphViz produces.

I also ask GraphViz to produce a “hot spot” map, which I use to give
visual cues to the user when he hovers the mouse on the various shapes
in the bitmap.

On 4/22/10, Mooffie n/a [email protected] wrote:

Caleb C. wrote:

The size and style drop-down boxes don’t work for me if I
close and then re-open drx a second time from within irb.

Thanks for reminding me of this Ruby/Tk bug. I think I’ll have a
workaround soon. It only happens for Tk 8.4, not for Tk 8.5.

I thought I had 8.5 installed… apparently not. Thanks for the
instructions for fixing it.

Is there any chance you’ll extend this to show an object’s
contents instead of or in addition to it’s class/type?

Yes, there’s a chance. I haven’t yet an idea how this feature will
look/behave.

I can give you some ideas, if you want. I realize that since the
contents of an object are potentially a much larger graph, that makes
displaying them rather more challenging.

You should consider using the EDITOR or VISUAL environment
variables instead of DRX_EDITOR_COMMAND.

There are several reasons for not doing this. Jakub has explained. I
certainly don’t want to use my EDITOR: mine works only in the console,
and gedit starts up faster.

EDITOR is supposed to be a console-only program. You’d have to launch
a new xterm (or whatever) and run EDITOR in that. If the user wants a
gui program, he should place it in VISUAL. Jakub’s scheme of looking
in DRX_EDITOR_COMMAND, then VISUAL, then perhaps EDITOR is probably
the best.

But really this was a very minor quibble, so feel free to ignore me.

(Besides, I don’t recommend people to use this environment variable
anyway. They should put all their configuration in ~/.drxrc: it’s much
better because they can backup it, copy to other systems, etc. This
DRX_EDITOR_COMMAND exists only because DrX didn’t have ~/.drxrc when I
wrote that section in the user manual.)

And that’s quite appropriate, of course. But it brings up another
point; since this is a gui program, shouldn’t it have gui dialog(s)
for setting all those configuration items? That’s always nice to have,
but again of minor importance at best.

On Wednesday 21 April 2010 11:20:12 pm Charles Oliver N. wrote:

stumbling block.
ref.class # now org.jruby.RubyString
ref.methods # now includes all Java-land methods on RubyString
cls = ref.metaclass # an org.jruby.RubyClass instance
cls.methods # should be the internal method table

It seems like this should be possible to do from bare Ruby, in a
portable way.
Clumsy, but possible. For example, as long as people don’t get smart and
use
Ruby 1.9’s BasicObject, you can do this:

Object.instance_method(:methods).bind(‘foo’).call

That takes care of things like Builder’s BlankSlate object, though:

Object.instance_method(:methods).bind(BlankSlate.new).call
=> [“send”, “instance_eval”, “id”]

BlankSlate itself hints at other ways to abuse Ruby for similar effects
– for
instance, I couldn’t readily find a way to discover where a method was
originally defined, and whether it’s been overridden, but it seems
likely that
if I could get my fangs deep into things like method_added before
anything
else was loaded, I could generate this kind of map.

I might be missing what you’re trying to do, though.

David M. wrote:

On Wednesday 21 April 2010 11:20:12 pm Charles Oliver N. wrote:

ref.class # now org.jruby.RubyString
ref.methods # now includes all Java-land methods on RubyString
cls = ref.metaclass # an org.jruby.RubyClass instance
cls.methods # should be the internal method table

It seems like this should be possible to do from bare Ruby, in a
portable way.
Clumsy, but possible.

How, for example, can you find an object’s class using pure Ruby?

The problem with Ruby’s #class is that it skips singletons. Example:

s = “blah”
def s.whatever; 666; end
p s.class

The above will print “String”, but it’s an error: the class should be
some singleton.

(Doing “class << s; self; end” isn’t a solution because it alters the
object model: it creates a singleton if none yet exists.)

Though maybe there is a way to find an object’s class, I don’t know (I
still consider myself a Ruby newbie).

cls.methods # should be the internal method table

It seems like this should be possible to do from bare Ruby, in a
portable way.

As another example, consider this:

module M
def whatever; 666; end
undef_method :whatever
end

M.instance_methods() won’t report the method ‘whatever’, whereas Ruby
keeps a stub under that name. I want to see it.

When I started writing DrX my intention was to figure out how Ruby
and/or MRI works. So high-fidelity was important to me. In fact, I
simply wanted to see the C structures. I’m not interested in
approximation.

(Though nothing prevents replacing the C extension with a pure-Ruby
implementation.)

On Sat, Apr 24, 2010 at 10:38 AM, David M. [email protected]
wrote:

For getting the data, you don’t even need to write an extension to
JRuby. The “jruby” library gives you introspective access to all
objects at a very direct level:
It seems like this should be possible to do from bare Ruby, in a portable way.
Clumsy, but possible. For example, as long as people don’t get smart and use
Ruby 1.9’s BasicObject, you can do this:

No, I’m pretty sure this isn’t possible on regular Ruby. What’s
happening in JRuby is that you’re getting direct access to the Java
object representing a Ruby class or object, and you then can do
anything to that object you’d normally have to write Java code for.

Now that I’m on my machine, here’s a more extensive example:

require ‘jruby’

class MyObject
def foo
‘hello’
end
end
obj = MyObject.new
cls = obj.class

obj_ref = JRuby.reference obj
cls_ref = JRuby.reference cls

accessing the raw method table on a class

methods = cls_ref.getMethods # this was the “.methods” call previously
p methods.class # => Java::JavaUtilConcurrent::ConcurrentHashMap
foo_method = methods[‘foo’]

foo_method is an instance of our internal method object

p foo_method.call(JRuby.runtime.current_context, obj, cls_ref, ‘foo’)

=> ‘hello’

changing the object’s class(!?)

class Foo; end
p obj.class # => ‘Object’
obj_ref.setMetaClass(JRuby.reference(Foo))
p obj.class # => ‘Foo’

modifying the current scope

scope = JRuby.runtime.current_context.current_scope
p scope.static_scope.variables.to_a

=> [“obj”, “cls”, “obj_ref”, “cls_ref”, “methods”, “foo_method”,

“scope”]
index = scope.static_scope.variables.to_a.index(‘scope’)
scope.set_value_depth_zero(‘hello’, index)
p scope # => ‘hello’

…and so on. Essentially anything you can call from Java, you can
call from Ruby once you have the appropriate reference, so you should
be able to programmatically walk all of the JRuby runtime structures
and any Ruby or Java objects they reference without writing any Java
code.

  • Charlie

On Sunday 25 April 2010 02:41:07 am Charles Oliver N. wrote:

On Sat, Apr 24, 2010 at 10:38 AM, David M. [email protected] wrote:

For getting the data, you don’t even need to write an extension to
JRuby. The “jruby” library gives you introspective access to all
objects at a very direct level:

It seems like this should be possible to do from bare Ruby, in a portable
way. Clumsy, but possible. For example, as long as people don’t get smart
and use Ruby 1.9’s BasicObject, you can do this:

No, I’m pretty sure this isn’t possible on regular Ruby.

Ah, wishful thinking of my part, then.

What’s
happening in JRuby is that you’re getting direct access to the Java
object representing a Ruby class or object, and you then can do
anything to that object you’d normally have to write Java code for.

I’ve raised this question before, and people seem to disagree with me,
but:

changing the object’s class(!?)

class Foo; end
p obj.class # => ‘Object’
obj_ref.setMetaClass(JRuby.reference(Foo))
p obj.class # => ‘Foo’

I think it should be possible to do that from within Ruby.

But I can’t even get most people behind this suggestion:

class A; end
class B; end
A.instance_method(:to_s).bind(B.new)

That gives me a type error, which just seems bizarre, especially after
the
relative freedom of JavaScript. Ah, well.

On 4/25/10, Mooffie n/a [email protected] wrote:

(Doing “class << s; self; end” isn’t a solution because it alters the
object model: it creates a singleton if none yet exists.)

Though maybe there is a way to find an object’s class, I don’t know (I
still consider myself a Ruby newbie).

I had thought that I had proved to myself that class<<s; self; end was
guaranteed to be nondestructive on all modern (>=1.8.6) versions of
ruby… maybe not, tho. I’m not sure now. I might need to change some
of my own code in light of this…

Your terminology is a bit wrong, or at any rate unorthodox.
Object#class works as it was designed. In the above snippet, the class
of s is always a string, even tho its singleton class changes. The
#class of an object is its birth type, even tho the type can change
subsequently. (The klass field of an object doesn’t always point
directly to an object’s class… klass is kind of misnamed, actually.)

Recent vintages of 1.9 are supposed to have Object#singleton_class.

On Monday 26 April 2010 10:04:04 am Charles Oliver N. wrote:

On Sun, Apr 25, 2010 at 3:23 PM, David M. [email protected] wrote:

On Sunday 25 April 2010 02:41:07 am Charles Oliver N. wrote:

I’ve raised this question before, and people seem to disagree with me,
but:
class A; end
short, you’d at best end up with methods that don’t function because
they’re not attached to an array, and at worst with methods that
outright segfault.

I think I’m OK with that. JavaScript doesn’t allow rebinding native
methods,
either. I would, however, strongly encourage fewer native methods when
possible – doesn’t Kernel#autoload still use a native call to the
native
require, thus bypassing any attempt to overload Kernel#require?

There’s no technical reason you couldn’t allow rebinding of Ruby
methods though.

Just a political one, I think. Every time I bring this up, I get a weak
justification that seems to be based around some desire for strong,
static
typing, and strict, rigid inheritance.

It’s especially frustrating when, as in my example above, I’m trying to
rebind
a method which was originally declared on a parent class to both
methods.
Having to figure out (or programmatically navigate!) the class hierarchy
to
find the exact point which is a superclass (or supermodule) of both
objects
I’m working with, yet still has the appropriate method, and then rebind
it all
the way down the hierarchy, rather than at least having it Just Work
(A.instance_method(:to_s) should return Object#to_s unless I actually
define
A#to_s), is the exact POLAR OPPOSITE of duck typing, do-what-I-mean,
beautiful
code, and everything Ruby is supposed to be about. Let me decide if the
class
is important – if I really care, I can check obj.kind_of?(umeth.owner),
but
there’s no good reason for the language to make that decision for me!
Ruby is
not supposed to be like Java!

deep breaths

I can definitely think of a few places where this would be useful. I can
probably hack around it anyway, though – it mostly just offends the
purist in
me. It is, IMO, the ugliest thing about Ruby’s otherwise-beautiful
object
model.

That’s roughly possible in JRuby if you go “under the
covers”
[snip]
…of course, the devil’s in the details.

As much as I like JRuby, I’d much prefer a portable solution. However, I
needed this for a project I’ve all but abandoned, so I’m not
particularly
motivated to write such a solution. (I’d guess the closest I would get
is a
single gem that does different hacks in different interpreters.)

This little gem does what you want (with some magic from some very thin
native extension) GitHub - oggy/looksee: Supercharged method introspection in IRB

Mooffie n/a wrote:

How, for example, can you find an object’s class using pure Ruby?

The problem with Ruby’s #class is that it skips singletons. Example:

s = “blah”
def s.whatever; 666; end
p s.class

The above will print “String”, but it’s an error: the class should be
some singleton.

On Sun, Apr 25, 2010 at 3:23 PM, David M. [email protected]
wrote:

But I can’t even get most people behind this suggestion:

class A; end
class B; end
A.instance_method(:to_s).bind(B.new)

That gives me a type error, which just seems bizarre, especially after the
relative freedom of JavaScript. Ah, well.

The main issue that comes up with this is that classes with native
methods (like all the core classes) would have to be given special
treatment. You couldn’t, for example, rebind a String method to Array
or an Array subclass since the in-memory structure is different. In
short, you’d at best end up with methods that don’t function because
they’re not attached to an array, and at worst with methods that
outright segfault.

There’s no technical reason you couldn’t allow rebinding of Ruby
methods though. That’s roughly possible in JRuby if you go “under the
covers”:

require ‘jruby’

class Foo
def foo
puts “This is foo in #{self.class}”
end
end

class Bar
end

foo_ref = JRuby.reference(Foo)
bar_ref = JRuby.reference(Bar)

bar_ref.add_method(‘bar’, foo_ref.search_method(‘foo’))

Bar.new.bar # => “This is foo in Bar”

…of course, the devil’s in the details.

  • Charlie