cri 2.15.1 → 2.15.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -4
- data/NEWS.md +6 -0
- data/README.md +176 -36
- data/lib/cri/command.rb +1 -1
- data/lib/cri/version.rb +1 -1
- data/test/test_command.rb +37 -0
- data/test/test_parser.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4ffb3eac4152f6f8450a1cafad2a319cc3946420de5c5a2d03d2330ac05714a9
|
4
|
+
data.tar.gz: 914f27475515b0fcad6023ec2ab70ad08b3245e0a4e24ed07130f1c472ee46b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1f0c7fe961d41ac672b11364037fc2f05c3263966b662aa8d439300812c2a7a5f5a932f7f213cf4d28cd96d43e9b159c32badb696d33adf050aad70a7473a27
|
7
|
+
data.tar.gz: 88a32db01b1c5b2c0c5b0e3967f779f1e99f6ef355f586b6dd94a7b05b0c06cb7873539002af644f45a0575d8f4574dd5d4ff76796a2cc57896ba0481012c86a
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cri (2.15.
|
4
|
+
cri (2.15.2)
|
5
5
|
colored (~> 1.2)
|
6
6
|
|
7
7
|
GEM
|
@@ -25,7 +25,7 @@ GEM
|
|
25
25
|
powerpack (0.1.2)
|
26
26
|
rainbow (3.0.0)
|
27
27
|
rake (12.3.1)
|
28
|
-
rubocop (0.
|
28
|
+
rubocop (0.59.2)
|
29
29
|
jaro_winkler (~> 1.5.1)
|
30
30
|
parallel (~> 1.10)
|
31
31
|
parser (>= 2.5, != 2.5.1.1)
|
@@ -42,7 +42,7 @@ GEM
|
|
42
42
|
term-ansicolor (1.6.0)
|
43
43
|
tins (~> 1.0)
|
44
44
|
thor (0.19.4)
|
45
|
-
tins (1.
|
45
|
+
tins (1.17.0)
|
46
46
|
unicode-display_width (1.4.0)
|
47
47
|
yard (0.9.16)
|
48
48
|
|
@@ -59,4 +59,4 @@ DEPENDENCIES
|
|
59
59
|
yard
|
60
60
|
|
61
61
|
BUNDLED WITH
|
62
|
-
1.16.
|
62
|
+
1.16.2
|
data/NEWS.md
CHANGED
data/README.md
CHANGED
@@ -105,32 +105,109 @@ flag nil, :more, 'do even more stuff'
|
|
105
105
|
option :s, :stuff, 'specify stuff to do', argument: :required
|
106
106
|
```
|
107
107
|
|
108
|
-
|
109
|
-
|
110
|
-
* `Cri::CommandDSL#option` or `Cri::CommandDSL#opt` (include an `argument` parameter: `:required` or `:optional` that specifies if the option requires or allows an argument)
|
111
|
-
* `Cri::CommandDSL#flag` (implies no arguments passed to option)
|
112
|
-
|
113
|
-
The following _deprecated_ methods can also be used to define options:
|
114
|
-
|
115
|
-
* `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.)
|
116
|
-
* `Cri::CommandDSL#optional` (implies an option that can optionally include an argument -- deprecated because `#optional` looks too similar to `#option`.)
|
117
|
-
|
118
|
-
All these methods take these arguments:
|
108
|
+
The most generic way of definition an option is using either `#option` or `#opt`. It takes the following arguments:
|
119
109
|
|
120
110
|
1. a short option name
|
121
111
|
2. a long option name
|
122
112
|
3. a description
|
123
113
|
4. optional extra parameters
|
114
|
+
* `argument:` (default: `:forbidden`)
|
115
|
+
* `transform:`
|
116
|
+
* `default:`
|
117
|
+
* `multiple:` (default: `false`)
|
118
|
+
5. optionally, a block
|
119
|
+
|
120
|
+
In more detail:
|
121
|
+
|
122
|
+
* 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.
|
123
|
+
|
124
|
+
* 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`.
|
125
|
+
|
126
|
+
* The extra parameters, `argument:`, `multiple:`, `default:`, and `transform:`, are described in the sections below.
|
127
|
+
|
128
|
+
* 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.
|
129
|
+
|
130
|
+
There are several convenience methods that are alternatives to `#option`/`#opt`:
|
131
|
+
|
132
|
+
* `#flag` sets `argument:` to `:forbidden`
|
133
|
+
* (**deprecated**) `#required` sets `argument:` to `:required` -- deprecated because `#required` suggests that the option is required, wich is incorrect; the _argument_ is required.)
|
134
|
+
* (**deprecated**) `#optional` sets `argument:` to `:optional` -- deprecated because `#optional` looks too similar to `#option`.
|
135
|
+
|
136
|
+
#### Forbidden, required, and optional arguments (`argument:`)
|
137
|
+
|
138
|
+
The `:argument` parameter can be set to `:forbidden`, `:required`, or `:optional`.
|
139
|
+
|
140
|
+
* `:forbidden` means that when the option is present, the value will be set to `true`, and `false` otherwise. For example:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
option :f, :force, 'push with force', argument: :forbidden
|
144
|
+
|
145
|
+
run do |opts, args, cmd|
|
146
|
+
puts "Force? #{opts[:force]}"
|
147
|
+
end
|
148
|
+
```
|
149
|
+
|
150
|
+
```sh
|
151
|
+
% ./push mypackage.zip
|
152
|
+
Force? false
|
153
|
+
|
154
|
+
% ./push --force mypackage.zip
|
155
|
+
Force? true
|
156
|
+
```
|
157
|
+
|
158
|
+
`:argument` is set to `:forbidden` by default.
|
159
|
+
|
160
|
+
* `: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:
|
124
161
|
|
125
|
-
|
126
|
-
|
127
|
-
|
162
|
+
```ruby
|
163
|
+
option :o, :output, 'specify output file', argument: :required
|
164
|
+
option :f, :fast, 'fetch faster', argument: :forbidden
|
128
165
|
|
129
|
-
|
130
|
-
|
131
|
-
|
166
|
+
run do |opts, args, cmd|
|
167
|
+
puts "Output file: #{opts[:output]}"
|
168
|
+
end
|
169
|
+
```
|
170
|
+
|
171
|
+
```sh
|
172
|
+
% ./fetch http://example.com/source.zip
|
173
|
+
Output file: nil
|
174
|
+
|
175
|
+
% ./fetch --output example.zip http://example.com/source.zip
|
176
|
+
Output file: example.zip
|
177
|
+
|
178
|
+
% ./fetch http://example.com/source.zip --output
|
179
|
+
fetch: option requires an argument -- output
|
180
|
+
|
181
|
+
% ./fetch --output --fast http://example.com/source.zip
|
182
|
+
fetch: option requires an argument -- output
|
183
|
+
```
|
184
|
+
|
185
|
+
* `: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:
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
option :o, :output, 'specify output file', argument: :optional
|
189
|
+
option :f, :fast, 'fetch faster', argument: :forbidden
|
190
|
+
|
191
|
+
run do |opts, args, cmd|
|
192
|
+
puts "Output file: #{opts[:output]}"
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
196
|
+
```sh
|
197
|
+
% ./fetch http://example.com/source.zip
|
198
|
+
Output file: nil
|
199
|
+
|
200
|
+
% ./fetch --output example.zip http://example.com/source.zip
|
201
|
+
Output file: example.zip
|
132
202
|
|
133
|
-
|
203
|
+
% ./fetch http://example.com/source.zip --output
|
204
|
+
Output file: true
|
205
|
+
|
206
|
+
% ./fetch --output --fast http://example.com/source.zip
|
207
|
+
Output file: true
|
208
|
+
```
|
209
|
+
|
210
|
+
#### Transforming options (`transform:`)
|
134
211
|
|
135
212
|
The `:transform` parameter specifies how the value should be transformed. It takes any object that responds to `#call`:
|
136
213
|
|
@@ -166,7 +243,7 @@ Default values are not transformed:
|
|
166
243
|
option :p, :port, 'set port', argument: :required, default: 8080, transform: PortTransformer.new
|
167
244
|
```
|
168
245
|
|
169
|
-
#### Options with default values
|
246
|
+
#### Options with default values (`default:`)
|
170
247
|
|
171
248
|
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:
|
172
249
|
|
@@ -182,10 +259,9 @@ OPTIONS
|
|
182
259
|
-a --animal[=<value>] add animal (default: giraffe)
|
183
260
|
```
|
184
261
|
|
185
|
-
#### Multivalued options
|
262
|
+
#### Multivalued options (`multiple:`)
|
186
263
|
|
187
|
-
|
188
|
-
option valus are accepted, and the option values will be stored in an array.
|
264
|
+
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.
|
189
265
|
|
190
266
|
For example, to parse the command line options string `-o foo.txt -o bar.txt`
|
191
267
|
into an array, so that `options[:output]` contains `[ 'foo.txt', 'bar.txt' ]`,
|
@@ -234,7 +310,7 @@ that is passed to your `run` block will be empty and the `args` array will be
|
|
234
310
|
|
235
311
|
### Argument parsing
|
236
312
|
|
237
|
-
Cri
|
313
|
+
Cri supports parsing arguments, as well as parsing options. To define the
|
238
314
|
parameters of a command, use `#param`, which takes a symbol containing the name
|
239
315
|
of the parameter. For example:
|
240
316
|
|
@@ -257,7 +333,46 @@ end
|
|
257
333
|
The command in this example has one parameter named `filename`. This means that
|
258
334
|
the command takes a single argument, named `filename`.
|
259
335
|
|
260
|
-
|
336
|
+
As with options, parameter definitions take `transform:`, which can be used for transforming and validating arguments:
|
337
|
+
|
338
|
+
```ruby
|
339
|
+
param :port, transform: method(:Integer)
|
340
|
+
```
|
341
|
+
|
342
|
+
(*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`.)
|
343
|
+
|
344
|
+
### Allowing arbitrary arguments
|
345
|
+
|
346
|
+
If no parameters are specified, Cri performs no argument parsing or validation;
|
347
|
+
any number of arguments is allowed.
|
348
|
+
|
349
|
+
```ruby
|
350
|
+
command = Cri::Command.define do
|
351
|
+
name 'publish'
|
352
|
+
usage 'publish [filename...]'
|
353
|
+
summary 'publishes the given file(s)'
|
354
|
+
description 'This command does a lot of stuff, but not option parsing.'
|
355
|
+
|
356
|
+
flag :q, :quick, 'publish quicker'
|
357
|
+
|
358
|
+
run do |opts, args, cmd|
|
359
|
+
args.each do |arg|
|
360
|
+
puts "Publishing #{arg}…"
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
```
|
365
|
+
|
366
|
+
```bash
|
367
|
+
% my-tool publish foo.zip bar.zip
|
368
|
+
Publishing foo.zip…
|
369
|
+
Publishing bar.zip…
|
370
|
+
%
|
371
|
+
```
|
372
|
+
|
373
|
+
### Forbidding any arguments
|
374
|
+
|
375
|
+
To explicitly specify that a command has no parameters, use `#no_params`:
|
261
376
|
|
262
377
|
```ruby
|
263
378
|
name 'reset'
|
@@ -281,14 +396,6 @@ Resetting…
|
|
281
396
|
|
282
397
|
A future version of Cri will likely make `#no_params` the default behavior.
|
283
398
|
|
284
|
-
As with options, parameter definitions take `transform:`, which can be used for transforming and validating arguments:
|
285
|
-
|
286
|
-
```ruby
|
287
|
-
param :port, transform: method(:Integer)
|
288
|
-
```
|
289
|
-
|
290
|
-
(*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`.)
|
291
|
-
|
292
399
|
### The run block
|
293
400
|
|
294
401
|
The last part of the command defines the execution itself:
|
@@ -308,10 +415,43 @@ The +Cri::CommandDSL#run+ method takes a block with the actual code to
|
|
308
415
|
execute. This block takes three arguments: the options, any arguments passed
|
309
416
|
to the command, and the command itself.
|
310
417
|
|
311
|
-
|
312
|
-
|
313
|
-
execution of the command. This makes it easier to break up large run blocks
|
314
|
-
|
418
|
+
### The command runner
|
419
|
+
|
420
|
+
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.
|
421
|
+
|
422
|
+
```ruby
|
423
|
+
name 'push'
|
424
|
+
option :f, :force, 'force'
|
425
|
+
param :filename
|
426
|
+
|
427
|
+
class MyRunner < Cri::CommandRunner
|
428
|
+
def run
|
429
|
+
puts "Pushing #{arguments[:filename]}…"
|
430
|
+
puts "… with force!" if options[:force]
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
runner MyRunner
|
435
|
+
```
|
436
|
+
|
437
|
+
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.
|
438
|
+
|
439
|
+
Here is an example interaction with the example command, defined above:
|
440
|
+
|
441
|
+
```
|
442
|
+
% push
|
443
|
+
push: incorrect number of arguments given: expected 1, but got 0
|
444
|
+
|
445
|
+
% push a
|
446
|
+
Pushing a…
|
447
|
+
|
448
|
+
% push -f
|
449
|
+
push: incorrect number of arguments given: expected 1, but got 0
|
450
|
+
|
451
|
+
% push -f a
|
452
|
+
Pushing a…
|
453
|
+
… with force!
|
454
|
+
```
|
315
455
|
|
316
456
|
### Subcommands
|
317
457
|
|
data/lib/cri/command.rb
CHANGED
@@ -311,7 +311,7 @@ module Cri
|
|
311
311
|
return if subcommand.nil?
|
312
312
|
|
313
313
|
# Run
|
314
|
-
subcommand.run(opts_and_args_after_subcmd, opts_before_subcmd, hard_exit: hard_exit)
|
314
|
+
subcommand.run(opts_and_args_after_subcmd, parent_opts.merge(opts_before_subcmd), hard_exit: hard_exit)
|
315
315
|
end
|
316
316
|
rescue CriExitException => e
|
317
317
|
exit(e.error? ? 1 : 0) if hard_exit
|
data/lib/cri/version.rb
CHANGED
data/test/test_command.rb
CHANGED
@@ -858,5 +858,42 @@ module Cri
|
|
858
858
|
assert_equal [], lines(out)
|
859
859
|
assert_equal [], lines(err)
|
860
860
|
end
|
861
|
+
|
862
|
+
def test_propagate_options_two_levels_down
|
863
|
+
cmd_a = Cri::Command.define do
|
864
|
+
name 'a'
|
865
|
+
flag :t, :test, 'test'
|
866
|
+
end
|
867
|
+
|
868
|
+
cmd_b = cmd_a.define_command('b') do
|
869
|
+
end
|
870
|
+
|
871
|
+
cmd_b.define_command('c') do
|
872
|
+
run do |opts, _args|
|
873
|
+
puts "test? #{opts[:test].inspect}!"
|
874
|
+
end
|
875
|
+
end
|
876
|
+
|
877
|
+
# test -t last
|
878
|
+
out, err = capture_io_while do
|
879
|
+
cmd_a.run(%w[b c -t])
|
880
|
+
end
|
881
|
+
assert_equal ['test? true!'], lines(out)
|
882
|
+
assert_equal [], lines(err)
|
883
|
+
|
884
|
+
# test -t mid
|
885
|
+
out, err = capture_io_while do
|
886
|
+
cmd_a.run(%w[b -t c])
|
887
|
+
end
|
888
|
+
assert_equal ['test? true!'], lines(out)
|
889
|
+
assert_equal [], lines(err)
|
890
|
+
|
891
|
+
# test -t first
|
892
|
+
out, err = capture_io_while do
|
893
|
+
cmd_a.run(%w[-t b c])
|
894
|
+
end
|
895
|
+
assert_equal ['test? true!'], lines(out)
|
896
|
+
assert_equal [], lines(err)
|
897
|
+
end
|
861
898
|
end
|
862
899
|
end
|
data/test/test_parser.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cri
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.15.
|
4
|
+
version: 2.15.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Defreyne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colored
|