clive
Clive lets you easily create command line interfaces, from simply checking for the presence of a few flags to multiple command behemoths.
Install
Install with:
$ gem install clive
Usage
NOTE: Throughout I will be using the new 1.9
{a: b}
hash syntax, obviously the old{:a => b}
syntax still works and can be used if you want or where 1.8 compatibility is needed.
Clive is generally used by creating a class to hold your command line interface as shown in the example below.
# my_app.rb
require 'clive'
module MyApp
VERSION = "0.1.4"
# some code
class CLI < Clive
config name: 'myapp'
opt :v, :version, 'Display the current version' do
puts MyApp::Version
exit 0
end
end
end
result = MyApp::CLI.run
Then run with my_app.rb --version
to display the version for MyApp. By default
#run
will use ARGV
as the input, but you can pass something else if
necessary.
.run
returns an instance of Clive::StructHash
by default, this is a hybrid
hash and struct allowing you to access keys by calling them or using #[]
. It
also stores any extra arguments that may have been passed which can be accessed
with #args
or #[:args]
.
class CLI
opt :n, :name, args: '<first> <last>'
opt :age, arg: '<age>', as: Integer
end
result = CLI.run %w(--name John Doe --age 23 "I like coding!")
bio = result.args #=> "I like coding!"
name = result.name #=> ['John', 'Doe']
age = result.age #=> 23
This simple example shows how Clive can handle multiple arguments, casting to
types (Integer in this case) and how extra arguments are stored in #args
.
Options
Options are defined using #opt
and/or #option
they can have short (-a
) or
long names (--abc
) and can also have arguments. The description can be given
as an argument to #opt
or can be defined before it using #desc
(or
#description
).
opt :v, :version, 'Display the current version' do
# ...
end
# is equivalent to
desc 'Display the current version'
opt :v, :version do
# ...
end
Longer option names, containing _
s are called by replacing the _
with a -
so
opt :longer_name_than_expected
would be called with --longer-name-than-expected
.
Boolean Options
Boolean options are options which can be called with a no-
prefix, which then
passes false
to the block/state. For example,
bool :a, :auto
Can be called with -a
or --auto
which would set :auto
to true
, or
--no-auto
which sets :auto
to false
. If a block is given you can retrieve
the truth by adding block parameters or using the truth
variable which is
automatically set.
bool :a, :auto do |t|
puts t
end
# OR
bool :a, :auto do
puts truth
end
Boolean options must have a long name.
Commands
Commands are defined using #command
. They can be used to group related Options
together acting like a namespace, but Commands are fully featured Options so can
also take arguments. Commands can be created with multiple names.
desc 'Create a new project'
command :new, :create, arg: '<dir>', as: Pathname do
# Set the default type to use
set :type, :basic
desc 'Select type of template to use'
opt :type, arg: '<choice>', in: %w(basic complex custom), as: Symbol
bool :force, 'Force overwrite'
action do
puts "Creating #{get :type} in #{dir}"
# do writing
end
end
The above example also shows using the #set
and #get
methods, these allow
you to set and get values from the state. Also note how the logic for executing
the new
command is given to #action
, this is because the block passed to
#command
is used for option definition.
Arguments
As previously talked about Options and Commands can take arguments by passing a
hash with the key :arg
or :args
.
opt :size, args: '<height> <width>'
The option --size
takes two arguments. These would be saved to state as an array,
for instance running with --size 10 40
would set :size
to ['10', '40']
.
Arguments can be made optional by enclosing one or more arguments with [
and ]
:
# both required
opt :size, args: '<h> <w>'
# --size 10 #=> Error
# first required
opt :size, args: '<h> [<w>]'
# --size 10 #=> [10, nil]
# second required
opt :size, args: '[<h>] <w>'
# --size 10 #=> [nil, 10]
# neither required
opt :size, args: '[<h> <w>]'
# --size 10 #=> [10, nil]
You can make an argument 'infinite' by appending the name with ...
, like
<arg>...
. Optional-ness is respected so <arg>...
expects at least one argument
whereas [<arg>...]
takes 0 or more arguments. Infinite arguments also play well
with standard arguments, and will return arrays of items even if only one argument
was passed.
opt :items, :arg => '<thing>...'
# --items #=> Error
# --items iPad #=> ['iPad']
# --items iPad iPod #=> ['iPad', 'iPod']
opt :items, :arg => '[<thing>...]'
# --items #=> []
# and same as previously in other cases
opt :items, :arg => '<amount> <thing>...', :as => [Integer, nil]
# --items 5 iPad iMac #=> [5, 'iPad', 'iMac']
There are also various options that can be passed to constrain or change the
arguments. If one of the below is passed to an option with :arg
or :args
a generic argument called <arg>
will be added.
Types (:types
, :type
, :kind
or :as
)
An argument will be checked if it matches how the type should look, then converts
it to that type. For more information see lib/clive/type/definitions.rb
.
opt :list, as: Array
This accepts a comma delimited list of items, --list a,b,c
and sets :list
to
['a', 'b', 'c']
.
Matches (:matches
or :match
)
Allows you to say that an argument must match a regular expression (or any object
which responds to #match
).
opt :word, match: /^\w+$/
This accepts --word hello
but not --word 123
.
Withins (:withins
, :within
or :in
)
Allows you to say that an argument must be within a passed Array, Set or Range
(any object which responds to #include?
).
opt :num, in: "1".."100"
This accepts --num 50
but not --num 900
. The example above had to use a range
of Strings because that is what is passed, you can use this with :type
to use
Integers.
opt :num, as: Integer, in: 1..100
Would work in the same way as the one above but return an Integer.
Defaults (:defaults
or :default
)
Allows you to give a default value that should be used if an argument is not given.
opt :type, default: 'house'
So --type
would set :type
to 'house'
, but --type shed
would set :type
to 'shed'
. The default value is only set if the option is used. To set a value
regardless of whether the option is used use #set
in the class or commands
body.
set :type, 'house'
opt :type
Would always set :type
to 'house'
even when --type
is not used.
Constraints (:constraint
or :constraint
)
Allows you to constrain the argument using a Proc, this is to cover the very few events where the above options do not satisfy the requirements.
opt :long_word, constraint: -> i { i.size >= 7 }
Accepts --long-word eventually
but not --long-word event
. You can also pass
a symbol which will have #to_proc
called on it.
opt :odd, as: Integer, constraint: :odd?
This only accepts odd Integers.
Runner
All blocks passed to options or given to a command's action are run in the Runner class. This provides a few shortcuts to make life easier. Here is a quick run down with examples.
Argument Referencing
You can reference an options or commands arguments directly by name without having to use block parameters.
opt :size, args: '<height> <width>', as: [Float, Float] do # no params!
puts "Area = #{height} * #{width} = #{height * width}"
end
As shown earlier the truthiness of a boolean option is set to the value truth
.
Working with the State
Four fundamental methods are defined for working with the state, #get
, #set
,
#update
and #has?
.
#get
allows you to get values previously set.
opt :get_some_key do
puts get(:some_key) #=> value set for :some_key
end
#set
allows you to set values in the state.
opt :set_some_key, arg: '<value>' do
set :some_key, value
end
#update
allows you to modify a value in the state.
set :list, []
opt :add, arg: '<item>' do
update :list, :<<, item
# or using a block
update(:list) {|l| l << item }
end
#has?
tells you whether a value has been set for the key.
opt :has_some_key do
puts has?(:some_key)
end
Help Formatters
Clive comes with two help formatters, one with colour and the other without. To use the plain formatter (colour is default), use
class CLI < Clive
config formatter: Clive::Formatter::Plain.new
# ...
end
CLI.run
To create your own formatter take a look at lib/clive/formatter.rb
.
Clive::Output
clive/output
contains various monkey patches on String that allow you to easily
colourise output.
puts "I'm blue".blue # will print blue text
puts "I'm green and bold".green.bold # will print green and bold text
puts "Crazy".blue.l_yellow_bg.underline
# etc
Colours available: white, green, red, magenta, yellow, blue, cyan, black. Effects available: bold, underline, blink, reverse.
Light versions can be used by prepending the name with l_
, ie. l_red
, the light
version of black is called grey.
All colours can be used as backgrounds by appending _bg
, ie. red_bg
, light
backgrounds are as expected, l_red_bg
.
Copyright
Copyright (c) 2010-12 Joshua Hawxwell. See LICENSE for details.