cl 0.1.12 → 0.1.13

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
  SHA1:
3
- metadata.gz: 9a4e37103d294db33627a373c3d1d19b2113b0a6
4
- data.tar.gz: 7733d1f9d8f3ca199fcea0a697e679829e758597
3
+ metadata.gz: 6c566fcf9fc49fe3d3565f2f5bad09aef48ff75a
4
+ data.tar.gz: 5dcdd36b075b21ece0b05780955029467d29986c
5
5
  SHA512:
6
- metadata.gz: bd906f7c16c3ea0fed71806baf8c12b0e78f62ebaa8f61ea398223d51383b22075bbbfa5afa87a95e549469fad46af93e231551cc01d12207379fda5ff4d55d8
7
- data.tar.gz: 26459916c941da8486acc6f92e87c89f91f03b37115b83149fb231843738c4eb03968c0c4b27737b8a9b525e0e7f51df6bfe21f989385622bb9bc3e3d8be002b
6
+ metadata.gz: 13b77f339a3d479f8a6b7295ee9f0ba22b0b352ad439af63223a31ab062d34936313f34a44cce9042099d38fea7243d31f64c70801b23a76cf765af848220297
7
+ data.tar.gz: 21bde54f28368e44ca3decb3bb0337e2e5c58606a0474e53beedaeae18540747ea9fbdc60744164079374174b6c24bc9d85cb47438c2fb35a18341efed195199
@@ -1,11 +1,12 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.0 (unreleased)
3
+ ## 0.1.x
4
4
 
5
5
  ### Added
6
6
 
7
7
  * Add config, reading from env vars and yml files (inspired by gem-release)
8
8
  * Add `abstract` in order to signal a cmd is a base class that is not meant to be executed
9
+ * Add `examples` in order to add examples for the command to the help output
9
10
  * Add `required :one, [:two, :three]` (DNF, i.e: either `:one` or both `:two` and `:three` must be given)
10
11
  * Add `opt '--one STR', type: :array` for options that can be given multiple times
11
12
  * Add `opt '--one STR', default: 'one'`
@@ -13,6 +14,7 @@
13
14
  * Add `opt '--one', alias: :other`
14
15
  * Add `opt '--one', deprecated: 'message'`, and `cmd.deprected_opts`, so clients can look up which deprecated options were used
15
16
  * Add `opt '--one', alias: :other, deprecated: :other`, so that `cmd.deprecated_opts` returns the alias name if it was used
17
+ * Add `opt '--int INT', min: 10, type: :integer`
16
18
  * Add `opt '--int INT', max: 10, type: :integer`
17
19
  * Add `opt '--one STR', format: /.+/`
18
20
  * Add `opt '--one STR', enum: ['one', /\w+/]`
@@ -26,8 +28,8 @@
26
28
  * Much improved help output, modeled after rubygems' help output
27
29
  * Cl is now a class
28
30
  * Use the regstry gem, remove the local Registry implementation
29
- * If a flag (boolean option) has a default `true` automatically add `[no-]` to
30
- it, allowing to opt out
31
+ * If a flag (boolean option) has a default `true` automatically add `[no-]` to it, allowing to opt out
32
+ * Runners are now registered in order to make them more easily extendable
31
33
 
32
34
  ### Removed
33
35
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cl (0.1.11)
4
+ cl (0.1.12)
5
5
  regstry (~> 1.0.3)
6
6
 
7
7
  GEM
@@ -9,7 +9,7 @@ GEM
9
9
  specs:
10
10
  diff-lcs (1.3)
11
11
  memfs (1.0.0)
12
- regstry (1.0.6)
12
+ regstry (1.0.9)
13
13
  rspec (3.8.0)
14
14
  rspec-core (~> 3.8.0)
15
15
  rspec-expectations (~> 3.8.0)
