Option Parser with an optional flag/switch for last argument

I am using OptionParser to parse command-line options. I would like to
run a program in following manner:

$ multiply-by.rb --factor 3 4
$ 12

where last number ‘4’ is an input argument which should not need any
option flag/switch. Any hints on how can it be done? Is it possible with
OptionParser or should I write my own option parser method?

thanks,
N

Yes, just use the ARGV as if you would without using OptionParser;
once it has parsed everything it recognizes, it will leave the rest of
arguments in ARGV.

– Matma R.

On Wed, May 16, 2012 at 12:03:07AM +0900, Neubyr N. wrote:

I am using OptionParser to parse command-line options. I would like to
run a program in following manner:

$ multiply-by.rb --factor 3 4
$ 12

where last number ‘4’ is an input argument which should not need any
option flag/switch. Any hints on how can it be done? Is it possible with
OptionParser or should I write my own option parser method?

You could just access it directly in ARGV after parsing everything else
using OptionParser.

Thanks for the reply everyone. I am taking approach as suggested by
Bartosz and Chad to assign ‘left-over’ ARGV to the input decimal number.

@Mike, the commandable gem looks really useful. I am not using it right
now, but it looks like it will be useful in some of my other
projects/command-line apps. Thanks for providing a detailed example.

You could also give Commandable a try (gem install commandable). Your
code might look something like this:

#!/usr/bin/env ruby

file: MultiplyBy

require ‘commandable’

class MultiplyBy
extend Commandable

command “multiply a set of numbers”
def factor(*numbers)
numbers.inject(1) {|memo, i| i.to_f * memo}
end

end

Commandable.execute

end

And you would run it like this:

$ ./MultiplyBy factor 3 4

12.0

No ugly “–” and you can even do more natural looking verbage like:

$ ./Multiply 3 by 4

12.0

Using code like:

#!/usr/bin/env ruby
require ‘commandable’

class MultiplyBy
extend Commandable

command “the base number”, :default, :required, priority: 1
def number(base_number)
@base_number = base_number.to_f
end

command “multiply a set of numbers by the base number”
def by(*numbers)
numbers.inject(@base_number) {|memo, i| puts “memo: #{memo}”; i.to_f

  • memo}
    end

end

Commandable.execute

On Tue, May 15, 2012 at 11:46 AM, Bartosz Dziewoński

On Wed, May 16, 2012 at 5:56 AM, Neubyr N. [email protected]
wrote:

Thanks for the reply everyone. I am taking approach as suggested by
Bartosz and Chad to assign ‘left-over’ ARGV to the input decimal number.

@Mike, the commandable gem looks really useful. I am not using it right
now, but it looks like it will be useful in some of my other
projects/command-line apps. Thanks for providing a detailed example.

if you need flexibility, then ARGV by itself is more than enough.

eg, re your sample,
$ cat -n test2.rb
1
2 operator=ARGV.shift
3
4 ops=%w(* / + -)
5
6 if not (ops).include? operator
7 raise “operator argument must be one of #{ops}”
8 end
9
10 factors=ARGV
11 if factors.size < 2
12 raise “need at least two args for operator”
13 end
14
15 factors=ARGV.map(&:to_f)
16
17 p factors.inject(operator.to_sym)
18
19
[email protected]:~
$ ruby test2.rb - 3 4 5 #subtract
-6.0
[email protected]:~
$ ruby test2.rb + 3 4 5 #add
12.0
[email protected]:~
$ ruby test2.rb “*” 3 4 5 #multiply; need to quote
60.0

just a thought.
kind regards -botp

On Tue, May 15, 2012 at 5:03 PM, Neubyr N. [email protected]
wrote:

I am using OptionParser to parse command-line options. I would like to
run a program in following manner:

$ multiply-by.rb --factor 3 4
$ 12

where last number ‘4’ is an input argument which should not need any
option flag/switch. Any hints on how can it be done? Is it possible with
OptionParser or should I write my own option parser method?

This is how I’d do it:

require ‘optparse’

factor = nil

OptionParser.new do |opts|
opts.on ‘-f’, ‘–factor=F’, Integer, ‘Multiplication factor’ do |v|
factor = v
end
end.parse! ARGV

abort “ERROR: need a factor” unless factor

ARGV.each {|v| puts(Integer(v) * factor)}

Kind regards

robert