toys 0.3.11 → 0.4.0
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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +35 -37
- data/builtins/system.rb +1 -1
- data/docs/guide.md +320 -262
- data/lib/toys/templates/gem_build.rb +1 -1
- data/lib/toys/templates/minitest.rb +3 -1
- data/lib/toys/templates/rdoc.rb +4 -4
- data/lib/toys/templates/rubocop.rb +3 -1
- data/lib/toys/templates/yardoc.rb +2 -1
- data/lib/toys/version.rb +1 -1
- metadata +16 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba4429bb2ffdb0b3022575052f06f6278cb2b44a65da21fe9b93d2e8df56ee11
|
4
|
+
data.tar.gz: af08f4cc228545c39b7829ea650b7f70a621a002b177163e6561c41e1a887de8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a887876d4fec040313fa6e6f9b40de1a98add4fb7f2d33f6ffb92b4dadc1f9be68f1551fe9ac1bd07751acb227c57e69453e60993f71e407418d0e298a11a8da
|
7
|
+
data.tar.gz: 7a453bbefbd8b729561f3a27559434cbbad6b46aeda5f065cf4a07f75787eecc0f8e96f70db7043dc3462419c91d111523153e4fc922e7cdc276073f69139dc5
|
data/CHANGELOG.md
CHANGED
@@ -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
|
4
|
-
|
5
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
92
|
-
|
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`
|
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
|
-
##
|
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
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
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
|
-
|
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
|
data/builtins/system.rb
CHANGED
@@ -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],
|
data/docs/guide.md
CHANGED
@@ -2,11 +2,14 @@
|
|
2
2
|
|
3
3
|
# Toys User Guide
|
4
4
|
|
5
|
-
Toys is a command line
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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;
|
28
|
-
that
|
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
|
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
|
133
|
+
toys system -v
|
131
134
|
|
132
135
|
Pass multiple long flags (for verbose output and recursive subtool search).
|
133
136
|
|
134
|
-
toys system
|
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
|
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
|
-
|
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.
|
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
|
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
|
-
|
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
|
-
|
408
|
-
|
409
|
-
|
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
|
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
|
-
|
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
|
445
|
-
|
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 "
|
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
|
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
|
482
|
-
|
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
|
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
|
518
|
-
|
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
|
-
####
|
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
|
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
|
561
|
-
|
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
|
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
|
589
|
-
Toys,
|
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
|
-
|
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
|
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
|
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
|
-
|
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,
|
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"
|
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.
|
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
|
810
|
-
deeper look at Toys files
|
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
|
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
|
828
|
-
are loaded when Toys looks for tool definitions.
|
829
|
-
Ruby file (and indeed its path relative to the
|
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.
|
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`.
|
856
|
-
|
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
|
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
|
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.
|
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
|
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
|
995
|
-
|
996
|
-
|
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
|
1028
|
-
`--verbose` and `--quiet` flags, (or `-v` and
|
1029
|
-
decrement the verbosity value, respectively. If you
|
1030
|
-
verbosity is incremented to 1, and the logger level
|
1031
|
-
set `-q`, the verbosity is decremented to -1, and the
|
1032
|
-
`ERROR`. So by using the provided logger, a tool can
|
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
|
1060
|
-
a tool can define additional methods
|
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
|
-
|
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
|
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.
|
1081
|
-
|
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
|
-
|
1124
|
-
|
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
|
1139
|
-
using the `include` directive. You can specify
|
1140
|
-
a built-in mixin such as `:exec` or
|
1141
|
-
own mixin using the `mixin`
|
1142
|
-
`include`d in that tool or any of
|
1143
|
-
so it's a useful way to share
|
1144
|
-
|
1145
|
-
|
1146
|
-
|
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
|
-
(
|
1150
|
-
do not support constants. See the next section on
|
1151
|
-
constants
|
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.
|
1354
|
-
|
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
|
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
|
-
|
1467
|
-
|
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
|
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,
|
1616
|
-
|
1617
|
-
|
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,
|
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
|
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.
|