Do something if no arguments present - ruby

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

Related

ArgumentError: wrong number of arguments (given 0, expected 1) Ruby

ArgumentError: wrong number of arguments (given 0, expected 1).
The code opens the file and looks at the paragraph and counts, the error
is in the center of the code. An error occurs when a method is called(1).
I can’t understand how to pass the argument methods.
#books = "You can use this knowledge to create small tools that might help."
require "colorize"
class Filecalculation
def select
loop do
puts "# Will we search : calculation_lines paragraph(1)".cyan
print "\n>>>>>> ".yellow
input = gets.chomp
search_method = "calc_#{input}"
if (respond_to?(search_method))
I can’t understand how to pass the argument to this place.
contents = send(search_method, #books)
else
puts "Unknown input: #{input.inspect}, method #{search_method} not defined."
end
end
end
# =================== calc_1 сounting words in Text File
def calc_1 paragraph
word_count = paragraph.split.length
puts "#{word_count} words"
end
end
Filecalculation.new.select
If you call send(search_method) you call a method without arguments. To pass arguments to the method being called, you need to pass them as next send args:
send(search_method, arg1, arg2)
in your case
send(search_method, paragraph)
Docs

Using gets() gives "No such file or directory" error when I pass arguments to my script

Hi I am making a simple ruby script practiced where I make a form using gets.chomp and arguments, the problem is that when gets.chomp use the script returns me an error when I apply the argument test.
The code:
#!usr/bin/ruby
def formulario(quien)
while (1)
print "[+] Word : "
word = gets.chomp
print quien + " -> " + word
end
end
quien = ARGV[0]
formulario(quien)
The error:
[+] Word : C:/Users/test/test.rb:8:in `gets': No such file or directory # rb_sysopen - test (Errno::E
NOENT)
from C:/Users/test/test.rb:8:in `gets'
from C:/Users/test/test.rb:8:in `formulario'
from C:/Users/test/test.rb:17:in `<main>'
Can anyone help?
It looks like you want to the user to type some input by reading a line from STDIN, the best way to do this is by calling STDIN.gets and not gets. So your line becomes:
word = STDIN.gets.chomp
This is documented as IO.gets. STDIN is an instance of IO.
Right now, you're executing Kernel.gets, which does something different (emphasis mine):
Returns (and assigns to $_) the next line from the list of files in ARGV (or $*), or from standard input if no files are present on the command line.
This appears to behave like STDIN.gets if ARGV is empty, but is not the same thing, hence the confusion.
If your program handle empty argument nor non-empty argument. You can use this module (especially if you already use default gets everywhere)
# A module that help to use method gets no matter what the file argument is
module InputHelper
# Handle input method based on its file argument
def gets
if ARGV.nil?
Kernel.gets
else
STDIN.gets
end
end
end
and then you could include it on your class
require 'input_helper'
class YourClass
...
include InputHelper
...
end
I ran into this issue today in Ruby 3.1.2. I can also confirm that STDIN.gets avoids this problem. An alternative workaround is to set ARGV to an empty array prior to capturing input via gets. You can simply set
ARGV = []
gets.chomp # works fine here
or store them elsewhere if you must get input before you've dealt with them all
cli_args = ARGV.dup
ARGV.clear
gets.chomp # works fine here

Check if no arguments passed

Here's some code:
$ cat 1.rb
#!/usr/bin/env ruby
def f p1 = nil
unless p1 # TODO
puts 'no parameters passed'
end
end
f
f nil
$ ./1.rb
no parameters passed
no parameters passed
The question is, is there a way to distinguish between no arguments and one nil argument passed?
UPD
I decided to add a use case in javascript to make things hopefully clearer:
someProp: function(value) {
if (arguments.length) {
this._someProp = value;
}
return this._someProp;
}
There are three ways in general use. One way is to use the default value to set another variable indicating whether or not the default value was evaluated:
def f(p1 = (no_argument_passed = true; nil))
'no arguments passed' if no_argument_passed
end
f # => 'no arguments passed'
f(nil) # => nil
The second way is to use some object that is only known inside the method as default value, so that it is impossible for an outsider to pass that object in:
-> {
undefined = BasicObject.new
define_method(:f) do |p1 = undefined|
'no arguments passed' if undefined.equal?(p1)
end
}.()
f # => 'no arguments passed'
f(nil) # => nil
Of these two, the first one is more idiomatic. The second one (actually, a variation of it) is used inside Rubinius, but I have never encountered it anywhere else.
A third solution would be to take a variable number of arguments using a splat:
def f(*ps)
num_args = ps.size
raise ArgumentError, "wrong number of arguments (#{num_args} for 0..1)" if num_args > 1
'no arguments passed' if num_args.zero?
end
f # => 'no arguments passed'
f(nil) # => nil
Note that this requires you to re-implement Ruby's arity checking by hand. (And we still haven't gotten it right, because this raises the exception inside the method, whereas Ruby would raise it at the call site.) It also requires you to manually document your method signature because automated documentation generators such as RDoc or YARD will infer an arbitrary number of parameters instead of a single optional one.
You could request for splat arguments:
def f(*args)
if args.empty?
puts 'no parameters passed'
else
p1 = args[0]
...
end
end
Some other option might be to have a private object to indicate no parameter passed:
def initialize
#no_param_passed = Object.new
end
def f(p1 = #no_param_passed)
if p1 == #no_param_passed
puts 'no parameters passed'
end
end

Empty array messing up default argument values

I'm following through the Hungry Academy curriculum using a post here: http://jumpstartlab.com/news/archives/2013/09/03/scheduling-six-months-of-classes
And I'm up to the EventReporter project found here: http://tutorials.jumpstartlab.com/projects/event_reporter.html
So far I've built a simple CLI that asks for a valid command and accepts additional arguments with the command. I'm working ONLY on the load functionality right now and I'm having some trouble getting a default listfile variable set in AttendeeLists initialize method. Here's the code so far:
require 'csv'
class Reporter
def initialize()
#command = ''
loop()
end
#Main reporter loop
def loop
while #command != 'quit' do
printf "Enter a valid command:"
user_command_input = gets.chomp
user_input_args = []
#command = user_command_input.split(" ").first.downcase
user_input_args = user_command_input.split(" ").drop(1)
#DEBUG - puts #command
#DEBUG - puts user_input_args.count
case #command
when "load"
attendee_list = AttendeeList.new(user_input_args[0])
when "help"
puts "I would print some help here."
when "queue"
puts "I will do queue operations here."
when "find"
puts "I would find something for you and queue it here."
when "quit"
puts "Quitting Now."
break
else
puts "The command is not recognized, sorry. Try load, help, queue, or find."
end
end
end
end
class AttendeeList
def initialize(listfile = "event_attendees.csv")
puts "Loaded listfile #{listfile}"
end
end
reporter = Reporter.new
I'm testing running the load command with no arguments and is see that when I initialize the AttendeeList that user_input_args[0] is an empty array [] which, to my understanding is not nil, so I think that's the problem. I'm a little lost on how to continue though when I want the args to be passed through to my new instance of AttendeeList. I'd also prefer not to include the default logic in my Reporter class since that kind of defeats the purpose of encapsulating within the list.
EDIT: I forgot to mention that listfile default for AttendeeList initialize method is argument I'm talking about.
You need to make this change:
def initialize(listfile = nil)
listfile ||= "event_attendees.csv"
puts "Loaded listfile #{listfile}"
end
Explanation
In fact, user_input_args[0] is nil, but nil has no special meaning for default argument values. Default values are used only if the arguments are omitted when calling a function.
In your case:
AttendeeList.new
would work as you expected, but
AttendeeList.new(user_input_args[0])
is effectively
AttendeeList.new(nil)
and parameter listfile becomes nil.

Ruby IF no ARGV given

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

Resources