STDIN.gets() Not Stopping for Input

#1

I am working on a backend kata that takes in a file name from the command line (ruby ./bin/boxing-kata <spec/fixtures/family_preferences.csv). That is working fine. After validation, I want to get input from the console. I have been trying multiple variations of “gets” and nothing seems to work. The program continues on to completion without stopping for input. Any ideas how I can get the console to recognize that I need input from it? Thanks

My code for attempting to get console input is. . .
p("Invalid data that will not harm the creation of “shipping” information was detected. Do you wish to continue (Y/N) ")
ARGV.clear
continue_answer = STDIN.gets()
puts("continue_answer: " + continue_answer.to_s)

My console output is. . .
Georges-Mac-mini:boxing-kata georgewalters$ ruby ./bin/boxing-kata <spec/fixtures/family_preferences_primary_errors.csv

Validation Items

First Data Record = ID: Name: Anakin ERROR: Primary Insured must have a numeric ID.

First Data Record = ID: Name: Anakin Primary Insured ID: 1 WARNING: Primary Insured should not have a reference back to another Primary Insured ID

First Data Record = ID: Name: Anakin CRITICAL ERROR: Primary Insured must have a Contract Effective Date. Please request a new file.

Second Data Record = ID: 3 Name: Padme ERROR: All family members Primary Insured ID should be the same as the Primary Insured record ID

Third Data Record = ID: 4 Name: Luke ERROR: All family members Primary Insured ID should be the same as the Primary Insured record ID

Fourth Data Record = ID: 5 Name: Leia ERROR: All family members Primary Insured ID should be the same as the Primary Insured record ID

Fifth Data Record = ID: 6 Name: Ben ERROR: All family members Primary Insured ID should be the same as the Primary Insured record ID

"Invalid data that will not harm the creation of “shipping” information was detected. Do you wish to continue (Y/N) "

continue_answer:

Georges-Mac-mini:boxing-kata georgewalters$

#2

I am not sure why this is happening.
But in general if you are using IDE like Atom + Atom Runner / VS Code + Code Runner, the STDIN.gets() will not wait for any input and simply return nil.

I am not sure yet what’s the configuration of your terminal, but in general, check if it’s a TTY in Ruby first:

p STDOUT.tty?
# Or
p STDOUT.isatty

If the output of the above code is false, you probably are not running a terminal!
Waiting for your further reply…

#3

SouravGoswami,

Thanks for the reply. I am very new at Ruby (only completed about a quarter of my on-line Ruby course). I ran the commands and the returns were “true”. I am totally at a loss. Any advise would be appreciated. Here is the output. . .

STDOUT.tty?true
STDOUT.isattytrue

Thanks,
George

#4

What do you get as return value after you run p STDIN.gets.to_s (and type something, press enter) ?

#5

I do not get the opportunity to type something. The program is continuing without letting me enter anything. The line “continue_answer:” is a “puts” of the console input; however, it is “nil” automatically. The end of my “def” looks like. . .
if (error_list.length > 0)
puts(“Validation Items”)
puts(error_list)
puts()
if (highest_err_level === “Critical”)
puts(“Critical issues were found. Please request a new file.”)
continue_answer = “N”
elsif (highest_err_level === “Error”)
p("Invalid data that will not harm the creation of “shipping” information was detected. Do you wish to continue (Y/N) ")
ARGV.clear
continue_answer = STDIN.gets()
end
end

    puts("continue_answer: " + continue_answer.to_s)
    return continue_answer, highest_err_level
  end # End of "def"

My console looks like. . .
Georges-Mac-mini:boxing-kata georgewalters$ ruby ./bin/boxing-kata <spec/fixtures/family_preferences_errors.csv
Validation Items
Second Data Record = ID: Name: Padme ERROR: All family members should be assigned a numeric ID
Third Data Record = ID: 4 Name: Luke CRITICAL ERROR: All family members must have chosen a brush color. Request a new file.
Fourth Data Record = ID: 5 Name: WARNING: All family members should have a name
Fifth Data Record = ID: 6 Name: Ben ERROR: All family members Primary Insured ID should be the same as the Primary Insured record ID
Sixth Data Record = ID: 7 Name: Crystal ERROR: All family members Primary Insured ID should be the same as the Primary Insured record ID
Seventh Data Record = ID: 8 Name: Patricia WARNING: Family Member Contract Effective Date should not exist.
continue_answer: Y
Georges-Mac-mini:boxing-kata georgewalters$ Y
-bash: Y: command not found
Georges-Mac-mini:boxing-kata georgewalters$

Thanks,
George

#6

I am not experienced about Mac. But here’s a code you can try:

require 'io/console'

str = ''
loop until STDIN.getch.to_s.chomp.tap { |x| print(x) || str.concat(x) }.empty?
puts

p str    # What you have typed...

It may not work. If it doesn’t please reply with the Error…
Note that you have to press the return key in order to break the loop… [ctrl + c] will not work…

