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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13bfd2fd90ec81e8bcc39c154881b0e54ac05696fce5a237cf17d3204b543c9c
4
- data.tar.gz: d14b7481ce82280b035fd0f20a78e62c417e47efe545d24bebf5302b1668fb3d
3
+ metadata.gz: 4ffb3eac4152f6f8450a1cafad2a319cc3946420de5c5a2d03d2330ac05714a9
4
+ data.tar.gz: 914f27475515b0fcad6023ec2ab70ad08b3245e0a4e24ed07130f1c472ee46b5
5
5
  SHA512:
6
- metadata.gz: 06ba0a5ab7632765e40bcf3b3245418f90e414b106fad162cbd4b59e50af3152bfed637da0fb9ed3b074922dcecb8e78d6d7501a849a6763d980be3030aee7b4
7
- data.tar.gz: 273ef37de868f8b546d084b48073a8f13d67b7fb57f765b4764bf4305c5992e863b46e016e45fbf4888b48291dc017a1892d6394a564374402a0466cafdb1e41
6
+ metadata.gz: a1f0c7fe961d41ac672b11364037fc2f05c3263966b662aa8d439300812c2a7a5f5a932f7f213cf4d28cd96d43e9b159c32badb696d33adf050aad70a7473a27
7
+ data.tar.gz: 88a32db01b1c5b2c0c5b0e3967f779f1e99f6ef355f586b6dd94a7b05b0c06cb7873539002af644f45a0575d8f4574dd5d4ff76796a2cc57896ba0481012c86a
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cri (2.15.1)
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.58.2)
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.16.3)
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.4
62
+ 1.16.2
data/NEWS.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Cri News
2
2
 
3
+ ## 2.15.2
4
+
5
+ Fixes:
6
+
7
+ * Fixed option propagation for two levels or more (#85, #86)
8
+
3
9
  ## 2.15.1
4
10
 
5
11
  Fixes:
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
- Options can be defined using the following methods:
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
- Either the short or the long form can be nil, but not both (because that
126
- would not make any sense). In the example above, the `--more` option has no
127
- short form.
162
+ ```ruby
163
+ option :o, :output, 'specify output file', argument: :required
164
+ option :f, :fast, 'fetch faster', argument: :forbidden
128
165
 
129
- Each of the above methods also take a block, which will be executed when the
130
- option is found. The arguments to the block are the option value (`true` in
131
- case the option does not have an argument) and the command.
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
- #### Transforming options
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
- Each of these four methods take a `:multiple` parameter. When set to true, multiple
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 also supports parsing arguments, outside of options. To define the
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
- 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`:
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
- Instead of defining a run block, it is possible to declare a class, the
312
- _command runner_ class (`Cri::CommandRunner`) that will perform the actual
313
- execution of the command. This makes it easier to break up large run blocks
314
- into manageable pieces.
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
 
@@ -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
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Cri
4
4
  # The current Cri version.
5
- VERSION = '2.15.1'
5
+ VERSION = '2.15.2'
6
6
  end
@@ -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
@@ -455,6 +455,7 @@ module Cri
455
455
  port = Class.new do
456
456
  def call(str)
457
457
  raise unless str.is_a?(String)
458
+
458
459
  Integer(str)
459
460
  end
460
461
  end.new
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.1
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-08-31 00:00:00.000000000 Z
11
+ date: 2018-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colored