README.md in cri-2.15.1 vs README.md in cri-2.15.2
- old
+ new
@@ -103,37 +103,114 @@
end
flag nil, :more, 'do even more stuff'
option :s, :stuff, 'specify stuff to do', argument: :required
```
-Options can be defined using the following methods:
+The most generic way of definition an option is using either `#option` or `#opt`. It takes the following arguments:
-* `Cri::CommandDSL#option` or `Cri::CommandDSL#opt` (include an `argument` parameter: `:required` or `:optional` that specifies if the option requires or allows an argument)
-* `Cri::CommandDSL#flag` (implies no arguments passed to option)
-
-The following _deprecated_ methods can also be used to define options:
-
-* `Cri::CommandDSL#required` (implies an option that requires an argument -- deprecated because `#required` suggests that the option is required, wich is incorrect; the _argument_ is required.)
-* `Cri::CommandDSL#optional` (implies an option that can optionally include an argument -- deprecated because `#optional` looks too similar to `#option`.)
-
-All these methods take these arguments:
-
1. a short option name
2. a long option name
3. a description
4. optional extra parameters
+ * `argument:` (default: `:forbidden`)
+ * `transform:`
+ * `default:`
+ * `multiple:` (default: `false`)
+5. optionally, a block
-Either the short or the long form can be nil, but not both (because that
-would not make any sense). In the example above, the `--more` option has no
-short form.
+In more detail:
-Each of the above methods also take a block, which will be executed when the
-option is found. The arguments to the block are the option value (`true` in
-case the option does not have an argument) and the command.
+* The short option name is a symbol containing one character, to be used in single-dash options, e.g. `:f` (corresponds to `-f`). The long option name is a symbol containing a string, to be used in double-dash options, e.g. `:force` (corresponds to `--force`). Either the short or the long option name can be nil, but not both.
-#### Transforming options
+* The description is a short, one-line text that shows up in the command’s help. For example, the `-v`/`--version` option might have the description `show version information and quit`.
+* The extra parameters, `argument:`, `multiple:`, `default:`, and `transform:`, are described in the sections below.
+
+* The block, if given, will be executed when the option is found. The arguments to the block are the option value (`true` in case the option does not have an argument) and the command.
+
+There are several convenience methods that are alternatives to `#option`/`#opt`:
+
+* `#flag` sets `argument:` to `:forbidden`
+* (**deprecated**) `#required` sets `argument:` to `:required` -- deprecated because `#required` suggests that the option is required, wich is incorrect; the _argument_ is required.)
+* (**deprecated**) `#optional` sets `argument:` to `:optional` -- deprecated because `#optional` looks too similar to `#option`.
+
+#### Forbidden, required, and optional arguments (`argument:`)
+
+The `:argument` parameter can be set to `:forbidden`, `:required`, or `:optional`.
+
+* `:forbidden` means that when the option is present, the value will be set to `true`, and `false` otherwise. For example:
+
+ ```ruby
+ option :f, :force, 'push with force', argument: :forbidden
+
+ run do |opts, args, cmd|
+ puts "Force? #{opts[:force]}"
+ end
+ ```
+
+ ```sh
+ % ./push mypackage.zip
+ Force? false
+
+ % ./push --force mypackage.zip
+ Force? true
+ ```
+
+ `:argument` is set to `:forbidden` by default.
+
+* `:required` means that the option must be followed by an argument, which will then be treated as the value for the option. It does not mean that the option itself is required. For example:
+
+ ```ruby
+ option :o, :output, 'specify output file', argument: :required
+ option :f, :fast, 'fetch faster', argument: :forbidden
+
+ run do |opts, args, cmd|
+ puts "Output file: #{opts[:output]}"
+ end
+ ```
+
+ ```sh
+ % ./fetch http://example.com/source.zip
+ Output file: nil
+
+ % ./fetch --output example.zip http://example.com/source.zip
+ Output file: example.zip
+
+ % ./fetch http://example.com/source.zip --output
+ fetch: option requires an argument -- output
+
+ % ./fetch --output --fast http://example.com/source.zip
+ fetch: option requires an argument -- output
+ ```
+
+* `:optional` means that the option can be followed by an argument. If it is, then the argument is treated as the value for the option; if it isn’t, the value for the option will be `true`. For example:
+
+ ```ruby
+ option :o, :output, 'specify output file', argument: :optional
+ option :f, :fast, 'fetch faster', argument: :forbidden
+
+ run do |opts, args, cmd|
+ puts "Output file: #{opts[:output]}"
+ end
+ ```
+
+ ```sh
+ % ./fetch http://example.com/source.zip
+ Output file: nil
+
+ % ./fetch --output example.zip http://example.com/source.zip
+ Output file: example.zip
+
+ % ./fetch http://example.com/source.zip --output
+ Output file: true
+
+ % ./fetch --output --fast http://example.com/source.zip
+ Output file: true
+ ```
+
+#### Transforming options (`transform:`)
+
The `:transform` parameter specifies how the value should be transformed. It takes any object that responds to `#call`:
```ruby
option :p, :port, 'set port', argument: :required,
transform: -> (x) { Integer(x) }
@@ -164,11 +241,11 @@
```ruby
option :p, :port, 'set port', argument: :required, default: 8080, transform: PortTransformer.new
```
-#### Options with default values
+#### Options with default values (`default:`)
The `:default` parameter sets the option value that will be used if the option is passed without an argument or isn't passed at all:
```ruby
option :a, :animal, 'add animal', default: 'giraffe', argument: :optional
@@ -180,14 +257,13 @@
```
OPTIONS
-a --animal[=<value>] add animal (default: giraffe)
```
-#### Multivalued options
+#### Multivalued options (`multiple:`)
-Each of these four methods take a `:multiple` parameter. When set to true, multiple
-option valus are accepted, and the option values will be stored in an array.
+The `:multiple` parameter allows an option to be specified more than once on the command line. When set to `true`, multiple option valus are accepted, and the option values will be stored in an array.
For example, to parse the command line options string `-o foo.txt -o bar.txt`
into an array, so that `options[:output]` contains `[ 'foo.txt', 'bar.txt' ]`,
you can use an option definition like this:
@@ -232,11 +308,11 @@
that is passed to your `run` block will be empty and the `args` array will be
`["--some=value", "-f", "yes"]`.
### Argument parsing
-Cri also supports parsing arguments, outside of options. To define the
+Cri supports parsing arguments, as well as parsing options. To define the
parameters of a command, use `#param`, which takes a symbol containing the name
of the parameter. For example:
```ruby
command = Cri::Command.define do
@@ -255,13 +331,52 @@
```
The command in this example has one parameter named `filename`. This means that
the command takes a single argument, named `filename`.
-If no parameters are specified, Cri performs no argument parsing or validation; any number of arguments is allowed. To explicitly specify that a command has no parameters, use `#no_params`:
+As with options, parameter definitions take `transform:`, which can be used for transforming and validating arguments:
```ruby
+param :port, transform: method(:Integer)
+```
+
+(*Why the distinction between argument and parameter?* A parameter is a name, e.g. `filename`, while an argument is a value for a parameter, e.g. `kitten.jpg`.)
+
+### Allowing arbitrary arguments
+
+If no parameters are specified, Cri performs no argument parsing or validation;
+any number of arguments is allowed.
+
+```ruby
+command = Cri::Command.define do
+ name 'publish'
+ usage 'publish [filename...]'
+ summary 'publishes the given file(s)'
+ description 'This command does a lot of stuff, but not option parsing.'
+
+ flag :q, :quick, 'publish quicker'
+
+ run do |opts, args, cmd|
+ args.each do |arg|
+ puts "Publishing #{arg}…"
+ end
+ end
+end
+```
+
+```bash
+% my-tool publish foo.zip bar.zip
+Publishing foo.zip…
+Publishing bar.zip…
+%
+```
+
+### Forbidding any arguments
+
+To explicitly specify that a command has no parameters, use `#no_params`:
+
+```ruby
name 'reset'
usage 'reset'
summary 'resets the site'
description '…'
no_params
@@ -279,18 +394,10 @@
%
```
A future version of Cri will likely make `#no_params` the default behavior.
-As with options, parameter definitions take `transform:`, which can be used for transforming and validating arguments:
-
-```ruby
-param :port, transform: method(:Integer)
-```
-
-(*Why the distinction between argument and parameter?* A parameter is a name, e.g. `filename`, while an argument is a value for a parameter, e.g. `kitten.jpg`.)
-
### The run block
The last part of the command defines the execution itself:
```ruby
@@ -306,13 +413,46 @@
The +Cri::CommandDSL#run+ method takes a block with the actual code to
execute. This block takes three arguments: the options, any arguments passed
to the command, and the command itself.
-Instead of defining a run block, it is possible to declare a class, the
-_command runner_ class (`Cri::CommandRunner`) that will perform the actual
-execution of the command. This makes it easier to break up large run blocks
-into manageable pieces.
+### The command runner
+
+Instead of defining a run block, it is possible to declare a class, the _command runner_ class that will perform the actual execution of the command. This makes it easier to break up large run blocks into manageable pieces.
+
+```ruby
+name 'push'
+option :f, :force, 'force'
+param :filename
+
+class MyRunner < Cri::CommandRunner
+ def run
+ puts "Pushing #{arguments[:filename]}…"
+ puts "… with force!" if options[:force]
+ end
+end
+
+runner MyRunner
+```
+
+To create a command runner, subclass `Cri::CommandRunner`, and define a `#run` method with no params. Inside the `#run` block, you can access `options` and `arguments`. Lastly, to connect the command to the command runner, call `#runner` with the class of the command runner.
+
+Here is an example interaction with the example command, defined above:
+
+```
+% push
+push: incorrect number of arguments given: expected 1, but got 0
+
+% push a
+Pushing a…
+
+% push -f
+push: incorrect number of arguments given: expected 1, but got 0
+
+% push -f a
+Pushing a…
+… with force!
+```
### Subcommands
Commands can have subcommands. For example, the `git` command-line tool would be
represented by a command that has subcommands named `commit`, `add`, and so on.