IRB'ing within a program


#1

Hello all

I’m hoping someone has a better idea as to how to do this than I. What
I’m looking to do, essentially, is start a new irb session within a ruby
program. This program would get input from the user, feed that input to
a the irb session that it creates (and it could recreate it everytime a
specific input is given from the user, such as “/irb_clear”), then
return the result from irb.

The program might look like this:

require "irb"
while input = gets.chomp do
    case input
        when /^\/exit.*/
            break
        when /^\/irb_clear.*/
            # Clear irb history
        when /^\/irb\s+(.*)$/
            #send $1 to irb, then puts the result.
        end
end

Let me know if any of this is confusing and needs further explaining.
Thanks!


#2

On 5/22/06, Geoff S. removed_email_address@domain.invalid wrote:

end

Let me know if any of this is confusing and needs further explaining.
Thanks!

Breakpoint! Breakpoint!
It’s extremely useful.

http://rubyforge.org/projects/ruby-breakpoint/

There’s even a gem: ruby-breakpoint

Les


#3

Leslie V. wrote:

Breakpoint! Breakpoint!
It’s extremely useful.

http://rubyforge.org/projects/ruby-breakpoint/

There’s even a gem: ruby-breakpoint

Les

Yeah, I already got breakpoint. I like it. The thing is, it’s not what
I’m going for. At least, I don’t think it is.

See, breakpoint actually starts a a new irb session and it uses all the
data from the current program. I want a new, clean irb session. Here’s
actually why I’m looking to do this.

Someone might remember I made a thread before about extending methods
for a plugin system. That was for an IRC client I’m making. So is this.
I’m looking to create an IRB plugin that will take input from a line
such as “/irb foo = 5”, send it to an irb session that is completely
removed from the irc client, then output the result.

In terms of a GUI, I’m thinking of having a separate pane to the side
for the irb session. Perhaps that pane will have it’s own textfield for
direct input into the irb session. Perhaps not. Even if it does, it
still needs to be able to take input from an external source (the input
textfield) and send its output to an external place (the output
textbox).

Thanks again


#4

Ohad L. wrote:

Is there any reason you specifically need IRB for this? Because I’d
definetely go ahead and use eval.

The purpose of this plugin is to teach and to facilitate learning.

Say I’m learning Ruby from someone through IRC. This IRB plugin allows
the teacher to quickly write some ruby code into IRB and get the output
to make sure it’s correct, then click a button or write a command that
copies (part of) that IRB session into the IRC channel. Similarly for
the student. It makes for one less terminal window and a whole lot less
copy and pasting.

Eval doesn’t cut it because it only works for one line. Besides, irb is
much more pretty and informative.


#5

Geoff S. wrote:

Someone might remember I made a thread before about extending methods
for a plugin system. That was for an IRC client I’m making. So is this.
I’m looking to create an IRB plugin that will take input from a line
such as “/irb foo = 5”, send it to an irb session that is completely
removed from the irc client, then output the result.

In terms of a GUI, I’m thinking of having a separate pane to the side
for the irb session. Perhaps that pane will have it’s own textfield for
direct input into the irb session. Perhaps not. Even if it does, it
still needs to be able to take input from an external source (the input
textfield) and send its output to an external place (the output
textbox).

Thanks again

Is there any reason you specifically need IRB for this? Because I’d
definetely go ahead and use eval.


#6

Geoff S. wrote:

Yeah, I already got breakpoint. I like it. The thing is, it’s not what
I’m going for. At least, I don’t think it is.

See, breakpoint actually starts a a new irb session and it uses all the
data from the current program. I want a new, clean irb session. Here’s
actually why I’m looking to do this.

Well, how about starting irb in another process and talking to it
via pipes?

Hal


#7

On May 22, 2006, at 12:00 PM, Geoff S. wrote:

copies (part of) that IRB session into the IRC channel. Similarly for

Well then short of scavenging thru the irb source picking out the
bits you need, seems like your options are:

a) run the IRC client inside irb, rather than the other way around.
b) IO.popen. This is icky though.

Incidentally irb is written in ruby, and does use eval. It just
happens to know just enough ruby to keep asking you for input when it
should. Also the prettiness and informative-ness comes from ruby’s
instropective capabilties.

e.g.
% cat simple_irb.rb
#!/usr/bin/env ruby
$SAFE = 0
print "> "
while gets
begin
puts eval($_).inspect
rescue Exception => ex
puts ex
end
print "> "
end

% ruby simple_irb.rb

