I am writing a script with different options in ruby, and I can't understand how the OptionParser could help me.
In particular, there is an example in the documentation: https://docs.ruby-lang.org/en/2.1.0/OptionParser.html
require 'optparse'
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: example.rb [options]"
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
options[:verbose] = v
end
end.parse!
p options
p ARGV
I can understand the exclamation mark on the "end.parse" line (but I expected a parameter after that), but I find the following 2 lines confusing, p hasn't been declared, and I can't understand if it's part of the example source.
And how do I use the '-v' option? Do I simply check if options[:v] is nil or true?
Last thing, what happens to the other options? Does the OptionParser only parse switches? What if I had other parameters after the '-v'? Like myscript -v duck ketchup banana?
To answer your questions:
I can understand the exclamation mark on the "end.parse" line (but I expected a parameter after that)
The documentation states that parse! takes an optional argv parameter. If it is not supplied, it defaults to default_argv, which I imagine is the string containing the arguments passed to this script in the command line.
p hasn't been declared, and I can't understand if it's part of the example source
p is defined in Kernel, so it is (almost) always available in Ruby. p obj is equivalent to puts obj.inspect.
In this context, p is just used to illustrate that after parsing the arguments, the options hash contains all the flags/options you defined in the OptionParser block.
And how do I use the '-v' option? Do I simply check if options[:v] is nil or true?
Yes, but that would actually be options[:verbose].
Last thing, what happens to the other options? Does the OptionParser only parse switches? What if I had other parameters after the '-v'? Like myscript -v duck ketchup banana?
You will have to make multiple calls to opts.on to match all the other switches/arguments you are interested in. Look at the documentation here for explanations on how to do that.
Related
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.>
I want to write a command in the terminal like config.section.key, parse the command, and get the strings "section" and "key". I want to use these two keys in my function to search a hash.
Is there any way to parse a command from the terminal to do this?
To execute terminal commands you can use either backticks or a system call here's some examples keep in mind that this is all pseudo code and I have no idea if this will run correctly:
def create_file
`touch test.txt`
end
def cmd
system('ls')
end
def check_file
results = cmd
if results.include?('test.txt')
puts 'File exists.'
else
puts 'Creating file..'
create_file
end
end
Now to the parsing part, depending on what you want to do, you can either save the information into a variable, or you could use a regex to extract the information. So if you wanted to extract digits with a regex: /\d+/ if you wanted to save the information: results = cmd..
I hope this answers your question.
To split the information, you could use the split method for example:
def cmd
`prt_jobs`
end
def check_jobs
res = cmd
res.split(".")
end
This will split the results of a print jobs command by periods and make them into an array. I'd show you more except I'm on my phone so it will have to wait
As Tadman commented, you can use the String#split method to split the argv on period characters, if that is your desire:
config, section, key, *rest = ARGF.argv.split('.')
Another good option when dealing with parsing command lines is the Ruby standard library OptionParser class. Rather than rebuild all of the CLI parsing by hand, the OptionParser class has that built in and much more. The resulting scripts can feel much more linux like and be familiar to anyone who's used bash before.
I have a Ruby app with a relatively broad set of command-line arguments. I would like to suppress "short" variants for a number of options so that they can only be used in the long ("double dash") form.
Can I somehow suppress short dash variants for some options?
UPDATE 2013/10/08
It turned out that indeed omitting the short variant works! However, for me it didn't because for some reason in my program all the short keys were prefixed with a space. So a simple case like this:
require 'optparse'
op = OptionParser.new
op.on(" -f", "--from FORMAT", "Use the specific format") {}
op.on("--flip", "Do a flip") {}
op.parse!
caused the exception:
ruby why.rb -f some-foos
why.rb:17:in `<main>': ambiguous option: -f (OptionParser::AmbiguousOption
while the advice given (note the lack of space after the opening quote):
require 'optparse'
OptionParser.new do |opts|
opts.on("-d", "--ding DING", "Should not conflict with dangerous-option") do
puts "ding set!"
end
opts.on("--dangerous-option", "Set dangerous option") do |v|
puts "dangerous option set to #{v}"
end
end.parse!
works fine.
$ruby dang.rb -d xyz
ding set!
So thanks p11y for pointing me in the right direction with a working example. Also, if this "leading space" is in place, optparse will not complain - but it will change the interpretation of your short keys (or, better to say, will ignore them and show them as part of your help line! - and still use the auto-generated keys instead).
Just drop the short form:
require 'optparse'
OptionParser.new do |opts|
opts.on("--dangerous-option", "Set dangerous option") do |v|
puts "dangerous option set to #{v}"
end
end.parse!
$ ruby foo.rb -h
Usage: foo [options]
--dangerous-option Set dangerous option
$ ruby foo.rb --dangerous-option
dangerous option set to true
I'm working on implementing Project Euler solutions as semantic Ruby one-liners. It would be extremely useful if I could coerce Ruby to automatically puts the value of the last expression. Is there a way to do this? For example:
#!/usr/bin/env ruby -Ilib -rrubygems -reuler
1.upto(100).into {|n| (n.sum.squared - n.map(&:squared).sum)
I realize I can simply puts the line, but for other reasons (I plan to eval the file in tests, to compare against the expected output) I would like to avoid an explicit puts. Also, it allots me an extra four characters for the solution. :)
Is there anything I can do?
You might try running it under irb instead of directly under a Ruby interpreter.
It seems like the options -f --noprompt --noverbose might be suitable (.
#!/usr/bin/env irb -f --noprompt --noverbose -Ilib -rrubygems -reuler
'put your one-liner here'
The options have these meanings:
-f: do not use .irbrc (or IRBRC)
--noverbose: do not display the source lines
--noprompt: do not prefix the output (e.g. with =>)
result = calculate_result
puts result if File.exist?(__FILE__)
result of eval is last executed operation just like any other code block in ruby
is doing
puts eval(file_contents)
an option for you?
EDIT
you can make use of eval's second parameter which is variables binding
try the following:
do_not_puts = true
eval(file_contents, binding)
and in the file:
....
result = final_result
if defined?(do_not_puts)
result
else
puts(result)
end
Is it an option to change the way you run scripts?
script.rb:
$_= 1.upto(100).into {|n| (n.sum.squared - n.map(&:squared).sum)
invoke with
echo nil.txt | /usr/bin/env/ruby -Ilib -rrubygems -reuler -p script.rb, where nil.txt is a file with a single newline.
Let's say that I have a simple Ruby app where I want the first argument (if any) to specify the environment: TEST, DEVELOPMENT or PRODUCTION (with DEVELOPMENT being the default if no argument is given). For instance,
ruby myapp.rb test
would run it in TEST mode. Also, shorthands should be accepted, so that for instance
ruby myapp.rb t
would run the app in TEST mode and
ruby myapp.rb dev
would run it in DEVELOPMENT mode.
I'd like to use OptionParser, but it behaves very weirdly. If myapp.rb is
require 'optparse'
environment = 'DEVELOPMENT'
opts = OptionParser.new
opts.on('test') { environment = 'TEST' }
opts.on('production') { environment = 'PRODUCTION' }
opts.parse!(ARGV)
then environment becomes PRODUCTION no matter what arguments I pass; for some reason, opts.on('production') always executes its block. (It doesn't if I use a flag-style string like '-production' instead.) And there's no way I can see to have OptionParser look for strings starting with 't' rather than the exact string 'test'.
Maybe OptionParser is the wrong tool for the job. Obviously it would be trivial to split up ARGV myself. I'm just wondering what's going on with this behavior. I'm on Ruby 1.9.2.
Provided you use the parse! method, any arguments handled by opts.on calls are stripped from the ARGV array destructively. This means that the original contents of the ARGV array will no longer contain those flags after the parse! method.
I recommend parsing the remaining set of arguments manually by comparing ARGV to an array containing 'test' and 'production'.
Check out the doc:
http://ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/OptionParser.html#method-i-parse-21
I'd say you need to parse out arguments like that from ARGV before running OptionParser
e.g.
env = ARGV.select{|arg| arg =~ /dev/test/prod/i}.first
P.S. I'd recommend Trollop. I find it much simpler, and it's good about picking defaults.