toys 0.3.6 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +6 -5
- data/bin/toys +2 -0
- data/builtins/do.rb +4 -5
- data/builtins/system.rb +29 -15
- data/docs/guide.md +199 -23
- data/lib/toys.rb +5 -0
- data/lib/toys/standard_cli.rb +2 -2
- data/lib/toys/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7744684eb5fd0d03f650315fad4bb84bc433d0ce4e0529c82f6bf2ebcb60f9f5
|
4
|
+
data.tar.gz: 26c4d2e48917887441bd6bc03986110f7269bdd2b1f0098d1b9cd3a19a5b0248
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61445d45a25a6d64f9f2fc547e38589b7f49d8cdf08a07e7bff33b3687307bbeed4b7aa1f8528c2c91a6abf52c3bea86a79392d3d0bbf98652fe5fd2d526f693
|
7
|
+
data.tar.gz: a08b400babfecc9c6fd119447d37f62df645986b3d23e5ef381cbf7e05d766b3d1eebd97d0947bb7a8c7cd5b5f53c59aaca329f4bfbb4a8c0463520b11ca1dca
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### 0.3.7 / 2018-05-30
|
4
|
+
|
5
|
+
* CHANGED: Execution runs in the same scope as the DSL, which lets us use normal methods instead of helper-blocks.
|
6
|
+
* CHANGED: Renamed "script" to "run", and allow setting of runnable by defining a "run" method
|
7
|
+
* CHANGED: Set up a constant scope for each config file, to make constant lookup make sense.
|
8
|
+
* CHANGED: Removed run_toys and dropped EXIT_ON_NONZERO_STATUS key in favor of using cli directly.
|
9
|
+
* CHANGED: Removed spinner helper and added terminal helper.
|
10
|
+
* ADDED: Helper modules scoped to the tool hierarchy
|
11
|
+
|
3
12
|
### 0.3.6 / 2018-05-21
|
4
13
|
|
5
14
|
* CHANGED: Removed Context#new_cli and exposed Context#cli instead.
|
data/README.md
CHANGED
@@ -69,8 +69,8 @@ current directory. Copy the following into the file, and save it:
|
|
69
69
|
tool "greet" do
|
70
70
|
desc "My first tool!"
|
71
71
|
flag :whom, default: "world"
|
72
|
-
|
73
|
-
puts "Hello, #{
|
72
|
+
def run
|
73
|
+
puts "Hello, #{option(:whom)}!"
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
@@ -107,9 +107,10 @@ various subtools, such as "version", are available under that namespace.
|
|
107
107
|
|
108
108
|
Toys provides a rich set of useful libraries for writing tools. It gives you a
|
109
109
|
logger and automatically provides flags to control verbosity of log output. It
|
110
|
-
includes
|
111
|
-
console-based interfaces, and
|
112
|
-
|
110
|
+
includes a simple library that you can use to produce styled output and basic
|
111
|
+
console-based interfaces, and another library that makes it easy to spawn and
|
112
|
+
control subprocesses. You can also take advantage of a variety of third-party
|
113
|
+
libraries such as Highline and TTY.
|
113
114
|
|
114
115
|
For a more detailed look at Toys, see the
|
115
116
|
{file:docs/tutorial.md Extended Tutorial} and the
|
data/bin/toys
CHANGED
data/builtins/do.rb
CHANGED
@@ -54,12 +54,11 @@ flag :delim, "-d", "--delim=VALUE",
|
|
54
54
|
|
55
55
|
remaining_args :args, desc: "A series of tools to run, separated by the delimiter"
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
.chunk { |arg| arg == delim ? :_separator : true }
|
57
|
+
def run
|
58
|
+
option(:args)
|
59
|
+
.chunk { |arg| arg == option(:delim) ? :_separator : true }
|
61
60
|
.each do |_, action|
|
62
|
-
code = run(action)
|
61
|
+
code = cli.run(action)
|
63
62
|
exit(code) unless code.zero?
|
64
63
|
end
|
65
64
|
end
|
data/builtins/system.rb
CHANGED
@@ -32,42 +32,56 @@ desc "A set of system commands for Toys"
|
|
32
32
|
long_desc "Contains tools that inspect, configure, and update Toys itself."
|
33
33
|
|
34
34
|
tool "version" do
|
35
|
-
desc "Print current Toys version
|
35
|
+
desc "Print the current Toys version"
|
36
36
|
|
37
|
-
|
37
|
+
def run
|
38
38
|
puts ::Toys::VERSION
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
tool "update" do
|
43
|
-
desc "Update Toys if a newer version is available
|
43
|
+
desc "Update Toys if a newer version is available"
|
44
44
|
|
45
45
|
long_desc "Checks rubygems for a newer version of Toys. If one is available, downloads" \
|
46
46
|
" and installs it."
|
47
47
|
|
48
48
|
flag :yes, "-y", "--yes", desc: "Do not ask for interactive confirmation"
|
49
49
|
|
50
|
-
|
51
|
-
|
50
|
+
include :exec
|
51
|
+
include :terminal
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
version_info =
|
53
|
+
def run
|
54
|
+
configure_exec(exit_on_nonzero_status: true)
|
55
|
+
version_info = terminal.spinner(leading_text: "Checking rubygems for the latest release... ",
|
56
|
+
final_text: "Done.\n") do
|
57
|
+
capture(["gem", "query", "-q", "-r", "-e", "toys"])
|
58
|
+
end
|
56
59
|
if version_info =~ /toys\s\((.+)\)/
|
57
60
|
latest_version = ::Gem::Version.new($1)
|
58
61
|
cur_version = ::Gem::Version.new(::Toys::VERSION)
|
59
62
|
if latest_version > cur_version
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
+
prompt = "Update toys from #{cur_version} to #{latest_version}?"
|
64
|
+
exit(1) unless option(:yes) || confirm(prompt)
|
65
|
+
result = terminal.spinner(leading_text: "Installing Toys version #{latest_version}... ",
|
66
|
+
final_text: "Done.\n") do
|
67
|
+
exec(["gem", "install", "toys", "--version", latest_version],
|
68
|
+
out_to: :capture, err_to: :capture)
|
69
|
+
end
|
70
|
+
if result.error?
|
71
|
+
puts(result.captured_out + result.captured_err)
|
72
|
+
puts("Toys failed to install version #{latest_version}", :red, :bold)
|
73
|
+
exit(1)
|
74
|
+
end
|
75
|
+
puts("Toys successfully installed version #{latest_version}", :green, :bold)
|
63
76
|
elsif latest_version < cur_version
|
64
|
-
|
65
|
-
|
77
|
+
puts("Toys is already at experimental version #{cur_version}, which is later than" \
|
78
|
+
" the latest released version #{latest_version}",
|
79
|
+
:yellow, :bold)
|
66
80
|
else
|
67
|
-
|
81
|
+
puts("Toys is already at the latest version: #{latest_version}", :green, :bold)
|
68
82
|
end
|
69
83
|
else
|
70
|
-
|
84
|
+
puts("Could not get latest Toys version", :red, :bold)
|
71
85
|
exit(1)
|
72
86
|
end
|
73
87
|
end
|
data/docs/guide.md
CHANGED
@@ -14,34 +14,34 @@ This user's guide covers everything you need to know to use Toys effectively.
|
|
14
14
|
|
15
15
|
Toys is a command line *framework*. It provides a binary called `toys` along
|
16
16
|
with basic functions such as argument parsing and online help. You provide the
|
17
|
-
actual behavior of the toys binary by writing
|
17
|
+
actual behavior of the toys binary by writing **configuration files**.
|
18
18
|
|
19
19
|
Toys is a multi-command binary. You may define a collection of commands, called
|
20
|
-
|
21
|
-
`toys` binary. Tools are arranged in a hierarchy; a tool may be a
|
20
|
+
**tools**, which can be invoked by passing the tool name as an argument to the
|
21
|
+
`toys` binary. Tools are arranged in a hierarchy; a tool may be a **namespace**
|
22
22
|
that has *subtools*.
|
23
23
|
|
24
|
-
Tools may recognize command line arguments in the form of
|
25
|
-
|
26
|
-
arguments may be
|
24
|
+
Tools may recognize command line arguments in the form of **flags** and
|
25
|
+
**positional arguments**. Flags can optionally take **values**, while
|
26
|
+
positional arguments may be **required** or **optional**.
|
27
27
|
|
28
|
-
The configuration of a tool may define
|
29
|
-
for each command line argument. These descriptions are displayed in the
|
30
|
-
|
31
|
-
appear in different styles of help.
|
28
|
+
The configuration of a tool may define **descriptions**, for the tool itself,
|
29
|
+
and for each command line argument. These descriptions are displayed in the
|
30
|
+
tool's **online help** screen. Descriptions come in **long** and **short**
|
31
|
+
forms, which appear in different styles of help.
|
32
32
|
|
33
|
-
Toys searches for configuration in specifically-named
|
34
|
-
|
35
|
-
and in a
|
33
|
+
Toys searches for configuration in specifically-named **configuration files**
|
34
|
+
and **configuration directories**. It searches for these in the current
|
35
|
+
directory, its ancestors, and in a **configuration search path**.
|
36
36
|
|
37
37
|
Toys provides various features to help you write tools. This includes providing
|
38
|
-
a
|
39
|
-
can call, and
|
40
|
-
configuration.
|
38
|
+
a **logger** for each tool, **helper modules** that provide common functions a
|
39
|
+
tool can call, and **templates** which are prefabricated tools you can add to
|
40
|
+
your configuration.
|
41
41
|
|
42
|
-
Finally, Toys provides certain
|
42
|
+
Finally, Toys provides certain **built-in behavior**, including automatically
|
43
43
|
providing flags to display help screens and set verbosity. It also includes a
|
44
|
-
built-in namespace of
|
44
|
+
built-in namespace of **system tools** that let you inspect and configure the
|
45
45
|
Toys system itself.
|
46
46
|
|
47
47
|
## The Toys Command Line
|
@@ -76,7 +76,7 @@ In the following command:
|
|
76
76
|
toys system blah
|
77
77
|
|
78
78
|
There is no subtool `blah` under the `system` namespace, so Toys works backward
|
79
|
-
until it finds
|
79
|
+
until it finds an existing tool. In this case, the `system` namespace itself
|
80
80
|
does exist, so it is interpreted as the tool, and `blah` is interpreted as an
|
81
81
|
argument passed to it.
|
82
82
|
|
@@ -152,8 +152,8 @@ That will cause `--recursive` to be treated as a positional argument. (In this
|
|
152
152
|
case, as we saw earlier, the root tool will respond by printing an error
|
153
153
|
message that no subtool named `--recursive` exists.)
|
154
154
|
|
155
|
-
Note that a single hyphen by itself `-` is not considered a flag
|
156
|
-
as a positional argument.
|
155
|
+
Note that a single hyphen by itself `-` is not considered a flag, nor does it
|
156
|
+
disable flag parsing. It is treated as a normal positional argument.
|
157
157
|
|
158
158
|
#### Standard Flags
|
159
159
|
|
@@ -224,16 +224,192 @@ like so:
|
|
224
224
|
|
225
225
|
## Defining Tools
|
226
226
|
|
227
|
+
Tools are defined by writing Toys *configuration files*. The simplest form of a
|
228
|
+
configuration file is a file named `.toys.rb` (note the leading period) in the
|
229
|
+
current working directory. Such a file may define tools that are available in
|
230
|
+
the current directory, and for this section we will assume we are writing such
|
231
|
+
a file. The following section on "Understanding Configurations" will cover the
|
232
|
+
larger concerns of how configuration files are looked up and how multiple
|
233
|
+
configurations interact.
|
234
|
+
|
235
|
+
### Basic Config Syntax
|
236
|
+
|
237
|
+
The format of a Toys configuration file is a Ruby DSL including method calls
|
238
|
+
and nested blocks. The actual DSL is specified in the
|
239
|
+
[Toys::DSL::Tool class](https://www.rubydoc.info/gems/toys-core/Toys/DSL/Tool).
|
240
|
+
|
241
|
+
To create a tool, write a `tool` block, giving the tool a name. Within the
|
242
|
+
block, set the properties of the tool, including a description, the flags and
|
243
|
+
arguments recognized by the tool, and the actual functionality of the tool.
|
244
|
+
|
245
|
+
Consider the following example:
|
246
|
+
|
247
|
+
tool "greet" do
|
248
|
+
desc "Print a friendly greeting."
|
249
|
+
long_desc "Prints a friendly greeting. You may customize whom to" \
|
250
|
+
" greet, and how friendly it should be.",
|
251
|
+
"",
|
252
|
+
"Example:",
|
253
|
+
[" toys greet --shout ruby"]
|
254
|
+
|
255
|
+
optional_arg :whom, default: "world", desc: "Whom to greet."
|
256
|
+
flag :shout, "-s", "--shout", desc: "Greet loudly."
|
257
|
+
|
258
|
+
def run
|
259
|
+
greeting = "Hello, #{option(:whom)}!"
|
260
|
+
greeting.upcase! if option(:shout)
|
261
|
+
puts greeting
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
Its results should be mostly self-evident. We'll take a look at some of the
|
266
|
+
details below.
|
267
|
+
|
268
|
+
### Descriptions
|
269
|
+
|
270
|
+
Each tool may have a short and a long description. The short description is a
|
271
|
+
generally a single string that is displayed with the tool name at the top of
|
272
|
+
its help page, or in a subtool list. The long description can include multiple
|
273
|
+
strings, which are displayed in multiple lines in the "description" section of
|
274
|
+
the tool's help page. Long descriptions may include blank lines to separate
|
275
|
+
paragraphs visually.
|
276
|
+
|
277
|
+
Each description string/line is word-wrapped by default when displayed. In the
|
278
|
+
long description above, the first line is a bit longer than 80 characters, and
|
279
|
+
may be word-wrapped if displayed on an 80-character terminal.
|
280
|
+
|
281
|
+
If you need to control the wrapping behavior, pass an array of strings for that
|
282
|
+
line. Each array element will be considered a unit for wrapping purposes, and
|
283
|
+
will not be split. The example command in the long description above
|
284
|
+
illustrates how to prevent a line from being word-wrapped. This is also a
|
285
|
+
useful technique for preserving spaces and indentation.
|
286
|
+
|
287
|
+
For more details, see the reference documentation for
|
288
|
+
[DSL::Tool#desc](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:desc)
|
289
|
+
and
|
290
|
+
[DSL::Tool#long_desc](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:long_desc).
|
291
|
+
|
292
|
+
### Positional Arguments
|
293
|
+
|
294
|
+
Tools may recognize required and optional positional arguments. Each argument
|
295
|
+
must provide a name, which defines how the argument value is exposed to the
|
296
|
+
tool at execution time. The above example uses the DSL method
|
297
|
+
[DSL::Tool#optional_arg](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:optional_arg)
|
298
|
+
to declare an optional argument named `:whom`. If the argument is provided on
|
299
|
+
the command line e.g.
|
300
|
+
|
301
|
+
toys greet ruby
|
302
|
+
|
303
|
+
Then the option `:whom` is set to the string `"ruby"`. The value is made
|
304
|
+
available via the `options` hash in the tools's script. Otherwise, if the
|
305
|
+
argument is omitted, e.g.
|
306
|
+
|
307
|
+
toys greet
|
308
|
+
|
309
|
+
Then the option `:whom` is set to the default value `"world"`.
|
310
|
+
|
311
|
+
Arguments may also be **required** which means they must be provided on the
|
312
|
+
command line; otherwise the tool will report a usage error. You may declare a
|
313
|
+
required argument using the DSL method
|
314
|
+
[DSL::Tool#required_arg](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:required_arg).
|
315
|
+
|
316
|
+
When command line arguments are parsed, the required arguments are matched
|
317
|
+
first, in order, followed by the optional arguments. For example:
|
318
|
+
|
319
|
+
tool "arguments" do
|
320
|
+
optional_arg :arg2
|
321
|
+
required_arg :arg1
|
322
|
+
# ...
|
323
|
+
|
324
|
+
If a user runs
|
325
|
+
|
326
|
+
toys arguments foo
|
327
|
+
|
328
|
+
Then the required argument `:arg1` will be set to `"foo"`, and the optional
|
329
|
+
argument `:arg2` will not be set (i.e. it will remain `nil`).
|
330
|
+
|
331
|
+
If the user runs:
|
332
|
+
|
333
|
+
toys arguments foo bar
|
334
|
+
|
335
|
+
Then `:arg1` is set to `"foo"`, and `:arg2` is set to `"bar"`.
|
336
|
+
|
337
|
+
Running the following:
|
338
|
+
|
339
|
+
toys arguments
|
340
|
+
|
341
|
+
Will produce a usage error, because no value is set for the required argument
|
342
|
+
`:arg1`. Similarly, running:
|
343
|
+
|
344
|
+
toys arguments foo bar baz
|
345
|
+
|
346
|
+
Will also produce an error, since the tool does not provide an argument to
|
347
|
+
match `"baz"`.
|
348
|
+
|
349
|
+
You can also provide an "argument" to match all remaining unmatched arguments
|
350
|
+
at the end, using the DSL method
|
351
|
+
[DSL::Tool#remaining_args](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:remaining_args). For example:
|
352
|
+
|
353
|
+
tool "arguments" do
|
354
|
+
optional_arg :arg2
|
355
|
+
required_arg :arg1
|
356
|
+
remaining_args :arg3
|
357
|
+
# ...
|
358
|
+
|
359
|
+
Now, running:
|
360
|
+
|
361
|
+
toys arguments foo bar baz bey
|
362
|
+
|
363
|
+
Sets the following option data:
|
364
|
+
|
365
|
+
{arg1: "foo", arg2: "bar", arg3: ["baz", "bey"]}
|
366
|
+
|
367
|
+
Positional arguments may also have short and long descriptions, which are
|
368
|
+
displayed in online help.
|
369
|
+
|
370
|
+
### Flags
|
371
|
+
|
372
|
+
Tools may also recognize flags on the command line. In our "greet" example, we
|
373
|
+
declared a flag named `:shout`:
|
374
|
+
|
375
|
+
flag :shout, "-s", "--shout", desc: "Greet loudly."
|
376
|
+
|
377
|
+
(guid is still incomplete)
|
378
|
+
|
379
|
+
### The Execution Script
|
380
|
+
|
381
|
+
### Namespaces
|
382
|
+
|
227
383
|
## Understanding Configurations
|
228
384
|
|
229
385
|
## Helper Methods and Modules
|
230
386
|
|
231
|
-
|
387
|
+
### The Standard Helpers
|
388
|
+
|
389
|
+
## The Execution Environment
|
390
|
+
|
391
|
+
### Built-in Context
|
392
|
+
|
393
|
+
### Logging and Verbosity
|
394
|
+
|
395
|
+
### Running Tools from Tools
|
396
|
+
|
397
|
+
### Executing Subprocesses
|
398
|
+
|
399
|
+
### Formatting Output
|
232
400
|
|
233
401
|
## Prefabricated Tools with Templates
|
234
402
|
|
235
|
-
|
403
|
+
### Defining Templates
|
236
404
|
|
237
405
|
## Advanced Tool Definition Techniques
|
238
406
|
|
407
|
+
### Aliases
|
408
|
+
|
409
|
+
### Includes
|
410
|
+
|
411
|
+
### Controlling Built-in Flags
|
412
|
+
|
413
|
+
## The System Tools
|
414
|
+
|
239
415
|
## Embedding Toys
|
data/lib/toys.rb
CHANGED
data/lib/toys/standard_cli.rb
CHANGED
@@ -75,7 +75,7 @@ module Toys
|
|
75
75
|
# Short description for the standard root tool
|
76
76
|
# @return [String]
|
77
77
|
#
|
78
|
-
DEFAULT_ROOT_DESC = "Your personal command line tool
|
78
|
+
DEFAULT_ROOT_DESC = "Your personal command line tool".freeze
|
79
79
|
|
80
80
|
##
|
81
81
|
# Help text for the standard root tool
|
@@ -125,9 +125,9 @@ module Toys
|
|
125
125
|
# `$HOME:/etc` by default.
|
126
126
|
# * The builtins for the standard toys binary.
|
127
127
|
#
|
128
|
+
# @param [Toys::CLI] cli Add paths to this CLI
|
128
129
|
# @param [String,nil] directory Starting search directory for configs.
|
129
130
|
# Defaults to the current working directory.
|
130
|
-
# @param [Toys::CLI] cli Add paths to this CLI
|
131
131
|
#
|
132
132
|
def self.add_standard_paths(cli, directory: nil)
|
133
133
|
cli.add_search_path_hierarchy(start: directory)
|
data/lib/toys/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: toys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Azuma
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-05-
|
11
|
+
date: 2018-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: toys-core
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.3.
|
19
|
+
version: 0.3.7
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.3.
|
26
|
+
version: 0.3.7
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: minitest
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|