Creating argument variable - ruby

I tested the code below:
cheese, apple, bread = ARGV
puts "The script is called: #{$0}"
puts "Your first variable is: #{cheese}"
puts "Your second variable is: #{apple}"
puts "Your third variable is: #{bread}"
I get empty outputs for line 2-4:
The script is called: /run_dir/repl.rb
Your first variable is:
Your second variable is:
Your third variable is:
It's not the expected result. I could not quite figure out what I am doing wrong. Could anyone give me a hand? What could be the reason for that?

cheese, apple, bread = ARGV is the equivalent to say ARGV[0], ARGV[1], ARGV[2] just in the first one you're storing every parameter passed at the moment in which you run your script, that's why if you're getting a NilClass object is because you're not using or setting parameters when you run the script.
Try this time running it as /run_dir/repl.rb cheese apple bread to get values for those variables initialized as ARGV.

Related

Ruby calling system or exec with a variable number of parameters

I want to invoke some system commands from a ruby script without having a shell fiddle with things. The catch is that at coding time I don't know how many args there will be.
If I were going through a shell I would build up the command line by concatenation...
I used to do this in perl by passing system and array with however many arguments I wanted. This worked because of the way parameters are passed in perl. Unsurprisingly Ruby does not support that.
Is there a way to do this?
Put the arguments in an array:
cmd = %w[ls -l -a]
and then splat that array when calling system:
system(*cmd)
# -----^ splat
That's the same as saying:
system('ls', '-l', '-a')
The same syntax is used to accept a variable number of arguments when calling a method:
def variadic_method(*args)
# This splat leaves all the arguments in the
# args array
...
end
Is this what you might be referring to? As shown on:
https://ruby-doc.com/docs/ProgrammingRuby/html/tut_methods.html
But what if you want to pass in a variable number of arguments, or want to capture multiple arguments into a single parameter? Placing an asterisk before the name of the parameter after the ``normal'' parameters does just that.
def varargs(arg1, *rest)
"Got #{arg1} and #{rest.join(', ')}"
end
varargs("one") » "Got one and "
varargs("one", "two") » "Got one and two"
varargs "one", "two", "three" » "Got one and two, three"
In this example, the first argument is assigned to the first method parameter as usual. However, the next parameter is prefixed with an asterisk, so all the remaining arguments are bundled into a new Array, which is then assigned to that parameter.>

Usage of "ARGV.first"

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"

How do I combine gets.chomp and ARGV in Ruby? [duplicate]

This question already has answers here:
Using gets() gives "No such file or directory" error when I pass arguments to my script
(3 answers)
Closed 6 years ago.
I'm new to learning ruby and currently stuck on having ARGV and gets.chomp in the same script.
I want the script to unpack 3 arguments first then I'll ask a question (gets.chomp) and then print string which includes one of the ARGV and gets.chomp variables. In the terminal I'm setting the ARGV as one two three (example: ruby file1.rb one two three). Example below of code:
first, second, third = ARGV
puts "Your first variable is: #{first}"
puts "Your second variable is: #{second}"
puts "Your third variable is: #{third}"
This works exactly how I would expect. In the terminal, it gives me one, two and three as variables in first, second and third.
I've added in a puts "What is your favourite colour" and this prints out as expected but when I set a gets.chomp for the input, I get an error.
first, second, third = ARGV
puts "Your first variable is: #{first}"
puts "Your second variable is: #{second}"
puts "Your third variable is: #{third}"
puts "What is your favourite colour? "
colour = gets.chomp #this is where the error occurs
puts "So your favourite number is #{first} and you like the colour #{colour}."
^The bottom line is what I want to print but I get an error at gets.chomp
This is what the terminal prints:
$ ruby ex13.rb one two three
Your first variable is: one
Your second variable is: two
Your third variable is: three
What is your favourite colour?
ex13.rb:8:in `gets': No such file or directory - one (Errno::ENOENT)
from ex13.rb:8:in `gets'
from ex13.rb:8:in `<main>'
I hoped I've explained the above well enough and let me know if any more information is needed.
Any help will be greatly appreciated!
Thanks,
I answered a question about this yesterday, which you can read here, but to address your situation specifically:
After first, second, third = ARGV, call ARGV.clear to empty it out.
Alternatively you could do first, second, third = 3.times.map { ARGV.shift }
The reason is that gets reads from ARGV if there's anything in it. You need to empty ARGV out before calling gets.

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