Ok, here's something that seems wierd. While writing some code to call Maxima
(http://maxima.sourceforge.net/) from Ruby, I wrote the following:


class IO
  # Read a line without blocking. If there isn't a line to be read, return
  # nil.
  def readline_nonblock
    line = ''

    begin
      char = read_nonblock 1 # A larger read would surely be more efficient.
      while char != "\n"
        line += char
        char = read_nonblock 1
      end
    rescue Errno::EAGAIN
$stderr.puts '*** rescued EAGAIN'
      line.reverse.each_byte { |c| ungetc(c) } # Replace partial line.
      line = nil
    rescue EOFError
      line = nil
    end

    line
  end

  # Yield once for every line recieved from readline_nonblocking, until it
  # returns nil.
  def each_nonblock
    line = readline_nonblock
    while not line.nil?
      yield line
      line = readline_nonblock
    end
  end
end


The wierdness is that this code behaves differently depending on whether its
called from IRB's toplevel or within a method. Here's some expected results:


irb(main):001:0> MaximaString = "maxima --batch-string='1+1;'"
=> "maxima --batch-string='1+1;'"
irb(main):002:0> ios = IO.popen MaximaString
=> #<IO:0xb79d6068>
irb(main):003:0> ios.each_nonblock { |line| puts line }
  i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo
  I I I I I I I      8     8   8           8     8     o  8    8
  I  \ `+' /  I      8         8           8     8        8    8
   \  `-+-'  /       8         8           8      ooooo   8oooo
    `-__|__-'        8         8           8           8  8
        |            8     o   8           8     o     8  8
  ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8

Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2003
--------------------------------------------------------------

Maxima 5.9.1 http://maxima.sourceforge.net
Using Lisp CLISP 2.38 (2006-01-24)
Distributed under the GNU Public License. See the file COPYING.
Dedicated to the memory of William Schelter.
This is a development version of Maxima. The function bug_report()
provides bug reporting information.
(%i1)                                1 + 1
(%o1)                                  2
=> nil


And now the unexpected:


irb(main):004:0> def foo
irb(main):005:1>   ios = IO.popen MaximaString
irb(main):006:1>   ios.each_nonblock { |line| puts line }
irb(main):007:1> end
=> nil
irb(main):008:0> foo
*** rescued EAGAIN
=> nil


WTF? If I use "ls" instead of "maxima --batch-string='1+1;'" then it works it
both cases. So is this a problem with Maxima, Ruby, or my code?

(Oh, and I know that non-blocking IO isn't required for the specific example
above, but I'd still like it to work to be more general in code I haven't
posted. And to understand why this is happening.)


-- 
Jesse Merriman
jessemerriman / warpmail.net
http://www.jessemerriman.com/