2

In the one answer I have found this stanza that waits for your input and prints it until you press enter:

require 'io/console'
require 'io/wait'

loop do
  chars = STDIN.getch
  chars << STDIN.getch while STDIN.ready?       # Process multi-char paste
  break if chars == ?\n
  STDOUT.print chars
end

However, in order to exit loop, I must press "Enter"(key for new line - \n) twice, or press something else after it.
When I try to execute the same loop again (copy-paste it into the same pry session) I am getting:

IOError: byte oriented read for character buffered IO

chars << STDIN.getch while STDIN.ready? cause raising, mentioned above, error. Without this line, ruby just doesn't show any error.

In both cases (with and without above line), in the loop:

  • when I press the enter and then some letter (for example 'z') I'm getting this error.
    In the next loop, above letter will show (without my input).

  • when I press the enter twice - no error, it will exit.
    In the next loop when I press some letter, error will show.
    In the next loop above letter will show

I remember that in C or C++ there was flush so you can empty the buffer. I have found s few methods, and tried like this:

 loop do
   STDIN.ioflush
   STDOUT.ioflush
   STDOUT.iflush
   STDIN.iflush
   STDOUT.oflush
   STDIN.oflush

   chars = STDIN.getch
   chars << STDIN.getch while STDIN.ready?
   break if chars == ?\n
   STDOUT.print chars
 end

but it didn't work.

How to solve this behavior with enter and 2nd letter & IOError. I think both are correlated in some way.

Community
  • 1
  • 1
Darek Nędza
  • 1,420
  • 1
  • 12
  • 19

1 Answers1

2

The code from that answer is a simplified version of a highline-like library I wrote for personal use. I never encountered that specific error myself, but it might be due to the fact I'm actually using something slightly different. My actual code goes something more like this:

require 'io/console'
require 'io/wait'

catch(:done) do
  loop do
    chars = STDIN.getch
    chars << STDIN.getch while STDIN.ready?       # Process multi-char paste
    throw :done if ["\r", "\n", "\r\n"].include?(chars)
    STDOUT.print chars
  end
end
STDOUT.print "\n"

I also have kill-signal handler, in case Ctrl+C (kill process) or Ctrl+D (end of input) get pressed; the first interrupts the program, and the second is wired to react as if enter was pressed.

The precise behavior might depend on the OS (I use it on OSX and FreeBSD), since the enter key could return any of "\r", "\n" or "\r\n" depending on the OS:

\r\n , \r , \n what is the difference between them?

Community
  • 1
  • 1
Denis de Bernardy
  • 75,850
  • 13
  • 131
  • 154
  • 1
    I'm still getting the same errors, but I've follow up hint about OS-dependent feature. I've found this method: `def read_char require "Win32API" Win32API.new("crtdll", "_getch", [], "L").Call.chr end` in the http://rubyquiz.com/quiz5.html AND in the http://stackoverflow.com/a/3983726/2597260 I installed `highline` and used `get_character`(`read_char` works too as well) instead of `STDIN.getch` and everything worked (even pasting). ps. on Windows, my OS, it returns `\r` (reads one character from STDIN). – Darek Nędza Jan 30 '14 at 18:28
  • Ya, `getch` reads bytes, so `"\r"` in `"\r\n"` until the part that calls `ready?`. Hat for highlighting Win-compatible code. – Denis de Bernardy Jan 30 '14 at 20:36