Answering a cli prompt in ruby with open3? - ruby

Apologies for lack of sample code, I'm on mobile at the moment.
I've gotten ruby+open3 to run commands and save stdout and stderr to a variable.
My question is, if the command line interface prompts the user is it possible to input text into the prompt and press enter? If so how would I go about doing this.
Example explanation
Runs program, program in terminal then asks "what is your name?" and waits for input.
I want to input a name, press enter.
Then it asks next question, I want to put to stdin and answer that as well
This is for an automation test. If anyone has a better idea than open3 I'm all ears but I'm restricted to ruby
Thanks

Consider this:
Create an input file using:
cat > test.input
bar
baz
Then press CTRL+D to terminate the input, which will cause the file test.input to be created.
In the same directory save this code as test.rb:
2.times do |i|
user_input = gets.chomp
puts "#{ i }: #{ user_input }"
end
Run the code using:
ruby test.rb < test.input
and you should see:
0: bar
1: baz
The reason this works is because gets reads the STDIN (by default) looking for a line-end, which in this case is the character trailing bar and baz. If I load the input file in IRB it's easy to see the content of the file:
input = File.read('test.input')
=> "bar\nbaz\n"
2.times says to read a line twice, so it reads both lines from the file and continues, falling out of the times loop.
This means you can create a file, pipe it into your script, and Ruby will do the right thing. If Ruby has called a sub-shell, the sub-shell will inherit Ruby's STDIN, STDOUT and STDERR streams. I can rewrite the test.rb code to:
puts `sh ./test.sh < #{ ARGV[0] }`
and create test.sh:
for i in 1 2
do
read line
echo $i $line
done
then call it using:
ruby test.rb test.input
and get:
1 bar
2 baz

Related

When specifying command-line arguments Ruby no longer waits for input using gets

When running a ruby script with command line arguments, the "gets" is no longer blocking, it doesn't work.
test.rb
#!/usr/bin/ruby
puts "should wait for input"
gets
puts "test"
and here is how I run it
$ ./test.rb test.rb
should wait for input
test
It didn't wait.
I'm running Ubuntu 16.04 desktop, and Ruby from repository ruby 2.3.1p112 (2016-04-26) [x86_64-linux-gnu]
What am I doing wrong?
In addition to STDIN.gets like others have recommended, you can use plain gets if you call ARGV.clear beforehand. The regular gets works as expected if there aren't command like arguments to the script, but if there are, then it will read them. It's not really clear why you're using ./test.rb test.rb, but the second filename is a command line argument.
More specifically, if regular gets is called when ARGV is populated, then the result will be the contents of the file.
max#max ~> echo "content" > test.txt
max#max ~> ruby -e "puts ARGV.inspect; puts gets" test.txt
["test.txt"]
content
Nevermind,
The "gets" actually takes the first line from the file I added in the cli arguments.
Very weird.

Ruby: Keep console open after script execution

I wrote a Ruby script like the following example. The basic functionality is the same:
# get input from the user
input = gets.chomp
# do awesome stuf with this input and print the response
puts do_awesome_stuff(input)
The problem is when I run the script it prints the solution I want, but the console window closes right after. I want the console to keep open.
I'm currently on windows, but the solution should be working on every system.
One way is to run the ruby script with a .bat file and pause it, like so:
ruby script.rb
PAUSE
I hope there is a way without the additional .bat file. Does Ruby has a function like PASUE integrated?
It seems like you double click the ruby script file.
Instead issue the following command in cmd shell.
ruby filename.rb
If you don't want that, you can add gets to the end of the script.
# get input from the user
input = gets.chomp
# do awesome stuf with this input and print the response
puts do_awesome_stuff(input)
gets # <----
But this is not recommended because .. if you run the command in cmd shell or terminal you should type extra Enter to return to the shell.
Use the -r options of irb.
irb -r ./filename.rb

Ruby "gets" does not wait for user input

This is a very silly question, but it doesn't work for me.
I am trying to make the program wait for my input. I tried replacing gets with stdin.gets, and $stdin.gets and when I try gets.chomp I get a nil class exception.
puts "Get works here?"
option = gets
puts option
To work this,you need to call your .rb file from your command prompt. Like say you save your code in a file called test.rb.
test.rb
puts "Get works here?"
option = gets
puts option
Then run from your command prompt:
C:\Users\arup> ruby test.rb
my script was also not waiting for input from gets(), but started to do so when I used
$stdin.gets("\n")

Detecting stdin content in Ruby

I want to know whether or not someone is trying to give a ruby program content on stdin. I do not want ruby to fall back to allowing interactive input. How do I do this?
# When called in bash like this, I want 'cat.rb' to exit immediately:
ruby cat.rb
# When called in bash like this, I want to see the word 'hello':
echo hello | ruby cat.rb
If I just have cat.rb contain puts gets then the first example will block, waiting for an EOF on interactive stdin. I don't want to modify the calling command, but wish to support both kinds of behavior.
Look at $stdin.tty?
ruby cat.rb
# $stdin.tty? -> true
echo hello | ruby cat.rb
# $stdin.tty? -> false

dropping user to IRB after reading from pipe

I have this script that drops the user to an IRB session when executed.
All good, but when I use *nix pipes to get the input (e.g. with cat), the IRB session ends immediately.
I could reduce the script (let's call it myscript.rb) to the following:
require 'irb'
if $stdin.stat.size > 0
#text = $stdin.read
else
#text= "nothing"
end
ARGV.clear
IRB.start
When executed like: ruby myscript.rb, I end up in the IRB session (as expected).
But (assuming foo.txt exists in the cwd): cat foo.txt | ruby myscript.rb will just print the IRB prompt and then the IRB session is closed (I'm being dropped to $bash).
Any known workarounds or ideas?
BTW: it has the same behavior on ruby 1.8.7 as well as on 1.9.2.
I think your problem is that when you pipe to your script STDIN will be the stream from your file, so when when you start IRB it will read from the same stream, but notice that it's at its end, and quit, just like it would when you type ctrl-D (which is a manual end of file signal).
You can reopen STDIN to read from the tty (i.e. the keyboard) like this:
STDIN.reopen(File.open('/dev/tty', 'r'))
but it looks a bit weird for me, I don't get the proper IRB promt. IRB works though.
#Theo identified the problem.
Also, requiring irb before IRB.start will fix missing IRB settings. In the end, the code looks like this:
if $stdin.stat.size > 0
#text = $stdin.read
$stdin.reopen(File.open("/dev/tty", "r"))
else
#text= "nothing"
end
require 'irb'
ARGV.clear
IRB.start
$stdin.read reads your input before IRB has a chance to read it (if you're trying to force IRB to execute commands from stdin).

Resources