optionparser pass an array to ruby file - ruby

I have a trouble with passing an arguments to my ruby file. IE,
OptionParser.new do |opts|
opts.banner = 'Usage: mp3split.rb [options]'
opts.on('-f', '--filename fName1,fName2,fName3', Array, 'absolute or relative pathes to file') { |f| options[:filenames] = f }
end.parse!
This approach requires me to write this commands:
ruby mp3split.rb --filename fursov_13.mp3,fursov_14.mp3,fursov_14_2.mp3,fursov_15.mp3,fursov_16.mp3,fursov_17.mp3
But I want to get array by this:
ruby mp3split.rb --filename fursov_13.mp3 fursov_14.mp3 fursov_14_2.mp3 fursov_15.mp3 fursov_16.mp3 fursov_17.mp3
How can I implement this functionality? I can't find anything helpful about this in docs.

With OptionParser you can’t. There is a workaround, though, when there is the only list you need to handle that way and you won’t pass other arguments to the script. OptionParser splits the input by spaces before it processes it. The unkeyed arguments remain in ARGV global constant after parsing. Assuming everything described above is met, here we go:
OptionParser.new do |opts|
options[:filenames] = []
opts.banner = 'Usage: mp3split.rb [options]'
opts.on('-f', '--filename fName1 fName2 fName3', Array,
'absolute or relative pathes to file') do |f|
options[:filenames] |= [*f]
end
end.parse!
options[:filenames] |= ARGV
I apparently fixed another glitch within your code: options[:filenames] should be appended not overwritten on every occurence of -f switch, OptionParser supports script -f f1 -f f2 -f f3.

Related

How to get the specified option flag from within OptionParser

I'd like to get the exact option flag that was specified on the command line from within Ruby's OptionParser.
For example, suppose I have the following code:
parser = OptionParser.new {
|opts|
opts.on('-f', '--file FILE', 'filename') {
|arg|
$filename = arg
# Here I'd like to know whether '-f' or '--file' was entered
# on the command line.
}
# ... etc. ...
}
I'd like to know whether the user happened to type '-f' or '--file' on the command line. Is this possible without writing two separate opts.on blocks?
I don't think you can get the flags being passed in when inside the OptionParser.new block. At that point it's too late. However, prior to OptionParser parsing the command-line, it's possible to look and see what's being passed in.
ARGV contains the raw command-line. For instance, if this is the command-line invocation for some code:
foo -i 1 -j 2
then ARGV will contain:
["-i", "1", "-j", "2"]
and, then it becomes pretty easy to grab the flags:
ARGV.grep(/^-/) # => ["-i", "-j"]
There are other OptionParser-like tools for Ruby, and those might let you access the flags being used, but I can't think of a reason I'd ever care to. Looking at your code it seems like you're not understanding how to use OptionParser:
parser = OptionParser.new {
|opts|
opts.on('-f', '--file FILE', 'filename') {
|arg|
$filename = arg
# Here I'd like to know whether '-f' or '--file' was entered
# on the command line.
}
# ... etc. ...
}
Instead of doing it that way, I'd write it:
options = {}
OptionParser.new do |opts|
opts.on('-f', '--file FILE', 'filename') { |arg| options[:filename] = arg }
end.parse!
if options[:filename]
puts 'exists' if File.exist?(options[:filename])
end
Then, later in your code you can check in the options hash to see if either of the -f or --file options was given, and what the value was. That it was one or the other of -f or --file shouldn't ever matter.
If it does then you need to differentiate between the two flags, instead of treating them as if they're aliases:
options = {}
OptionParser.new do |opts|
opts.on('-f', 'filename') { |arg| options[:f] = arg }
opts.on('--file FILE', 'filename') { |arg| options[:file] = arg }
end.parse!
if options[:file] || options[:f]
puts 'exists' if File.exist?(options[:file] || options[:f])
end

Parse multiple command line options in Ruby using OptionParser