#7

SouravGoswami,

Thanks for the suggestion. Unfortunately, it did not work. Command is inappropriate ioctl for device.

Georges-Mac-mini:boxing-kata georgewalters$ ruby ./bin/boxing-kata <spec/fixtures/family_preferences_error_level.csv
Traceback (most recent call last):
3: from ./bin/boxing-kata:4:in <main>' 2: from ./bin/boxing-kata:4:inrequire’
1: from /Users/georgewalters/IT_Projects/boxing-kata/lib/boxing/kata/boxing_kata.rb:48:in <top (required)>' /Users/georgewalters/IT_Projects/boxing-kata/lib/boxing/kata/boxing_kata.rb:48:ingetch’: Inappropriate ioctl for device ( Errno::ENOTTY )
Georges-Mac-mini:boxing-kata georgewalters$

Will continue looking at io commands. Any other ideas would be appreciated.

Thanks,
George

#8

SouravGoswami,

This may have nothing to do with the issue, but. . .

The kata I am trying to resolve starts out by taking in a “file name” from the command line. . .
ruby ./bin/boxing-kata <spec/fixtures/family_preferences_valid_file.csv
There was a test to ensure the file name was present on the command line. . .
def self.report
unless has_input_file?
puts “Usage: ruby ./bin/boxing-kata <spec/fixtures/family_preferences.csv”
end
def self.has_input_file?
!STDIN.tty?
end

I used “family_file = $stdin” to capture the file name and pass it on to the Module method that reads and validates the file ("$stdin.each" did not work in the Module method). . .
csv_file = Boxing::Kata::LoadFamily.new
highest_err_level, continue_answer = csv_file.load_validate_family_preferences(family_file, family_data)

The Module method reads the data with. . .
family_file.each
.with_index do |line, i|
fields = line.split(",")
and processes it correctly. At the end: If no issues or just “warning” issues, the process will continue normally. If the error is “critical” the console displays that a “new file” must be requested and the process shuts down. If the error does not effect the processing, but is not considered valid data for other purposes, the operator is asked if they wish to continue. The process is not stopping for this response.

Could there be some thing that I need to set or reset to switch “$stdin/STDIN” to allow input from the console instead of from the command line? I am totally at a loss as to why a “STDIN.gets” does not stop and require an input from the console. I thought it was suppose to. Nothing that I can find thru Google or Ruby Forum seems to address this. Thanks again for all your help and time.

Thanks,
George

#9

SouravGoswami,

My sincerest apologies. I have been running us around in circles. My stupidity knows no bounds. When I tested for “tty”, I used the examples you gave and did not notice they were for “STDOUT.tty”. I am able to “puts” to the console fine. I can not read from the console. I changed the code to “STDIN.tty” and found them to be false. I am now trying to find a way to turn them “on (true)”.

Any advise would be appreciated.

Thanks,
George

#10

Ah ha, got it. As I said if you are not running a TTY, Kernel#gets or STDIN#gets will not work, and neither will STDIN#getch This is also true for other programming languages AFAIK.

Anyways, on the last comment, I don’t think there’s any tty method. My Ruby 2.6.3 raises NoMethodError (because it’s tty? as suggested by did_you_mean gem!!)
So basically if you are not using a TTY, it can’t read input. Yes, Same thing on Atom Runner / Code Runner and whatnot. Yet you can see the code output. I suggest you try STDIN.gets.to_s because STDIN.gets will not take input, and return nil but you expect a string object… There’s no way I know to get input in those non tty…

I bet you can’t also run other programming languages there to get the user input.
It’s ruby forum, but you may still try a perl and a python program on your environment:

#!/usr/bin/env perl
$x = <STDIN> ;
print "Typed: $x" ;

Or python:

#!/usr/bin/env python
print(f"You typed {input()}")

I don’t know where you are running the code, you may try running a command prompt or terminal…

#11

SouravGoswami,

Thanks, so much. There has got to be a way to do this. I can not believe the kata was created that can not be coded. I just am not good enough yet to figure out what needs to be done.

Thanks again for all the help and time.
George

#12

SouravGoswami,

One more note on this. I found a solution. Not sure how eloquent it is, but it works.

As we suspected, the STDIN was attached to the receiving end of a pipe by the invoking shell to bring in the file name from the command line. I found an example where I could open the tty input directly, leaving stdin bound to the pipe. The code in the example did not quite work with my set-up, but with a few tweaks I was able to get this working. . .

continue_answer = open(’/dev/tty’) do |f| f.gets end

Not comfortable with the “/dev” part (not sure I understand it), but we will see what the reviewers say about it.

Again, thanks for all you did and all the time you spent.
George

#13

Thank you too!
If the /dev/tty works fine, it’s great. You may check if it exist with File.exist?(File.join(%w(/ dev tty)))… Because OS like windows will not have the file tty