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.
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.
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.
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']
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.
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
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.
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.
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?
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.
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 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']