Clive

Arguments

As previously talked about in the Options and Commands sections there are different options that can be passed to #opt(ion) and #command for arguments.

The most basic option being :arg (or :args).

opt :size, args: '<height> <width>'

But by passing other options we can force the arguments to be of particular types, and even tranform them to more useful types.

Arguments

Clive supports options and commands which take arguments, they can have multiple arguments and optional arguments. To make an option or command which takes arguments simply pass :args or :arg with the desired pattern.

# takes a single argument
# eg. --length 150
opt :length, args: '<cm>'

# takes two arguments
# eg. --rect 32 45
opt :rect, args: '<x> <y>'

# takes three arguments
# eg. --box 4 5 6
opt :box, args: '<x> <y> <z>'

# and so on...

Argument names are surrounded by < and >. These arguments must be given or an error is raised.

Optional Arguments

To make arguments optional surround them with [ and ].

# first argument required, second optional
# eg. --convert input.mp4
# or  --convert input.mp4 output.mp3
opt :convert, args: '<in> [<out>]'

# second argument required, first optional
# eg. --convert input.mp3
# or  --convert input.mp4 output.mp3
opt :convert, args: '[<in>] <out>'

# both arguments are optional
opt :convert, args: '[<in> <out>]'

This works with any number of arguments and with breaks between the optional arguments, for instance

opt :weird, args: '[<a>] <b> [<c>] <d> [<e>]'

also works.

Greedy Arguments

Arguments can also be “greedy”. Simply append the name of the argument with .... A greedy argument will expect to match at least one item, to make an argument take 0 or more items surround it with [ and ] as usual.

opt :items, arg: '<thing>...'
# --items            # Error
# --items iPad       #=> ['iPad']
# --items iPad iPod  #=> ['iPad', 'iPod']

opt :items, arg: '[<thing>...]'
# --items            #=> []
# --items iPad       #=> ['iPad']
# --items iPad iPod  #=> ['iPad', 'iPod']

Types

Arguments can be given a specific type, this will make sure that the argument given looks right and will then convert it. See Types for a full list of available types along with full explanations.

opt :size, arg: '<cm>', as: Float

You can use :as, :type, :types or :kind to set the type.

Matches

By passing a regular expression (or any object responding to #match) with :match or :matches you can check the argument looks right.

opt :simple_number, match: /\A\d+\Z/
 
# with a custom object
crazy_matcher = Object.new
def crazy_matcher.match(arg)
  rand < (1.0 / arg.size)
end

opt :crazy, match: crazy_matcher

Withins

Use :in, :within or :withins to check if the argument is in a given Array, Range or other object responding to #include?.

opt :letter, in: 'a'..'z'

To use with non-String values you will need to use type as well. So,

opt :number, in: 1..100

will not work as you expect. But,

opt :number, as: Integer, in: 1..100

will.

Defaults

Arguments can be given default values using :default or :defaults. The value passed will be set if the option is used but the argument is not given.

opt :name, default: 'John'
# --name       #=> 'John'
# --name Dave  #=> 'Dave'

It is not set when the option is not used. Read that again. Half the time you will want to set the value regardless of whether the option is called, for this use #set. For example,

set :name, 'John'
opt :name, arg: '[<arg>]'

Will always set :name to John regardless of whether --name is passed.

Constraints

If you've read through the above and they don't cover your case, this is what you need. :constraint or :constraints will accept a Proc, or a symbol. The argument will be passed to this Proc, or have the method with the name given by the symbol called on it.

opt :long_word, constraint: -> i { i.size >= 7 }

Actually it will be passed twice, first as a String, then converted by the Type given. This means you can do this,

opt :odd, as: Integer, constraint: :odd?

Advanced Tips & Tricks

Assumed Arguments

If any of the options described below are given, it is possible to omit :arg or :args. Clive will create and argument called arg automatically, though it is recommended to manually name your arguments as this makes it easier for users to know what each argument is for.

Actually, as you may have noticed, throughout most of these examples I've been using this feature.

Mulitple Arguments, Revisited

You are not constrained to applying a certain filter, type, etc. to every argument an option takes, you can have the first an Integer, the second contain only letters and the third be within the set mac, linux, windows. Simply pass the argument options as Arrays with the element at the index corresponding to the argument. Here's an example:

opt :nerd, 
  args: '<age>      <name>         <os>',
  as:    [Integer,  nil,           nil],
  match: [nil,      /[A-Z][a-z]+/, nil],
  in:    [nil,      nil,           %w(mac linux windows)]

I've tabulated it so that it's easier to see what matches to which argument. See that wherever I didn't care about the value and wanted the default I've used nil.

Greedy Arguments, Revisited

Greedy arguments can be combined with normal arguments, but they must come last.

opt :items,
  args: '<amount> <thing>...',
  as:   [Integer, nil]
  
  # eg. --items 5 iPad iPod  #=> [5, 'iPad', 'iPod']