Re-opening STDIN after it's been closed?

here's a summary of a script I just wrote:

while (true) do
puts "Make your selection from the list below: \n\n"
puts "a) foo\n"
puts "b) bar\n\n"
gets
handle_action($_)
end

handle_action does stuff that isn't relevant to my question.

The program works fine except when I hit CTRL-D. After I hit CTRL-D, the
program runs in an endless loop and seems to skip over the gets statement.
Doesn't look good, I can't even break out of it (CTRL-C). Of course CTRL-D
indicates end of file. My guess is that this closes STDIN.

I just thought of a "work around", consisting of inserting

exit unless $_

after the gets statement

I think it might be better to simply re-open STDIN as if nothing had
happened.. is this a good idea and is it possible?

Thanks,

···

--
David Vincelli

Hi,

At Sun, 15 May 2005 06:20:24 +0900,
David Vincelli wrote in [ruby-talk:142655]:

while (true) do
puts "Make your selection from the list below: \n\n"
puts "a) foo\n"
puts "b) bar\n\n"
gets
handle_action($_)
end

You should alwasy check if get succeeded.

  prompt = <<PROMPT
  Make your selection from the list below: \n
  a) foo
  b) bar

  PROMPT

  while (print(prompt); ans = gets)
    handle_action(ans)
  end

Or even better if you can use readline:

  while ans = readline(prompt)
    handle_action(ans)
  end

I think it might be better to simply re-open STDIN as if nothing had
happened.. is this a good idea and is it possible?

No way to do it. If you believe STDIN is connected to tty, you
may want to do STDIN.reopen("/dev/tty").

···

--
Nobu Nakada

The program works fine except when I hit CTRL-D. After I hit CTRL-D, the
program runs in an endless loop and seems to skip over the gets statement.
Doesn't look good, I can't even break out of it (CTRL-C). Of course CTRL-D
indicates end of file. My guess is that this closes STDIN.

<snip>

I think it might be better to simply re-open STDIN as if nothing had
happened.. is this a good idea and is it possible?

I don't think it actually closes stdin - try this:

while true
  puts "type something"
  $stdin.gets
  if $stdin.closed?
    puts "it's closed"
    break
  elsif $stdin.eof?
    puts "apparently eof"
    $stdin.seek( 0, IO::SEEK_CUR )
  end
end

Ruby doesn't seem to have an equivalent to clearerr(3), which might
help here - but a successful seek is supposed to reset the eof flag,
though it's fairly ugly, and isn't guaranteed to succeed (it'll
probably break with pipes for one thing). You might try an
ungetc/getc pair as another workaround, but there's probably a much
nicer way.

···

On Sun, May 15, 2005 at 06:20:24AM +0900, David Vincelli wrote:

--
Stephen Lewis

Hi,

You should alwasy check if get succeeded.

prompt = <<PROMPT
Make your selection from the list below: \n
a) foo
b) bar

PROMPT

while (print(prompt); ans = gets)
handle_action(ans)
end

I haven't tried this yet but it's definately better than what I originally
posted.

Or even better if you can use readline:

while ans = readline(prompt)
handle_action(ans)
end

But I did try this. I don't think your usage of readline is correct. ri
tells me that readline takes a single parameter and it's the line seperator.

I suppose you meant this:

while (print prompt; ans = readline)
handle_action(ans)
end

No way to do it. If you believe STDIN is connected to tty, you

may want to do STDIN.reopen("/dev/tty").

Thanks for the tip. I'll stick to the fixed up while loop.

···

On 5/14/05, nobu.nokada@softhome.net <nobu.nokada@softhome.net> wrote:

--
David Vincelli

In article <20050515024916.GA7991@ws0.localdomain>,
  Stephen Lewis <slewis@orcon.net.nz> writes:

Ruby doesn't seem to have an equivalent to clearerr(3), which might
help here - but a successful seek is supposed to reset the eof flag,
though it's fairly ugly, and isn't guaranteed to succeed (it'll
probably break with pipes for one thing). You might try an
ungetc/getc pair as another workaround, but there's probably a much
nicer way.

Since 1.8.3, Ruby calls clearerr(3) before getc(3) in IO#gets. So you
don't need to clear the eof flag in this case.

···

--
Tanaka Akira

Hi,

At Sun, 15 May 2005 10:44:00 +0900,
David Vincelli wrote in [ruby-talk:142672]:

> Or even better if you can use readline:
>
> while ans = readline(prompt)
> handle_action(ans)
> end

But I did try this. I don't think your usage of readline is correct. ri
tells me that readline takes a single parameter and it's the line seperator.

Sorry, I forgot "Readline." before it.

  require 'readline'
  while ans = Readline.readline(prompt)
    handle_action(ans)
  end

···

--
Nobu Nakada

David Vincelli wrote:

Hi,

You should alwasy check if get succeeded.

prompt = <<PROMPT
Make your selection from the list below: \n
a) foo
b) bar

PROMPT

while (print(prompt); ans = gets)
handle_action(ans)
end

I haven't tried this yet but it's definately better than what I originally posted.

Or even better if you can use readline:

while ans = readline(prompt)
handle_action(ans)
end

But I did try this. I don't think your usage of readline is correct. ri tells me that readline takes a single parameter and it's the line seperator.

I suppose you meant this:

while (print prompt; ans = readline)
handle_action(ans)
end

No way to do it. If you believe STDIN is connected to tty, you

may want to do STDIN.reopen("/dev/tty").

Thanks for the tip. I'll stick to the fixed up while loop.

Have you taken a look at some libraries to help you with this?

Cmd[1] is a simple tool for creating command-line oriented interpreters
        (think of sqlite/svnadmin/mysqladmin etc.)

HighLine[2] provides a higher-level interface to the command-line from
             your script.

E

[1] http://rubyforge.org/projects/cmd/
[2] http://rubyforge.org/projects/highline/

···

On 5/14/05, nobu.nokada@softhome.net <nobu.nokada@softhome.net> wrote:

--
template<typename duck>
void quack(duck& d) { d.quack(); }