# IRB as test interface to existing object

**URL:** <https://www.ruby-forum.com/t/irb-as-test-interface-to-existing-object/89126>\
**Category:** Ruby\
**Created:** [March 17, 2007, 2:55pm UTC](https://www.ruby-forum.com/t/irb-as-test-interface-to-existing-object/89126 "2007-03-17T14:55:06Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [March 17, 2007, 2:55pm UTC](https://www.ruby-forum.com/t/irb-as-test-interface-to-existing-object/89126/1 "2007-03-17T14:55:06Z")

</div>

Hello,

I have some object classes to which I want to add an interactive  
command-line shell for testing. At the moment, at the end of the source  
file  
I have something like

if **FILE** == $0  
obj = MyClass.new(\*ARGV)  
CLI.run(obj, "MyClass\> ")  
end

Now, I had started writing a CLI module which reads lines from stdin,  
splits  
them into an array, runs obj.send(\*args), and prints the response. Then  
it  
occurred to me that this is what IRB is for. But I don’t know how to  
start  
IRB in such a way that the default “self” receiver is an object which I  
created.

Here’s an example of what I’d like to end up with:

class Foo  
attr\_reader :addr  
def initialize(addr)  
@addr = addr  
end

def do\_stuff(n)  
n.times { puts “doing stuff with #{@addr}” }  
end  
end

if **FILE** == $0  
obj = Foo.new(\*ARGV)  
prompt = "Foo(#{obj.addr})\> "  
IRB.run(obj, prompt) # \<\<\<— what do I put here?  
end

$ ruby foo.rb 127.0.0.1  
Foo(127.0.0.1)\> do\_stuff 3  
doing stuff with 127.0.0.1  
doing stuff with 127.0.0.1  
doing stuff with 127.0.0.1  
nil  
Foo(127.0.0.1)\>

Reading the irb manpage, I can see that you can use the ‘irb’ command  
(interactively) to set the default receiver in a subshell:

irb(main):012:0\> obj = Foo.new(“127.0.0.1”)  
=\> #\<Foo:0xb7c46730 @addr=“127.0.0.1”\>  
irb(main):013:0\> irb obj  
irb#1(#Foo:0xb7c46730):001:0\> do\_stuff 3  
doing stuff with 127.0.0.1  
doing stuff with 127.0.0.1  
doing stuff with 127.0.0.1  
=\> 3

But I can’t work out how to invoke an initial IRB instance with my own  
‘main’ object from the start. I’ve tried going through the source, but I  
get  
lost in Contexts and Workspaces well before I get to subirb.rb 🙂 I’d  
also  
prefer to implement it in a way which uses a ‘standard’ interface to  
Irb,  
such that it won’t break with a future version of Ruby.

Any clues gratefully received.

Thanks,

Brian.

---

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [March 17, 2007, 5:43pm UTC](https://www.ruby-forum.com/t/irb-as-test-interface-to-existing-object/89126/2 "2007-03-17T17:43:27Z")

</div>

Brian C. wrote:

> def initialize(addr)  
> prompt = "Foo(#{obj.addr})\> "
> 
> =\> 3
> 
> Brian.

The following drops into (or _back_ into) an irb session. (Customizing  
the prompt is another matter, and I don’t remember how to do that, but  
it might be findable on ruby-talk.)

(I use typically this in a long running process. I set my INT handler  
and top-level exception handlers to start\_session on some main object.  
So ^C drops into irb, and ^D jumps back out.)

#!/usr/bin/env ruby

require ‘irb’  
require ‘irb/completion’

module IRB  
def IRB.parse\_opts  
# Don’t touch ARGV, which belongs to the app which called this  
module.  
end

def IRB.start\_session(\*args)  
unless $irb  
IRB.setup nil  
## maybe set some opts here, as in parse\_opts in irb/init.rb?  
end

```
 workspace = WorkSpace.new(*args)

 if @CONF[:SCRIPT] ## normally, set by parse_opts
   $irb = Irb.new(workspace, @CONF[:SCRIPT])
 else
   $irb = Irb.new(workspace)
 end

 @CONF[:IRB_RC].call($irb.context) if @CONF[:IRB_RC]
 @CONF[:MAIN_CONTEXT] = $irb.context

 trap 'INT' do
   $irb.signal_handle
 end

 custom_configuration if defined?(IRB.custom_configuration)

 catch :IRB_EXIT do
   $irb.eval_input
 end

 ## might want to reset your app's interrupt handler here

```

end  
end

class Object  
include IRB::ExtendCommandBundle # so that Marshal.dump works  
end

if **FILE** == $0  
x = Object.new  
puts “\nStarted irb shell for x”  
IRB.start\_session(x)  
puts “\nStarted irb shell for x with current binding”  
IRB.start\_session(binding, x)  
puts “\nRestarted irb shell for x with current binding”  
$irb.eval\_input  
puts “\nExited irb shell”  
p x  
end

---

<div class="post-metadata">

**Author:** ![stickstone](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/6f9a4e/32.png) [@stickstone](https://www.ruby-forum.com/u/stickstone)\
**Post date:** [March 17, 2007, 6:41pm UTC](https://www.ruby-forum.com/t/irb-as-test-interface-to-existing-object/89126/3 "2007-03-17T18:41:38Z")

</div>

On Sun, Mar 18, 2007 at 01:42:42AM +0900, Joel VanderWerf wrote:

> The following drops into (or _back_ into) an irb session.

This works perfectly, thank you (great to get command history!)

It also looks suspiciously like IRB.start in /usr/lib/ruby/1.8/irb.rb -  
shame that doesn’t take a second optional parameter for the workspace.

> (Customizing  
> the prompt is another matter, and I don’t remember how to do that, but  
> it might be findable on ruby-talk.)

Just defining a to\_s method on the object works well enough for me. I  
have  
also found more details about IRB.conf in “man irb” (actually “man  
irb1.8”  
on this Ubuntu box)

Thanks again,

Brian.
