toys 0.3.11 → 0.4.0

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: e808d6aa4a3e6a57484c458c7c2633ce1dc248991327c69d3c728b3eb502f135
4
- data.tar.gz: 5092670abd0a8cdf65d6d62dc1d34455229022e9780384ec2d91dd34553a8615
3
+ metadata.gz: ba4429bb2ffdb0b3022575052f06f6278cb2b44a65da21fe9b93d2e8df56ee11
4
+ data.tar.gz: af08f4cc228545c39b7829ea650b7f70a621a002b177163e6561c41e1a887de8
5
5
  SHA512:
6
- metadata.gz: 932274290953fe6bbcc60f58c87b808b2f0ebec867ca6a8d21c9342ca49788131fbad9f1d7755147c4f5635177da7615e51d22f88fe91d9fe617a499b20b2748
7
- data.tar.gz: 5d4f9b1651d79c9cbb71cedc014cbf1af5c63f22817a1f7a87f588316ee5080b8afb0a0437275428d15a15ac4bce188cd021d94f594703e165237a6dadf90fd4
6
+ metadata.gz: a887876d4fec040313fa6e6f9b40de1a98add4fb7f2d33f6ffb92b4dadc1f9be68f1551fe9ac1bd07751acb227c57e69453e60993f71e407418d0e298a11a8da
7
+ data.tar.gz: 7a453bbefbd8b729561f3a27559434cbbad6b46aeda5f065cf4a07f75787eecc0f8e96f70db7043dc3462419c91d111523153e4fc922e7cdc276073f69139dc5
@@ -1,5 +1,15 @@
1
1
  # Release History
2
2
 
3
+ ### 0.4.0 / 2018-07-03
4
+
5
+ Now declaring this alpha quality. Backward-incompatible changes are still
6
+ possible from this point, but I'll try to avoid them.
7
+
8
+ * CHANGED: Utils::Terminal#confirm default is now unset by default
9
+ * CHANGED: Moved gem install/activation methods into a mixin
10
+ * IMPROVED: Toys::Utils::Gems can suppress the confirmation prompt
11
+ * IMPROVED: Magic comments are now honored in toys files.
12
+
3
13
  ### 0.3.11 / 2018-07-02
4
14
 
5
15
  * CHANGED: Require Ruby 2.3 or later
data/README.md CHANGED
@@ -1,34 +1,13 @@
1
1
  # Toys
2
2
 
3
- Toys is a command line binary that lets you build your own personal suite of
4
- command line tools using a Ruby DSL. Toys handles argument parsing, error
5
- reporting, logging, help text, and many other details for you. Toys is designed
6
- for software developers, IT specialists, and other power users who want to
7
- write and organize scripts to automate their workflows.
3
+ Toys is a configurable command line tool. Write commands in config files using
4
+ a simple DSL, and Toys will provide the command line binary and take care of
5
+ all the details such as argument parsing, online help, and error reporting.
8
6
 
9
- I wrote Toys because I was accumulating dozens of ad hoc Ruby scripts that I
10
- had written to automate various tasks in my workflow, everything from
11
- refreshing credentials, to displaying git history in my favorite format, to
12
- running builds and tests of complex multi-component projects. It was becoming
13
- difficult to remember which scripts did what, and what arguments each required,
14
- and I was constantly digging back into their source just to remember how to use
15
- them. Furthermore, when writing new scripts, I was repeating the same
16
- OptionParser boilerplate and common functionality.
17
-
18
- Toys was designed to address those problems by providing a framework for
19
- writing and organizing your own command line scripts. You provide the actual
20
- functionality, and Toys takes care of all the other details expected from a
21
- good command line tool. It provides a streamlined interface for defining and
22
- handling command line flags and positional arguments, and sensible ways to
23
- organize shared code. It automatically generates help text, so you can see
24
- usage information at a glance, and it also provides a search feature to help
25
- you find the script you need.
26
-
27
- Toys can also be used to share scripts. For example, it can be used instead of
28
- Rake to provide build and test scripts for a project—tools that, unlike Rake
29
- tasks, can be invoked and passed arguments using familiar unix command line
30
- arguments and flags. The Toys github repo itself comes with Toys configs
31
- instead of Rakefiles.
7
+ Toys is designed for software developers, IT professionals, and other power
8
+ users who want to write and organize scripts to automate their workflows. It
9
+ can also be used as a Rake replacement, providing a more natural command line
10
+ interface for your project's build tasks.
32
11
 
33
12
  Unlike most command line frameworks, Toys is *not primarily* designed to help
34
13
  you build and ship a custom command line binary written in Ruby. However, you
@@ -88,8 +67,8 @@ flags. It can also validate arguments. Try this:
88
67
 
89
68
  toys greet --bye
90
69
 
91
- Notice that Toys automatically generated a usage summary for your tool. It can
92
- also automatically generate a full help screen, which you can view using the
70
+ Notice that Toys automatically generated a usage summary for your tool. It also
71
+ automatically generates a full help screen, which you can view using the
93
72
  `--help` flag:
94
73
 
95
74
  toys greet --help
@@ -101,7 +80,7 @@ also that the tools you create in the config file are available only in this
101
80
  directory and its subdirectories. If you move into a different directory tree,
102
81
  Toys will instead look for a config file in that directory. Thus, you can
103
82
  define tools scoped to particular projects. You can also define "global" tools
104
- by creating a `.toys.rb` config in your home directory.
83
+ by creating a `.toys.rb` file in your home directory.
105
84
 
106
85
  Toys provides a rich set of useful libraries for writing tools and subtools. It
107
86
  gives you a logger and automatically provides flags to control verbosity of log
@@ -113,14 +92,31 @@ third-party libraries such as Highline and TTY.
113
92
  For a more detailed look at Toys, see the
