Ruby Threads and Shoes

TL;DR: How do you pass execution from within a PTY.spawn block back to
the calling thread long enough to allow the caller to update GUI
elements?

I have a situation that I doubt is particularly unique, but Google
hasn't been a lot of help, so I thought I'd try you guys as a last
resort. So...to jump right in to it:

I've built a front-end GUI for running Cucumber tests using Shoes. All
the app really does is take user selections from the GUI and use them to
string together a command line that I'm then passing in to it's own
process through a PTY.spawn call.

The point of using the PTY library was to be able to grab the STDOUT
stream of the child process in real time, as per this stack-overflow:

When testing the bare-bones of my code in a terminal, it works
beautifully...the external process is spawned, and I'm able to pull the
stdout of the external process and see it in real time. However, my
situation has the added layer of a GUI. Despite the fact that I'm sure
that the IO pipes are flowing properly, I'm still not getting an update
on my GUI until after the child process terminates.

I've done enough reading to understand that this has something to do
with the way Ruby handles thread priority, but I'm having a little bit
of trouble groking a potential solution to my problem. In short, what
I'm looking for is a way to 'give back' execution to my GUI process long
enough to let it update itself from the STDOUT output of the child
process.

I hope I was clear enough, but feel free to ask clarifying questions,
and I appreciate any insight!

My code, for reference:

def spawn_command_in_pty(cmd, env, outwindow)
      env.each do |k, v|
        ENV[k] = v
      end
      PTY.spawn(cmd) do |r, w, pid|
        begin
          r.each{|line| outwindow.text = outwindow.text + line }
        rescue Errno::EIO => e
          raise e
        end
      end

    end

Steve

···

--
Posted via http://www.ruby-forum.com/.

Did you see this?

It uses an .append method, maybe that has built in smarts to allow the GUI
to update
Tried to have a look but th docs are as funky as _why's manual :wink:

BTW, having a rescue that just re-raises is redundant

···

On Tue, Jan 15, 2013 at 9:26 PM, Steve L. <lists@ruby-forum.com> wrote:

TL;DR: How do you pass execution from within a PTY.spawn block back to
the calling thread long enough to allow the caller to update GUI
elements?

I have a situation that I doubt is particularly unique, but Google
hasn't been a lot of help, so I thought I'd try you guys as a last
resort. So...to jump right in to it:

I've built a front-end GUI for running Cucumber tests using Shoes. All
the app really does is take user selections from the GUI and use them to
string together a command line that I'm then passing in to it's own
process through a PTY.spawn call.

The point of using the PTY library was to be able to grab the STDOUT
stream of the child process in real time, as per this stack-overflow:

shell - Continuously read from STDOUT of external process in Ruby - Stack Overflow

When testing the bare-bones of my code in a terminal, it works
beautifully...the external process is spawned, and I'm able to pull the
stdout of the external process and see it in real time. However, my
situation has the added layer of a GUI. Despite the fact that I'm sure
that the IO pipes are flowing properly, I'm still not getting an update
on my GUI until after the child process terminates.

I've done enough reading to understand that this has something to do
with the way Ruby handles thread priority, but I'm having a little bit
of trouble groking a potential solution to my problem. In short, what
I'm looking for is a way to 'give back' execution to my GUI process long
enough to let it update itself from the STDOUT output of the child
process.

I hope I was clear enough, but feel free to ask clarifying questions,
and I appreciate any insight!

My code, for reference:

def spawn_command_in_pty(cmd, env, outwindow)
      env.each do |k, v|
        ENV[k] = v
      end
      PTY.spawn(cmd) do |r, w, pid|
        begin
          r.each{|line| outwindow.text = outwindow.text + line }
        rescue Errno::EIO => e
          raise e
        end
      end

    end

Steve

--
Posted via http://www.ruby-forum.com/\.