I have a simple task that needs to wait for something to change on the filesystem (it's essentially a compiler for prototypes). So I've a simple infinite loop with a 5 second sleep after the check for changed files.
loop do
# if files changed
# process files
# and puts result
sleep 5
end
Instead of the Ctrl+C
salute, I'd rather be able to test and see if a key has been pressed, without blocking the loop. Essentially I just need a way to tell if there are incoming key presses, then a way to grab them until a Q is met, then exit out of the program.
What I want is:
def wait_for_Q
key_is_pressed && get_ch == 'Q'
end
loop do
# if files changed
# process files
# and puts result
wait_for_Q or sleep 5
end
Or, is this something Ruby just doesn't do (well)?
You may also want to investigate the 'io/wait' library for Ruby which provides the
ready?
method to all IO objects. I haven't tested your situation specifically, but am using it in a socket based library I'm working on. In your case, provided STDIN is just a standard IO object, you could probably quit the momentready?
returns a non-nil result, unless you're interested in finding out what key was actually pressed. This functionality can be had throughrequire 'io/wait'
, which is part of the Ruby standard library. I am not certain that it works on all environments, but it's worth a try. Rdocs: http://ruby-doc.org/stdlib/libdoc/io/wait/rdoc/Now use this
You can also do this without the buffer. In unix based systems it is easy:
This will wait for a key to be pressed and return the char code. No need to press .
Put the
char = STDIN.getc
into a loop and you've got it!If you are on windows, according to The Ruby Way, you need to either write an extension in C or use this little trick (although this was written in 2001, so there might be a better way)
Here is my reference: great book, if you don't own it you should
By combinig the various solutions I just read, I came up with a cross-platform way to solve that problem. Details here, but here is the relevant piece of code: a
GetKey.getkey
method returning the ASCII code ornil
if none was pressed.Should work both on Windows and Unix.
And here is a simple program to test it:
In the link provided above, I also show how to use the
curses
library, but the result gets a bit whacky on Windows.A combination of the other answers gets the desired behavior. Tested in ruby 1.9.3 on OSX and Linux.
Here's one way to do it, using
IO#read_nonblock
:Bear in mind that even though this uses non-blocking IO, it's still buffered IO. That means that your users will have to hit
Q
then<Enter>
. If you want to do unbuffered IO, I'd suggest checking out ruby's curses library.