cl 0.1.12 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.