Usage of "ARGV.first" - ruby

I was trying the following code:
user = ARGV.first # supposed to ask for user name
puts "Hi, #{user}. How do you like this?"
It does not print as expected. It only prints:
Hi, . Do you like me?
Can someone give me a hint on this?

argv holds the command line arguments.
./your_script.rb USER_NAME
… it has nothing to do with reading data from a prompt.
It looks like you are reading this tutorial. You need to read past the first three lines of code.
The code to read from the prompt is on line 7.
likes = $stdin.gets.chomp

Quentin's given a good answer but he's referring to the "Do you like me?" prompt.
There's no prompt for user name in the Ruby code.
You enter your user name by passing it as an argument to your script.
So, if your script is called "ext14.rb" (as in the tutorial) you would do...
roby ext14.rb Azat
This will put "Azat" in the first element of ARGV (ARGV[0] or ARGV.first) so the user_name variable will contain the string "Azat"

Related

How to read a file from command line using < operator and read user input afterwards?

I am writing a program in which I am taking in a csv file via the < operator on the command line. After I read in the file I would also like to ask the user questions and have them input their response via the command line. However, whenever I ask for user input, my program skips right over it.
When I searched stack overflow I found what seems to be the python version here, but it doesn't really help me since the methods are obviously different.
I read my file using $stdin.read. And I have tried to use regular gets, STDIN.gets, and $stdin.gets. However, the program always skips over them.
Sample input ruby ./bin/kata < items.csv
Current File
require 'csv'
n = $stdin.read
arr = CSV.parse(n)
input = ''
while true
puts "What is your choice: "
input = $stdin.gets.to_i
if input.zero?
break
end
end
My expected result is to have What is your choice: display in the command and wait for user input. However, I am getting that phrase displayed over and over in an infinite loop. Any help would be appreciated!
You can't read both file and user input from stdin. You must choose. But since you want both, how about this:
Instead of piping the file content to stdin, pass just the filename to your script. The script will then open and read the file. And stdin will be available for interaction with the user (through $stdin or STDIN).
Here is a minor modification of your script:
arr = CSV.parse(ARGF) # the important part.
input = ''
while true
puts "What is your choice: "
input = STDIN.gets.to_i
if input.zero?
break
end
end
And you can call it like this:
ruby ./bin/kata items.csv
You can read more about ARGF in the documentation: https://ruby-doc.org/core-2.6/ARGF.html
This has nothing to do with Ruby. It is a feature of the shell.
A file descriptor is connected to exactly one file at any one time. The file descriptor 0 (standard input) can be connected to a file or it can be connected to the terminal. It can't be connected to both.
So, therefore, what you want is simply not possible. And it is not just not possible in Ruby, it is fundamentally impossible by the very nature of how shell redirection works.
If you want to change this, there is nothing you can do in your program or in Ruby. You need to modify how your shell works.

Start Command Prompt with Ruby doesn't work

I can't get this to work with the Start Command Prompt with Ruby on windows.
I got this simple programm:
puts "Whats your name?"
name = gets
puts "Hello" + name + ". How are you?"
But if I call it with "ruby program.rb", instead for waiting for my input, it just prints out:
Whats your name?
Helloputs "Whats your name?"
. How are you?
It is like the "gets" command is not been recognized. Why does this happen?
It looks like you are (somehow) passing the name of your programm two times on the command line. Your described behavior is reproducible when you are running
ruby program.rb program.rb
This works the way it does since gets does not read from STDIN in all cases. Instead, it prefers to read the files mentioned on the command line first. Only if there is no additional file on the command line, gets falls back to read from STDIN
The question on why you are passing the filename of your ruby program twi times is unfortunately less clear. If you are not calling it that way on your own, this might be caused by some strange environment options in your shell or due to your Ruby setup.
I was curious as well, and found this link How does gets and gets.chomp in ruby work?
Apparently it created a new line therefore could not find the name.
This seemed to work, (following the instructions in the link)
puts "Whats your name?"
name = gets
puts "Hello " + name.chomp + ". How are you?"
Have fun.
Also if you start using rails, you can also test in your console
Example
> def test1
> ...code ..
> end
> test1
#Ray Ban I have used your code
puts "Whats your name?"
name = gets
puts "Hello" + name + ". How are you?"
in gets.rb file and run it using $ ruby gets.rb and it worked as expected.
I am using ruby-2.3.0

How do I pass a text file or a string to a Ruby script and output the result in the command line?

