# IRB module with non-blocking asynchronous gets

**URL:** <https://www.ruby-forum.com/t/irb-module-with-non-blocking-asynchronous-gets/112979>\
**Category:** Ruby\
**Created:** [August 25, 2007, 10:09am UTC](https://www.ruby-forum.com/t/irb-module-with-non-blocking-asynchronous-gets/112979 "2007-08-25T10:09:13Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![sjml](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b19c9b/32.png) [@sjml](https://www.ruby-forum.com/u/sjml)\
**Post date:** [August 25, 2007, 10:09am UTC](https://www.ruby-forum.com/t/irb-module-with-non-blocking-asynchronous-gets/112979/1 "2007-08-25T10:09:13Z")

</div>

Is there a way to use the IRB module so that it evaluates code on-demand  
only instead of running in a constant loop?

I don’t need to use readline and have IRB wait for input – I can  
trigger its need to evaluate from elsewhere in the program. I was  
hoping, though, that I could have the gets function from my  
IRB::StdioInputMethod subclass return a properly formatted string, let  
IRB do its thing, and then give me back control until it was needed  
again.

It seems, though, that the eval\_input function just keeps executing gets  
and never returns control. I understand that’s the intended behavior of  
eval\_input, but I’m a little surprised there’s not a more asynchronous  
way of requesting evaluation.

Am I just approaching the problem from the wrong angle? I keep feeling  
like Ruby has to provide a way to do what I’m after, but I haven’t been  
able to track it down thus far.

Any help would be appreciated.

---

<div class="post-metadata">

**Author:** ![sjml](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b19c9b/32.png) [@sjml](https://www.ruby-forum.com/u/sjml)\
**Post date:** [August 26, 2007, 5:18am UTC](https://www.ruby-forum.com/t/irb-module-with-non-blocking-asynchronous-gets/112979/2 "2007-08-26T05:18:53Z")

</div>

On Aug 25, 2007, at 3:09 AM, Shane Liesegang wrote:

> Is there a way to use the IRB module so that it evaluates code on-  
> demand  
> only instead of running in a constant loop?

I’m working on my glue code speech for Lone Star Rubyconf today so my  
first thought was:

#!/usr/bin/env ruby -wKU

class IRbOnDemand  
def initialize  
@irb = IO.popen(“irb -f --simple-prompt --noreadline”, “r+”)  
end

def run(ruby)  
@irb.puts ruby  
@irb.flush

```
 @irb.each do |line|
   return eval($1) if line =~ /\A=>\s*(.+)/
 end

```

end  
end

irb = IRbOnDemand.new  
result = irb.run %Q{a = %w[words] \* 3}  
puts “Result: #{result.inspect}”

puts “Doing other things…”  
sleep 3

result = irb.run %Q{a}  
puts “Result: #{result.inspect}”

**END**

Is that what you are after? If it is, do we really need IRb at all?  
How’s this:

#!/usr/bin/env ruby -wKU

class IRbOnDemand  
def initialize  
@binding = binding  
end

def run(ruby)  
eval ruby, @binding  
end  
end

irb = IRbOnDemand.new  
result = irb.run %Q{a = %w[words] \* 3}  
puts “Result: #{result.inspect}”

puts “Doing other things…”  
sleep 3

result = irb.run %Q{a}  
puts “Result: #{result.inspect}”

**END**

James Edward G. II

---

<div class="post-metadata">

**Author:** ![sjml](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b19c9b/32.png) [@sjml](https://www.ruby-forum.com/u/sjml)\
**Post date:** [August 27, 2007, 4:46pm UTC](https://www.ruby-forum.com/t/irb-module-with-non-blocking-asynchronous-gets/112979/3 "2007-08-27T16:46:00Z")

</div>

Hi James. Thanks for the recommendations.

James G. wrote:

> Is that what you are after? If it is, do we really need IRb at all?  
> How’s this:

I could just use eval to run the strings; that’s true. I was hoping to  
leverage IRB’s prompt mechanism and the ability to define functions on  
the fly. As below:

* * *

## irb(main):001:0\> def test irb(main):002:1\> puts “testing…” irb(main):003:1\> end =\> nil irb(main):004:0\> test testing… =\> nil irb(main):005:0\>

I’m finding that it’s pretty tricky, though. I managed to make it  
non-blocking for a single line by overriding eval\_input and having it  
break after evaluating a line instead of waiting for input. That seems  
to work fine, but when doing any kind of multi-line input, it still goes  
into a loop that it doesn’t want to return from.

It seems like IRB, to its core, is based on constantly waiting for  
input, and trying to make it work in an on-demand fashion is like  
running uphill. I’m still rooting through its source, trying to find the  
spots where I can poke at it to make it work that way, but it’s slow  
going with a large mass of interrelated code that’s not terribly easy  
for humans to parse. 🙂

---

<div class="post-metadata">

**Author:** ![sjml](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b19c9b/32.png) [@sjml](https://www.ruby-forum.com/u/sjml)\
**Post date:** [August 28, 2007, 3:52am UTC](https://www.ruby-forum.com/t/irb-module-with-non-blocking-asynchronous-gets/112979/4 "2007-08-28T03:52:50Z")

</div>

go with #eval, it makes it dead simple:

> > arbitrary\_code = \<\<-MUPPETS  
> > def muppets  
> > “muppets”  
> > end  
> > MUPPETS  
> > =\> “def muppets\n “muppets”\nend\n”  
> > muppets  
> > NameError: undefined local variable or method `muppets’ for main:Object  
> > from (irb):6  
> > eval(arbitrary\_code)  
> > =\> nil  
> > muppets  
> > =\> “muppets”

is that what you need, basically?

–  
Giles B.

Blog: [http://gilesbowkett.blogspot.com](http://gilesbowkett.blogspot.com)  
Portfolio: [http://www.gilesgoatboy.org](http://www.gilesgoatboy.org)  
Tumblelog: [http://giles.tumblr.com/](http://giles.tumblr.com/)

---

<div class="post-metadata">

**Author:** ![sjml](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b19c9b/32.png) [@sjml](https://www.ruby-forum.com/u/sjml)\
**Post date:** [August 28, 2007, 7:41pm UTC](https://www.ruby-forum.com/t/irb-module-with-non-blocking-asynchronous-gets/112979/5 "2007-08-28T19:41:35Z")

</div>

Giles B. wrote:

> is that what you need, basically?

Close, but it doesn’t let me enter arbitrary lines of input and know  
whether they need to be joined to execution or can be executed  
individually, the way IRB does.

I’ve got the majority of my desired behavior now, by applying some  
patches to RubyLex: [Parked at Loopia](http://pastie.caboo.se/91797)

When the user presses enter, I call get\_statement on the lexer, which  
either returns the line and line number if it’s ready for execution or  
nil if it’s not.

The only thing this doesn’t currently handle is string continuations –  
once again, IRB happily enters an infinite loop when it detects an  
incomplete string in a line. I would like to hit this border case as  
well, but it’s looking like it’s going to require some pretty deep digs  
into the lexing code. It doesn’t terribly excite me, and I don’t  
personally use string continuation very much, so I’m tempted to just  
call it a halfway-victory.

Unless there are some particularly knowledgeable IRB hackers waiting in  
the wings to offer advice…

---

<div class="post-metadata">

**Author:** ![sjml](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b19c9b/32.png) [@sjml](https://www.ruby-forum.com/u/sjml)\
**Post date:** [August 29, 2007, 8:08pm UTC](https://www.ruby-forum.com/t/irb-module-with-non-blocking-asynchronous-gets/112979/6 "2007-08-29T20:08:41Z")

</div>

For anyone still reading this thread (or who stumbles across it in the  
future), I have been able to solve the string continuation problem – it  
may be a bit inefficient, but I run my own processing on the line before  
trying to pass it to the lexer. If I determine that it’s the start of a  
string continuation, I set the flags appropriately.

No code in pastie this time, but the algorithm for finding unfinished  
strings is pretty straightforward, provided you cover all the cases  
provided in Ruby (single quotes, double quotes, %q, %w, %x, %Q, %W, %X,  
and heredocs).

I leave it as an exercise to the reader. 🙂

---

<div class="post-metadata">

**Author:** ![sjml](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/b19c9b/32.png) [@sjml](https://www.ruby-forum.com/u/sjml)\
**Post date:** [August 29, 2007, 12:57am UTC](https://www.ruby-forum.com/t/irb-module-with-non-blocking-asynchronous-gets/112979/7 "2007-08-29T00:57:01Z")

</div>

> Unless there are some particularly knowledgeable IRB hackers waiting in  
> the wings to offer advice…

I wish! I know a bunch of IRB tricks and tidbits but this is getting  
pretty deep into IRB internals.

–  
Giles B.

Blog: [http://gilesbowkett.blogspot.com](http://gilesbowkett.blogspot.com)  
Portfolio: [http://www.gilesgoatboy.org](http://www.gilesgoatboy.org)  
Tumblelog: [http://giles.tumblr.com/](http://giles.tumblr.com/)