data/NOTES.md CHANGED
@@ -1,9 +1,13 @@
1
- - properly catch errors, see examples/cast etc
2
- - add conditional required: ->(opts) { opts[:key].nil? }
3
-
4
-
1
+ x add args descriptions
2
+ x add Cmd#examples
3
+ x add min to opts
4
+ x error message for required option (see readme/required)
5
+ x document arg splats, types
6
+ x make sure runners raise proper exceptions if a command was not found
7
+ x register runners, accept any object as a runner, too
8
+ x readme passing a block to opt
9
+ x complete readme (e.g. description, summary, examples)
10
+ x add toc
11
+
12
+ - add yard docs
5
13
  - refactor Help::Cmd and Table so that everything goes into one big table
6
-
7
- - add args descriptions
8
-
9
-
data/README.md CHANGED
@@ -1,16 +1,47 @@
1
- # CL [![Build Status](https://travis-ci.org/svenfuchs/cl.svg?branch=master)](https://travis-ci.org/svenfuchs/cl)
1
+ # Cl [![Build Status](https://travis-ci.org/svenfuchs/cl.svg?branch=master)](https://travis-ci.org/svenfuchs/cl)
2
2
 
3
3
  This library wraps Ruby's `OptionParser` in order to make it easier to use it
4
4
  in an object oriented context.
5
5
 
6
6
  It uses `OptionParser` for parsing your options, so you get all the goodness that