114
93
  [User Guide](https://www.rubydoc.info/gems/toys/file/docs/guide.md).
115
94
 
116
- ## Contributing
95
+ ## Why Toys?
96
+
97
+ I wrote Toys because I was accumulating dozens of ad hoc Ruby scripts that I
98
+ had written to automate various tasks in my workflow, everything from
99
+ refreshing credentials, to displaying git history in my favorite format, to
100
+ running builds and tests of complex multi-component projects. It was becoming
101
+ difficult to remember which scripts did what, and what arguments each required,
102
+ and I was constantly digging back into their source just to remember how to use
103
+ them. Furthermore, when writing new scripts, I was repeating the same
104
+ OptionParser boilerplate and common functionality.
117
105
 
118
- While we appreciate contributions, please note that this software is currently
119
- highly experimental, and the code is evolving very rapidly. Please contact the
120
- author before embarking on a major pull request. More detailed contribution
121
- guidelines will be provided when the software stabilizes further.
106
+ Toys was designed to address those problems by providing a framework for
107
+ writing and organizing your own command line scripts. You provide the actual
108
+ functionality, and Toys takes care of all the other details expected from a
109
+ good command line tool. It provides a streamlined interface for defining and
110
+ handling command line flags and positional arguments, and sensible ways to
111
+ organize shared code. It automatically generates help text, so you can see
112
+ usage information at a glance, and it also provides a search feature to help
113
+ you find the script you need.
122
114
 
123
- The source can be found on Github at https://github.com/dazuma/toys
115
+ Toys can also be used to share scripts. For example, it can be used instead of
116
+ Rake to provide build and test scripts for a project—tools that, unlike Rake
117
+ tasks, can be invoked and passed arguments using familiar unix command line
118
+ arguments and flags. The Toys github repo itself comes with Toys config files
119
+ instead of Rakefiles.
124
120
 
125
121
  ## License
126
122
 
@@ -129,3 +125,5 @@ Copyright 2018 Daniel Azuma
129
125
  This software is licensed under the 3-clause BSD license.
130
126
 
131
127
  See the LICENSE.md file for more information.
128
+
129
+ The source can be found on Github at https://github.com/dazuma/toys
@@ -63,7 +63,7 @@ tool "update" do
63
63
  cur_version = ::Gem::Version.new(::Toys::VERSION)
64
64
  if latest_version > cur_version
65
65
  prompt = "Update toys from #{cur_version} to #{latest_version}?"
66
- exit(1) unless yes || confirm(prompt)
66
+ exit(1) unless yes || confirm(prompt, default: true)
67
67
  result = terminal.spinner(leading_text: "Installing Toys version #{latest_version}... ",
68
68
  final_text: "Done.\n") do
69
69
  exec(["gem", "install", "toys", "--version", latest_version.to_s],
@@ -2,11 +2,14 @@
2
2
 
3
3
  # Toys User Guide
4
4
 
5
- Toys is a command line binary that lets you build your own personal suite of
6
- command line tools using a Ruby DSL. Toys handles argument parsing, error
7
- reporting, logging, help text, and many other details for you. Toys is designed
8
- for software developers, IT specialists, and other power users who want to
9
- write and organize scripts to automate their workflows.
5
+ Toys is a configurable command line tool. Write commands in config files using
6
+ a simple DSL, and Toys will provide the command line binary and take care of
7
+ all the details such as argument parsing, online help, and error reporting.
8
+
9
+ Toys is designed for software developers, IT professionals, and other power
10
+ users who want to write and organize scripts to automate their workflows. It
11
+ can also be used as a Rake replacement, providing a more natural command line
12
+ interface for your project's build tasks.
10
13
 
11
14
  Unlike most command line frameworks, Toys is *not primarily* designed to help
12
15
  you build and ship a custom command line binary written in Ruby. Rather, it
@@ -24,8 +27,8 @@ actual behavior of the Toys binary by writing **Toys files**.
24
27
 
25
28
  Toys is a multi-command binary. You may define any number of commands, called
26
29
  **tools**, which can be invoked by passing the tool name as an argument to the
27
- `toys` binary. Tools are arranged in a hierarchy; a tool may be a **namespace**
28
- that has **subtools**.
30
+ `toys` binary. Tools are arranged in a hierarchy; you may define **namespaces**
31
+ that have **subtools**.
29
32
 
30
33
  Tools may recognize command line arguments in the form of **flags** and
31
34
  **positional arguments**. Flags can optionally take **values**, while
@@ -101,8 +104,8 @@ tool**, the toplevel namespace:
101
104
 
102
105
  toys
103
106
 
104
- Like any namespace, the root tool displays its help screen, including the list
105
- of its subtools.
107
+ Like any namespace, invoking the root tool displays its help screen, including
108
+ showing the list of all its subtools.
106
109
 
107
110
  One last example:
108
111
 
@@ -127,15 +130,15 @@ optional **values** for flags. Following are a few examples.
127
130
 
128
131
  Pass a single short flag (for verbose output).
129
132
 
130
- toys system version -v
133
+ toys system -v
131
134
 
132
135
  Pass multiple long flags (for verbose output and recursive subtool search).
133
136
 
134
- toys system version --verbose --recursive
137
+ toys system --verbose --recursive
135
138
 
136
139
  You can combine short flags. This does the same as the previous example.
137
140
 
138
- toys system version -rv
141
+ toys system -rv
139
142
 
140
143
  Pass a value using a long flag. The root tool supports the `--search` flag to
141
144
  search for tools that have the given keyword.
@@ -230,18 +233,22 @@ Let's force `do` to treat all its arguments as positional, by starting with
230
233
  |--------ARGS--------|
231
234
  toys do -- --help , system --help
232
235
 
236
+ Now `toys do` behaves as we intended.
237
+
233
238
  ## Defining Tools
234
239
 
240
+ So far we've been experimenting only with the built-in tools provided by Toys.
235
241
  In this section, you will learn how to define tools by writing a **Toys file**.
236
-
237
- A file named `.toys.rb` (note the leading period) in the current working
238
- directory defines tools available in that directory and its subdirectories. We
239
- will cover how to write tools, including specifying the functionality of the
242
+ We will cover how to write tools, including specifying the functionality of the
240
243
  tool, the flags and arguments it takes, and how its description appears in the
241
244
  help screen.
242
245
 
243
246
  ### Basic Toys Syntax
244
247
 
248
+ A file named `.toys.rb` (note the leading period) in the current working
249
+ directory is called a **Toys file**. It defines tools available in that
250
+ directory and its subdirectories.
251
+
245
252
  The format of a Toys file is a Ruby DSL that includes directives, methods, and
246
253
  nested blocks. The actual DSL is specified in the
247
254
  [Toys::DSL::Tool class](https://www.rubydoc.info/gems/toys-core/Toys/DSL/Tool).
@@ -251,7 +258,7 @@ block, use directives to set the properties of the tool, including descriptions
251
258
  and the flags and arguments recognized by the tool. The actual functionality of
252
259
  the tool is set by defining a `run` method.
253
260
 
254
- Consider the following example:
261
+ Let's start with an example:
255
262
 
256
263
  tool "greet" do
257
264
  desc "Print a friendly greeting."
@@ -271,19 +278,18 @@ Consider the following example:
271
278
  end
272
279
  end
273
280
 
274
- Its results should be mostly self-evident. We'll take a look at some of the
275
- details below.
281
+ Its results should be mostly self-evident. But let's unpack a few details.
276
282
 
277
- ### Descriptions
283
+ ### Tool Descriptions
278
284
 
279
285
  Each tool may have a **short description** and/or a **long description**. The
280
286
  short description is a generally a single string that is displayed with the
281
287
  tool name, at the top of its help page or in a subtool list. The long
282
- description typically includes multiple strings, which are displayed in
288
+ description generally includes multiple strings, which are displayed in
283
289
  multiple lines in the "description" section of the tool's help page. Long
284
290
  descriptions may include blank lines to separate paragraphs visually.
285
291
 
286
- Each description string/line is word-wrapped by default when displayed. In the
292
+ By default, each description string/line is word-wrapped when displayed. In the
287
293
  long description example above, the first line is a bit longer than 80
288
294
  characters, and may be word-wrapped if displayed on an 80-character terminal.
289
295
 
@@ -319,6 +325,12 @@ argument is omitted, e.g.
319
325
 
320
326
  Then the option `:whom` is set to the default value `"world"`.
321
327
 
328
+ If the option name is a valid method name, Toys will provide a method that you
329
+ can use to retrieve the value. In the above example, we retrieve the value for
330
+ the option `:whom` by calling the method `whom`. If the option name cannot be
331
+ made into a method, you can retrieve the value by calling
332
+ [Toys::Tool#get](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:get).
333
+
322
334
  An argument may also be **required**, which means it must be provided on the
323
335
  command line; otherwise the tool will report a usage error. You may declare a
324
336
  required argument using the directive
@@ -404,9 +416,9 @@ This sets the following option data:
404
416
 
405
417
  {arg1: "foo", arg2: nil, arg3: []}
406
418
 
407
- Whereas your tool can include any number of `required_arg` and `optional_arg`
408
- directives, declaring any number of required and optional arguments, it can
409
- have only at most a single `remaining_args` directive.
419
+ Tools can include any number of `required_arg` and `optional_arg` directives,
420
+ declaring any number of required and optional arguments, but they can have only
421
+ at most one `remaining_args` directive.
410
422
 
411
423
  #### Descriptions and the Args DSL
412
424
 
@@ -421,11 +433,11 @@ an example:
421
433
  long_desc: ["Long descriptions may have multiple lines.",
422
434
  "This is the second line."]
423
435
 
424
- See the above section on Descriptions for more information on how descriptions
425
- are rendered and word wrapped.
436
+ See the [above section on Descriptions](#descriptions) for more information on
437
+ how descriptions are rendered and word wrapped.
426
438
 
427
- Long descriptions may be unwieldly to write as a hash argument in this way. So
428
- Toys provides an alternate syntax for defining arguments using a block.
439
+ Because long descriptions may be unwieldly to write as a hash argument in this
440
+ way, Toys provides an alternate syntax for defining arguments using a block.
429
441
 
430
442
  required_arg :arg do
431
443
  desc "This is a short description for the arg"
@@ -437,13 +449,12 @@ Toys provides an alternate syntax for defining arguments using a block.
437
449
  For detailed info on configuring an argument using a block, see the
438
450
  [Toys::DSL::Arg class](https://www.rubydoc.info/gems/toys-core/Toys/DSL/Arg).
439
451
 
440
- #### Acceptors
452
+ #### Argument Acceptors
441
453
 
442
454
  Finally, positional arguments may use **acceptors** to define how to validate
443
455
  arguments and convert them to Ruby objects for your tool to consume. By
444
- default, Toys will accept an argument string in any form, and expose it to your
445
- tool as a raw string. However, you may provide an acceptor to change this
446
- behavior.
456
+ default, Toys will accept any argument string, and expose it to your tool as a
457
+ raw string. However, you may provide an acceptor to change this behavior.
447
458
 
448
459
  Acceptors are part of the OptionParser interface, and are described under the
449
460
  [type coercion](http://ruby-doc.org/stdlib/libdoc/optparse/rdoc/OptionParser.html#class-OptionParser-label-Type+Coercion)
@@ -451,7 +462,7 @@ section. For example, you can provide the `Integer` class as an acceptor, which
451
462
  will validate that the argument is a well-formed integer, and convert it to an
452
463
  integer during parsing:
453
464
 
454
- tool "args-demo" do
465
+ tool "acceptor-demo" do
455
466
  required_arg :age, accept: Integer
456
467
  def run
457
468
  puts "Next year I will be #{age + 1}" # Age is an integer
@@ -465,8 +476,8 @@ including the special types such as
465
476
  and
466
477
  [OptionParser::OctalInteger](http://ruby-doc.org/stdlib/libdoc/optparse/rdoc/OptionParser.html#OctalInteger).
467
478
 
468
- You may also create **custom acceptors**. See the section below on Custom
469
- Acceptors for more information.
479
+ You may also create **custom acceptors**. See the
480
+ [section below on Custom Acceptors](#custom-acceptors) for more information.
470
481
 
471
482
  ### Flags
472
483
 
@@ -478,13 +489,19 @@ we declared a flag named `:shout`:
478
489
  Like a positional argument, a flag sets an option based on the command line
479
490
  arguments passed to the tool. In the case above, the `:shout` option is set to
480
491
  `true` if either `-s` or `--shout` is provided on the command line; otherwise
481
- it is set to `false`. Any number of short or long flags can be declared; they
482
- will be synonyms and have the same effect.
492
+ it remains falsy. The two flags `-s` and `--shout` are effectively synonyms and
493
+ have the same effect. A flag declaration may include any number of synonyms.
494
+
495
+ As with arguments, Toys will provide a method that you can call to retrieve the
496
+ option value set by a flag. In this case, a method called `shout` will be
497
+ available, and will return either true or false. If the option name cannot be
498
+ made into a method, you can retrieve the value by calling
499
+ [Toys::Tool#get](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:get).
483
500
 
484
501
  #### Flag Types
485
502
 
486
503
  Toys recognizes the same syntax used by the standard OptionParser library. This
487
- means you can also declare a flag that can be both set and unset:
504
+ means you can also declare a flag that can be set either to true or false:
488
505
 
489
506
  flag :shout, "--[no-]shout"
490
507
 
@@ -514,8 +531,8 @@ a value. (This is the same behavior as OptionParser.) In this example:
514
531
 
515
532
  flag :whom, "-w", "--whom=VALUE"
516
533
 
517
- The `-w` flag will also implicitly take a value, because it is defined as an
518
- alias with another flag that takes a value.
534
+ The `-w` flag will also implicitly take a value, because it is defined as a
535
+ synonym of another flag that takes a value.
519
536
 
520
537
  Note also that Toys will raise an error if those flags are incompatible. For
521
538
  example:
@@ -525,7 +542,7 @@ example:
525
542
  Raises an error because one flag's value is optional while the other is
526
543
  required. (Again, this is consistent with OptionParser's behavior.)
527
544
 
528
- #### Custom Acceptors
545
+ #### Flag Acceptors
529
546
 
530
547
  Flags may use **acceptors** to define how to validate values and convert them
531
548
  to Ruby objects for your tool to consume. By default, Toys will accept a flag
@@ -552,13 +569,13 @@ including the special types such as
552
569
  and
553
570
  [OptionParser::OctalInteger](http://ruby-doc.org/stdlib/libdoc/optparse/rdoc/OptionParser.html#OctalInteger).
554
571
 
555
- You may also create **custom acceptors**. See the section below on Custom
556
- Acceptors for more information.
572
+ You may also create **custom acceptors**. See the
573
+ [section below on Custom Acceptors](#custom-acceptors) for more information.
557
574
 
558
575
  #### Defaults and Handlers
559
576
 
560
- Currently, flags are always optional and a flag can appear in a command line
561
- zero, one, or any number of times. If a flag is not passed in the command line
577
+ Currently, flags are always optional; a flag can appear in a command line zero,
578
+ one, or any number of times. If a flag is not passed in the command line
562
579
  arguments for a tool, by default its corresponding option value will be `nil`.
563
580
 
564
581
  You may change this by providing a default value for a flag:
@@ -572,8 +589,8 @@ appearance of the flag will take effect. That is, suppose you define this flag:
572
589
 
573
590
  Now if you pass `--shout --no-shout`, then the value of the `:shout` option
574
591
  will be `false`, i.e. the last value set on the command line. This is because a
575
- flag *sets* its option value, replacing any previous value. You may change this
576
- behavior by providing a **handler**.
592
+ flag *sets* its option value, replacing any previously set value. You may
593
+ change this behavior by providing a **handler**.
577
594
 
578
595
  A handler is a proc that governs what a flag does to its option value. It takes
579
596
  two arguments, the new value given, and the previously set value (which might
@@ -585,15 +602,15 @@ equivalent to the following handler:
585
602
 
586
603
  For example, most tools automatically get a "--verbose" flag. This flag may
587
604
  appear any number of times, and each appearance increases the verbosity. The
588
- value of this verbosity is an integer. This flag is actually implemented by
589
- Toys, as follows:
605
+ value of this verbosity is an integer. This flag is provided automatically by
606
+ Toys, and its implementation looks something like this:
590
607
 
591
608
  flag Toys::Tool::Keys::VERBOSITY, "-v", "--verbose",
592
609
  default: 0,
593
610
  handler: proc { |_val, prev| prev + 1 }
594
611
 
595
612
  Similarly, the "--quiet" flag, which decreases the verbosity, is implemented
596
- as follows:
613
+ like this:
597
614
 
598
615
  flag Toys::Tool::Keys::VERBOSITY, "-q", "--quiet",
599
616
  default: 0,
@@ -602,7 +619,7 @@ as follows:
602
619
  Note that both flags affect the same option value, `VERBOSITY`. The first
603
620
  increments it each time it appears, and the second decrements it. A tool can
604
621
  query this option and get an integer telling the requested verbosity level, as
605
- you will see below in the section on execution environment.
622
+ you will see [below](#logging-and-verbosity).
606
623
 
607
624
  #### Descriptions and the Flags DSL
608
625
 
@@ -616,11 +633,11 @@ directive. The `desc:` argument takes a single string description, while the
616
633
  long_desc: ["Long descriptions may have multiple lines.",
617
634
  "This is the second line."]
618
635
 
619
- See the above section on Descriptions for more information on how descriptions
620
- are rendered and word wrapped.
636
+ See the [above section on Descriptions](#descriptions) for more information on
637
+ how descriptions are rendered and word wrapped.
621
638
 
622
- Long descriptions may be unwieldly to write as a hash argument in this way. So
623
- Toys provides an alternate syntax for defining flags using a block.
639
+ Because long descriptions may be unwieldly to write as a hash argument in this
640
+ way, Toys provides an alternate syntax for defining flags using a block.
624
641
 
625
642
  flag :my_flag do
626
643
  flags "--my-flag"
@@ -642,7 +659,8 @@ your tools.
642
659
 
643
660
  Note: If you do not define the `run` method for a tool, Toys provides a default
644
661
  implementation that displays the tool's help screen. This is typically used for
645
- namespaces, as we shall see below. Most tools, however, should define `run`.
662
+ namespaces, as we shall see [below](#namespaces-and-subtools). Most tools,
663
+ however, should define `run`.
646
664
 
647
665
  Let's revisit the "greet" example we covered earlier.
648
666
 
@@ -732,7 +750,7 @@ Like many command line frameworks, Toys supports **subtools**. You may, for
732
750
  example create a tool called "test" that runs your tests for a particular
733
751
  project, but you might also want "test unit" and "test integration" tools to
734
752
  run specific subsets of the test suite. One way to do this, of course, is for
735
- the "test" tool to parse "unit" and "integration" as arguments. However, you
753
+ the "test" tool to parse "unit" or "integration" as arguments. However, you
736
754
  could also define them as separate tools, subtools of "test".
737
755
 
738
756
  To define a subtool, create nested `tool` directives. Here's a simple example:
@@ -800,34 +818,29 @@ Now running `toys test` will run its own implementation.
800
818
  recommend doing so, because then you lose the root tool's useful default
801
819
  implementation that lists all your tools.)
802
820
 
803
- Toys allows subtools to be nested arbitrarily deep. Although in practice, more
821
+ Toys allows subtools to be nested arbitrarily deep. In practice, however, more
804
822
  than two or three levels of hierarchy can be confusing to use.
805
823
 
806
824
  ## Understanding Toys Files
807
825
 
808
826
  Toys commands are defined in Toys files. We covered the basic syntax for these
809
- files in the above section on defining tools. In this section, we will take a
810
- deeper look at Toys files, including:
811
-
812
- * Defining subtools in their own files
813
- * Global and local Toys files
814
- * The `TOYS_PATH`
815
- * Overriding tools
827
+ files in the [above section on defining tools](#defining-tools). In this
828
+ section, we will take a deeper look at what you can do with Toys files.
816
829
 
817
830
  ### Toys Directories
818
831
 
819
832
  So far we have been defining tools by writing a Toys file named `.toys.rb`
820
833
  located in the current working directory. This works great if you have a small
821
834
  number of fairly simple tools, but if you are defining many tools or tools with
822
- long or complex implementations, you may find it better to define some tools in
835
+ long or complex implementations, you may find it better to split your tools in
823
836
  separate files. You can have Toys load tools from multiple files by creating a
824
837
  **Toys directory**.
825
838
 
826
839
  A Toys directory is a directory called `.toys` located in the current working
827
- directory. Ruby files inside a Toys directory (or any of its subdirectories)
828
- are loaded when Toys looks for tool definitions. Furthermore, the name of the
829
- Ruby file (and indeed its path relative to the Toys directory) determines which
830
- tool it defines.
840
+ directory. (Again, note the leading period.) Ruby files inside a Toys directory
841
+ (or any of its subdirectories) are loaded when Toys looks for tool definitions.
842
+ Furthermore, the name of the Ruby file (and indeed its path relative to the
843
+ Toys directory) determines which tool it defines.
831
844
 
832
845
  For example, one way to create a "greet" tool, as we saw before, is to write a
833
846
  `.toys.rb` file in the current directory, and populate it like this:
@@ -840,7 +853,15 @@ For example, one way to create a "greet" tool, as we saw before, is to write a
840
853
  end
841
854
 
842
855
  You could also create the same tool by creating a `.toys` directory, and then
843
- creating a file `greet.rb` inside that directory. The contents would be:
856
+ creating a file `greet.rb` inside that directory.
857
+
858
+ (current directory)
859
+ |
860
+ +- .toys/
861
+ |
862
+ +- greet.rb
863
+
864
+ The contents of `greet.rb` would be:
844
865
 
845
866
  optional_arg :whom, default: "world"
846
867
  def run
@@ -852,8 +873,8 @@ name of the file `greet.rb` already provides a tool context: Toys already knows
852
873
  that we are defining a "greet" tool.
853
874
 
854
875
  If you do include a `tool` block inside the `greet.rb` file, it will create a
855
- *subtool* of `greet`. So, inside a Toys directory, the path to each Ruby file
856
- defines the "starting point" namespace for the tools defined in that file.
876
+ *subtool* of `greet`. In other words, the path to the Ruby file defines a
877
+ "starting point" for the names of tools defined in that file.
857
878
 
858
879
  If you create subdirectories inside a Toys directory, their names also
859
880
  contribute to the namespace of created tools. For example, if you create a
@@ -879,7 +900,7 @@ will define subtools of `test unit`.
879
900
 
880
901
  The file name `.toys.rb` can also be used inside Toys directories and
881
902
  subdirectories. Such files are called **index files**, and they create tools
882
- with the directory as the "starting point" namespace. For example, if you
903
+ with the *directory* as the "starting point" namespace. For example, if you
883
904
  create an index file directly underneath a `.toys` directory, it will define
884
905
  top level tools (just like a `.toys.rb` file in the current directory.) An
885
906
  index file located inside `.toys/test` will define tools with `test` as the
@@ -907,7 +928,8 @@ in the separate file `.toys/test/unit.rb`.
907
928
 
908
929
  Toys also loads index files first before other files in the directory. This
909
930
  means they are convenient places to define shared code that can be used by all
910
- the subtools, as we shall see later in the section on helpers.
931
+ the subtools defined in that directory, as we shall see later in the
932
+ [section on sharing code](#sharing-code).
911
933
 
912
934
  ### The Toys Search Path
913
935
 
@@ -921,7 +943,7 @@ When Toys runs, it looks for tools in a **search path**. Specifically:
921
943
  (1) It looks for a `.toys.rb` file and/or a `.toys` directory in the *current
922
944
  working directory*.
923
945
  (2) It does the same in the *parent directory* of the current directory, and
924
- its parent, all the way up to the root of the file system.
946
+ then its parent, all the way up to the root of the file system.
925
947
  (3) It does the same in the current user's *home directory*.
926
948
  (4) It does the same in the system configuration directory (i.e. `/etc` on unix
927
949
  systems)
@@ -947,17 +969,17 @@ directory, and you also define it in the `.toys/greet.rb` file in the same
947
969
  current directory, Toys will also report an error, since both are defined at
948
970
  the same point (the current directory) in the search path.
949
971
 
950
- #### Global Toys
972
+ #### Global Tools
951
973
 
952
974
  Note that in the search path above, steps (1) and (2) are *context-dependent*.
953
975
  That is, they may be different depending on what directory you are in. However,
954
976
  steps (3) and (4) are *not* context-dependent, and are searched regardless of
955
- where you are located. Toys defined here are **global**, available everywhere.
977
+ where you are located. Tools defined here are **global**, available everywhere.
956
978
 
957
979
  By default, global tools are defined in your home directory and the system
958
980
  configuration directory. However, you can change this by defining the
959
981
  environment variable `TOYS_PATH`. This environment variable should contain a
960
- colon-delimited list of paths that should be searched for global toys. If you
982
+ colon-delimited list of paths that should be searched for global tools. If you
961
983
  do define it, it replaces (3) and (4) with the paths you specify.
962
984
 
963
985
  ## The Execution Environment
@@ -991,9 +1013,10 @@ The `TOOL_NAME` constant above is a well-known key that corresponds to the full
991
1013
  name (as an array of strings) of the running tool. A variety of well-known keys
992
1014
  are defined in the
993
1015
  [Toys::Tool::Keys module](https://www.rubydoc.info/gems/toys-core/Toys/Tool/Keys).
994
- They range from the tool name and the original command line arguments passed to
995
- it (before they were parsed), to references to some of the Toys objects that
996
- can be used to do things like write to the log or look up and call other tools.
1016
+ They include information about the current execution, such as the tool name and
1017
+ the original command line arguments passed to it (before they were parsed).
1018
+ They also include some internal Toys objects, which can be used to do things
1019
+ like write to the log or look up and call other tools.
997
1020
 
998
1021
  Most of the important context also can be accessed from convenience methods.
999
1022
  For example, the `TOOL_NAME` is also available from the
@@ -1024,13 +1047,13 @@ or the
1024
1047
  [Toys::Tool#verbosity method](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:verbosity).
1025
1048
  The verbosity is set to 0 by default. This corresponds to a logger level of
1026
1049
  `WARN`. That is, warnings, errors, and fatals are displayed, while infos and
1027
- debugs are not. However, as we saw earlier, tools automatically respond to the
1028
- `--verbose` and `--quiet` flags, (or `-v` and `-q`), which increment and
1029
- decrement the verbosity value, respectively. If you run a tool with `-v`, the
1030
- verbosity is incremented to 1, and the logger level is set to `INFO`. If you
1031
- set `-q`, the verbosity is decremented to -1, and the logger level is set to
1032
- `ERROR`. So by using the provided logger, a tool can easily provide command
1033
- line based control of the output verbosity.
1050
+ debugs are not. However, [as we saw earlier](#standard-flags), most tools
1051
+ automatically respond to the `--verbose` and `--quiet` flags, (or `-v` and
1052
+ `-q`), which increment and decrement the verbosity value, respectively. If you
1053
+ run a tool with `-v`, the verbosity is incremented to 1, and the logger level
1054
+ is set to `INFO`. If you set `-q`, the verbosity is decremented to -1, and the
1055
+ logger level is set to `ERROR`. So by using the provided logger, a tool can
1056
+ easily provide command line based control of the output verbosity.
1034
1057
 
1035
1058
  ### Running Tools from Tools
1036
1059
 
@@ -1053,11 +1076,16 @@ execute, and return a process status object (i.e. 0 for success, and nonzero
1053
1076
  for error). Make sure you handle the exit status. For example, in most cases,
1054
1077
  you should probably exit if the tool you are calling returns a nonzero code.
1055
1078
 
1079
+ You may also use the `exec` mixin [described below](#executing-subprocesses) to
1080
+ run a tool in a separate process. This is particularly useful if you need to
1081
+ capture or manipulate that tool's input or output.
1082
+
1056
1083
  ### Helper Methods and Mixins
1057
1084
 
1058
1085
  The methods of [Toys::Tool](https://www.rubydoc.info/gems/toys-core/Toys/Tool)
1059
- are not the only methods available for your tool to call. We saw earlier that
1060
- a tool can define additional methods that you can use as helpers.
1086
+ are not the only methods available for your tool to call. We
1087
+ [saw earlier](#tool-execution-basics) that a tool can define additional methods
1088
+ that you can use as helpers.
1061
1089
 
1062
1090
  You can also include **mixins**, which are modules that bring in a whole set of
1063
1091
  helper methods. Include a mixin using the `include` directive:
@@ -1069,16 +1097,19 @@ helper methods. Include a mixin using the `include` directive:
1069
1097
  end
1070
1098
  end
1071
1099
 
1072
- Th mixins may be specified by providing a module itself, or by providing a
1100
+ A mixin may be specified by providing a module itself, or by providing a
1073
1101
  **mixin name**. In the above example, we used `:terminal`, which is the name
1074
1102
  of a built-in mixin that Toys provides. Among other things, it defines a
1075
1103
  special `puts` method that lets you include style information such as `:bold`,
1076
1104
  which affects the display on ANSI-capable terminals.
1077
1105
 
1078
- For details on the standard mixins provided by Toys, see the modules under
1106
+ For details on the built-in mixins provided by Toys, see the modules under
1079
1107
  [Toys::StandardMixins](https://www.rubydoc.info/gems/toys-core/Toys/StandardMixins).
1080
- We will look at a few examples of the use of these mixins below. You can also
1081
- define your own mixins, as we will see in the next section on sharing code.
1108
+ We will look at a few examples of the use of these mixins below. Built-in
1109
+ mixins have names that are symbols.
1110
+
1111
+ You can also define your own mixins, as we will see in the
1112
+ [next section on sharing code](#defining-mixins).
1082
1113
 
1083
1114
  ### Executing Subprocesses
1084
1115
 
@@ -1101,6 +1132,15 @@ their output, and a powerful block-based interface for controlling streams. The
1101
1132
  exec mixin also lets you set a useful default option that causes the tool to
1102
1133
  exit automatically if one of its subprocesses exits abnormally.
1103
1134
 
1135
+ The exec mixin provides methods for running several different kinds of
1136
+ subprocesses:
1137
+
1138
+ * Normal processes started by the operating system.
1139
+ * Another Ruby process.
1140
+ * A shell script.
1141
+ * Another tool run in a separate (forked) process.
1142
+ * A block run in a separate (forked) process.
1143
+
1104
1144
  For more information, see the
1105
1145
  [Toys::StandardMixins::Exec mixin module](https://www.rubydoc.info/gems/toys-core/Toys/StandardMixins/Exec)
1106
1146
  and the underyling library
@@ -1120,10 +1160,15 @@ and the underyling library
1120
1160
  [Toys::Utils::Terminal](https://www.rubydoc.info/gems/toys-core/Toys/Utils/Terminal).
1121
1161
 
1122
1162
  If you prefer the venerable Highline library interface, Toys provides a mixin
1123
- that makes Highline available. It also automatically installs the highline
1124
- gem (version 2.x) if it is not available. For more information, see the
1163
+ called `:highline` that automatically installs the highline gem (version 2.x)
1164
+ if it is not available, and makes a highline object available to the tool. For
1165
+ more information, see the
1125
1166
  [Toys::StandardMixins::Highline mixin module](https://www.rubydoc.info/gems/toys-core/Toys/StandardMixins/Highline).
1126
1167
 
1168
+ You may also use other third-party gems such as
1169
+ [tty](https://github.com/piotrmurach/tty). The section below on
1170
+ [useful gems](#useful-gems) provides some examples.
1171
+
1127
1172
  ## Sharing Code
1128
1173
 
1129
1174
  As you accumulate additional and more complex tools, you may find that some of
@@ -1135,20 +1180,22 @@ classes, and constants, that you might define in your tools.
1135
1180
 
1136
1181
  ### Defining Mixins
1137
1182
 
1138
- We saw earlier that you can mix a module (with all its methods) into your tool
1139
- using the `include` directive. You can specify a module itself, or the name of
1140
- a built-in mixin such as `:exec` or `:terminal`. But you can also define your
1141
- own mixin using the `mixin` directive. A mixin defined in a tool can be
1142
- `include`d in that tool or any of its subtools or their subtools, recursively,
1143
- so it's a useful way to share code. Here's how that works.
1144
-
1145
- Define a mixin using the `mixin` directive, and give it a name and a block. In
1146
- the block, you can define methods that will be made available to any tool that
1183
+ We [saw earlier](#helper-methods-and-mixins) that you can mix a module (with
1184
+ all its methods) into your tool using the `include` directive. You can specify
1185
+ a module itself, or the name of a built-in mixin such as `:exec` or
1186
+ `:terminal`. But you can also define your own mixin using the `mixin`
1187
+ directive. A mixin defined in a tool can be `include`d in that tool or any of
1188
+ its subtools or their subtools, recursively, so it's a useful way to share
1189
+ code. Here's how that works.
1190
+
1191
+ Define a mixin using the `mixin` directive, and give it a name and a block. The
1192
+ mixin name must be a string. (Symbols are reserved for built-in mixins.) In the
1193
+ block, you can define methods that will be made available to any tool that
1147
1194
  includes the mixin, in the same way that you can include a Ruby module.
1148
1195
 
1149
- (Unlike full modules, however, mixins allow only methods to be shared. Mixins
1150
- do not support constants. See the next section on using constants to learn how
1151
- constants are treated by Toys.)
1196
+ (Note that, unlike full modules, mixins allow only methods to be shared. Mixins
1197
+ do not support constants. See the next section on
1198
+ [using constants](#using-constants) to learn how Toys handles constants.)
1152
1199
 
1153
1200
  Here's an example. Suppose you had common setup code that you wanted to share
1154
1201
  among your testing tools.
@@ -1350,8 +1397,10 @@ to your block, letting you modify its properties:
1350
1397
 
1351
1398
  Toys provides several built-in templates that are useful for project and gem
1352
1399
  development, including templates that generate build, test, and documentation
1353
- tools. You can read more about these templates in the next section on using
1354
- Toys as a Rake replacement.
1400
+ tools. The `:minitest` template illustrated above is one of these built-in
1401
+ templates. Like built-in mixins, built-in template names are always symbols.
1402
+ You can read more about them in the next section on using
1403
+ [Toys as a Rake replacement](#toys-as-a-rake-replacement).
1355
1404
 
1356
1405
  You may also write your own templates. Here's how...
1357
1406
 
@@ -1359,7 +1408,8 @@ You may also write your own templates. Here's how...
1359
1408
 
1360
1409
  One way to define a template is to use the `template` directive. Like the
1361
1410
  `mixin` directive, this creates a named template that you can access inside the
1362
- current tool and any of its subtools.
1411
+ current tool and any of its subtools. Also, like mixins, your template name
1412
+ must be a string.
1363
1413
 
1364
1414
  Following is a simple template example:
1365
1415
 
@@ -1407,7 +1457,7 @@ those methods need access to the `template` variable, you can use
1407
1457
  instead of `def`.
1408
1458
 
1409
1459
  By convention, it is a good idea for configuration options for your template to
1410
- be settable either as arguments to the constructor, or as `attr_accessor`
1460
+ be settable *both* as arguments to the constructor, *and* as `attr_accessor`
1411
1461
  properties. In this way, when you expand the template, options can be provided
1412
1462
  either as arguments to the `expand` directive, or in a block passed to the
1413
1463
  directive by setting properties on the template object.
@@ -1457,14 +1507,160 @@ following in their Toys file:
1457
1507
  require "my_analysis"
1458
1508
  expand MyAnalysis::ToysTemplate
1459
1509
 
1510
+ ## Using Third-Party Gems
1511
+
1512
+ The Ruby community has developed many resources for building command line
1513
+ tools, including a variety of gems that provide alternate command line parsing,
1514
+ control of the ANSI terminal, formatted output such as trees and tables, and
1515
+ effects such as hidden input, progress bars, various subprocess tools, and so
1516
+ forth.
1517
+
1518
+ This section describes how to use a third-party gem in your tool.
1519
+
1520
+ ### Activating Gems
1521
+
1522
+ The toys gem itself includes only two gems: **toys** and **toys-core**. It has
1523
+ no other gem dependencies. However, if you want to use a third-party gem in
1524
+ your tool, Toys provides a convenient mechanism to ensure the gem is installed.
1525
+
1526
+ To access the gem services, include the `:gems` mixin. This mixin adds a `gem`
1527
+ directive to ensure a gem is installed and activated when you're defining a
1528
+ tool, and a `gem` method to ensure a gem is available when you're running a
1529
+ tool.
1530
+
1531
+ Both the `gem` directive and the `gem` method take the name of the gem, and an
1532
+ optional set of version requirements. If a gem matching the given version
1533
+ requirements is installed, it is activated. If not, the gem is installed (which
1534
+ the user can confirm or abort). Or, if Toys is being run in a bundle, a message
1535
+ is printed informing the user that they need to add the gem to their Gemfile.
1536
+
1537
+ For example, here's a way to configure a tool with flags for each of the
1538
+ HighLine styles. Because highline is needed to decide what flags to define, we
1539
+ use the `gem` directive to ensure highline is installed while the tool is being
1540
+ defined.
1541
+
1542
+ tool "highline-styles-demo" do
1543
+ include :gems
1544
+ gem "highline", "~> 2.0"
1545
+ require "highline"
1546
+ HighLine::BuiltinStyles::STYLES.each do |style|
1547
+ style = style.downcase
1548
+ flag style.to_sym, "--#{style}", "Apply #{style} to the text"
1549
+ end
1550
+ def run
1551
+ # ...
1552
+
1553
+ Here's an example tool that just runs `rake`. Because it requires rake to be
1554
+ installed in order to *run* the tool, we call the
1555
+ [Toys::StandardMixins::Gems#gem](https://www.rubydoc.info/gems/toys-core/Toys%2FStandardMixins%2FGems:gem)
1556
+ method provided by the `:gems` mixin when running.
1557
+
1558
+ tool "rake" do
1559
+ include :gems
1560
+ remaining_args :rake_args
1561
+ def run
1562
+ gem "rake", "~> 12.0"
1563
+ Kernel.exec(["rake"] + rake_args)
1564
+ end
1565
+ end
1566
+
1567
+ If a gem satisfying the given version constraints is already activated, it
1568
+ remains active. If a gem with a conflicting version is already activated, an
1569
+ exception is raised.
1570
+
1571
+ If you are not in the Toys DSL context—for example from a class-based
1572
+ mixin—you should use
1573
+ [Toys::Utils::Gems.activate](https://www.rubydoc.info/gems/toys-core/Toys%2FUtils%2FGems.activate)
1574
+ instead. For example:
1575
+
1576
+ Toys::Utils::Gems.activate("highline", "~> 2.0")
1577
+
1578
+ Note these methods are a bit different from the
1579
+ [gem method](http://ruby-doc.org/stdlib/libdoc/rubygems/rdoc/Kernel.html)
1580
+ provided by Rubygems. The Toys version attempts to install a missing gem for
1581
+ you, whereas Rubygems will just throw an exception.
1582
+
1583
+ ### Useful Gems
1584
+
1585
+ Now that you know how to ensure a gem is installed, let's look at some third-
1586
+ party gems that you might find useful when writing tools.
1587
+
1588
+ We already saw how to use the **highline** gem. Highline generally provides two
1589
+ features: terminal styling, and prompts. For these capabilities and many more,
1590
+ you might also consider [TTY](https://github.com/piotrmurach/tty). It comprises
1591
+ a suite of gems that you can use separately or in tandem. Here are a few
1592
+ examples.
1593
+
1594
+ To produce styled output, consider
1595
+ [Pastel](https://github.com/piotrmurach/pastel).
1596
+
1597
+ tool "fancy-output" do
1598
+ def run
1599
+ gem "pastel", "~> 0.7"
1600
+ require "pastel"
1601
+ pastel = Pastel.new
1602
+ puts pastel.red("Rubies!")
1603
+ end
1604
+ end
1605
+
1606
+ To create rich user prompts, consider
1607
+ [tty-prompt](https://github.com/piotrmurach/tty-prompt).
1608
+
1609
+ tool "favorite-language" do
1610
+ def run
1611
+ gem "tty-prompt", "~> 0.16"
1612
+ require "tty-prompt"
1613
+ prompt = TTY::Prompt.new
1614
+ lang = prompt.select("What is your favorite language?",
1615
+ %w[Elixir Java Python Ruby Rust Other])
1616
+ prompt.say("#{lang} is awesome!")
1617
+ end
1618
+ end
1619
+
1620
+ To create tabular output, consider
1621
+ [tty-table](https://github.com/piotrmurach/tty-table).
1622
+
1623
+ tool "matrix" do
1624
+ def run
1625
+ gem "tty-table", "~> 0.10"
1626
+ require "tty-table"
1627
+ table = TTY::Table.new(["Language", "Creator"],
1628
+ [["Ruby", "Matz"],
1629
+ ["Python", "Guido"],
1630
+ ["Elixir", "Jose"]])
1631
+ puts table.render(:ascii)
1632
+ end
1633
+ end
1634
+
1635
+ To show progress, consider
1636
+ [tty-progressbar](https://github.com/piotrmurach/tty-progressbar) for
1637
+ deterministic processes, or
1638
+ [tty-spinner](https://github.com/piotrmurach/tty-spinner) for
1639
+ non-deterministic.
1640
+
1641
+ tool "waiting" do
1642
+ def run
1643
+ gem "tty-progressbar", "~> 0.15"
1644
+ require "tty-progressbar"
1645
+ bar = TTY::ProgressBar.new("Waiting [:bar]", total: 30)
1646
+ 30.times do
1647
+ sleep(0.1)
1648
+ bar.advance(1)
1649
+ end
1650
+ end
1651
+ end
1652
+
1653
+ A variety of other useful gems can also be found in
1654
+ [this article](https://lab.hookops.com/ruby-cli-gems.html).
1655
+
1460
1656
  ## Toys as a Rake Replacement
1461
1657
 
1462
1658
  Toys was designed to organize scripts that may be "scoped" to a project or
1463
1659
  directory. Rake is also commonly used for this purpose: you can write a
1464
1660
  "Rakefile" that defines rake tasks scoped to a directory. In many cases, Toys
1465
- can be used as a replacement for Rake. Indeed, the Toys repository itself,
1466
- rather than a Rakefile, contains a `.toys.rb` file that defines tools for
1467
- running tests, builds, and so forth.
1661
+ can be used as a replacement for Rake. Indeed, the Toys repository itself
1662
+ contains a `.toys.rb` file that defines tools for running tests, builds, and so
1663
+ forth, instead of a Rakefile that is otherwise often used for this purpose.
1468
1664
 
1469
1665
  This section will explore the differences between Toys and Rake, and describe
1470
1666
  how to use Toys for some of the things traditionally done with Rake.
@@ -1583,7 +1779,7 @@ example:
1583
1779
  expand :clean, paths: ["pkg", "doc", "tmp"]
1584
1780
 
1585
1781
  See the {Toys::Templates::Clean} documentation for details on the various
1586
- options for clean tools.
1782
+ options for clean.
1587
1783
 
1588
1784
  ### Building Documentation
1589
1785
 
@@ -1612,9 +1808,9 @@ all the basic tools for a Ruby gem. It includes:
1612
1808
  actually build) the documentation for warnings and completeness.
1613
1809
 
1614
1810
  Below is the full annotated `.toys.rb` file. For many gems, you could drop this
1615
- into the gem source repo with minimal or no modifications. Indeed, this is
1616
- essentially identical to the Toys files provided for the **toys** and
1617
- **toys-core** gems themselves.
1811
+ into the gem source repo with minimal or no modifications. Indeed, it is
1812
+ nearly identical to the Toys files provided for the **toys** and **toys-core**
1813
+ gems themselves.
1618
1814
 
1619
1815
  # A "clean" tool that cleans out gem builds (from the pkg directory), and
1620
1816
  # documentation builds (from doc and .yardoc)
@@ -1677,144 +1873,6 @@ essentially identical to the Toys files provided for the **toys** and
1677
1873
  end
1678
1874
  end
1679
1875
 
1680
- ## Using Third-Party Gems
1681
-
1682
- The Ruby community has developed many resources for building command line
1683
- tools, including a variety of gems that provide alternate command line parsing,
1684
- control of the ANSI terminal, formatted output such as trees and tables, and
1685
- effects such as hidden input, progress bars, various subprocess tools, and so
1686
- forth.
1687
-
1688
- This section describes how to use a third-party gem in your tool.
1689
-
1690
- ### Activating Gems
1691
-
1692
- The toys gem itself includes only two gems: **toys** and **toys-core**. It has
1693
- no other gem dependencies. However, if you want to use a third-party gem in
1694
- your tool, Toys provides a convenient mechanism to ensure the gem is installed.
1695
-
1696
- If the gem is needed to *define* the tool, use the `gem` directive to ensure
1697
- the gem is installed and activated. This takes the name of the gem, and an
1698
- optional set of version requirements. If a gem matching the given version
1699
- requirements is installed, it is activated. If not, the gem is installed (which
1700
- the user can confirm or abort). Or, if Toys is being run in a bundle, a message
1701
- is printed informing the user that they need to add the gem to their Gemfile.
1702
-
1703
- For example, here's a way to configure a tool with flags for each of the
1704
- HighLine styles:
1705
-
1706
- tool "highline-styles-demo" do
1707
- gem "highline", "~> 2.0"
1708
- require "highline"
1709
- HighLine::BuiltinStyles::STYLES.each do |style|
1710
- style = style.downcase
1711
- flag style.to_sym, "--#{style}", "Apply #{style} to the text"
1712
- end
1713
- def run
1714
- # ...
1715
-
1716
- If the gem is *not* needed to define the tool, but is needed to *run* the tool,
1717
- then you can call
1718
- [Toys::Tool#gem](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:gem) from
1719
- your `run` method. Here's an example:
1720
-
1721
- tool "rake" do
1722
- disable_argument_passing
1723
- def run
1724
- gem "rake", "~> 12.0"
1725
- Kernel.exec(["rake"] + args)
1726
- end
1727
- end
1728
-
1729
- If a gem satisfying the given version constraints is already activated, it
1730
- remains active. If a gem with a conflicting version is already activated, an
1731
- exception is raised.
1732
-
1733
- If you are not in the Toys DSL context—e.g. you are writing a class-based
1734
- mixin—you should use
1735
- [Toys::Utils::Gems.activate](https://www.rubydoc.info/gems/toys-core/Toys%2FUtils%2FGems:activate)
1736
- instead. For example:
1737
-
1738
- Toys::Utils::Gems.activate("highline", "~> 2.0")
1739
-
1740
- Note these methods are a bit different from the
1741
- [gem method](http://ruby-doc.org/stdlib/libdoc/rubygems/rdoc/Kernel.html)
1742
- provided by Rubygems. The Toys version attempts to install a missing gem for
1743
- you, whereas Rubygems will just throw an exception.
1744
-
1745
- ### Useful Gems
1746
-
1747
- Now that you know how to ensure a gem is installed, let's look at some third-
1748
- party gems that you might find useful when writing tools.
1749
-
1750
- We already saw how to use the **highline** gem. Highline generally provides two
1751
- features: terminal styling, and prompts. For these capabilities and many more,
1752
- you might also consider [TTY](https://github.com/piotrmurach/tty). It comprises
1753
- a suite of gems that you can use separately or in tandem. Here are a few
1754
- examples.
1755
-
1756
- To produce styled output, consider
1757
- [Pastel](https://github.com/piotrmurach/pastel).
1758
-
1759
- tool "fancy-output" do
1760
- def run
1761
- gem "pastel", "~> 0.7"
1762
- require "pastel"
1763
- pastel = Pastel.new
1764
- puts pastel.red("Rubies!")
1765
- end
1766
- end
1767
-
1768
- To create rich user prompts, consider
1769
- [tty-prompt](https://github.com/piotrmurach/tty-prompt).
1770
-
1771
- tool "favorite-language" do
1772
- def run
1773
- gem "tty-prompt", "~> 0.16"
1774
- require "tty-prompt"
1775
- prompt = TTY::Prompt.new
1776
- lang = prompt.select("What is your favorite language?",
1777
- %w[Elixir Java Python Ruby Rust Other])
1778
- prompt.say("#{lang} is awesome!")
1779
- end
1780
- end
1781
-
1782
- To create tabular output, consider
1783
- [tty-table](https://github.com/piotrmurach/tty-table).
1784
-
1785
- tool "matrix" do
1786
- def run
1787
- gem "tty-table", "~> 0.10"
1788
- require "tty-table"
1789
- table = TTY::Table.new(["Language", "Creator"],
1790
- [["Ruby", "Matz"],
1791
- ["Python", "Guido"],
1792
- ["Elixir", "Jose"]])
1793
- puts table.render(:ascii)
1794
- end
1795
- end
1796
-
1797
- To show progress, consider
1798
- [tty-progressbar](https://github.com/piotrmurach/tty-progressbar) for
1799
- deterministic processes, or
1800
- [tty-spinner](https://github.com/piotrmurach/tty-spinner) for
1801
- non-deterministic.
1802
-
1803
- tool "waiting" do
1804
- def run
1805
- gem "tty-progressbar", "~> 0.15"
1806
- require "tty-progressbar"
1807
- bar = TTY::ProgressBar.new("Waiting [:bar]", total: 30)
1808
- 30.times do
1809
- sleep(0.1)
1810
- bar.advance(1)
1811
- end
1812
- end
1813
- end
1814
-
1815
- A variety of other useful gems can also be found in
1816
- [this article](https://lab.hookops.com/ruby-cli-gems.html).
1817
-
1818
1876
  ## Advanced Tool Definition Techniques
1819
1877
 
1820
1878
  This section covers some additional features that are often useful for writing
@@ -1928,11 +1986,11 @@ completely disable decreasing the verbosity, disable both `-q` and `--quiet`.
1928
1986
  ### Disabling Argument Parsing
1929
1987
 
1930
1988
  Normally Toys handles parsing command line arguments for you. This makes
1931
- writing tools easier, but also allows Toys to generate documentation
1989
+ writing tools easier, and also allows Toys to generate documentation
1932
1990
  automatically for flags and arguments. However, occasionally you'll not want
1933
1991
  Toys to perform any parsing, but just to give you the command line arguments
1934
- raw. One common case is if your tool turns around and passes its arguments to
1935
- another subprocess.
1992
+ raw. One common case is if your tool turns around and passes its arguments
1993
+ verbatim to another subprocess.
1936
1994
 
1937
1995
  To disable argument parsing, use the `disable_argument_parsing` directive. This
1938
1996
  directive disables parsing and validation of flags and positional arguments.