Ruby IF no ARGV given - ruby

This is my code:
if ARGV[0] == false
puts "Usage: ./script.rb argument"
exit
end
print "Yey we got an argument: " ARGV[0]
But I just cant make the code check if ARGV[0] is given or not, how should I do that ?

Check if it's empty? (or check its length):
if ARGV.empty?
puts ...
exit
end
Consider using any of the Ruby command line argument parsers, like OptionParser.

The simplest way to process positional arguments (other than using a gem to do it) is to shift them off, one at a time:
arg1 = ARGV.shift
arg2 = ARGV.shift
A missing argument will be nil. Let's exploit that to give arg2 a default value:
arg1 = ARGV.shift
arg2 = ARGV.shift || 'default value goes here'
Checking for a required argument is trivial:
raise "missing argument" unless arg1
It's also easy to see if too many arguments have been supplied:
raise "too many arguments" unless ARGV.empty?

I realize a good solution is already given, but nobody mentioned the real reason why your example didn't work.
The issue with your example code is that if there are no arguments given, ARGV[0] will return nil, and nil == false is false. nil is "falsy", but not equal to false. What you could have done is:
unless ARGV[0]
puts "Usage: ..."
exit 1
end
Which would have worked, because this statement now depends on falsyness, rather than on equality to the actual false.
But don't use this code, it's far more clear if you state your actual intent, which is that you want to know if there are any arguments (instead of whether the first argument is falsy). So use the code others suggested:
if ARGV.empty?
puts "Usage..."
exit 1
end

