Forum: Ruby IRB'ing within a program

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
C2bcdb28414d5ca01b0b4c03aba7e62c?d=identicon&s=25 Geoff Stanley (minsc)
on 2006-05-22 15:58
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!
37ee5fa90f5eaeef62553629382497f7?d=identicon&s=25 Leslie Viljoen (Guest)
on 2006-05-22 16:44
(Received via mailing list)
On 5/22/06, Geoff Stanley <geoffstanley@gmail.com> 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
C2bcdb28414d5ca01b0b4c03aba7e62c?d=identicon&s=25 Geoff Stanley (minsc)
on 2006-05-22 17:25
Leslie Viljoen 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
426d8be2204a36c4e609ace097d7c554?d=identicon&s=25 Ohad Lutzky (Guest)
on 2006-05-22 17:30
Geoff Stanley 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.
C2bcdb28414d5ca01b0b4c03aba7e62c?d=identicon&s=25 Geoff Stanley (minsc)
on 2006-05-22 18:00
Ohad Lutzky 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.
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-05-23 02:03
(Received via mailing list)
On May 22, 2006, at 12:00 PM, Geoff Stanley 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:in
`signal_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:in
`gets'
         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:in `signal_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:in
`buf_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:in `eval_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:in `start'
         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.
C1bcb559f87f356698cfad9f6d630235?d=identicon&s=25 Hal Fulton (Guest)
on 2006-05-23 07:19
(Received via mailing list)
Geoff Stanley 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
C2bcdb28414d5ca01b0b4c03aba7e62c?d=identicon&s=25 Geoff Stanley (minsc)
on 2006-05-23 19:21
Logan Capaldo 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 Fulton 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.
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-05-23 19:45
(Received via mailing list)
On Wed, 24 May 2006, Geoff Stanley 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
C2bcdb28414d5ca01b0b4c03aba7e62c?d=identicon&s=25 Geoff Stanley (minsc)
on 2006-05-24 23:02
unknown wrote:
> On Wed, 24 May 2006, Geoff Stanley 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.
This topic is locked and can not be replied to.