dropping user to IRB after reading from pipe - ruby

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).

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.

Get newline in terminal after execution of Ruby scripts

I have an extremely simple hello.rb file containing only:
print 'Hello world!'
I then try to run this file from my Ubuntu 14 terminal using:
ruby hello.rb
However, this ends up looking just about like this:
user#machine:~/Documents/Ruby/HelloWorld$ ruby hello.rb
Hello world!user#machine:~/Documents/Ruby/HelloWorld$
I guess that's technically correct, but it would be more readable if a newline is inserted after the output Ruby's execution. For regular terminal commands such as dir this newline is inserted, and the prompt starts on a new line.In other words, I'd like to see this:
user#machine:~/Documents/Ruby/HelloWorld$ ruby hello.rb
Hello world!
user#machine:~/Documents/Ruby/HelloWorld$
What do I need to change to get this behavior? Do I need to change the way I call Ruby? Or should I change my terminal settings?
Use puts instead of print. It adds the newline.

Answering a cli prompt in ruby with open3?

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

Execute program file with irb and remain interactive

Is it possible to run irb, pass it a .rb file that gets automatically executed, and have irb stay running in interactive mode?
On Windows, I have a file called checkme.bat that basically does the following:
irb checkme.rb
The problem right now is that when I run checkme.bat, irb executes the program file but then simply exits, leaving me back at the command line.
One way to do this is to use pry and add the line binding.pry at the point in your script where you want to bail out into the repl.
x = 3
puts "Hello!"
binding.pry
Then you can run your script with pry and it'll let you examine what's going on.
~> pry d.rb
Hello
[1] pry(main)> x
=> 3
[2] pry(main)>
I'm not quite sure but on Windows when you execute a .rb file it instantly closes, try using gets at the end of the program.

Why does IRB not ignore EOF as per IRB.conf hash

I'm trying to start IRB and run a file, foo.rb, in one command,
irb foo.rb
When foo.rb is done I want another IRB prompt. Instead, it prints an IRB prompt, then exits.
I checked the IRB docs and I changed IRB.conf[:IGNORE_EOF] = true. I confirmed that hash value inside IRB. Is the behavior I want set by this hash? If so, what else could I be doing wrong?
The docs for irb say about that configuration:
**conf.ignore_eof = true/false**
Whether ^D (control-d) will be ignored or not. If false is set, ^D means quit.
So, no that setting isn't meant to do what you're looking for. As far as I can tell, there isn't a way to do what you want with irb. The closest would be to start irb without an argument, then use require './foo.rb' to run that file.

Resources