From: Marcello Barnaba Date: 2007-02-11T00:50:04+09:00 Subject: Re: Your favorite bit of ruby code? Hi, On Saturday 10 February 2007 15:07, Brian Candler wrote: > On Sat, Feb 10, 2007 at 08:10:52AM +0900, Marcello Barnaba wrote: > > require 'irb' > > > > module IRB > > def IRB.start_in_binding(b) > > setup(nil) > > irb = IRB::Irb.new(WorkSpace.new(b)) > > @CONF[:MAIN_CONTEXT] = irb.context > > catch(:IRB_EXIT) { irb.eval_input } > > end > > end > > I've no idea how this works; it has to rate as cool Ruby, even if it isn't > implemented in Ruby :-) 3) 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 :). 1) 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 < 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 . even that was fun. ruby's magic dust.. :) [3]: http://rubyurl.com/K4P -- pub 1024D/8D2787EF 723C 7CA3 3C19 2ACE 6E20 9CC1 9956 EB3C 8D27 87EF