7
- this true gem from Ruby's stoneage provides. But on top of that it also provides
8
- a rich DSL for defining, validating, and normalizing options, and automatic and
9
- gorgeous help output (modelled after Rubygem's `gem --help` output).
7
+ this gem from Ruby's stoneage provides.
8
+
9
+ But on top of that it also provides a rich DSL for defining, validating, and
10
+ normalizing options, as well as automatic and gorgeous help output (modeled
11
+ after Rubygem's `gem --help` output).
12
+
13
+ Further documentation is available on [rubydoc.info](https://www.rubydoc.info/github/svenfuchs/cl)
14
+
15
+ ## Table of Contents
16
+
17
+ * [Basic Usage](#basic-usage)
18
+ * [Command Registry](#command-registry)
19
+ * [Runners](#runners)
20
+ * [Command DSL](#command-dsl)
21
+ * [Description, Summary, Examples](#description-summary-examples)
22
+ * [Arguments](#arguments)
23
+ * [Types](#types)
24
+ * [Splat](#splat)
25
+ * [Options](#options)
26
+ * [Aliases](#aliases)
27
+ * [Defaults](#defaults)
28
+ * [Deprecations](#deprecations)
29
+ * [Downcase](#downcase)
30
+ * [Enum](#enum)
31
+ * [Example](#example)
32
+ * [Format](#format)
33
+ * [Internal](#internal)
34
+ * [Min and Max](#min-and-max)
35
+ * [See Also](#see-also)
36
+ * [Types](#types)
37
+ * [Required Options](#required-options)
38
+ * [Config Files](#config-files)
39
+ * [Environment Variables](#environment-variables)
10
40
 
11
41
  ## Basic Usage
12
42
 
13
43
  ```ruby
44
+ # lib/cli/owners/add.rb
14
45
  module Owners
15
46
  class Add < Cl::Cmd
16
47
  summary 'Add one or more owners to an existing owner group'
@@ -19,23 +50,43 @@ module Owners
19
50
  Use this command to add one or more owners to an existing
20
51
  owner group.
21
52
 
22
- These will be visible in [...]
53
+ [...]
23
54
  str
24
55
 
25
56
  args :owners
26
57
 
27
- opt '-t', '--to TO', 'An existing owner group' do |value|
28
- opts[:to] = value
58
+ opt '-t', '--to TO', 'An existing owner group'
59
+
60
+ def run
61
+ # add owners as listed in `owners` to the group given in
62
+ # `to`, as well as `opts[:to]`.
29
63
  end
30
64
  end
31
65
  end
66
+
67
+ # bin/owners
68
+ Cl.new('owners').run(ARGV)
32
69
  ```
33
70
 
71
+ Running this, e.g. using `bin/owners add one,two --to group` will instantiate the
72
+ class `Owners::Add`, and call the method `run` on it.
73
+
34
74
  Help output:
35
75
 
36
76
  ```txt
37
77
  Usage: owners add [owners] [options]
38
78
 
79
+ Summary:
80
+
81
+ Add one or more owners to an existing owner group
82
+
83
+ Description:
84
+
85
+ Use this command to add one or more owners to an existing
86
+ owner group.
87
+
88
+ These will be visible in [...]
89
+
39
90
  Arguments:
40
91
 
41
92
  owners type: string
@@ -44,15 +95,848 @@ Options:
44
95
 
45
96
  -t --to TO An existing owner group (type: string, required: true)
46
97
  --help Get help on this command (type: flag)
98
+ ```
47
99
 
48
- Summary:
100
+ ### Command Registry
49
101
 
50
- Add one or more owners to an existing owner group
102
+ Commands are Ruby classes that extend the class `Cl::Cmd`.
51
103
 
52
- Description:
104
+ They register to a [Ruby class registry](https://github.com/svenfuchs/registry) in order
105
+ to decouple looking up command classes from their Ruby namespace.
53
106
 
54
- Use this command to add one or more owners to an existing
55
- owner group.
107
+ For example:
56
108
 
57
- These will be visible in [...]
109
+ ```ruby
110
+ module One
111
+ class Cmd < Cl::Cmd
112
+ register :one
113
+ end
114
+ end
115
+
116
+ module Two
117
+ class Cmd < Cl::Cmd
118
+ register :two
119
+ end
120
+ end
121
+
122
+ Cl::Cmd[:one] # => One::Cmd
123
+ Cl::Cmd[:two] # => Two::Cmd
124
+ ```
125
+
126
+ Commands auto register themselves with the underscored name of the last part of
127
+ their class name (as seen in the example above). It is possible to ovewrite this
128
+ key by manually registering the class, like so:
129
+
130
+ ```ruby
131
+ module One
132
+ class Cmd < Cl::Cmd
133
+ register :'cmd:one'
134
+ end
135
+ end
136
+ ```
137
+
138
+ ### Runners
139
+
140
+ Runners lookup the command to execute from the registry, by checking the
141
+ arguments given by the user for registered command keys.
142
+
143
+ With the two command classes `One` and `Two` from the example above (and
144
+ assuming that the executable that calls `Cl` is `bin/run`) the default runner
145
+ would recognize and run the following commands:
146
+
147
+ ```
148
+ $ bin/run one something else
149
+ # instantiates One, passing the args array `["something", "else"]`, and calls `run`
150
+
151
+ $ bin/run two something else
152
+ # instantiates One, passing an empty args arry `[]`, and calls `run`
153
+ ```
154
+
155
+ The default runner also supports nested namespaces, and checks for command classes
156
+ with keys separated by colons. For instance:
157
+
158
+ ```ruby
159
+ module Git
160
+ class Pull < Cl::Cmd
161
+ register :'git:pull'
162
+ end
163
+ end
164
+
165
+ module Git
166
+ class Push < Cl::Cmd
167
+ register :'git:push'
168
+ end
169
+ end
170
+ ```
171
+
172
+ With these classes registered (and assuming the executable that calls `Cl` is
173
+ `bin/git`) the default runner would recognize and run the following commands:
174
+
175
+ ```
176
+ $ bin/git pull:master # instantiates Git::Pull, and passes ["master"] as args
177
+ $ bin/git pull master # does the same
178
+
179
+ $ bin/git push:master # instantiates Git::Push, and passes ["master"] as args
180
+ $ bin/git push master # does the same
181
+ ```
182
+
183
+ Runners are registered on the module `Cl::Runner`. It is possible to register custom
184
+ runners, and use them by passing the option `runner` to `Cl.new`:
185
+
186
+ ```
187
+ # in bin/run
188
+ Cli.new('run', runner: :custom).run(ARGV)
189
+
190
+ # anywhere in your library
191
+ class Runner
192
+ Cl::Runner.register :custom, self
193
+
194
+ def initialize(ctx, args)
195
+ # ...
196
+ end
197
+
198
+ def run
199
+ const = identify_cmd_class_from_args
200
+ const.new(ctx, args).run
201
+ end
202
+ end
203
+ ```
204
+
205
+ See `Cl::Runner::Default` for more details.
206
+
207
+ There also is an experimental runner `:multi`, which supports rake-style
208
+ execution of multiple commands at once, like so:
209
+
210
+ ```
211
+ bin/rake db:drop production -f db:create db:migrate production -v 1
212
+ ```
213
+
214
+ See the example [rakeish](blob/master/examples/rakeish) for more details.
215
+
216
+ ## Command DSL
217
+
218
+ The DSL is defined on the class body.
219
+
220
+ ## Description, Summary, Examples
221
+
222
+ The description, summary, and examples are used in the help output.
223
+
224
+ ```
225
+ module Owners
226
+ class Add < Cl::Cmd
227
+ summary 'Add one or more owners to an existing owner group'
228
+
229
+ description <<~str
230
+ Use this command to add one or more owners to an existing
231
+ owner group.
232
+ str
233
+
234
+ examples <<~str
235
+ Adding a single user to the group admins:
236
+
237
+ ./bin/owners add user --to admins
238
+
239
+ Adding a several users at once:
240
+
241
+ ./bin/owners add one two three --to admins
242
+ str
243
+ end
244
+ end
58
245
  ```
246
+
247
+ ### Arguments
248
+
249
+ Arguments can be declared like so:
250
+
251
+ ```ruby
252
+ arg :arg_name, description: 'arg description', type: :[array|string|integer|float|boolean]
253
+ ```
254
+
255
+ This will define an `attr_accessor` on the `Cmd` class. I.e. in the following
256
+ example the method `ownsers` will be available on the `Cmd` instance:
257
+
258
+ ```ruby
259
+ class Add < Cl::Cmd
260
+ arg :owner
261
+
262
+ def run
263
+ p owner
264
+ end
265
+ end
266
+
267
+ Cl.new('owners').run(%w(add one))
268
+
269
+ # => "one"
270
+
271
+ ```
272
+
273
+ #### Types
274
+
275
+ Arguments can have a type. Known types are: `:array`, `:string`, `:integer`,
276
+ `:float`, `:boolean`.
277
+
278
+ The type `:array` makes sure the argument accessible on the `Cmd` instance is a
279
+ Ruby Array. (This currently only supports arrays of strings).
280
+
281
+ If the option `sep` is given on the argument, then the argument value is split
282
+ using this separator.
283
+
284
+ ```ruby
285
+ class Add < Cl::Cmd
286
+ arg :owners, type: :array, sep: ','
287
+
288
+ def run
289
+ p owners
290
+ end
291
+ end
292
+
293
+ Cl.new('owners').run(%w(add one,two))
294
+
295
+ # => ["one", "two"]
296
+
297
+ ```
298
+
299
+ Other types cast the given argument to the expected Ruby type.
300
+
301
+ ```ruby
302
+ class Cmd < Cl::Cmd
303
+ arg :one, type: :integer
304
+ arg :two, type: :float
305
+ arg :three, type: :boolean
306
+
307
+ def run
308
+ p [one.class, two.class, three.class]
309
+ end
310
+ end
311
+
312
+ Cl.new('owners').run(%w(cmd 1 2.1 yes))
313
+
314
+ # => [Integer, Float, TrueClass]
315
+
316
+ ```
317
+
318
+ #### Splat
319
+
320
+ Array arguments support splats, modeled after Ruby argument splats.
321
+
322
+ For example:
323
+
324
+ ```ruby
325
+ class Cmd < Cl::Cmd
326
+ arg :one, type: :integer
327
+ arg :two, type: :float
328
+ arg :three, type: :boolean
329
+
330
+ def run
331
+ p [one.class, two.class, three.class]
332
+ end
333
+ end
334
+
335
+ Cl.new('owners').run(%w(cmd 1 2.1 yes))
336
+
337
+ # => [Integer, Float, TrueClass]
338
+
339
+ ```
340
+
341
+ ### Options
342
+
343
+ Declaring options can be done by calling the method `opt` on the class body.
344
+
345
+ This will add the option, if given by the user, to the hash `opts` on the `Cmd` instance.
346
+ It also defines a reader method that returns the respective value from the `opts` hash,
347
+ and a predicate that will be true if the option has been given.
348
+
349
+ For example:
350
+
351
+ ```ruby
352
+ class Add < Cl::Cmd
353
+ opt '--to GROUP', 'Target group to add owners to'
354
+
355
+ def run
356
+ p opts, to, to?
357
+ end
358
+ end
359
+
360
+ Cl.new('owners').run(%w(add --to one))
361
+
362
+ # Output:
363
+ #
364
+ # {"to" => "one"}
365
+ # "one"
366
+ # true
367
+
368
+ Cl.new('owners').run(%w(add --help))
369
+
370
+ # Usage: opts add [options]
371
+ #
372
+ # Options:
373
+ #
374
+ # --to GROUP Target group to add owners to (type: string)
375
+ # --help Get help on this command
376
+
377
+ ```
378
+
379
+ Options optionally accept a block in case custom normalization is needed.
380
+
381
+ Depending on the block's arity the following arguments are passed to the block:
382
+ option value, option name, option type, collection of all options defined on
383
+ the command.
384
+
385
+ ```ruby
386
+ class Add < Cl::Cmd
387
+ # depending on its arity the block can receive:
388
+ #
389
+ # * value
390
+ # * value, name
391
+ # * value, name, type
392
+ # * value, name, type, opts
393
+ opt '--to GROUP' do |value|
394
+ opts[:to] = "#{value.upcase}!"
395
+ end
396
+
397
+ def run
398
+ p to
399
+ end
400
+ end
401
+
402
+ Cl.new('owners').run(%w(add --to one))
403
+
404
+ # Output:
405
+ #
406
+ # "ONE!"
407
+
408
+ ```
409
+
410
+ #### Aliases
411
+
412
+ Options can have one or many alias names, given as a Symbol or Array of Symbols:
413
+
414
+ ```ruby
415
+ class Add < Cl::Cmd
416
+ opt '--to GROUP', alias: :group
417
+
418
+ def run
419
+ p opts, to, to?, group, group?
420
+ end
421
+ end
422
+
423
+ Cl.new('owners').run(%w(add --to one))
424
+
425
+ # Output:
426
+ #
427
+ # {"to" => "one"}
428
+ # "one"
429
+ # true
430
+ # "one"
431
+ # true
432
+
433
+ ```
434
+
435
+ #### Defaults
436
+
437
+ Options can have a default value.
438
+
439
+ I.e. this value is going to be used if the user does not provide the option:
440
+
441
+ ```ruby
442
+ class Add < Cl::Cmd
443
+ opt '--to GROUP', default: 'default'
444
+
445
+ def run
446
+ p to
447
+ end
448
+ end
449
+
450
+ Cl.new('owners').run(%w(add))
451
+
452
+ # Output:
453
+ #
454
+ # "default"
455
+
456
+ ```
457
+
458
+ #### Deprecations
459
+
460
+ Options, and option alias name can be deprecated.
461
+
462
+ For a deprecated option:
463
+
464
+ ```ruby
465
+ class Add < Cl::Cmd
466
+ opt '--to GROUP'
467
+ opt '--target GROUP', deprecated: 'Deprecated: --target'
468
+
469
+ def run
470
+ p to, deprecated_opts
471
+ end
472
+ end
473
+
474
+ Cl.new('owners').run(%w(add --target one))
475
+
476
+ # Output:
477
+ #
478
+ # "one"
479
+ # {:target=>'Deprecated: --target'}
480
+
481
+
482
+ ```
483
+
484
+ For a deprecated option alias name:
485
+
486
+ ```ruby
487
+ class Add < Cl::Cmd
488
+ opt '--to GROUP', alias: :target, deprecated: :target
489
+
490
+ def run
491
+ p to, deprecated_opts
492
+ end
493
+ end
494
+
495
+ Cl.new('owners').run(%w(add --target one))
496
+
497
+ # Output:
498
+ #
499
+ # "one"
500
+ # {:target=>:to}
501
+
502
+
503
+ ```
504
+
505
+ #### Downcase
506
+
507
+ Options can be declared to be downcased.
508
+
509
+ For example:
510
+
511
+ ```ruby
512
+ class Add < Cl::Cmd
513
+ opt '--to GROUP', downcase: true
514
+
515
+ def run
516
+ p to
517
+ end
518
+ end
519
+
520
+ Cl.new('owners').run(%w(add --to ONE))
521
+
522
+ # Output:
523
+ #
524
+ # "one"
525
+
526
+ ```
527
+
528
+ #### Enum
529
+
530
+ Options can be enums (i.e. have known values).
531
+
532
+ If an unknown values is given by the user the parser will reject the option,
533
+ and print the help output for this command.
534
+
535
+ For example:
536
+
537
+ ```ruby
538
+ class Add < Cl::Cmd
539
+ opt '--to GROUP', enum: %w(one two)
540
+
541
+ def run
542
+ p to
543
+ end
544
+ end
545
+
546
+ Cl.new('owners').run(%w(add --to one))
547
+
548
+ # Output:
549
+ #
550
+ # "one"
551
+
552
+ Cl.new('owners').run(%w(add --to unknown))
553
+
554
+ # Unknown value: to=unknown (known values: one, two)
555
+ #
556
+ # Usage: enum add [options]
557
+ #
558
+ # Options: ...
559
+
560
+ ```
561
+
562
+ #### Example
563
+
564
+ Options can have examples that will be printed in the help output.
565
+
566
+ ```ruby
567
+ class Add < Cl::Cmd
568
+ opt '--to GROUP', example: 'group-one'
569
+ end
570
+
571
+ Cl.new('owners').run(%w(add --help))
572
+
573
+ # Usage: example add [options]
574
+ #
575
+ # Options:
576
+ #
577
+ # --to GROUP type: string, e.g.: group-one
578
+ # --help Get help on this command
579
+
580
+ ```
581
+
582
+ #### Format
583
+
584
+ Options can have a required format.
585
+
586
+ If a value is given by the user that does not match the format then the parser
587
+ will reject the option, and print the help output for this command.
588
+
589
+ For example:
590
+
591
+ ```ruby
592
+ class Add < Cl::Cmd
593
+ opt '--to GROUP', format: /^\w+$/
594
+
595
+ def run
596
+ p to
597
+ end
598
+ end
599
+
600
+ Cl.new('owners').run(%w(add --to one))
601
+
602
+ # Output:
603
+ #
604
+ # "one"
605
+
606
+ Cl.new('owners').run(['add', '--to', 'does not match!'])
607
+
608
+ Invalid format: to (format: /^\w+$/)
609
+
610
+ Usage: format add [options]
611
+
612
+ Options:
613
+
614
+ --to GROUP type: string, format: /^\w+$/
615
+ --help Get help on this command
616
+
617
+ ```
618
+
619
+ #### Internal
620
+
621
+ Options can be declared to be internal, hiding the option from the help output.
622
+
623
+ For example:
624
+
625
+ ```ruby
626
+ class Add < Cl::Cmd
627
+ opt '--to GROUP'
628
+ opt '--hidden', internal: true
629
+ end
630
+
631
+ Cl.new('owners').run(%w(add --help))
632
+
633
+ # Usage: example add [options]
634
+ #
635
+ # Options:
636
+ #
637
+ # --to GROUP type: string, e.g.: group-one
638
+ # --help Get help on this command
639
+
640
+ ```
641
+
642
+ #### Min and Max
643
+
644
+ Options can have mininum and/or maximum values.
645
+
646
+ If a value is given by the user that does not match the required min and/or max
647
+ values then the parser will reject the option, and print the help output for
648
+ this command.
649
+
650
+ For example:
651
+
652
+ ```ruby
653
+ class Add < Cl::Cmd
654
+ opt '--retries COUNT', type: :integer, min: 1, max: 5
655
+
656
+ def run
657
+ p retries
658
+ end
659
+ end
660
+
661
+ Cl.new('owners').run(%w(add --retries 1))
662
+
663
+ # Output:
664
+ #
665
+ # 1
666
+
667
+ Cl.new('owners').run(%w(add --retries 10))
668
+
669
+ # Out of range: retries (max: 5)
670
+ #
671
+ # Usage: max add [options]
672
+ #
673
+ # Options:
674
+ #
675
+ # --retries COUNT type: integer, min: 1, max: 5
676
+ # --help Get help on this command
677
+
678
+ ```
679
+
680
+ #### See Also
681
+
682
+ Options can refer to documentation using the `see` option. This will be printed
683
+ in the help output.
684
+
685
+ For example:
686
+
687
+ ```ruby
688
+ class Add < Cl::Cmd
689
+ opt '--to GROUP', see: 'https://docs.io/cli/owners/add'
690
+
691
+ def run
692
+ p retries
693
+ end
694
+ end
695
+
696
+ Cl.new('owners').run(%w(add --help))
697
+
698
+ # Usage: see add [options]
699
+ #
700
+ # Options:
701
+ #
702
+ # --to GROUP type: string, see: https://docs.io/cli/owners/add
703
+ # --help Get help on this command
704
+
705
+ ```
706
+
707
+ #### Types
708
+
709
+ Options can have a type. Known types are: `:array`, `:string`, `:integer`,
710
+ `:float`, `:boolean`.
711
+
712
+ The type `:array` allows an option to be given multiple times, and makes sure
713
+ the value accessible on the `Cmd` instance is a Ruby Array. (This currently
714
+ only supports arrays of strings).
715
+
716
+ ```ruby
717
+ class Add < Cl::Cmd
718
+ opt '--to GROUP', type: :array
719
+
720
+ def run
721
+ p to
722
+ end
723
+ end
724
+
725
+ Cl.new('owners').run(%w(add --to one --to two))
726
+
727
+ # Output:
728
+ #
729
+ # ["one", "two"]
730
+
731
+ ```
732
+
733
+ Other types cast the given value to the expected Ruby type.
734
+
735
+ ```ruby
736
+ class Add < Cl::Cmd
737
+ opt '--active BOOL', type: :boolean
738
+ opt '--retries INT', type: :integer
739
+ opt '--sleep FLOAT', type: :float
740
+
741
+ def run
742
+ p active.class, retries.class, sleep.class
743
+ end
744
+ end
745
+
746
+ Cl.new('owners').run(%w(add --active yes --retries 1 --sleep 0.1))
747
+
748
+ # Output:
749
+ #
750
+ # TrueClass
751
+ # Integer
752
+ # Float
753
+
754
+ ```
755
+
756
+ #### Required Options
757
+
758
+ There are three ways options can be required:
759
+
760
+ * using `required: true` on the option: the option itself is required to be given
761
+ * using `requires: :other`on the option: the option requires another option to be given
762
+ * using `required :one, [:two, :three]` on the class: either `one` or both `two` and `three` must be given
763
+
764
+ For example, this simply requires the option `--to`:
765
+
766
+ ```ruby
767
+ class Add < Cl::Cmd
768
+ opt '--to GROUP', required: true
769
+
770
+ def run
771
+ p to
772
+ end
773
+ end
774
+
775
+ Cl.new('owners').run(%w(add --to one))
776
+
777
+ # Output:
778
+ #
779
+ # "one"
780
+
781
+ Cl.new('owners').run(%w(add))
782
+
783
+ # Missing required option: to
784
+ #
785
+ # Usage: required add [options]
786
+ #
787
+ # Options:
788
+ #
789
+ # --to GROUP type: string, required: true
790
+ # --help Get help on this command
791
+
792
+ ```
793
+
794
+ This will make the option `--retries` depend on the option `--to`:
795
+
796
+ ```ruby
797
+ class Add < Cl::Cmd
798
+ opt '--to GROUP'
799
+ opt '--retries INT', requires: :to
800
+
801
+ def run
802
+ p to, retries
803
+ end
804
+ end
805
+
806
+ Cl.new('owners').run(%w(add --to one --retries 1))
807
+
808
+ # Output:
809
+ #
810
+ # "one"
811
+ # 1
812
+
813
+ Cl.new('owners').run(%w(add --retries 1))
814
+
815
+ # Missing option: to (required by retries)
816
+ #
817
+ # Usage: requires add [options]
818
+ #
819
+ # Options:
820
+ #
821
+ # --to GROUP type: string
822
+ # --retries INT type: string, requires: to
823
+ # --help Get help on this command
824
+
825
+ ```
826
+
827
+ This requires either the option `--api_key` or both options `--username` and
828
+ `--password` to be given:
829
+
830
+ ```ruby
831
+ class Add < Cl::Cmd
832
+ # read DNF, i.e. "apikey OR username AND password
833
+ required :api_key, [:username, :password]
834
+
835
+ opt '--api_key KEY'
836
+ opt '--username NAME'
837
+ opt '--password PASS'
838
+
839
+ def run
840
+ p to, retries
841
+ end
842
+ end
843
+
844
+ Cl.new('owners').run(%w(add --to one --retries 1))
845
+
846
+ # Output:
847
+ #
848
+ # "one"
849
+ # 1
850
+
851
+ Cl.new('owners').run(%w(add --retries 1))
852
+
853
+ # Missing option: to (required by retries)
854
+ #
855
+ # Usage: requires add [options]
856
+ #
857
+ # Options:
858
+ #
859
+ # --to GROUP type: string
860
+ # --retries INT type: string, requires: to
861
+ # --help Get help on this command
862
+
863
+ ```
864
+
865
+ ### Config Files
866
+
867
+ Cl automatically reads config files that match the given executable name (inspired by
868
+ [gem-release](https://github.com/svenfuchs/gem-release)), stored either in the
869
+ user directory or the current working directory.
870
+
871
+ For example:
872
+
873
+ ```ruby
874
+ module Api
875
+ class Login < Cl::Cmd
876
+ opt '--username USER'
877
+ opt '--password PASS'
878
+ end
879
+ end
880
+
881
+ # bin/api
882
+ CL.new('api').run(ARGV)
883
+
884
+ # ~/api.yml
885
+ login:
886
+ username: 'someone'
887
+ password: 'password'
888
+
889
+ # ./api.yml
890
+ login:
891
+ username: 'someone else'
892
+ ```
893
+
894
+ then running
895
+
896
+ ```
897
+ $ bin/api login
898
+ ```
899
+
900
+ instantiates `Api::Login`, and passes the hash
901
+
902
+ ```ruby
903
+ { username: 'someone else', password: 'password' }
904
+ ```
905
+
906
+ as `opts`.
907
+
908
+ Options passed by the user take precedence over defaults defined in config
909
+ files.
910
+
911
+ ### Environment Variables
912
+
913
+ Cl automatically defaults options to environment variables that are prefixed
914
+ with the given executable name (inspired by [gem-release](https://github.com/svenfuchs/gem-release)).
915
+
916
+ ```ruby
917
+ module Api
918
+ class Login < Cl::Cmd
919
+ opt '--username USER'
920
+ opt '--password PASS'
921
+ end
922
+ end
923
+
924
+ # bin/api
925
+ CL.new('api').run(ARGV)
926
+ ```
927
+
928
+ then running
929
+
930
+ ```
931
+ $ API_USERNAME=someone API_PASSWORD=password bin/api login
932
+ ```
933
+
934
+ instantiates `Api::Login`, and passes the hash
935
+
936
+ ```ruby
937
+ { username: 'someone', password: 'password' }
938
+ ```
939
+
940
+ Options passed by the user take precedence over defaults given as environment
941
+ variables, and environment variables take precedence over defaults defined in
942
+ config files.