Hi,
On Saturday 10 February 2007 15:07, Brian C. wrote:
end
I’ve no idea how this works; it has to rate as cool Ruby, even if it isn’t
implemented in Ruby
- PREFACE
I understood your sentence as “i’ve no idea how
works…” and started explaining how it works and what can be done with
it,
translating the concept being explained in the article I linked in my
previous post (code from the inside out 3).
In the end, just some picoseconds before hitting “SEND”, I realized that
you
were referring to tryruby.hobix.com.
I’d feel even dumber if I had thrown away the writeup, maybe it could
prove
interesting for someone. I also surely made lots of errors and said lots
of
imprecise things. Please correct me. TIA :).
- WRITEUP
the IRB.start_in_binding method makes you able to start an IRB in
whichever
context you want, attaching it to a running ruby program, in the context
you
define. let’s say, e.g., that you’re dissatisfied by using “puts”
or “debugger” to inspect how “things” in your program work, and you’d
like to
be inside your code, in order to better feel the presence of methods
and
objects that you can call and inspect, in some nested place in your
code.
e.g. you’d like to write an association extension, but really don’t know
which
methods can call from that context, or you don’t immediately understand
in
which scope the association extension code is being called.
start_in_binding
to the rescue!
has_many :things do
current_binding = binding # verbose assignment, to make
IRB.start_in_binding(current_binding) # things more clear.
end
when that “has_many” method is run (e.g. by require’ing the model with
this
association) another IRB prompt will greet you. welcome inside your
program!
with
self.class
=> Array
and
self.class.ancestors.include? AssociationProxy
=> true
you can really feel like being an intruder in a foreign land ;), you can
try
to call things around, or you can define methods and test them
directly
into the code. So, the ruby code doesn’t go from the source file into
the
running instance, it goes exactly the opposite way: you write it inside
the
running instance, and if it works you copy it into the source file.
Pretty
neat :). The article I linked in my previous post explains this
“intruder
pattern”, but uses a Tk program as an intrusion point.
if you are unfamiliar with “binding”, it is an “execution context”, with
all
the local variables, methods and ‘self’ value left in place. Someone can
describe it in more detail than me, or you can just “ri Binding” [1].
You can
pass Binding instances as a second argument to an eval() call, so that
the
given code will be evaluated in the passed binding’s context.
Kernel#binding returns the current binding.
Some other very neat (hacky?) bit (bunch?) of binding-related code is in
irb/workspace.rb:55
when 3 # binging in function on TOPLEVEL_BINDING(default)
@binding = eval("def irb_binding; binding; end; irb_binding",
TOPLEVEL_BINDING,
__FILE__,
__LINE__ - 3)
here it is defined a method that returns ITS binding, and then it is
being
called. that method is executed in TOPLEVEL_BINDING context, and its
return
value (a “clean” binding inside Object#irb_binding) is stored in
@binding.
@binding is used for further evaluation. that’s schweet :).
other options, always in workspace.rb:
when 0 # binding in proc on TOPLEVEL_BINDING
@binding = eval("proc{binding}.call",
TOPLEVEL_BINDING,
__FILE__,
__LINE__)
here the binding is pulled out from an anonymous lambda call…
the most hacky, imho:
when 1 # binding in loaded file
require "tempfile"
f = Tempfile.open("irb-binding")
f.print <<EOF
$binding = binding
EOF
f.close
load f.path
@binding = $binding
write-some-temp-file-that-stores-the-binding-in-a-global-var-and-pull-out-that-one-using-load
!
sorry for this long blob of things that experienced ruby users know like
their
hands, but I went through this stuff some time ago, and while I was
understanding how it works, i learnt all the Binding stuff [2]. it was
like
being in a journey through different execution worlds and I had lot
of fun
putting all the pieces together. And I’m sharing my fun and my horrid
english ;).
Marcello
- FOOTNOTES
[1]: i suggest http://eigenclass.org/hiki.rb?fastri if you feel that
ri is
too (fscking) slow in doing its job.
[2]: the next step were eigenclasses, which I understood completely only
after
reading the RHG http://rhg.rubyforge.org. even that was fun. ruby’s
magic
dust…