How it works: in Python you can do:
try: do stuff except: exc_type, exc, tb = sys.exc_info()
That tb object is basically one line in the traceback, linked to the previous line by tb.tb_next. The tb object is pretty boring, but it has a link to the frame (tb.tb_frame). The frame object contains the local and global variables, so you can evaluate expressions in the context of those variables. I stuff the entire set of frames into a module-global variable, so that it doesn't disappear as long as you don't restart the server (this in effect leaks substantial memory, but this should only be enabled for debugging), and all the interaction is keyed off where I put the frames (each set gets an id) and the specific frame (each frame gets an id). The interpreter is a basic Ajax interpreter, nothing too fancy.
The system also includes a way to annotate tracebacks, which was taken from Zope (written by Shane Hathaway I think), which uses magic local variables and the same introspection to find the annotations. So if you just define a local variable like __traceback_info__ = 'index.html line 10' then that will show up in the traceback. Currently that is just used for templating languages, where there's typically a disconnect between the template source code and the code being run (both in the case of interpreters and compilers). Currently only ZPT uses this (and I guess DTML) but it would be good if more did -- hopefully Kid will soon too.
With all of these, all the work is done only when an exception goes all the way up to the exception catcher (which is an application wrapper, aka middleware). So there's no real overhead to using these either. And they are complimentary to the normal way exceptions work, so show a very accurate indication of the state and real context of the exception -- a lot of other attempts to make exceptions better for template code covers up errors above or below the template.
Anyway, that's how it works. There's also lots of people that have run their applications under pdb, which may be more similar to how ruby-breakpoint works. Pdb is a traditional debugger and uses a special mode of the Python interpreter to do its thing (sys.settrace()). I've used pdb here and there, but somehow it could never catch for me; winpdb looks considerably easier to use, but I haven't tried it.
Ah, Ruby doesn't have a way of going from an exception to the frames it passed through (called bindings in Ruby).
Having that makes all this quite straightforward. Still quite cool stuff.
What ruby-breakpoint uses is a hackish way of getting the breakpoint() caller's binding which will then be used for the debugging session.
pdb seems similar to debug.rb that comes with Ruby. It's more of a traditional debugger, but I found an interactive environment very natural to do this kind of thing.
Currently ruby-breakpoint doesn't require a permanent global trace function which is a good thing because those are quite slow in Ruby.
WinPDB looks nice. Already has some of the features I would like my GUI client to have.
Thanks for all the information. This has been very insightful!