1 + 2
3
x
undefined local variable or method `x’ for main:Object
x = “Hello”
“Hello”
puts x
Hello
nil
exit!

Here’s a “solution” involving IO.popen:

% cat irb_remote.rb
puts “Welcome to my pseudo irb frontend. Good luck with this.”

IO.popen(‘irb’, ‘r+’) do |irb|
while line = gets
irb.puts line
puts irb.gets
end
end

% ruby irb_remote.rb
Welcome to my pseudo irb frontend. Good luck with this.
1 + 2
1 + 2

3
4 + 1

4 + 1

5
^C/usr/local/ruby/lib/ruby/1.8/irb.rb:240:in write': Broken pipe (Errno::EPIPE) from /usr/local/ruby/lib/ruby/1.8/irb.rb:240:insignal_handle’
from /usr/local/ruby/lib/ruby/1.8/irb.rb:66:in start' from /usr/local/ruby/lib/ruby/1.8/irb/input-method.rb:49:ingets’
from /usr/local/ruby/lib/ruby/1.8/irb.rb:132:in eval_input' from /usr/local/ruby/lib/ruby/1.8/irb.rb:259:insignal_status’
from /usr/local/ruby/lib/ruby/1.8/irb.rb:131:in eval_input' from /usr/local/ruby/lib/ruby/1.8/irb/ruby-lex.rb:189:inbuf_input’
from /usr/local/ruby/lib/ruby/1.8/irb/ruby-lex.rb:104:in getc' ... 7 levels... from /usr/local/ruby/lib/ruby/1.8/irb.rb:146:ineval_input’
from /usr/local/ruby/lib/ruby/1.8/irb.rb:70:in start' from /usr/local/ruby/lib/ruby/1.8/irb.rb:69:instart’
from /usr/local/ruby/bin/irb:13
irb_remote.rb:4:in `gets’: Interrupt
from irb_remote.rb:4
from irb_remote.rb:3

As you can see IO.popen is quite fun to get working the way you want
it to. I think the best idea would be to reimplement irb.


#8

Logan C. wrote:

Here’s a “solution” involving IO.popen:

% cat irb_remote.rb
puts “Welcome to my pseudo irb frontend. Good luck with this.”

IO.popen(‘irb’, ‘r+’) do |irb|
while line = gets
irb.puts line
puts irb.gets
end
end

Hal F. wrote:

Well, how about starting irb in another process and talking to it
via pipes?

Logan and Hal, this sounds like a good idea. However, as Logan’s code
illustrated, pipes are difficult to get working right. I was just
playing around with them myself; I’ve discovered a few problems that
might not be overcome.

First, the code that I was using:
irb = IO.popen(‘irb’, ‘r+’)
loop do
print ">> "
irb.puts gets
irb.gets # Gets the line that we just put.
puts “=> #{irb.gets.chomp.inspect}”
end

Now, the problems:

  1. Everything we get back is a string. 1+2 should return the Fixnum 3,
    but we read that Fixnum 3 through the pipe as a string. To overcome
    this, we’d have to know what type of value we should get in return.
    That’s basically redoing a good portion of irb.

  2. This code doesn’t get lines in the right proportion. It works for
    basic things like ‘1+2’ and ‘foo = 42’, but for a multiline piece of
    code, such as a method definition, it breaks down:

    def foo
    puts “bar”
    end
    foo
    … hello?
    As you can see, I got no output back.

Any way popen could be used more effectively? I don’t want to have to
reimplement irb – that would be a lot of work, I imagine.


#9

On Wed, 24 May 2006, Geoff S. wrote:

   irb.gets        # Gets the line that we just put.

basic things like ‘1+2’ and ‘foo = 42’, but for a multiline piece of
code, such as a method definition, it breaks down:

def foo
puts “bar”
end
foo
… hello?
As you can see, I got no output back.

Any way popen could be used more effectively? I don’t want to have to
reimplement irb – that would be a lot of work, I imagine.

you are trying way to hard:

harp:~ > cat a.rb
system ‘irb’
puts ‘done’

harp:~ > ruby a.rb
irb(main):001:0> def foo
irb(main):002:1> 42
irb(main):003:1> end
=> nil
irb(main):004:0> foo
=> 42
irb(main):005:0> exit
done

irb uses readline so you need to use pty to control it. otherwise
you’ll not
see the prompt.

-a


#10

unknown wrote:

On Wed, 24 May 2006, Geoff S. wrote:

   irb.gets        # Gets the line that we just put.

basic things like ‘1+2’ and ‘foo = 42’, but for a multiline piece of
code, such as a method definition, it breaks down:

def foo
puts “bar”
end
foo
… hello?
As you can see, I got no output back.

Any way popen could be used more effectively? I don’t want to have to
reimplement irb – that would be a lot of work, I imagine.

you are trying way to hard:

harp:~ > cat a.rb
system ‘irb’
puts ‘done’

harp:~ > ruby a.rb
irb(main):001:0> def foo
irb(main):002:1> 42
irb(main):003:1> end
=> nil
irb(main):004:0> foo
=> 42
irb(main):005:0> exit
done

irb uses readline so you need to use pty to control it. otherwise
you’ll not
see the prompt.

-a

Starting an irb session within a program is pretty easy. But it’s not
what I want. I need to send a line to irb and receive the output.
(Actually, it would be best if I could receive what the ‘input’ line
looks like – “irb(main):006:0> foo = 5” or the like. I don’t know even
if piping can do this.

I was looking at the FXIRB code (http://rubyforge.org/projects/fxirb/)
and it seems they’ve had to go to quite a great length to do it.