3
link:http://rubygems.org/gems/cri[image:http://img.shields.io/gem/v/cri.svg[]]
4
link:https://travis-ci.org/ddfreyne/cri[image:http://img.shields.io/travis/ddfreyne/cri.svg[]]
5
link:https://coveralls.io/r/ddfreyne/cri[image:http://img.shields.io/coveralls/ddfreyne/cri.svg[]]
6
link:https://codeclimate.com/github/ddfreyne/cri[image:http://img.shields.io/codeclimate/github/ddfreyne/cri.svg[]]
7
link:http://inch-pages.github.io/github/ddfreyne/cri/[image:http://inch-pages.github.io/github/ddfreyne/cri.png[]]
9
Cri is a library for building easy-to-use commandline tools with support for
14
The central concept in Cri is the _command_, which has option definitions as
15
well as code for actually executing itself. In Cri, the commandline tool
16
itself is a command as well.
18
Here’s a sample command definition:
21
--------------------------------------------------------------------------------
22
command = Cri::Command.define do
24
usage 'dostuff [options]'
27
description 'This command does a lot of stuff. I really mean a lot.'
29
flag :h, :help, 'show help for this command' do |value, cmd|
33
flag nil, :more, 'do even more stuff'
34
option :s, :stuff, 'specify stuff to do', argument: :required
36
run do |opts, args, cmd|
37
stuff = opts.fetch(:stuff, 'generic stuff')
38
puts "Doing #{stuff}!"
41
puts 'Doing it even more!'
45
--------------------------------------------------------------------------------
47
To run this command, invoke the `#run` method with the raw arguments. For
48
example, for a root command (the commandline tool itself), the command could
52
--------------------------------------------------------------------------------
54
--------------------------------------------------------------------------------
56
Each command has automatically generated help. This help can be printed using
57
`Cri::Command#help`; something like this will be shown:
59
--------------------------------------------------------------------------------
60
usage: dostuff [options]
64
This command does a lot of stuff. I really mean a lot.
68
-h --help show help for this command
69
--more do even more stuff
70
-s --stuff specify stuff to do
71
--------------------------------------------------------------------------------
73
=== General command metadata ===
75
Let’s disect the command definition and start with the first five lines:
78
--------------------------------------------------------------------------------
80
usage 'dostuff [options]'
83
description 'This command does a lot of stuff. I really mean a lot.'
84
--------------------------------------------------------------------------------
86
These lines of the command definition specify the name of the command (or the
87
commandline tool, if the command is the root command), the usage, a list of
88
aliases that can be used to call this command, a one-line summary and a (long)
89
description. The usage should not include a “usage:” prefix nor the name of
90
the supercommand, because the latter will be automatically prepended.
92
Aliases don’t make sense for root commands, but for subcommands they do.
94
=== Command-line options ===
96
The next few lines contain the command’s option definitions:
99
--------------------------------------------------------------------------------
100
flag :h, :help, 'show help for this command' do |value, cmd|
104
flag nil, :more, 'do even more stuff'
105
option :s, :stuff, 'specify stuff to do', argument: :required
106
--------------------------------------------------------------------------------
108
Options can be defined using the following methods:
110
* `Cri::CommandDSL#option` or `Cri::CommandDSL#opt`
111
* `Cri::CommandDSL#flag` (implies no arguments passed to option)
112
* `Cri::CommandDSL#required` (implies required argument)
113
* `Cri::CommandDSL#optional` (implies optional argument)
115
All these methods take the short option form as their first argument, and a
116
long option form as their second argument. Either the short or the long form
117
can be nil, but not both (because that would not make any sense). In the
118
example above, the `--more` option has no short form.
120
Each of the above methods also take a block, which will be executed when the
121
option is found. The argument to the block are the option value (`true` in
122
case the option does not have an argument) and the command.
124
==== Multivalued options ====
126
Each of these four methods take a `:multiple` option. When set to true, multiple
127
option valus are accepted, and the option values will be stored in an array.
129
For example, to parse the command line options string `-o foo.txt -o bar.txt`
130
into an array, so that `options[:output]` contains `[ 'foo.txt', 'bar.txt' ]`,
131
you can use an option definition like this:
134
--------------------------------------------------------------------------------
135
option :o, :output, 'specify output paths', argument: :required, multiple: true
136
--------------------------------------------------------------------------------
138
This can also be used for flags (options without arguments). In this case, the
139
length of the options array is relevant.
141
For example, you can allow setting the verbosity level using `-v -v -v`. The
142
value of `options[:verbose].size` would then be the verbosity level (three in
143
this example). The option definition would then look like this:
146
--------------------------------------------------------------------------------
147
flag :v, :verbose, 'be verbose (use up to three times)', multiple: true
148
--------------------------------------------------------------------------------
150
=== The run block ===
152
The last part of the command defines the execution itself:
155
--------------------------------------------------------------------------------
156
run do |opts, args, cmd|
157
stuff = opts.fetch(:stuff, 'generic stuff')
158
puts "Doing #{stuff}!"
161
puts 'Doing it even more!'
164
--------------------------------------------------------------------------------
166
The +Cri::CommandDSL#run+ method takes a block with the actual code to
167
execute. This block takes three arguments: the options, any arguments passed
168
to the command, and the command itself.
170
Instead of defining a run block, it is possible to declare a class, the
171
_command runner_ class (`Cri::CommandRunner`) that will perform the actual
172
execution of the command. This makes it easier to break up large run blocks
173
into manageable pieces.
177
Commands can have subcommands. For example, the `git` commandline tool would be
178
represented by a command that has subcommands named `commit`, `add`, and so on.
179
Commands with subcommands do not use a run block; execution will always be
180
dispatched to a subcommand (or none, if no subcommand is found).
182
To add a command as a subcommand to another command, use the
183
`Cri::Command#add_command` method, like this:
186
--------------------------------------------------------------------------------
187
root_cmd.add_command(cmd_add)
188
root_cmd.add_command(cmd_commit)
189
root.cmd.add_command(cmd_init)
190
--------------------------------------------------------------------------------
197
Thanks for Lee “injekt” Jarvis for link:https://github.com/injekt/slop[Slop],
198
which has inspired the design of Cri 2.0.