To check if ARGV[0] (or more args) is given or not:
puts 'Usage: ...' if ARGV.length == 0
You could also use ARGV.empty? (#DaveNewton's answer)

You can check the length of ARGV. If it has zero elements then ARGV[0] wasn't given.

I do this and work's:
url = ARGV[0]
if url.nil?
puts "The shell script needs the arguments."
exit
end

Here's what I do:
a = 'defaultvalue' if (a = ARGV.shift).nil?
Someone else suggested this:
a = ARGV.shift || 'defaultvalue'
This is wrong, since any false value will cause defaultvalue to be assigned, e.g.:
args=[false]; a=args.shift||true; # a has final value true when it should be false

Related

Do something if no arguments present

This is a small test script I wrote:
#!/usr/bin/env ruby
require 'packetfu'
def mac(host)
if host
rmac = PacketFu::Utils.arp(host, :iface => 'wlan0')
puts rmac
else
whoami = PacketFu::Utils.whoami?(:iface => 'wlan0')
puts whoami
end
end
mac(ARGV[0])
What I want to do is have it print the second variable if no argument is specified. Instead I get an ArgumentError. There's obviously an easier way that I'm just missing.
If you want to be able to call the function without any arguments, you need to change its definition to such that it does not require an argument. One way is to give the argument a default value. Then you can check for that, e.g.,
def mac(host = nil)
if host
puts "host: #{host}"
else
puts 'no host'
end
end
If you want to distinguish between no argument given and argument given with the default value, you could use a variable number of arguments:
def mac2(*args)
if args.empty?
puts "no arguments"
else
host = args[0]
end
end
On the other hand, if your problem is detecting whether ARGV was empty (i.e., no command-line argument given), you can check that higher up. For example, only call mac if an argument was given:
if ARGV.empty?
puts "Usage: …"
exit 1
end
mac(ARGV[0])

Looping through a case statement in Ruby?

I am trying to determine the best way to loop through a case statement until a user provides a certain input (in this case, exit).
So far, my code works with a while loop, but it seems a little redundant when I have input = gets.chomp over and over.
Here's a bit of abbreviated code:
input = gets.chomp
while input.downcase != 'exit'
case input.downcase
when 'help'
puts "Available commands are..."
input = gets.chomp
#more when statements go here...
else
puts "That is not a valid command. Type 'HELP' for available commands."
input = gets.chomp
end
end
puts "Goodbye!"
I'd write it like:
loop do
input = gets.chomp.downcase
case input
when 'help'
puts "Available commands are..."
# more when statements go here...
when 'exit'
break
else
puts "That is not a valid command. Type 'HELP' for available commands."
end
end
puts "Goodbye!"
A loop is designed for this sort of case, where you just want to loop cleanly, and then eventually break out on some condition.
For ultimate clarity in what the code is doing, I'd put the exit immediately after reading the input, instead of being embedded in the case statements. It's a minor thing, but is useful to remember if you're coding and others have to help maintain it:
loop do
input = gets.chomp.downcase
break if input == 'exit'
case input
when 'help'
puts "Available commands are..."
# more when statements go here...
else
puts "That is not a valid command. Type 'HELP' for available commands."
end
end
puts "Goodbye!"
Why don't you change the while to:
while (input = gets.chomp.downcase) != 'exit'
Note that this also means that instead of using case input.downcase, you can use case input, as it has already been made lowercase.
edit: my roots in C betray me...
As mentioned in the comments, this is not a particularly "ruby-esque" solution. It also causes a stack trace when gets returns nil. You might prefer to split it into two lines:
while (input = gets)
input = input.chomp.downcase
break if input == 'exit'
case input
# when statements
else
puts "That is not a valid command. Type 'HELP' for available commands."
end
end
I separated the "exit" from the case criteria for a couple of reasons:
It was part of the loop logic in the question, so it's (arguably) more readable to keep it separate from the other cases.
I didn't realise that break behaves differently in Ruby case statements to other languages that I am more familiar with, so I didn't think it would do what you wanted.
You could equally well do this:
while (input = gets)
case input.chomp.downcase
when 'exit'
break
# other when statements
else
puts "That is not a valid command. Type 'HELP' for available commands."
end
end
edit: I am delighted to hear that like Perl, Ruby also has the $_ variable, to which the value of gets will be assigned:
while gets
case $_.chomp.downcase
when 'exit'
break
# other when statements
else
puts "That is not a valid command. Type 'HELP' for available commands."
end
end
You can even get rid of input by exiting the loop with break instead of checking the result in the while condition
while true
case gets.chomp.downcase
when 'exit'
break
when 'help'
# stuff
else
# other stuff
end
end

Ruby ARGV array search

I am having some issues searching for what options have been passed in the ARGV. I have,
if ARGV.include? '-v' == true
puts "Do junk"
else
puts "Nope"
end
This seems like a shockingly simple thing but I always get "Nope" either when I place "-v" or when I do not. Am I missing something simple here?
I don know if it's your problem, but you don't need the == true.
if ARGV.include? '-v'
puts "Do junk"
else
puts "Nope"
end
The include? method returns true or false.
Why are you searching ARGV for options? Use the standard library's OptionParser class, which is made for this.
require 'optparse'
require 'pp'
options = {}
OptionParser.new { |opt|
opt.on('-v', '--verbose', 'Be verbose') { |o| options[:verbose] = o }
}.parse!
pp options
Save that, and run it with something like: ruby test.rb -v or ruby test.rb --verbose and you'll see:
{:verbose=>true}
Run it with ruby test.rb -h or ruby test.rb --help and you'll see:
Usage: test [options]
-v, --verbose Be verbose
OptionParser has all sorts of nice (and intelligent) tricks for setting booleans, required parameters, coercing values so you can get multiple values for a parameter returned as an array, etc. And, notice that it created the help for me, including using -h or --help for the flag.
Look at the examples in the documentation for additional ideas of what it can do.
This is a precedence problem. Write as'
if ARGV.include?('-v') == true
puts "Do junk"
else
puts "Nope"
end
In your case if ARGV.include? '-v' == true has been interpreted as if ARGV.include?
('-v' == true). Now '-v' == true returns false, and false is not included in your ARGV array, so if evaluates as false, and else part is getting executed.
Better to write as
if ARGV.include? '-v'
puts "Do junk"
else
puts "Nope"
end
Because ARGV is an array, and Array#include?(ob) returns true, if the ob found inside the array.
All of the other answers so far are right in that it's a precedence problem.
Here are a couple helpful notes, the first of which has already been touched on:
You don't need == true, since the include? method already returns true or false.
For parsing command-line arguments, you might find it more intuitive to use a library like Trollop. Using Trollop, your example could be done like this:
require 'trollop'
opts = Trollop::options do
opt :verbose, "Run verbosely" # (-v is created automatically from this)
end
if opts[:v]
puts "yes"
else
puts "no"
end
(EDIT: See also the Tin Man's answer re: optparse)

how to re-ask a user for input if none was given the first time?

My current code is this:
print "Feed me input."
def get_input
input_value=gets.chomp
if !input_value
print "you didn't type anything"
else
input_value.downcase!
if input_value.include? "s"
input_value.gsub!(/s/,"th")
else
print "You entered a string but it had no 's' letters."
end
end
return input_value
end
get_input()
if !get_input
get_input
else
puts "#{get_input}"
end
I'm not sure why it isn't working. When I run it I get prompted for input then when I press enter after entering none I get the "You entered a string but it had no 's' letters", not the "you didn't type anything" that I wanted.
Every object except false and nil is treated as false if they are used as predicates. Even empty string is treated as true:
s = ""
puts true if s # => true
Use String#empty? to check if it is empty string.
As you said When I run it I get prompted for input then when I press enter after entering none - It means what happened acctually is
input_value="\n".chomp #( you gets methods take only `\n` as input)
"\n".chomp # => ""
so your input_value variable holds and empty string object. Now in Ruby every object has true value, except nil and false. Said that "" is also true,but you did !input_value,which means you are making it false explicitly. That's the reason in the below if-else block, else part has been executed and you didn't see the expected output "you didn't type anything".
if !input_value
print "you didn't type anything"
else
input_value.downcase!
if input_value.include? "s"
#.. rest code.
So I would suggest you in such a context replace the line if !input_value to if input_value.empty?, Which will make your code to behave as you are expecting. I didn't take your logic as a whole,but tries to show you how to code to meet your needs:
print "Feed me input."
def get_input
input_value=gets.chomp
if input_value.empty?
puts "you didn't type anything"
false
else
puts "found value"
input_value.downcase!
end
end
until input = get_input
# code
end
puts input
output
kirti#kirti-Aspire-5733Z:~/Ruby$ ruby test.rb
Feed me input.
you didn't type anything
you didn't type anything
you didn't type anything
HH
found value
hh
kirti#kirti-Aspire-5733Z:~/Ruby$

Program not entering in if-else block in Ruby

If i give input as 1 or 2, regardless of that program goes in default. Tried comparing input with "1" and 1 both. Same result.
My first Ruby program, plz excuse for naivety.
$choice
def getInfo
puts "Info"
end
def getMoreInfo
puts "MoreInfo"
end
def switch
if $choice == "1" #intentionally in ""
getInfo
elsif $choice == 2 #intentionally without ""
getMoreInfo
else
puts "default"
end
end
def callMainMenu
puts "Choose the operation:"
puts "[1] Get some Info"
puts "[2] Get some moreInfo"
$choice=gets
$choice.chomp
end
callMainMenu
switch
You need to use the destructive version of chomp if you're going to assign it like that.
$choice.chomp!
Or
$choice = $choice.chomp
In order to debug this, what I'd do is add puts $choice.inspect at the beginning of your switch method to see exactly what's in the variable. That said, I believe the problem here is that you're calling $choice.chomp instead of $choice.chomp!. The former will return the result, and the latter will change the variable in place.
When you change $choice.chomp to $choice.chomp! and get rid of the // (change those to #), then you'll have something working. Keep refining it , it is not perfect yet.
Use $choice.chomp!. chomp without ! does not alter $choice. It returns a new string. This a naming convention in Ruby.

Resources