I've just started using OptionParser for Ruby and I wanted to use flags that would use more than just one argument.
For instance, I would like to be able to run:
script --move src dst
Note how src and dst are not separated using a coma.
My initial idea was:
opts.on("-m src dst", "--move src dst ", "move file from SRCto DST") do |src|
# do something
end
But this is not working. I assume that this is not the right approach. But how could this be done?
The example under the "Complete Example" section of the OptionParser details how a list of items can be accepted.
Here is a sample program based on that example. The third parameter Array in opts.on indicates that input src, dst should be used to create an array. To run this sample, you need to do gem install trollop.
# test.rb
require 'optparse'
options = {}
OptionParser.new do |opt|
opt.on("-m src, dst", "--move src, dst", Array, "Move from src to dst") do |list|
options[:src] = list[0]
options[:dst] = list[1]
end
end.parse!
puts options # It's a hash of parsed options
Sample run:
> ruby test.rb -m from,to
{:src=>"src", :dst=>"dst"}
>ruby test.rb -h
Usage: test [options]
-m, --move src, dst Move from src to dst
The above script forces one to separate the options using comma.
As indicated by "Really Cheap Command-Line Option Parsing in Ruby", there seems to be a gem, trollop, that can be quite easy to use for command-line parsing.
A sample program based on Trollop is given below, which allows usage of spaces for specifying options with multiple values
# test.rb
require "trollop"
opts = Trollop::options do
banner "Command line parsing using Trollop"
opt :move, "--move src dst', Move from src to dst", :short => "-m", :long => "--move", :type => :strings
end
# An array of option values
p opts.move
Sample run:
>ruby test.rb -m hello world
["hello", "world"]
>ruby test.rb -h
Command line parsing using Trollop
-m, --move=<s+> '--move src dst', Move from src to dst
-h, --help Show this message
There is a subtle difference between the help output between the two approaches. Trollop produces help text where --move=<s+> does not indicate clearly that it needs accepts two values, so I had to repeat the command syntax description.
OptionParser doesn't support that; It could be patched to do so, but I'm not sure it's worth the trouble.
Consider this code:
require 'optparse'
options = {}
OptionParser.new do |opt|
opt.on('-m', '--move') { |o| options[:move] = o }
end.parse!
from_name, to_name = ARGV
puts "Should move: #{ options.key?(:move) }"
puts "From: #{ from_name }"
puts "To: #{ to_name }"
Saving it and running it with various combinations of the parameters returns:
> ruby test.rb --move from to
Should move: true
From: from
To: to
> ruby test.rb from to
Should move: false
From:
To:
If the code is supposed to move files by default then don't bother with the --move flag, simply use:
test.rb from to
and consider removing the OptionParser block entirely.
If the code is supposed to normally copy with the option to move, then --move becomes more sensible to act as a flag that moving is desired.
ruby test.rb --move from to
I'd have code that tests for options[:move] and run the code to move instead of copy at that point.
In either case, the filenames shouldn't be tied to the flag, they should be supplied separately and retrieved from ARGV after OptionParser has finished parsing the command-line and removing entries it's handled.

How to get command line argument using optparse?

I'm working on command line search tool which searches through source files using given keyword. I use optparse to parse command line options. For now it look like this:
qs -p ~/Desktop/project -k line
if no -p argument is provided I use default(current) directory:
qs -k line
But, what I really want is doing the same as above but without -k, like this:
qs line
For now I have this:
OptionParser.new do |options|
options.banner = "Usage: qs [options] [path] [keyword]\n" \
"\nSearch through files for a given keyword at specified path.\n" \
"If path is no specified current directory used by default."
options.separator ""
options.separator "Specific options:"
options.on("--no-rec", "Looking in files only at that level.") do |r|
$values[:recursion] = r
end
options.on('-p', '--path PATH', String, 'Path where to start search') do |path|
$values[:path] = path
end
options.on('-k', '--key WORD', String, 'Word you are looking for ') do |key|
$values[:keyword] = key
end
options.on_tail("-h" , "--help", "Help documentation.") do
$stderr.puts options
exit 1
end
end.parse!
As you can see it's impossible to do something like this:
$values[:keyword] = ARGV[2]
because there is no guarantee that all arguments will be present.
Is it possible to do this, without losing all this support from optparse ?
Thanks in advance.
When you use parse! (with the !), Optparse removes the options from ARGV, so afterward any other items (that Optparse doesn’t recognise) will be at ARGV[0] onwards.
So you should be able to do something like this:
OptionParser.new do |options|
# as before, but without k option
end.parse!
# At this point all the options optparse knows about will be
# removed from ARGV, so you can get at what's left:
$values[:keyword] = ARGV[0]