As an exercise to learn Ruby, I would like to create a script that will be run from the terminal. It should accept as input either a string or a text file and it should output the result of various string parsing mechanisms that I will write myself.
To get me started, would you please translate this pseudo-code into proper Ruby for me?
In terminal: ruby myscript.rb (either a string or a text file).
In myscript.rb: Retrieve input. Set my_input to the input.
Set my_output to the result of various_string_parsing_voodoo (done to my_input).
puts my_output
I intend to actually write the code myself, but if someone could supply me with a skeleton .rb file to send in "Hello World" and get "[World] is pleased by your [hello]" or something equally inane that'd be a great help.
Here are some key pieces:
ARGV is an array containing the arguments you passed when running your script from command line.
the File class contains several utilies. For example, File.exists?(path) returns true if the path exists, and File.file?(path) returns true if the path exists and is a file (not a dir).
I think this may help you quite a bit.

What's the difference between gets.chomp() vs. STDIN.gets.chomp()?

Are they the same, or are there subtle differences between the two commands?
gets will use Kernel#gets, which first tries to read the contents of files passed in through ARGV. If there are no files in ARGV, it will use standard input instead (at which point it's the same as STDIN.gets.
Note: As echristopherson pointed out, Kernel#gets will actually fall back to $stdin, not STDIN. However, unless you assign $stdin to a different input stream, it will be identical to STDIN by default.
http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-gets
gets.chomp() = read ARGV first
STDIN.gets.chomp() = read user's input
If your color.rb file is
first, second, third = ARGV
puts "Your first fav color is: #{first}"
puts "Your second fav color is: #{second}"
puts "Your third fav color is: #{third}"
puts "what is your least fav color?"
least_fav_color = gets.chomp
puts "ok, i get it, you don't like #{least_fav_color} ?"
and you run in the terminal
$ ruby color.rb blue yellow green
it will throw an error (no such file error)
now replace 'gets.chomp' by 'stdin.gets.chomp' on the line below
least_fav_color = $stdin.gets.chomp
and run in the terminal the following command
$ ruby color.rb blue yellow green
then your program runs!!
Basically once you've started calling ARGV from the get go (as ARGV is designed to) gets.chomp can't do its job properly anymore. Time to bring in the big artillery: $stdin.gets.chomp
because
if there is stuff in ARGV, the default gets method tries to treat the first one as a file and read
from that. To read from the user's input (i.e., stdin) in such a situation, you have to use
it STDIN.gets explicitly.

One liner in Ruby for displaying a prompt, getting input, and assigning to a variable?

Often I find myself doing the following:
print "Input text: "
input = gets.strip
Is there a graceful way to do this in one line? Something like:
puts "Input text: #{input = gets.strip}"
The problem with this is that it waits for the input before displaying the prompt. Any ideas?
I think going with something like what Marc-Andre suggested is going to be the way to go, but why bring in a whole ton of code when you can just define a two line function at the top of whatever script you're going to use:
def prompt(*args)
print(*args)
gets
end
name = prompt "Input name: "
Check out highline:
require "highline/import"
input = ask "Input text: "
One liner hack sure. Graceful...well not exactly.
input = [(print 'Name: '), gets.rstrip][1]
I know this question is old, but I though I'd show what I use as my standard method for getting input.
require 'readline'
def input(prompt="", newline=false)
prompt += "\n" if newline
Readline.readline(prompt, true).squeeze(" ").strip
end
This is really nice because if the user adds weird spaces at the end or in the beginning, it'll remove those, and it keeps a history of what they entered in the past (Change the true to false to not have it do that.). And, if ARGV is not empty, then gets will try to read from a file in ARGV, instead of getting input. Plus, Readline is part of the Ruby standard library so you don't have to install any gems. Also, you can't move your cursor when using gets, but you can with Readline.
And, I know the method isn't one line, but it is when you call it
name = input "What is your name? "
Following #Bryn's lead:
def prompt(default, *args)
print(*args)
result = gets.strip
return result.empty? ? default : result
end
The problem with your proposed solution is that the string to be printed can't be built until the input is read, stripped, and assigned. You could separate each line with a semicolon:
$ ruby -e 'print "Input text: "; input=gets.strip; puts input'
Input text: foo
foo
I found the Inquirer gem by chance and I really like it, I find it way more neat and easy to use than Highline, though it lacks of input validation by its own.
Your example can be written like this
require 'inquirer'
inputs = Ask.input 'Input text'

Resources