# IRB as test interface to existing object

**URL:** <https://rubytalk.org/t/irb-as-test-interface-to-existing-object/36225>\
**Category:** ruby-talk\
**Created:** [17 March 2007 13:54 UTC](https://rubytalk.org/t/irb-as-test-interface-to-existing-object/36225 "2007-03-17T13:54:34Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Brian\_Candler](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Brian\_Candler](https://rubytalk.org/u/Brian_Candler)\
**Post date:** [17 March 2007 13:54 UTC](https://rubytalk.org/t/irb-as-test-interface-to-existing-object/36225/1 "2007-03-17T13:54:34Z")

</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  
&nbsp;&nbsp;obj = MyClass.new(\*ARGV)  
&nbsp;&nbsp;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  
&nbsp;&nbsp;attr\_reader :addr  
&nbsp;&nbsp;def initialize(addr)  
&nbsp;&nbsp;&nbsp;&nbsp;@addr = addr  
&nbsp;&nbsp;end

&nbsp;&nbsp;def do\_stuff(n)  
&nbsp;&nbsp;&nbsp;&nbsp;n.times { puts "doing stuff with #{@addr}" }  
&nbsp;&nbsp;end  
end

if \_\_FILE\_\_ == $0  
&nbsp;&nbsp;obj = Foo.new(\*ARGV)  
&nbsp;&nbsp;prompt = "Foo(#{obj.addr})\> "  
&nbsp;&nbsp;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:** ![Joel\_VanderWerf1](https://avatars.discourse-cdn.com/v4/letter/j/94ad74/32.png) [@Joel\_VanderWerf1](https://rubytalk.org/u/Joel_VanderWerf1)\
**Post date:** [17 March 2007 16:42 UTC](https://rubytalk.org/t/irb-as-test-interface-to-existing-object/36225/2 "2007-03-17T16:42:42Z")

</div>

Brian Candler wrote:

> 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  
> &nbsp;&nbsp;obj = MyClass.new(\*ARGV)  
> &nbsp;&nbsp;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  
> &nbsp;&nbsp;attr\_reader :addr  
> &nbsp;&nbsp;def initialize(addr)  
> &nbsp;&nbsp;&nbsp;&nbsp;@addr = addr  
> &nbsp;&nbsp;end
> 
> &nbsp;&nbsp;def do\_stuff(n)  
> &nbsp;&nbsp;&nbsp;&nbsp;n.times { puts "doing stuff with #{@addr}" }  
> &nbsp;&nbsp;end  
> end
> 
> if \_\_FILE\_\_ == $0  
> &nbsp;&nbsp;obj = Foo.new(\*ARGV)  
> &nbsp;&nbsp;prompt = "Foo(#{obj.addr})\> "  
> &nbsp;&nbsp;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  
> 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  
> =\> 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.

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  
&nbsp;&nbsp;&nbsp;def IRB.parse\_opts  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Don't touch ARGV, which belongs to the app which called this module.  
&nbsp;&nbsp;&nbsp;end

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

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;workspace = WorkSpace.new(\*args)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if @CONF[:SCRIPT] ## normally, set by parse\_opts  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$irb = Irb.new(workspace, @CONF[:SCRIPT])  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$irb = Irb.new(workspace)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@CONF[:IRB\_RC].call($irb.context) if @CONF[:IRB\_RC]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@CONF[:MAIN\_CONTEXT] = $irb.context

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;trap 'INT' do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$irb.signal\_handle  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;custom\_configuration if defined?(IRB.custom\_configuration)

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;catch :IRB\_EXIT do  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$irb.eval\_input  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;## might want to reset your app's interrupt handler here  
&nbsp;&nbsp;&nbsp;end  
end

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

if \_\_FILE\_\_ == $0  
&nbsp;&nbsp;&nbsp;x = Object.new  
&nbsp;&nbsp;&nbsp;puts "\nStarted irb shell for x"  
&nbsp;&nbsp;&nbsp;IRB.start\_session(x)  
&nbsp;&nbsp;&nbsp;puts "\nStarted irb shell for x with current binding"  
&nbsp;&nbsp;&nbsp;IRB.start\_session(binding, x)  
&nbsp;&nbsp;&nbsp;puts "\nRestarted irb shell for x with current binding"  
&nbsp;&nbsp;&nbsp;$irb.eval\_input  
&nbsp;&nbsp;&nbsp;puts "\nExited irb shell"  
&nbsp;&nbsp;&nbsp;p x  
end

> **···**
>
> --  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

---

<div class="post-metadata">

**Author:** ![Brian\_Candler](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Brian\_Candler](https://rubytalk.org/u/Brian_Candler)\
**Post date:** [17 March 2007 17:40 UTC](https://rubytalk.org/t/irb-as-test-interface-to-existing-object/36225/3 "2007-03-17T17:40:37Z")

</div>

> 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.

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