Optparse doesn't seem to return ARGV array. Argument Required Error

This is homework and I do not expect you to give me the complete answer.
I'm trying to parse a command line entry such as:
./apacheReport.rb -u testlog.txt
When I enter this:
./apacheReport.rb -u testlog.txt
I get:
Argument required
My code is:
require_relative 'CommonLog'
require 'optparse'
# puts ARGV.inspect
optparser = OptionParser.new
optU = false
optI = false
optS = false
optH = false
optparser.banner = "apacheReport.rb [options] filename"
optparser.parse!
rescue => m
puts m.message
puts optparser
exit
end
if ARGV.length < 1
puts "Argument required"
exit
end
userInputFile = ARGV[0]
userInputFile.to_s
file = CommonLog.new(userInputFile)
It should parse the leftover portion of the command into ARGV[0] then should store it as userInputFile and then create a CommonLog object using the file as the constructor. At that point I call the methods that were specified in the command.
It seems that for some reason my ARGV is not being returned. I'm not sure what the issue is.
Ruby's OptionParser is easy to use, but you have to puzzle through the documentation. Here's a little example that'd be useful for your code:
require 'optparse'
options = {}
OptionParser.new do |opt|
opt.on('-u', '--use_this FILE', 'Use this file') { |o| options[:use_this] = o }
end.parse!
options will contain the flags. In this case, if you pass in -u foo, options[:use_this] will be foo.
Save that and try running it without and with a parameter. Also try running it with just a -h flag.
You can search StackOverflow for more answers where I was dealing with OptionParser.
It's hard to tell what's wrong since you code doesn't seem to be working at the moment. The problem may be that the parse! method removes found options from ARGV. So when you write:
optparser.parse!
It removes your two parameters (-u testlog.txt) and this code always fails:
if ARGV.length < 1
puts "Argument required"
exit
end
Instead of looking at ARGV, you need to set up optparser correctly. Perhaps something like:
optparser = OptionParser.new do |opts|
opts.banner = "apacheReport.rb [options] filename"
opts.on("-u", "--u-short-for-this", "Whatever u stands for") do |u|
optU = u
end
end
Then optU will be true only if the user passed -u and the filename will be in ARGV[0].

Extracting filenames from command line arguments with Ruby

I'm trying to use optparse to parse command line arguments. I would like my program to accept arguments like that:
$ ./myscript.rb [options] filename
I can easily manage the [options] part:
require 'optparse'
options = { :verbose => false, :type => :html }
opts = OptionParser.new do |opts|
opts.on('-v', '--verbose') do
options[:verbose] = true
end
opts.on('-t', '--type', [:html, :css]) do |type|
options[:type] = type
end
end
opts.parse!(ARGV)
But how do I get the filename?
I could extract it manually from ARGV, but there has to be a better solution, just can't figure out how
The "parse" method returns the unprocessed ARGV. So in your example, it will return a one element array with the filename in it.
I can't just use ARGV.pop. For example
when the last argument is "css" it
could either be a file or belong to
--type switch.
But if your script requires the last argument to be a filename (which is what your usage output inquires) this case should never happen the script should exit with a non-zero and the user should get a usage report or error.
Now if you want to make a default filename or not require a filename as the last argument but leave it optional then you could just test to see if the last argument is a valid file. If so use it as expected otherwise continue without etc.
Hope this answer can still be useful.
Ruby has one built-in variable __FILE__ can do this type of work.
puts __FILE__
it will print out your file's name.
I don't think extracting it before sending it to OptionParser is bad, I think it makes sense. I probably say this because I have never used OptionParser before, but oh well.
require 'optparse'
file = ARGV.pop
opts = OptionParser.new do |opts|
# ...
end

Resources