toys 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/toys CHANGED
@@ -1,33 +1,25 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- # Copyright 2018 Daniel Azuma
4
+ # Copyright 2019 Daniel Azuma
5
5
  #
6
- # All rights reserved.
6
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ # of this software and associated documentation files (the "Software"), to deal
8
+ # in the Software without restriction, including without limitation the rights
9
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ # copies of the Software, and to permit persons to whom the Software is
11
+ # furnished to do so, subject to the following conditions:
7
12
  #
8
- # Redistribution and use in source and binary forms, with or without
9
- # modification, are permitted provided that the following conditions are met:
13
+ # The above copyright notice and this permission notice shall be included in
14
+ # all copies or substantial portions of the Software.
10
15
  #
11
- # * Redistributions of source code must retain the above copyright notice,
12
- # this list of conditions and the following disclaimer.
13
- # * Redistributions in binary form must reproduce the above copyright notice,
14
- # this list of conditions and the following disclaimer in the documentation
15
- # and/or other materials provided with the distribution.
16
- # * Neither the name of the copyright holder, nor the names of any other
17
- # contributors to this software, may be used to endorse or promote products
18
- # derived from this software without specific prior written permission.
19
- #
20
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
- # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24
- # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
- # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
- # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29
- # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
- # POSSIBILITY OF SUCH DAMAGE.
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
+ # IN THE SOFTWARE.
31
23
  ;
32
24
 
33
25
  ::ENV["TOYS_BIN_PATH"] ||= ::File.absolute_path(__FILE__)
@@ -35,4 +27,4 @@
35
27
  $LOAD_PATH.unshift(::File.absolute_path(::File.join(::File.dirname(__dir__), "lib")))
36
28
  require "toys"
37
29
 
38
- exit(::Toys::StandardCLI.create.run(::ARGV))
30
+ exit(::Toys::StandardCLI.new.run(::ARGV))
@@ -1,33 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright 2018 Daniel Azuma
3
+ # Copyright 2019 Daniel Azuma
4
4
  #
5
- # All rights reserved.
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
6
11
  #
7
- # Redistribution and use in source and binary forms, with or without
8
- # modification, are permitted provided that the following conditions are met:
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
9
14
  #
10
- # * Redistributions of source code must retain the above copyright notice,
11
- # this list of conditions and the following disclaimer.
12
- # * Redistributions in binary form must reproduce the above copyright notice,
13
- # this list of conditions and the following disclaimer in the documentation
14
- # and/or other materials provided with the distribution.
15
- # * Neither the name of the copyright holder, nor the names of any other
16
- # contributors to this software, may be used to endorse or promote products
17
- # derived from this software without specific prior written permission.
18
- #
19
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
- # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
- # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
- # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
- # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
- # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
- # POSSIBILITY OF SUCH DAMAGE.
30
- ;
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
+ # IN THE SOFTWARE.
31
22
 
32
23
  desc "Run multiple tools in order"
33
24
 
@@ -39,25 +30,34 @@ long_desc \
39
30
  "",
40
31
  "Example: Suppose you have a \"rails build\" tool and a \"deploy\" tool. You could run them" \
41
32
  " in order like this:",
42
- [" toys do rails build , deploy"],
43
- "",
44
- "However, if you want to pass flags to the tools to run, you need to preface the arguments" \
45
- " with \"--\" in order to prevent \"do\" from trying to use them as its own flags. That" \
46
- " might look something like this:",
47
- [" toys do -- rails build --staging , deploy --migrate"],
33
+ [" toys do rails build --staging , deploy --migrate"],
48
34
  "",
49
35
  "You may change the delimiter using the --delim flag. For example:",
50
- [" toys do --delim=/ -- rails build --staging / deploy --migrate"]
36
+ [" toys do --delim=/ rails build --staging / deploy --migrate"],
37
+ "The --delim flag must appear first before the tools to run. Any flags that appear later in" \
38
+ " the command line will be passed to the tools themselves."
51
39
 
52
- flag :delim, "-d", "--delim=VALUE",
53
- default: ",",
54
- desc: "Set the delimiter",
55
- long_desc: "Sets the delimiter that separates tool invocations. The default value is \",\"."
40
+ flag :delim do
41
+ flags "-d", "--delim=VALUE"
42
+ default ","
43
+ desc "Set the delimiter"
44
+ long_desc "Sets the delimiter that separates tool invocations. The default value is \",\"."
45
+ end
46
+
47
+ remaining_args :commands do
48
+ complete do |context|
49
+ commands = context.arg_parser.data[:commands]
50
+ last_command = commands.inject([]) { |acc, arg| arg == "," ? [] : (acc << arg) }
51
+ new_context = context.with(previous_words: last_command, disable_flags: commands.empty?)
52
+ new_context.tool.completion.call(new_context)
53
+ end
54
+ desc "A series of tools to run, separated by the delimiter"
55
+ end
56
56
 
57
- remaining_args :args, desc: "A series of tools to run, separated by the delimiter"
57
+ enforce_flags_before_args
58
58
 
59
59
  def run
60
- args
60
+ commands
61
61
  .chunk { |arg| arg == delim ? :_separator : true }
62
62
  .each do |_, action|
63
63
  code = cli.run(action)
@@ -1,33 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright 2018 Daniel Azuma
3
+ # Copyright 2019 Daniel Azuma
4
4
  #
5
- # All rights reserved.
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
6
11
  #
7
- # Redistribution and use in source and binary forms, with or without
8
- # modification, are permitted provided that the following conditions are met:
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
9
14
  #
10
- # * Redistributions of source code must retain the above copyright notice,
11
- # this list of conditions and the following disclaimer.
12
- # * Redistributions in binary form must reproduce the above copyright notice,
13
- # this list of conditions and the following disclaimer in the documentation
14
- # and/or other materials provided with the distribution.
15
- # * Neither the name of the copyright holder, nor the names of any other
16
- # contributors to this software, may be used to endorse or promote products
17
- # derived from this software without specific prior written permission.
18
- #
19
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
- # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23
- # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24
- # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
- # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
- # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29
- # POSSIBILITY OF SUCH DAMAGE.
30
- ;
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
+ # IN THE SOFTWARE.
31
22
 
32
23
  desc "A set of system commands for Toys"
33
24
 
@@ -54,18 +45,18 @@ tool "update" do
54
45
 
55
46
  def run
56
47
  configure_exec(exit_on_nonzero_status: true)
57
- version_info = terminal.spinner(leading_text: "Checking rubygems for the latest release... ",
58
- final_text: "Done.\n") do
48
+ version_info = spinner(leading_text: "Checking rubygems for the latest release... ",
49
+ final_text: "Done.\n") do
59
50
  capture(["gem", "query", "-q", "-r", "-e", "toys"])
60
51
  end
61
52
  if version_info =~ /toys\s\((.+)\)/
62
- latest_version = ::Gem::Version.new($1)
53
+ latest_version = ::Gem::Version.new(::Regexp.last_match(1))
63
54
  cur_version = ::Gem::Version.new(::Toys::VERSION)
64
55
  if latest_version > cur_version
65
56
  prompt = "Update Toys from #{cur_version} to #{latest_version}? "
66
57
  exit(1) unless yes || confirm(prompt, default: true)
67
- result = terminal.spinner(leading_text: "Installing Toys version #{latest_version}... ",
68
- final_text: "Done.\n") do
58
+ result = spinner(leading_text: "Installing Toys version #{latest_version}... ",
59
+ final_text: "Done.\n") do
69
60
  exec(["gem", "install", "toys", "--version", latest_version.to_s],
70
61
  out: :capture, err: :capture)
71
62
  end
@@ -88,3 +79,93 @@ tool "update" do
88
79
  end
89
80
  end
90
81
  end
82
+
83
+ tool "bash-completion" do
84
+ desc "Bash tab completion for Toys"
85
+
86
+ long_desc \
87
+ "Tools that manage tab completion for Toys in the bash shell.",
88
+ "",
89
+ "To install tab completion for Toys, execute the following line in a bash shell, or" \
90
+ " include it in an init file such as your .bashrc:",
91
+ [" $(toys system bash-completion install)"],
92
+ "",
93
+ "To remove tab completion, execute:",
94
+ [" $(toys system bash-completion remove)"],
95
+ "",
96
+ "It is also possible to install completions for different executable names if you have" \
97
+ " aliases for Toys. See the help for the \"install\" and \"remove\" tools for details.",
98
+ "",
99
+ "The \"eval\" tool is the actual completion command invoked by bash when it needs to" \
100
+ " complete a toys command line. You shouldn't need to invoke it directly."
101
+
102
+ tool "eval" do
103
+ desc "Tab completion command (executed by bash)"
104
+
105
+ long_desc \
106
+ "Completion command invoked by bash to compete a toys command line. Generally you do not" \
107
+ " need to invoke this directly. It reads the command line context from the COMP_LINE" \
108
+ " and COMP_POINT environment variables, and outputs completion candidates to stdout."
109
+
110
+ disable_argument_parsing
111
+
112
+ def run
113
+ require "toys/utils/completion_engine"
114
+ result = ::Toys::Utils::CompletionEngine::Bash.new(cli).run
115
+ if result > 1
116
+ logger.fatal("This tool must be invoked as a bash completion command.")
117
+ end
118
+ exit(result)
119
+ end
120
+ end
121
+
122
+ tool "install" do
123
+ desc "Install bash tab completion"
124
+
125
+ long_desc \
126
+ "Outputs a command to set up Toys tab completion in the current bash shell.",
127
+ "",
128
+ "To use, execute the following line in a bash shell, or include it in an init file" \
129
+ " such as your .bashrc:",
130
+ [" $(toys system bash-completion install)"],
131
+ "",
132
+ "This will associate the toys tab completion logic with the `toys` executable by default." \
133
+ " If you have aliases for the toys executable, pass them as arguments. e.g.",
134
+ [" $(toys system bash-completion install my-toys-alias another-alias)"]
135
+
136
+ remaining_args :executable_names,
137
+ desc: "Names of executables for which to set up tab completion" \
138
+ " (default: #{::Toys::StandardCLI::EXECUTABLE_NAME})"
139
+
140
+ def run
141
+ require "shellwords"
142
+ path = ::File.join(::File.dirname(__dir__), "share", "bash-completion.sh")
143
+ exes = executable_names.empty? ? [::Toys::StandardCLI::EXECUTABLE_NAME] : executable_names
144
+ puts Shellwords.join(["source", path] + exes)
145
+ end
146
+ end
147
+
148
+ tool "remove" do
149
+ desc "Remove bash tab completion"
150
+
151
+ long_desc \
152
+ "Outputs a command to remove Toys tab completion from the current bash shell.",
153
+ "",
154
+ "To use, execute the following line in a bash shell:",
155
+ [" $(toys system bash-completion remove)"],
156
+ "",
157
+ "If you have other names or aliases for the toys executable, pass them as arguments. e.g.",
158
+ [" $(toys system bash-completion remove my-toys-alias another-alias)"]
159
+
160
+ remaining_args :executable_names,
161
+ desc: "Names of executables for which to set up tab completion" \
162
+ " (default: #{::Toys::StandardCLI::EXECUTABLE_NAME})"
163
+
164
+ def run
165
+ require "shellwords"
166
+ path = ::File.join(::File.dirname(__dir__), "share", "bash-completion-remove.sh")
167
+ exes = executable_names.empty? ? [::Toys::StandardCLI::EXECUTABLE_NAME] : executable_names
168
+ puts Shellwords.join(["source", path] + exes)
169
+ end
170
+ end
171
+ end
@@ -3,8 +3,8 @@
3
3
  # Toys User Guide
4
4
 
5
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.
6
+ a simple DSL, and Toys will provide the command line executable and take care
7
+ of all the details such as argument parsing, online help, and error reporting.
8
8
 
9
9
  Toys is designed for software developers, IT professionals, and other power
10
10
  users who want to write and organize scripts to automate their workflows. It
@@ -12,23 +12,33 @@ can also be used as a Rake replacement, providing a more natural command line
12
12
  interface for your project's build tasks.
13
13
 
14
14
  Unlike most command line frameworks, Toys is *not primarily* designed to help
15
- you build and ship a custom command line binary written in Ruby. Rather, it
16
- provides a single binary called `toys`. You define the commands recognized by
17
- the Toys binary by writing configuration files. (You can, however, build your
18
- own custom command line binary using the related **toys-core** library.)
19
-
20
- This user's guide covers everything you need to know to use Toys effectively.
21
-
22
- ## Conceptual Overview
23
-
24
- Toys is a command line *framework*. It provides a binary called `toys` along
15
+ you build and ship a custom command line executable written in Ruby. Rather, it
16
+ provides a single executable called `toys`. You define the commands recognized
17
+ by the Toys executable by writing configuration files. (You can, however, build
18
+ your own custom command line executable using the related **toys-core**
19
+ library.)
20
+
21
+ If this is your first time using Toys, we recommend starting with the
22
+ [README](https://www.rubydoc.info/gems/toys/file/README.md), which includes a
23
+ tutorial that introduces how to install Toys, write and execute tools, and even
24
+ use Toys to replace Rake. The tutorial will likely give you enough information
25
+ to start using Toys effectively.
26
+
27
+ This user's guide is also structured like an extended tutorial, but it is much
28
+ longer and covers all the features of Toys in much more depth. Read it when
29
+ you're ready to unlock all the capabilities of Toys to create sophisticated
30
+ command line tools.
31
+
32
+ ## Conceptual overview
33
+
34
+ Toys is a command line *framework*. It provides an executable called `toys`
25
35
  with basic functions such as argument parsing and online help. You provide the
26
- actual behavior of the Toys binary by writing **Toys files**.
36
+ actual behavior of the Toys executable by writing **Toys files**.
27
37
 
28
- Toys is a multi-command binary. You may define any number of commands, called
29
- **tools**, which can be invoked by passing the tool name as an argument to the
30
- `toys` binary. Tools are arranged in a hierarchy; you may define **namespaces**
31
- that have **subtools**.
38
+ Toys is a multi-command executable. You may define any number of commands,
39
+ called **tools**, which can be invoked by passing the tool name as an argument
40
+ to the `toys` executable. Tools are arranged in a hierarchy; you may define
41
+ **namespaces** that have **subtools**.
32
42
 
33
43
  Tools may recognize command line arguments in the form of **flags** and
34
44
  **positional arguments**. Flags can optionally take **values**, while
@@ -42,12 +52,12 @@ tool's **online help** screen. Descriptions come in **long** and **short**
42
52
  forms, which appear in different styles of help.
43
53
 
44
54
  Toys searches for tools in specifically-named **Toys files** and **Toys
45
- directories**. It searches for these in the current directory, its ancestors,
46
- and in the Toys **search path**.
55
+ directories**. It searches for these in the current directory, in its
56
+ ancestors, and in the Toys **search path**.
47
57
 
48
58
  Toys provides various features to help you write tools. This includes providing
49
59
  a **logger** for each tool, **mixins** that provide common functions a tool can
50
- call (such as controlling subprocesses and styling output), and **templates**
60
+ call (such as to control subprocesses and style output), and **templates**
51
61
  which are prefabricated tools that you can configure for your needs.
52
62
 
53
63
  Finally, Toys provides useful **built-in behavior**, including automatically
@@ -55,7 +65,7 @@ providing flags to display help screens and set verbosity. It also includes a
55
65
  built-in namespace of **system tools** that let you inspect and configure the
56
66
  Toys system itself.
57
67
 
58
- ## The Toys Command Line
68
+ ## The Toys command line
59
69
 
60
70
  In this section, you will learn how Toys parses its command line, identifies a
61
71
  tool to run, and interprets flags and other command line arguments.
@@ -73,8 +83,8 @@ first **positional argument**), or until there are no more arguments.
73
83
 
74
84
  For example, in the following command:
75
85
 
76
- |----TOOL----|
77
- toys system version
86
+ |----TOOL----|
87
+ $ toys system version
78
88
 
79
89
  The tool name is `system version`. Notice that the tool name may have multiple
80
90
  words. Tools are arranged hierarchically. In this case, `system` is a
@@ -85,13 +95,13 @@ The words in a tool name can be delimited with spaces as shown above, or
85
95
  alternately periods or colons. The following commands also invoke the tool
86
96
  `system version`:
87
97
 
88
- toys system.version
89
- toys system:version
98
+ $ toys system.version
99
+ $ toys system:version
90
100
 
91
101
  In the following command:
92
102
 
93
- |TOOL| |ARG|
94
- toys system frodo
103
+ |TOOL| |ARG|
104
+ $ toys system frodo
95
105
 
96
106
  There is no subtool `frodo` under the `system` namespace, so Toys works
97
107
  backward until it finds an existing tool. In this case, the `system` namespace
@@ -103,7 +113,7 @@ other tool. In the above case, it takes the argument `frodo`, determines it has
103
113
  no subtool of that name, and prints an error message. More commonly, though,
104
114
  you might execute a namespace without arguments:
105
115
 
106
- toys system
116
+ $ toys system
107
117
 
108
118
  This displays the **online help screen** for the `system` namespace, which
109
119
  includes a list of all its subtools and what they do.
@@ -111,14 +121,14 @@ includes a list of all its subtools and what they do.
111
121
  It is also legitimate for the tool name to be empty. This invokes the **root
112
122
  tool**, the toplevel namespace:
113
123
 
114
- toys
124
+ $ toys
115
125
 
116
126
  Like any namespace, invoking the root tool displays its help screen, including
117
127
  showing the list of all its subtools.
118
128
 
119
129
  One last example:
120
130
 
121
- toys frodo
131
+ $ toys frodo
122
132
 
123
133
  If there is no tool called `frodo` in the toplevel namespace, then once again,
124
134
  `frodo` is interpreted as an argument to the root tool. The root tool responds
@@ -134,38 +144,51 @@ tool, the tool will generally display an error message.
134
144
 
135
145
  Toys follows the typical unix conventions for flags, specifically those covered
136
146
  by Ruby's OptionParser library. You can provide short (single-character) flags
137
- with a single hyphen, or long flags with a double hyphen. You can also provide
138
- optional **values** for flags. Following are a few examples.
147
+ with a single hyphen, or long flags with a double hyphen. Some flags can also
148
+ take **values**. Following are a few examples.
149
+
150
+ Here we pass a single short flag (for verbose output).
151
+
152
+ $ toys system -v
139
153
 
140
- Pass a single short flag (for verbose output).
154
+ Here we pass multiple long flags (for verbose output and recursive subtool
155
+ search).
141
156
 
142
- toys system -v
157
+ $ toys system --verbose --recursive
143
158
 
144
- Pass multiple long flags (for verbose output and recursive subtool search).
159
+ You can combine short flags. The following passes both the `-v` and `-r` flags
160
+ (i.e. it has the same effect as the previous example.)
145
161
 
146
- toys system --verbose --recursive
162
+ $ toys system -vr
147
163
 
148
- You can combine short flags. This does the same as the previous example.
164
+ Long flags can be abbreviated, as long as the abbreviation is not ambiguous.
165
+ For example, there is only one flag (`--recursive`) beginning with the string
166
+ `--rec`, so you can use the shortened form.
149
167
 
150
- toys system -rv
168
+ $ toys --rec
151
169
 
152
- Pass a value using a long flag. The root tool supports the `--search` flag to
153
- search for tools that have the given keyword.
170
+ However, there are two flags (`--version` and `--verbose`) beginning with
171
+ `--ver`, so it cannot be used as an abbreviation. This will cause an error:
154
172
 
155
- toys --search=build
156
- toys --search build
173
+ $ toys --ver
157
174
 
158
- Pass a value using a short flag.
175
+ Some flags take values. The root tool supports the `--search` flag to search
176
+ for tools that have the given keyword.
159
177
 
160
- toys -s build
161
- toys -sbuild
178
+ $ toys --search=build
179
+ $ toys --search build
180
+
181
+ The short form of the search flag `-s` also takes a value.
182
+
183
+ $ toys -s build
184
+ $ toys -sbuild
162
185
 
163
186
  If a double hyphen `--` appears by itself in the arguments, it disables flag
164
187
  parsing from that point. Any further arguments are treated as positional
165
188
  arguments, even if they begin with hyphens. For example:
166
189
 
167
- |--FLAG--| |---ARG---|
168
- toys --verbose -- --recursive
190
+ |--FLAG--| |---ARG---|
191
+ $ toys --verbose -- --recursive
169
192
 
170
193
  That will cause `--recursive` to be treated as a positional argument. (In this
171
194
  case, as we saw earlier, the root tool will respond by printing an error
@@ -174,7 +197,7 @@ message that no tool named `--recursive` exists.)
174
197
  Note that a single hyphen by itself `-` is not considered a flag, nor does it
175
198
  disable flag parsing. It is treated as a normal positional argument.
176
199
 
177
- #### Standard Flags
200
+ #### Standard flags
178
201
 
179
202
  For the most part, each tool specifies which flags and arguments it recognizes.
180
203
  However, Toys adds a few standard flags globally to every tool. (It is possible
@@ -196,18 +219,19 @@ flag, but it has no additional effect.) Namespaces also support the following
196
219
  additional flags:
197
220
 
198
221
  * `--all` which displays all subtools, including
199
- [hidden subtools](#Hidden_Tools) and namespaces.
200
- * `--[no-]recursive` (also `-r`) which displays all subtools recursively,
201
- instead of only the immediate subtools.
222
+ [hidden subtools](#Hidden_tools) and namespaces.
223
+ * `--no-recursive` which displays only immediate subtools, instead of the
224
+ default behavior of showing all subtools recursively.
202
225
  * `--search=TERM` which displays only subtools whose name or description
203
226
  contain the specified search term.
204
- * `--tools` which displays just the list of subtools.
227
+ * `--tools` which displays just the list of subtools rather than the entire
228
+ help screen.
205
229
 
206
230
  Finally, the root tool also supports:
207
231
 
208
232
  * `--version` which displays the current Toys version.
209
233
 
210
- ### Positional Arguments
234
+ ### Positional arguments
211
235
 
212
236
  Any arguments not recognized as flags or flag arguments, are interpreted as
213
237
  **positional arguments**. Positional arguments are recognized in order and may
@@ -222,32 +246,70 @@ recognizes any number of positional arguments. Those arguments specify which
222
246
  tools to run and what arguments to pass to them. If, for example, you had a
223
247
  `build` tool and a `test` tool, you could run them in sequence with:
224
248
 
225
- |---ARGS---|
226
- toys do build , test
249
+ |---ARGS---|
250
+ $ toys do build , test
227
251
 
228
- The three arguments `build`, `,`, and `test` are positional arguments to the
252
+ The three arguments `build` and `,` and `test` are positional arguments to the
229
253
  `do` tool. (The `do` tool uses `,` to delimit the tools that it should run.)
230
254
 
231
- Here is a more complex example illustrating the interaction between flags and
232
- positional arguments. Suppose we want to use `do` to display the help screens
233
- for the root tool and the system tool in sequence. That is, we want to run
234
- `toys --help` and `toys system --help` in sequence. We might start by trying:
255
+ Most tools allow flags and positional arguments to be interspersed. A flag will
256
+ be recognized even if it appears after some of the positional arguments.
257
+
258
+ However, this approach would not work for the `do` tool because its common case
259
+ is to pass flags down to the steps it runs. (That is, `do` wants most arguments
260
+ to be treated as positional even if they look like flags.) So `do` stops
261
+ recognizing flags once it encounters its first positional argument. That is,
262
+ you could do this:
263
+
264
+ |------------ARGS-----------|
265
+ $ toys do build --staging , test --help
266
+
267
+ Each tool can choose which behavior it will support, whether or not to enforce
268
+ [flags before positional args](#Enforcing_flags_before_args).
235
269
 
236
- |FLAG| |-ARGS-| |FLAG|
237
- toys do --help , system --help
270
+ You can also, of course, stop recognizing flags on the command line by passing
271
+ `--` as an argument.
238
272
 
239
- However, this simply displays the help for the `do` tool itself, because the
240
- first `--help` is interpreted as a flag for `do`. What we actually want is for
241
- `do` to treat it as a positional argument specifying the first tool to run. So
242
- Let's force `do` to treat all its arguments as positional, by starting with
243
- `--` like so:
273
+ ### Tab completion
244
274
 
245
- |--------ARGS--------|
246
- toys do -- --help , system --help
275
+ If you are using the Bash shell, Toys provides custom tab completion. See
276
+ [this section](#Installing_tab_completion_for_Bash) for instructions on
277
+ installing tab completion.
247
278
 
248
- Now `toys do` behaves as we intended.
279
+ Toys will complete tool and subtool names, flags, values passed to flags, and
280
+ positional argument values, and it will respect the current context. For
281
+ example, if you type:
249
282
 
250
- ## Defining Tools
283
+ $ toys <TAB><TAB>
284
+
285
+ The tab completion will show you a list of reasonable things that could appear
286
+ next, including the defined tool names (such as `system` and `do`) as well as
287
+ all the flags supported by the root tool (such as `--help` and `-v`). And of
288
+ course, if you start typing something, tab completion will limit the display to
289
+ matching completions. The following displays only flags, i.e. completions that
290
+ begin with a hyphen:
291
+
292
+ $ toys -<TAB><TAB>
293
+
294
+ And if you type the following:
295
+
296
+ $ toys sys<TAB>
297
+
298
+ It is likely only one tool name starts with `sys`, so completion will
299
+ automatically type the rest of `system` for you.
300
+
301
+ The tab completion for Toys also supports values passed to flags and positional
302
+ args. As we shall see later, when you define a flag or a positional argument,
303
+ you can specify how completions are computed.
304
+
305
+ **Note:** Because of the highly dynamic nature of Toys in which tools, flags,
306
+ and arguments can be highly customized, the completion implementation actually
307
+ requires *executing Toys* so it can analyze your tool configurations. This
308
+ unfortunately means paying some upfront latency as the Ruby interpreter starts
309
+ up. So you can expect a slight pause when evaluating tab completion for Toys,
310
+ at least in comparison with most other tab completions.
311
+
312
+ ## Defining tools
251
313
 
252
314
  So far we've been experimenting only with the built-in tools provided by Toys.
253
315
  In this section, you will learn how to define tools by writing a **Toys file**.
@@ -255,7 +317,7 @@ We will cover how to write tools, including specifying the functionality of the
255
317
  tool, the flags and arguments it takes, and how its description appears in the
256
318
  help screen.
257
319
 
258
- ### Basic Toys Syntax
320
+ ### Basic Toys syntax
259
321
 
260
322
  A file named `.toys.rb` (note the leading period) in the current working
261
323
  directory is called a **Toys file**. It defines tools available in that
@@ -285,14 +347,14 @@ Let's start with an example:
285
347
 
286
348
  def run
287
349
  greeting = "Hello, #{whom}!"
288
- greeting.upcase! if shout
350
+ greeting = greeting.upcase if shout
289
351
  puts greeting
290
352
  end
291
353
  end
292
354
 
293
355
  Its results should be mostly self-evident. But let's unpack a few details.
294
356
 
295
- ### Tool Descriptions
357
+ ### Tool descriptions
296
358
 
297
359
  Each tool may have a **short description** and/or a **long description**. The
298
360
  short description is a generally a single string that is displayed with the
@@ -316,7 +378,7 @@ For more details, see the reference documentation for
316
378
  and
317
379
  [Toys::DSL::Tool#long_desc](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:long_desc).
318
380
 
319
- ### Positional Arguments
381
+ ### Positional arguments
320
382
 
321
383
  Tools may recognize any number of **positional arguments**. Each argument must
322
384
  have a name, which is a key that the tool can use to obtain the argument's
@@ -328,12 +390,14 @@ The above example uses the directive
328
390
  to declare an **optional argument** named `:whom`. If the argument is provided
329
391
  on the command line e.g.
330
392
 
331
- toys greet ruby
393
+ $ toys greet ruby
394
+ Hello, ruby!
332
395
 
333
396
  Then the option `:whom` is set to the string `"ruby"`. Otherwise, if the
334
397
  argument is omitted, e.g.
335
398
 
336
- toys greet
399
+ $ toys greet
400
+ Hello, world!
337
401
 
338
402
  Then the option `:whom` is set to the default value `"world"`.
339
403
 
@@ -341,14 +405,14 @@ If the option name is a valid method name, Toys will provide a method that you
341
405
  can use to retrieve the value. In the above example, we retrieve the value for
342
406
  the option `:whom` by calling the method `whom`. If the option name cannot be
343
407
  made into a method, you can retrieve the value by calling
344
- [Toys::Tool#get](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:get).
408
+ [Toys::Context#get](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:get).
345
409
 
346
410
  An argument may also be **required**, which means it must be provided on the
347
411
  command line; otherwise the tool will report a usage error. You may declare a
348
412
  required argument using the directive
349
413
  [Toys::DSL::Tool#required_arg](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:required_arg).
350
414
 
351
- #### Parsing Required and Optional Arguments
415
+ #### Parsing required and optional arguments
352
416
 
353
417
  When command line arguments are parsed, the required arguments are matched
354
418
  first, in order, followed by the optional arguments. For example:
@@ -356,29 +420,35 @@ first, in order, followed by the optional arguments. For example:
356
420
  tool "args-demo" do
357
421
  optional_arg :arg2
358
422
  required_arg :arg1
359
- # ...
423
+
424
+ def run
425
+ puts "options data is #{options.inspect}"
426
+ end
427
+ end
360
428
 
361
429
  If a user runs
362
430
 
363
- toys args-demo foo
431
+ $ toys args-demo foo
432
+ Options data is {arg1: "foo", arg2: nil}
364
433
 
365
434
  Then the required argument `:arg1` will be set to `"foo"`, and the optional
366
435
  argument `:arg2` will not be set (i.e. it will remain `nil`).
367
436
 
368
437
  If the user runs:
369
438
 
370
- toys args-demo foo bar
439
+ $ toys args-demo foo bar
440
+ Options data is {arg1: "foo", arg2: "bar"}
371
441
 
372
442
  Then `:arg1` is set to `"foo"`, and `:arg2` is set to `"bar"`.
373
443
 
374
444
  Running the following:
375
445
 
376
- toys args-demo
446
+ $ toys args-demo
377
447
 
378
448
  Will produce a usage error, because no value is set for the required argument
379
449
  `:arg1`. Similarly, running:
380
450
 
381
- toys args-demo foo bar baz
451
+ $ toys args-demo foo bar baz
382
452
 
383
453
  Will also produce an error, since the tool does not define an argument to
384
454
  match `"baz"`.
@@ -389,16 +459,21 @@ not provided on the command line. For example:
389
459
  tool "args-demo" do
390
460
  required_arg :arg1
391
461
  optional_arg :arg2, default: "the-default"
392
- # ...
462
+
463
+ def run
464
+ puts "options data is #{options.inspect}"
465
+ end
466
+ end
393
467
 
394
468
  Now running the following:
395
469
 
396
- toys args-demo foo
470
+ $ toys args-demo foo
471
+ Options data is {arg1: "foo", arg2: "the-default"}
397
472
 
398
473
  Will set the required argument to `"foo"` as usual, and the optional argument,
399
474
  because it is not provided, will default to `"the-default"` instead of `nil`.
400
475
 
401
- #### Remaining Arguments
476
+ #### Remaining arguments
402
477
 
403
478
  Normally, unmatched arguments will result in an error message. However, you can
404
479
  provide an "argument" to match all **remaining** unmatched arguments at the
@@ -410,29 +485,25 @@ For example:
410
485
  required_arg :arg1
411
486
  optional_arg :arg2
412
487
  remaining_args :arg3
413
- # ...
414
488
 
415
- Now, running:
416
-
417
- toys args-demo foo bar baz bey
418
-
419
- Sets the following option data:
420
-
421
- {arg1: "foo", arg2: "bar", arg3: ["baz", "bey"]}
422
-
423
- If instead you run:
489
+ def run
490
+ puts "Options data is #{options.inspect}"
491
+ end
492
+ end
424
493
 
425
- toys args-demo foo
494
+ Now, we can see how the remaining arguments (if any) are collected by `:arg3`:
426
495
 
427
- This sets the following option data:
496
+ $ toys args-demo foo bar baz qux
497
+ Options data is {arg1: "foo", arg2: "bar", arg3: ["baz", "qux"]}
428
498
 
429
- {arg1: "foo", arg2: nil, arg3: []}
499
+ $ toys args-demo foo
500
+ Options data is {arg1: "foo", arg2: nil, arg3: []}
430
501
 
431
502
  Tools can include any number of `required_arg` and `optional_arg` directives,
432
- declaring any number of required and optional arguments, but they can have only
433
- at most one `remaining_args` directive.
503
+ declaring any number of required and optional arguments. But tools can have at
504
+ most only one `remaining_args` directive.
434
505
 
435
- #### Descriptions and the Args DSL
506
+ #### Descriptions and the args DSL
436
507
 
437
508
  Positional arguments may also have short and long descriptions, which are
438
509
  displayed in online help. Set descriptions via the `desc:` and `long_desc:`
@@ -445,7 +516,7 @@ an example:
445
516
  long_desc: ["Long descriptions may have multiple lines.",
446
517
  "This is the second line."]
447
518
 
448
- See the [above section on Descriptions](#Tool_Descriptions) for more
519
+ See the [above section on Descriptions](#Tool_descriptions) for more
449
520
  information on how descriptions are rendered and word wrapped.
450
521
 
451
522
  Because long descriptions may be unwieldly to write as a hash argument in this
@@ -459,9 +530,9 @@ way, Toys provides an alternate syntax for defining arguments using a block.
459
530
  end
460
531
 
461
532
  For detailed info on configuring an argument using a block, see the
462
- [Toys::DSL::Arg class](https://www.rubydoc.info/gems/toys-core/Toys/DSL/Arg).
533
+ [Toys::DSL::PositionalArg class](https://www.rubydoc.info/gems/toys-core/Toys/DSL/PositionalArg).
463
534
 
464
- #### Argument Acceptors
535
+ #### Argument acceptors
465
536
 
466
537
  Finally, positional arguments may use **acceptors** to define how to validate
467
538
  arguments and convert them to Ruby objects for your tool to consume. By
@@ -478,7 +549,8 @@ integer during parsing:
478
549
  required_arg :age, accept: Integer
479
550
  def run
480
551
  puts "Next year I will be #{age + 1}" # Age is an integer
481
- ...
552
+ end
553
+ end
482
554
 
483
555
  If you pass a non-integer for this argument, Toys will report a usage error.
484
556
 
@@ -489,7 +561,31 @@ and
489
561
  [OptionParser::OctalInteger](http://ruby-doc.org/stdlib/libdoc/optparse/rdoc/OptionParser.html#OctalInteger).
490
562
 
491
563
  You may also create **custom acceptors**. See the
492
- [section below on Custom Acceptors](#Custom_Acceptors) for more information.
564
+ [section below on Custom Acceptors](#Custom_acceptors) for more information.
565
+
566
+ #### Argument completions
567
+
568
+ Shell tab completion supports positional arguments, and arguments can be
569
+ configured to present a set of completion candidates for themselves.
570
+
571
+ By default, an argument does not provide any completions for itself. To change
572
+ that, set the `completion` option. Currently there are three ways to set the
573
+ completion:
574
+
575
+ * Provide a static set of possible values, as an array of strings.
576
+ * Specify that values should be paths in the file system by setting the
577
+ symbol `:file_system`.
578
+ * Provide a `Proc` that returns possible values.
579
+
580
+ The following are two example arguments, one that supports a static set of
581
+ completions and the other that supports file paths.
582
+
583
+ required_arg :language, complete: ["ruby", "elixir", "rust"]
584
+ required_arg :path, complete: :file_system
585
+
586
+ Completions are somewhat related to acceptors, and it is a common pattern to
587
+ set both in concert. But they perform distinct functions. Acceptors affect
588
+ argument parsing, whereas completions affect tab completion in the shell.
493
589
 
494
590
  ### Flags
495
591
 
@@ -508,21 +604,15 @@ As with arguments, Toys will provide a method that you can call to retrieve the
508
604
  option value set by a flag. In this case, a method called `shout` will be
509
605
  available, and will return either true or false. If the option name cannot be
510
606
  made into a method, you can retrieve the value by calling
511
- [Toys::Tool#get](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:get).
607
+ [Toys::Context#get](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:get).
512
608
 
513
- #### Flag Types
609
+ #### Flag types
514
610
 
515
611
  Toys recognizes the same syntax used by the standard OptionParser library. This
516
612
  means you can also declare a flag that can be set either to true or false:
517
613
 
518
614
  flag :shout, "--[no-]shout"
519
615
 
520
- If you do not provide any actual flags, Toys will infer a long flag from the
521
- name of the option. Hence, the following two definitions are equivalent:
522
-
523
- flag :shout
524
- flag :shout, "--shout"
525
-
526
616
  You can declare that a short or long flag takes a value:
527
617
 
528
618
  flag :whom, "--whom=VALUE"
@@ -554,7 +644,106 @@ example:
554
644
  Raises an error because one flag's value is optional while the other is
555
645
  required. (Again, this is consistent with OptionParser's behavior.)
556
646
 
557
- #### Flag Acceptors
647
+ #### Inferred flags
648
+
649
+ If you do not provide any actual flags, Toys will attempt to infer one from the
650
+ name of the option. A one-character name will yield a short flag, and a longer
651
+ name a long flag. Hence, the following two definitions are equivalent:
652
+
653
+ flag :shout
654
+ flag :shout, "--shout"
655
+
656
+ And the following two are equivalent:
657
+
658
+ flag :S
659
+ flag :S, "-S"
660
+
661
+ Inferred flags will convert underscores to hyphens. So the following two
662
+ definitions are also equivalent:
663
+
664
+ flag :call_out
665
+ flag :call_out, "--call-out
666
+
667
+ #### Handling optional values
668
+
669
+ There are some subtleties in how the Ruby OptionParser library treats flags
670
+ with optional values. Although Toys does not use OptionParser interally, it
671
+ does, for the most part, replicate OptionParser's behavior. It is thus
672
+ important to understand that behavior if you use optional values.
673
+
674
+ First, if a flag has an optional value that is not provided on the command
675
+ line, then the option is set to `true`, as if it were a normal boolean flag
676
+ that didn't take a value. Consider this example:
677
+
678
+ tool "flags-demo" do
679
+ flag :output, "--output [DIRECTORY]", default: "."
680
+ def run
681
+ puts "output is #{output.inspect}"
682
+ end
683
+ end
684
+
685
+ If a user executes this without passing the `--output` flag, the default will
686
+ be printed as we expect.
687
+
688
+ $ toys flags-demo
689
+ output is "."
690
+
691
+ If a user executes this and provides a value for `--output`, it will show up:
692
+
693
+ $ toys flags-demo --output /etc
694
+ output is "/etc"
695
+
696
+ If a user provides `--output` but omits the value, it displays `true`:
697
+
698
+ $ toys flags-demo --output
699
+ output is true
700
+
701
+ Second, if the following argument looks like a flag (i.e. it begins with a
702
+ hyphen), it is not treated as an optional value. In this example, the argument
703
+ `--verbose` is not treated as the value of `--output` but as a separate flag.
704
+ (If `--output` had a *required* value, then `--verbose` would have been treated
705
+ as the value.)
706
+
707
+ $ toys flags-demo --output --verbose
708
+ output is true
709
+
710
+ Finally, there is an important difference between the syntax
711
+ `"--output [DIRECTORY]"` and `"--output=[DIRECTORY]"`. In the former case, the
712
+ following argument (as long as it doesn't look like a flag) will be treated as
713
+ the value. In the latter case, however, the following argument is *never*
714
+ treated as the value. In that latter case, you *must* use the equals sign
715
+ syntax to provide a value.
716
+
717
+ To illustrate, consider two flags with optional values, one using space and the
718
+ other using equals.
719
+
720
+ tool "flags-demo-space" do
721
+ flag :output, "--output [DIRECTORY]", default: "."
722
+ set_remaining_args :remaining
723
+ def run
724
+ puts "output is #{output.inspect}"
725
+ end
726
+ end
727
+ tool "flags-demo-equals" do
728
+ flag :output, "--output=[DIRECTORY]", default: "."
729
+ set_remaining_args :remaining
730
+ def run
731
+ puts "output is #{output.inspect}"
732
+ end
733
+ end
734
+
735
+ Here is the behavior:
736
+
737
+ $ toys flags-demo-space --output=/etc
738
+ output is "/etc"
739
+ $ toys flags-demo-space --output /etc
740
+ output is "/etc"
741
+ $ toys flags-demo-equals --output=/etc
742
+ output is "/etc"
743
+ $ toys flags-demo-equals --output /etc
744
+ output is true
745
+
746
+ #### Flag acceptors
558
747
 
559
748
  Flags may use **acceptors** to define how to validate values and convert them
560
749
  to Ruby objects for your tool to consume. By default, Toys will accept a flag
@@ -567,11 +756,12 @@ section. For example, you can provide the `Integer` class as an acceptor, which
567
756
  will validate that the argument is a well-formed integer, and convert it to an
568
757
  integer during parsing:
569
758
 
570
- tool "args-demo" do
759
+ tool "flags-demo" do
571
760
  flag :age, accept: Integer
572
761
  def run
573
762
  puts "Next year I will be #{age + 1}" # Age is an integer
574
- ...
763
+ end
764
+ end
575
765
 
576
766
  If you pass a non-integer for this flag value, Toys will report a usage error.
577
767
 
@@ -582,15 +772,16 @@ and
582
772
  [OptionParser::OctalInteger](http://ruby-doc.org/stdlib/libdoc/optparse/rdoc/OptionParser.html#OctalInteger).
583
773
 
584
774
  You may also create **custom acceptors**. See the
585
- [section below on Custom Acceptors](#Custom_Acceptors) for more information.
775
+ [section below on Custom Acceptors](#Custom_acceptors) for more information.
586
776
 
587
- #### Defaults and Handlers
777
+ #### Defaults and handlers
588
778
 
589
- Currently, flags are always optional; a flag can appear in a command line zero,
590
- one, or any number of times. If a flag is not passed in the command line
591
- arguments for a tool, by default its corresponding option value will be `nil`.
779
+ Flags are usually optional; a flag can appear in a command line zero, one, or
780
+ any number of times.
592
781
 
593
- You may change this by providing a default value for a flag:
782
+ If a flag is not passed in the command line arguments for a tool, by default
783
+ its corresponding option value will be `nil`. You may change this by providing
784
+ a default value for a flag:
594
785
 
595
786
  flag :age, accept: Integer, default: 21
596
787
 
@@ -601,39 +792,61 @@ appearance of the flag will take effect. That is, suppose you define this flag:
601
792
 
602
793
  Now if you pass `--shout --no-shout`, then the value of the `:shout` option
603
794
  will be `false`, i.e. the last value set on the command line. This is because a
604
- flag *sets* its option value, replacing any previously set value. You may
605
- change this behavior by providing a **handler**.
795
+ flag normally *sets* its option value, replacing any previously set value.
796
+
797
+ You can, however, change this behavior by providing a **handler**. A handler is
798
+ a Ruby Proc that defines what a flag does to its option value. It takes two
799
+ arguments, the new value given, and the previously set value (which might be
800
+ the default value if this is the first appearance of the flag), and returns the
801
+ new value that should be set.
606
802
 
607
- A handler is a proc that governs what a flag does to its option value. It takes
608
- two arguments, the new value given, and the previously set value (which might
609
- be the default value if this is the first appearance of the flag), and returns
610
- the new value that should be set. So effectively, the default behavior is
611
- equivalent to the following handler:
803
+ Effectively, the default behavior (setting the value and ignoring the previous
804
+ value) is equivalent to the following handler:
612
805
 
613
806
  flag :shout, "--[no-]shout", handler: proc { | val, _prev| val }
614
807
 
615
- For example, most tools automatically get a "--verbose" flag. This flag may
616
- appear any number of times, and each appearance increases the verbosity. The
617
- value of this verbosity is an integer. This flag is provided automatically by
618
- Toys, and its implementation looks something like this:
808
+ Toys gives the default handler the special name `:set`. So the above is also
809
+ equivalent to:
619
810
 
620
- flag Toys::Tool::Keys::VERBOSITY, "-v", "--verbose",
811
+ flag :shout, "--[no-]shout", handler: :set
812
+
813
+ The `--verbose` flag, provided automatically by Toys for most tools, shows an
814
+ example of an alternate handler. Verbosity is represented by an integer value,
815
+ defaulting to 0. The `--verbose` flag may appear any number of times, and
816
+ *each* appearance increases the verbosity. Its implementation is internal to
817
+ Toys, but looks something like this:
818
+
819
+ flag Toys::Context::Key::VERBOSITY, "-v", "--verbose",
621
820
  default: 0,
622
821
  handler: proc { |_val, prev| prev + 1 }
623
822
 
624
823
  Similarly, the "--quiet" flag, which decreases the verbosity, is implemented
625
824
  like this:
626
825
 
627
- flag Toys::Tool::Keys::VERBOSITY, "-q", "--quiet",
826
+ flag Toys::Context::Key::VERBOSITY, "-q", "--quiet",
628
827
  default: 0,
629
828
  handler: proc { |_val, prev| prev - 1 }
630
829
 
631
- Note that both flags affect the same option value, `VERBOSITY`. The first
830
+ Note that both flags affect the same option name, `VERBOSITY`. The first
632
831
  increments it each time it appears, and the second decrements it. A tool can
633
832
  query this option and get an integer telling the requested verbosity level, as
634
- you will see [below](#Logging_and_Verbosity).
833
+ you will see [below](#Logging_and_verbosity).
834
+
835
+ Toys provides a few built-in handlers that can be specified by name. We already
836
+ discussed the default handler that can be specified by its name `:set` or by
837
+ simply omitting the `handler:` option. Another named handler is `:push`. This
838
+ handler is intended for flags that take values and can be provided more than
839
+ once. The final value is then an array of values.
635
840
 
636
- #### Descriptions and the Flags DSL
841
+ In the following example, an invocation can provide any number of `--include`
842
+ flags, and the `:include` option will be set to an array of the given paths.
843
+
844
+ flag :include, "-I", "--include PATH", default: [], handler: :push
845
+
846
+ The `:push` handler is equivalent to
847
+ `proc { |val, array| array.nil? ? [val] : array << val }`.
848
+
849
+ #### Descriptions and the flags DSL
637
850
 
638
851
  Flags may also have short and long descriptions, which are displayed in online
639
852
  help. Set descriptions via the `desc:` and `long_desc:` arguments to the flag
@@ -645,7 +858,7 @@ directive. The `desc:` argument takes a single string description, while the
645
858
  long_desc: ["Long descriptions may have multiple lines.",
646
859
  "This is the second line."]
647
860
 
648
- See the [above section on Descriptions](#Tool_Descriptions) for more information on
861
+ See the [above section on Descriptions](#Tool_descriptions) for more information on
649
862
  how descriptions are rendered and word wrapped.
650
863
 
651
864
  Because long descriptions may be unwieldly to write as a hash argument in this
@@ -662,7 +875,31 @@ way, Toys provides an alternate syntax for defining flags using a block.
662
875
  For detailed info on configuring an flag using a block, see the
663
876
  [Toys::DSL::Flag class](https://www.rubydoc.info/gems/toys-core/Toys/DSL/Flag).
664
877
 
665
- #### Flag Groups
878
+ #### Flag completions
879
+
880
+ Shell tab completion supports flag values, and flags can be configured to
881
+ present a set of completion candidates for themselves.
882
+
883
+ By default, a flag does not provide any completions for itself. To change that,
884
+ set the `completion` option. Currently there are three ways to set the
885
+ completion:
886
+
887
+ * Provide a static set of possible values, as an array of strings.
888
+ * Specify that values should be paths in the file system by setting the
889
+ symbol `:file_system`.
890
+ * Provide a `Proc` that returns possible values.
891
+
892
+ The following are two example flags, one that supports a static set of
893
+ completions and the other that supports file paths.
894
+
895
+ flag :language, "--lang=VAL", complete_values: ["ruby", "elixir", "rust"]
896
+ flag :path, "--path=VAL", complete_values: :file_system
897
+
898
+ Completions are somewhat related to acceptors, and it is a common pattern to
899
+ set both in concert. But they perform distinct functions. Acceptors affect
900
+ option parsing, whereas completions affect tab completion in the shell.
901
+
902
+ #### Flag groups
666
903
 
667
904
  Flags may be organized into groups. This serves two functions:
668
905
 
@@ -699,8 +936,11 @@ The `all_required` directive is actually just shorthand for passing
699
936
  flag :password, "--password=VAL", desc: "Set the password (required)"
700
937
  end
701
938
 
702
- There are several other types of flag groups:
939
+ The following are the supported types of flag groups:
703
940
 
941
+ * The `:required` type, which you can create using the directive
942
+ `all_required`. All flags from the group are required and must be provided
943
+ on the command line to avoid an error.
704
944
  * The `:exactly_one` type, which you can create using the directive
705
945
  `exactly_one_required`. Exactly one, and no more than one, flag from the
706
946
  group must be provided on the command line to avoid an error.
@@ -710,6 +950,9 @@ There are several other types of flag groups:
710
950
  * The `:at_least_one` type, which you can create using the directive
711
951
  `at_least_one_required`. At least one flag from the group must be provided
712
952
  on the command line to avoid an error.
953
+ * The `:optional` type is the default created using the directive
954
+ `flag_group` when no type is specified. Flags in the group are ordinary
955
+ optional flags.
713
956
 
714
957
  Flag group types are useful for a variety of tools. For example, suppose you
715
958
  are writing a tool that deploys an app to one of several different kinds of
@@ -724,11 +967,12 @@ configuration for your tool with a flag group:
724
967
  end
725
968
 
726
969
  def run
727
- # Now exactly one of server, vm, or container will be set.
970
+ # Now exactly one of server, vm, or container will be set. The other
971
+ # two options will be their default value, nil.
728
972
  end
729
973
  end
730
974
 
731
- ### Tool Execution Basics
975
+ ### Tool execution basics
732
976
 
733
977
  When you run a tool from the command line, Toys will build the tool based on
734
978
  its definition in a Toys file, and then it will attempt to execute it by
@@ -737,7 +981,7 @@ your tools.
737
981
 
738
982
  Note: If you do not define the `run` method for a tool, Toys provides a default
739
983
  implementation that displays the tool's help screen. This is typically used for
740
- namespaces, as we shall see [below](#Namespaces_and_Subtools). Most tools,
984
+ namespaces, as we shall see [below](#Namespaces_and_subtools). Most tools,
741
985
  however, should define `run`.
742
986
 
743
987
  Let's revisit the "greet" example we covered earlier.
@@ -748,7 +992,7 @@ Let's revisit the "greet" example we covered earlier.
748
992
 
749
993
  def run
750
994
  greeting = "Hello, #{whom}!"
751
- greeting.upcase! if shout
995
+ greeting = greeting.upcase if shout
752
996
  puts greeting
753
997
  end
754
998
  end
@@ -759,12 +1003,12 @@ Ruby `$stdout`, `$stderr`, and `$stdin` streams.
759
1003
  Note also how the `run` method can access values that were assigned by flags or
760
1004
  positional arguments by just calling a method with that flag or argument name.
761
1005
  When you declare a flag or argument, if the option name is a symbol that is a
762
- valid Ruby method name, Toys will provide a method of that name that you can
763
- call to get the value.
1006
+ valid Ruby method name, Toys will provide a method that you can call to get the
1007
+ value. In the above example, `whom` and `shout` are such methods.
764
1008
 
765
- If you create a flag or argument whose option name is not a symbol _or_ is not
1009
+ If you create a flag or argument whose option name is not a symbol *or* is not
766
1010
  a valid method name, you can still get the value by calling the
767
- [Toys::Tool#get](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:get)
1011
+ [Toys::Context#get](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:get)
768
1012
  method. For example:
769
1013
 
770
1014
  tool "greet" do
@@ -775,7 +1019,7 @@ method. For example:
775
1019
  def run
776
1020
  # We can access the "whom-to-greet" option using the "get" method.
777
1021
  greeting = "Hello, #{get('whom-to-greet')}!"
778
- greeting.upcase! if shout
1022
+ greeting = greeting.upcase if shout
779
1023
  puts greeting
780
1024
  end
781
1025
  end
@@ -783,7 +1027,7 @@ method. For example:
783
1027
  If a tool's `run` method finishes normally, Toys will exit with a result code
784
1028
  of 0, indicating success. You may exit immediately and/or provide a nonzero
785
1029
  result by calling the
786
- [Toys::Tool#exit](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:exit)
1030
+ [Toys::Context#exit](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:exit)
787
1031
  method:
788
1032
 
789
1033
  def run
@@ -797,7 +1041,8 @@ exit with a nonzero code.
797
1041
 
798
1042
  Finally, you may also define additional methods within the tool. These are
799
1043
  available to be called by your `run` method, and can be used to decompose your
800
- tool implementation. Here's a contrived example:
1044
+ tool implementation. Indeed, a tool is actually a class under the hood, and
1045
+ you can define methods as with any other class. Here's a contrived example:
801
1046
 
802
1047
  tool "greet-many" do
803
1048
  # Support any number of arguments on the command line
@@ -807,7 +1052,7 @@ tool implementation. Here's a contrived example:
807
1052
  # You can define helper methods like this.
808
1053
  def greet(name)
809
1054
  greeting = "Hello, #{name}!"
810
- greeting.upcase! if shout
1055
+ greeting = greeting.upcase if shout
811
1056
  puts greeting
812
1057
  end
813
1058
 
@@ -822,14 +1067,14 @@ This should be enough to get you started implementing tools. A variety of
822
1067
  additional features are available for your tool implementation and will be
823
1068
  discussed further below. But first we will cover a few important topics.
824
1069
 
825
- ### Namespaces and Subtools
1070
+ ### Namespaces and subtools
826
1071
 
827
1072
  Like many command line frameworks, Toys supports **subtools**. You may, for
828
1073
  example create a tool called "test" that runs your tests for a particular
829
1074
  project, but you might also want "test unit" and "test integration" tools to
830
1075
  run specific subsets of the test suite. One way to do this, of course, is for
831
- the "test" tool to parse "unit" or "integration" as arguments. However, you
832
- could also define them as separate tools, subtools of "test".
1076
+ the "test" tool to parse "unit" or "integration" as arguments. However, it's
1077
+ often easier to define them as separate tools, subtools of "test".
833
1078
 
834
1079
  To define a subtool, create nested `tool` directives. Here's a simple example:
835
1080
 
@@ -849,15 +1094,17 @@ To define a subtool, create nested `tool` directives. Here's a simple example:
849
1094
 
850
1095
  You can now invoke them like this:
851
1096
 
852
- toys test unit
853
- toys test integration
1097
+ $ toys test unit
1098
+ run unit tests here...
1099
+ $ toys test integration
1100
+ run integration tests here...
854
1101
 
855
1102
  Notice in this case, the parent "test" tool itself has no `run` method. This is
856
1103
  a common pattern: "test" is just a "container" for tools, a way of organizing
857
1104
  your tools. In Toys terminology, it is called a **namespace**. But it is still
858
1105
  a tool, and it can still be run:
859
1106
 
860
- toys test
1107
+ $ toys test
861
1108
 
862
1109
  As discussed earlier, Toys provides a default implementation that displays the
863
1110
  help screen, which includes a list of the subtools and their descriptions.
@@ -865,7 +1112,7 @@ help screen, which includes a list of the subtools and their descriptions.
865
1112
  As another example, the "root" tool is also normally a namespace. If you just
866
1113
  run Toys with no arguments:
867
1114
 
868
- toys
1115
+ $ toys
869
1116
 
870
1117
  The root tool will display the overall help screen for Toys.
871
1118
 
@@ -899,13 +1146,13 @@ implementation that lists all your tools.)
899
1146
  Toys allows subtools to be nested arbitrarily deep. In practice, however, more
900
1147
  than two or three levels of hierarchy can be confusing to use.
901
1148
 
902
- ## Understanding Toys Files
1149
+ ## Understanding Toys files
903
1150
 
904
1151
  Toys commands are defined in Toys files. We covered the basic syntax for these
905
- files in the [above section on defining tools](#Defining_Tools). In this
1152
+ files in the [above section on defining tools](#Defining_tools). In this
906
1153
  section, we will take a deeper look at what you can do with Toys files.
907
1154
 
908
- ### Toys Directories
1155
+ ### Toys directories
909
1156
 
910
1157
  So far we have been defining tools by writing a Toys file named `.toys.rb`
911
1158
  located in the current working directory. This works great if you have a small
@@ -947,8 +1194,8 @@ The contents of `greet.rb` would be:
947
1194
  end
948
1195
 
949
1196
  Notice that we did not use a `tool "greet"` block here. That is because the
950
- name of the file `greet.rb` already provides a tool context: Toys already knows
951
- that we are defining a "greet" tool.
1197
+ name of the file `greet.rb` already provides a naming context: Toys already
1198
+ knows that we are defining a "greet" tool.
952
1199
 
953
1200
  If you do include a `tool` block inside the `greet.rb` file, it will create a
954
1201
  *subtool* of `greet`. In other words, the path to the Ruby file defines a
@@ -974,7 +1221,7 @@ Once again, `test unit` is the "starting point" for tools defined in the
974
1221
  file will define the `test unit` tool. Any `tool` blocks you add to that file
975
1222
  will define subtools of `test unit`.
976
1223
 
977
- #### Index Files
1224
+ #### Index files
978
1225
 
979
1226
  The file name `.toys.rb` can also be used inside Toys directories and
980
1227
  subdirectories. Such files are called **index files**, and they create tools
@@ -1007,9 +1254,9 @@ in the separate file `.toys/test/unit.rb`.
1007
1254
  Toys also loads index files first before other files in the directory. This
1008
1255
  means they are convenient places to define shared code that can be used by all
1009
1256
  the subtools defined in that directory, as we shall see later in the
1010
- [section on sharing code](#Sharing_Code).
1257
+ [section on sharing code](#Sharing_code).
1011
1258
 
1012
- ### The Toys Search Path
1259
+ ### The Toys search path
1013
1260
 
1014
1261
  So far we have seen how to define tools by writing a `.toys.rb` file in the
1015
1262
  current directory, or by writing files inside a `.toys` directory in the
@@ -1018,14 +1265,16 @@ move to a different directory, they may not be available.
1018
1265
 
1019
1266
  When Toys runs, it looks for tools in a **search path**. Specifically:
1020
1267
 
1021
- (1) It looks for a `.toys.rb` file and/or a `.toys` directory in the *current
1268
+ 1. It looks for a `.toys.rb` file and/or a `.toys` directory in the *current
1022
1269
  working directory*.
1023
- (2) It does the same in the *parent directory* of the current directory, and
1024
- then its parent, all the way up to the root of the file system.
1025
- (3) It does the same in the current user's *home directory* (but does not
1026
- proceed to parents of the home directory).
1027
- (4) It does the same in the system configuration directory (i.e. `/etc` on unix
1028
- systems).
1270
+ 2. It does the same in the *parent directory* of the current directory, and
1271
+ then its parent, and so on until it hits either the root of the file system
1272
+ or one of the global directories described in (3).
1273
+ 3. It looks in a list of *global directories*, specified in the environment
1274
+ variable `TOYS_PATH`. This variable can contain a colon-delimited list of
1275
+ directory paths. If the variable is not set, the current user's *home
1276
+ directory*, and the system configuration directory (`/etc` on unix systems)
1277
+ are used by default. Toys does *not* search parents of global directories.
1029
1278
 
1030
1279
  It uses the *first* implementation that it finds for the requested tool. For
1031
1280
  example, if the tool `greet` is defined in the `.toys.rb` file in the current
@@ -1048,40 +1297,31 @@ directory, and you also define it in the `.toys/greet.rb` file in the same
1048
1297
  current directory, Toys will also report an error, since both are defined at
1049
1298
  the same point (the current directory) in the search path.
1050
1299
 
1051
- #### Global Tools
1052
-
1053
1300
  Note that in the search path above, steps (1) and (2) are *context-dependent*.
1054
1301
  That is, they may be different depending on what directory you are in. However,
1055
- steps (3) and (4) are *not* context-dependent, and are searched regardless of
1056
- where you are located. Tools defined here are **global**, available everywhere.
1057
-
1058
- By default, global tools are defined in your home directory and the system
1059
- configuration directory. However, you can change this by defining the
1060
- environment variable `TOYS_PATH`. This environment variable should contain a
1061
- colon-delimited list of paths that should be searched for global tools. If you
1062
- do define it, it replaces (3) and (4) with the paths you specify.
1302
+ step (3) is *not* context-dependent, and is searched regardless of where you
1303
+ are located. Tools defined here are **global**, available everywhere.
1063
1304
 
1064
- ## The Execution Environment
1305
+ ## The execution environment
1065
1306
 
1066
1307
  This section describes the context and resources available to your tool when it
1067
1308
  is running; that is, what you can call from your tool's `run` method.
1068
1309
 
1069
- Generally, your tool is executed in an object of type
1070
- [Toys::Tool](https://www.rubydoc.info/gems/toys-core/Toys/Tool). This class
1071
- defines a number of methods, and provides access to a variety of data and
1310
+ Each tool is defined as a class that subclasses
1311
+ [Toys::Context](https://www.rubydoc.info/gems/toys-core/Toys/Context). The base
1312
+ class defines a number of methods, and provides access to a variety of data and
1072
1313
  objects relevant to your tool. We have already seen earlier how to use the
1073
- [Toys::Tool#get](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:get)
1314
+ [Toys::Context#get](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:get)
1074
1315
  method to retrieve option values, and how to use the
1075
- [Toys::Tool#exit](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:exit)
1316
+ [Toys::Context#exit](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:exit)
1076
1317
  method to exit immediately and return an exit code. Now we will cover other
1077
1318
  resources available to your tool.
1078
1319
 
1079
- ### Built-in Context
1320
+ ### Built-in context
1080
1321
 
1081
- The options set by your tool's flags and command line arguments are only a
1082
- subset of the data you can access. A variety of other data and objects are
1083
- also accessible using the
1084
- [Toys::Tool#get method](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:get)
1322
+ In addition to the options set by your tool's flags and command line arguments,
1323
+ a variety of other data and objects are also accessible using the
1324
+ [Toys::Context#get method](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:get)
1085
1325
  For example, you can get the full name of the tool being executed like this:
1086
1326
 
1087
1327
  def run
@@ -1091,15 +1331,15 @@ For example, you can get the full name of the tool being executed like this:
1091
1331
  The `TOOL_NAME` constant above is a well-known key that corresponds to the full
1092
1332
  name (as an array of strings) of the running tool. A variety of well-known keys
1093
1333
  are defined in the
1094
- [Toys::Tool::Keys module](https://www.rubydoc.info/gems/toys-core/Toys/Tool/Keys).
1334
+ [Toys::Context::Key module](https://www.rubydoc.info/gems/toys-core/Toys/Context/Key).
1095
1335
  They include information about the current execution, such as the tool name and
1096
1336
  the original command line arguments passed to it (before they were parsed).
1097
1337
  They also include some internal Toys objects, which can be used to do things
1098
- like write to the log or look up and call other tools.
1338
+ like write to the logger or look up and call other tools.
1099
1339
 
1100
1340
  Most of the important context also can be accessed from convenience methods.
1101
1341
  For example, the `TOOL_NAME` is also available from the
1102
- [Toys::Tool#tool_name method](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:tool_name):
1342
+ [Toys::Context#tool_name method](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:tool_name):
1103
1343
 
1104
1344
  def run
1105
1345
  puts "Current tool is #{tool_name}"
@@ -1108,12 +1348,12 @@ For example, the `TOOL_NAME` is also available from the
1108
1348
  Let's take a look at a few things your tool can do with the objects you can
1109
1349
  access from built-in context.
1110
1350
 
1111
- ### Logging and Verbosity
1351
+ ### Logging and verbosity
1112
1352
 
1113
1353
  Toys provides a Logger (a simple instance of the Ruby standard library logger
1114
1354
  that writes to standard error) for your tool to use to report status
1115
1355
  information. You can access this logger via the `LOGGER` context key, or the
1116
- [Toys::Tool#logger method](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:logger).
1356
+ [Toys::Context#logger method](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:logger).
1117
1357
  For example:
1118
1358
 
1119
1359
  def run
@@ -1123,10 +1363,10 @@ For example:
1123
1363
  The current logger level is controlled by the verbosity. Verbosity is an
1124
1364
  integer context value that you can retrieve using the `VERBOSITY` context key
1125
1365
  or the
1126
- [Toys::Tool#verbosity method](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:verbosity).
1366
+ [Toys::Context#verbosity method](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:verbosity).
1127
1367
  The verbosity is set to 0 by default. This corresponds to a logger level of
1128
1368
  `WARN`. That is, warnings, errors, and fatals are displayed, while infos and
1129
- debugs are not. However, [as we saw earlier](#Standard_Flags), most tools
1369
+ debugs are not. However, [as we saw earlier](#Standard_flags), most tools
1130
1370
  automatically respond to the `--verbose` and `--quiet` flags, (or `-v` and
1131
1371
  `-q`), which increment and decrement the verbosity value, respectively. If you
1132
1372
  run a tool with `-v`, the verbosity is incremented to 1, and the logger level
@@ -1134,11 +1374,11 @@ is set to `INFO`. If you set `-q`, the verbosity is decremented to -1, and the
1134
1374
  logger level is set to `ERROR`. So by using the provided logger, a tool can
1135
1375
  easily provide command line based control of the output verbosity.
1136
1376
 
1137
- ### Running Tools from Tools
1377
+ ### Running tools from tools
1138
1378
 
1139
1379
  A common operation a tool might want to do is "call" another tool. This can be
1140
1380
  done via the CLI object, which you can retrieve using the `CLI` key or the
1141
- [Toys::Tool#cli method](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:cli).
1381
+ [Toys::Context#cli method](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:cli).
1142
1382
  These return the current instance of
1143
1383
  [Toys::CLI](https://www.rubydoc.info/gems/toys-core/Toys/CLI) which is the
1144
1384
  "main" interface to Toys. In particular, it provides the
@@ -1155,15 +1395,15 @@ execute, and return a process status code (i.e. 0 for success, and nonzero for
1155
1395
  error). Make sure you handle the exit status. For example, in most cases, you
1156
1396
  should probably exit if the tool you are calling returns a nonzero code.
1157
1397
 
1158
- You may also use the `exec` mixin [described below](#Executing_Subprocesses) to
1398
+ You may also use the `exec` mixin [described below](#Executing_subprocesses) to
1159
1399
  run a tool in a separate process. This is particularly useful if you need to
1160
1400
  capture or manipulate that tool's input or output stream.
1161
1401
 
1162
- ### Helper Methods and Mixins
1402
+ ### Helper methods and mixins
1163
1403
 
1164
- The methods of [Toys::Tool](https://www.rubydoc.info/gems/toys-core/Toys/Tool)
1404
+ The methods of [Toys::Context](https://www.rubydoc.info/gems/toys-core/Toys/Context)
1165
1405
  are not the only methods available for your tool to call. We
1166
- [saw earlier](#Tool_Execution_Basics) that a tool can define additional methods
1406
+ [saw earlier](#Tool_execution_basics) that a tool can define additional methods
1167
1407
  that you can use as helpers.
1168
1408
 
1169
1409
  You can also include **mixins**, which are modules that bring in a whole set of
@@ -1188,9 +1428,9 @@ We will look at a few examples of the use of these mixins below. Built-in
1188
1428
  mixins have names that are symbols.
1189
1429
 
1190
1430
  You can also define your own mixins, as we will see in the
1191
- [upcoming section on defining mixins](#Defining-Mixins).
1431
+ [upcoming section on defining mixins](#Defining_mixins).
1192
1432
 
1193
- ### Executing Subprocesses
1433
+ ### Executing subprocesses
1194
1434
 
1195
1435
  Another common operation you might do in a tool is to execute other binaries.
1196
1436
  For example, you might write a tool that shells out to `scp` to copy files to
@@ -1199,8 +1439,8 @@ a remote server.
1199
1439
  Ruby itself provides a few convenient methods for simple execution, such as the
1200
1440
  [Kernel#system](http://ruby-doc.org/core/Kernel.html#method-i-system) method.
1201
1441
  However, these typically provide limited ability to control or interact with
1202
- subprocess streams, and you need to remember to handle the exit status
1203
- yourself. If you do want to exert any control over subprocesses, you can use
1442
+ subprocess streams, and you also need to remember to handle the exit status
1443
+ yourself. If you do want to exert more control over subprocesses, you can use
1204
1444
  [Process.spawn](http://ruby-doc.org/core/Process.html#method-c-spawn), or a
1205
1445
  higher-level wrapper such as the
1206
1446
  [open3 library](http://ruby-doc.org/stdlib/libdoc/open3/rdoc/index.html).
@@ -1225,7 +1465,7 @@ For more information, see the
1225
1465
  and the underyling library
1226
1466
  [Toys::Utils::Exec](https://www.rubydoc.info/gems/toys-core/Toys/Utils/Exec).
1227
1467
 
1228
- ### Formatting Output
1468
+ ### Formatting output
1229
1469
 
1230
1470
  Interacting with the user is a very common function of a command line tool, and
1231
1471
  many modern tools include intricately designed and styled output, and terminal
@@ -1236,7 +1476,7 @@ First, there is `:terminal`, which provides some basic terminal features such
1236
1476
  as styled output and simple spinners. For information, see the
1237
1477
  [Toys::StandardMixins::Terminal mixin module](https://www.rubydoc.info/gems/toys-core/Toys/StandardMixins/Terminal)
1238
1478
  and the underyling library
1239
- [Toys::Utils::Terminal](https://www.rubydoc.info/gems/toys-core/Toys/Utils/Terminal).
1479
+ [Toys::Terminal](https://www.rubydoc.info/gems/toys-core/Toys/Terminal).
1240
1480
 
1241
1481
  If you prefer the venerable Highline library interface, Toys provides a mixin
1242
1482
  called `:highline` that automatically installs the highline gem (version 2.x)
@@ -1246,9 +1486,9 @@ more information, see the
1246
1486
 
1247
1487
  You may also use other third-party gems such as
1248
1488
  [tty](https://github.com/piotrmurach/tty). The section below on
1249
- [useful gems](#Useful_Gems) provides some examples.
1489
+ [useful gems](#Useful_gems) provides some examples.
1250
1490
 
1251
- ## Sharing Code
1491
+ ## Sharing code
1252
1492
 
1253
1493
  As you accumulate additional and more complex tools, you may find that some of
1254
1494
  your tools need to share some common configuration, data, or logic. You might,
@@ -1257,9 +1497,9 @@ authentication. This section describes several techniques for sharing code
1257
1497
  between tools, and describes the scope of Ruby structures, such as methods,
1258
1498
  classes, and constants, that you might define in your tools.
1259
1499
 
1260
- ### Defining Mixins
1500
+ ### Defining mixins
1261
1501
 
1262
- We [saw earlier](#Helper_Methods_and_Mixins) that you can mix a module (with
1502
+ We [saw earlier](#Helper_methods_and_mixins) that you can mix a module (with
1263
1503
  all its methods) into your tool using the `include` directive. You can specify
1264
1504
  a module itself, or the name of a built-in mixin such as `:exec` or
1265
1505
  `:terminal`. But you can also define your own mixin using the `mixin`
@@ -1274,7 +1514,7 @@ includes the mixin, in the same way that you can include a Ruby module.
1274
1514
 
1275
1515
  (Note that, unlike full modules, mixins allow only methods to be shared. Mixins
1276
1516
  do not support constants. See the next section on
1277
- [using constants](#Using_Constants) to learn how Toys handles constants.)
1517
+ [using constants](#Using_constants) to learn how Toys handles constants.)
1278
1518
 
1279
1519
  Here's an example. Suppose you had common setup code that you wanted to share
1280
1520
  among your testing tools.
@@ -1312,15 +1552,15 @@ define a mixin in a file located in a `.toys` directory, it will be visible to
1312
1552
  descendant tools defined in that same directory, but not in a different `.toys`
1313
1553
  directory.
1314
1554
 
1315
- A common technique, for example, would be to define a mixin in the index file
1316
- in a Toys directory. You can then include it from any subtools defined in other
1317
- files in that same directory.
1555
+ A common technique, for example, would be to define a mixin in the
1556
+ [index file](#Index_files) in a Toys directory. You can then include it from
1557
+ any subtools defined in other files in that same directory.
1318
1558
 
1319
1559
  #### Mixin initializers
1320
1560
 
1321
1561
  Sometimes a mixin will want to initialize some state before the tool executes.
1322
1562
  For example, the `:highline` mixin creates an instance of Highline during tool
1323
- initialization. To do so, provide a `to_initialize` block in the mixin block.
1563
+ initialization. To do so, provide an `on_initialize` block in the mixin block.
1324
1564
  The initializer block is called within the context of the tool before it
1325
1565
  initializes, so it has access to the tool's built-in context and options.
1326
1566
 
@@ -1333,8 +1573,9 @@ pass a value to the mixin's initializer:
1333
1573
 
1334
1574
  tool "test" do
1335
1575
  mixin "common_test_code" do
1336
- # Initialize the mixin, and receive the argument passed to include
1337
- to_initialize do |type|
1576
+ # Initialize the mixin, and receive the argument passed to the
1577
+ # include directive
1578
+ on_initialize do |type|
1338
1579
  # Initializers are called in the context of the tool, and so can
1339
1580
  # affect the tool's state.
1340
1581
  set(:test_type, type)
@@ -1363,7 +1604,7 @@ pass a value to the mixin's initializer:
1363
1604
  end
1364
1605
  end
1365
1606
 
1366
- ### Using Constants
1607
+ ### Using constants
1367
1608
 
1368
1609
  You can define and use Ruby constants, i.e. names beginning with a capital
1369
1610
  letter, in a Toys file. However, they are subject to Ruby's rules regarding
@@ -1375,7 +1616,7 @@ Toys file), it is important to understand how they work.
1375
1616
  Constants in Toys are visible only within the Toys file in which they are
1376
1617
  defined. They normally behave as though they are defined at the "top level" of
1377
1618
  the file. Even if you define a constant lexically "inside" a tool or a mixin,
1378
- the constant does _not_ end up connected to that tool or mixin; it is defined
1619
+ the constant does *not* end up connected to that tool or mixin; it is defined
1379
1620
  at the file level.
1380
1621
 
1381
1622
  tool "test" do
@@ -1397,7 +1638,8 @@ at the file level.
1397
1638
  end
1398
1639
 
1399
1640
  (Note it is still possible to attach constants to a tool or mixin by defining
1400
- them with `self::`. However, this isn't very common practice in Ruby.)
1641
+ them with `self::`. However, this is uncommon Ruby practice and is mildly
1642
+ discouraged.)
1401
1643
 
1402
1644
  Because of this, it is highly recommended that you define constants only at the
1403
1645
  top level of a Toys file, so it doesn't "look" like it is scoped to something
@@ -1437,11 +1679,11 @@ constants, and thus follow the same rules. So you could, for example, define a
1437
1679
  The difference between this technique and using the `mixin` directive we saw
1438
1680
  earlier, is the scope. The module here is accessed via a constant, and so, like
1439
1681
  any constant, it is visible only in the same file it is defined in. The `mixin`
1440
- directive creates mixins that are visible from _all_ files at the same point in
1682
+ directive creates mixins that are visible from *all* files at the same point in
1441
1683
  the search path.
1442
1684
 
1443
1685
  Not also, when you define a mixin in this way, you should include `Toys::Mixin`
1444
- in the module, as illustrated above. This makes `to_initialize` available in
1686
+ in the module, as illustrated above. This makes `on_initialize` available in
1445
1687
  the module.
1446
1688
 
1447
1689
  ### Templates
@@ -1481,11 +1723,11 @@ development, including templates that generate build, test, and documentation
1481
1723
  tools. The `:minitest` template illustrated above is one of these built-in
1482
1724
  templates. Like built-in mixins, built-in template names are always symbols.
1483
1725
  You can read more about them in the next section on using
1484
- [Toys as a Rake replacement](#Toys_as_a_Rake_Replacement).
1726
+ [Toys as a Rake replacement](#Toys_as_a_Rake_replacement).
1485
1727
 
1486
1728
  You may also write your own templates. Here's how...
1487
1729
 
1488
- #### Defining Templates
1730
+ #### Defining templates
1489
1731
 
1490
1732
  One way to define a template is to use the `template` directive. Like the
1491
1733
  `mixin` directive, this creates a named template that you can access inside the
@@ -1502,7 +1744,7 @@ Following is a simple template example:
1502
1744
  attr_accessor :name
1503
1745
  attr_accessor :whom
1504
1746
 
1505
- to_expand do |template|
1747
+ on_expand do |template|
1506
1748
  tool template.name do
1507
1749
  desc "A greeting tool generated from a template"
1508
1750
  to_run do
@@ -1521,15 +1763,15 @@ will typically have a constructor, and methods to access configuration
1521
1763
  properties. When the template is expanded, the class gets instantiated, and you
1522
1764
  can set those properties.
1523
1765
 
1524
- Next, a template has a `to_expand` block. This block contains the Toys file
1766
+ Next, a template has an `on_expand` block. This block contains the Toys file
1525
1767
  directives that should be generated by the template. The template object is
1526
1768
  passed to the block, so it can access the template configuration when
1527
1769
  generating directives. The "greet" template in the above example generates a
1528
1770
  tool whose name is set by the template's `name` property.
1529
1771
 
1530
- Notice that in the above example, we used `to_run do`, providing a _block_ for
1772
+ Notice that in the above example, we used `to_run do`, providing a *block* for
1531
1773
  the tool's execution, rather than `def run`, providing a method. Both forms are
1532
- valid and will work in a template (as well in a normal Toys file), but the
1774
+ valid and will work in a template (as well as in a normal Toys file), but the
1533
1775
  block form is often useful in a template because you can access the `template`
1534
1776
  variable inside the block, whereas it would not be accessible if you defined a
1535
1777
  method. Similarly, if your template generates helper methods, and the body of
@@ -1543,7 +1785,7 @@ properties. In this way, when you expand the template, options can be provided
1543
1785
  either as arguments to the `expand` directive, or in a block passed to the
1544
1786
  directive by setting properties on the template object.
1545
1787
 
1546
- #### Template Classes
1788
+ #### Template classes
1547
1789
 
1548
1790
  Finally, templates are classes, and you can create a template directly as a
1549
1791
  class by including the
@@ -1560,7 +1802,7 @@ in your class definition.
1560
1802
  attr_accessor :name
1561
1803
  attr_accessor :whom
1562
1804
 
1563
- to_expand do |template|
1805
+ on_expand do |template|
1564
1806
  tool template.name do
1565
1807
  desc "A greeting tool generated from a template"
1566
1808
  to_run do
@@ -1576,7 +1818,8 @@ Remember that classes created this way are constants, and so the name
1576
1818
  `GreetTemplate` is available only inside the Toys file where it was defined.
1577
1819
 
1578
1820
  You must `include Toys::Template` if you define a template directly as a class,
1579
- but you can omit it if you use the `template` directive to define the template.
1821
+ but you can omit it if you use the `template` directive to define the template
1822
+ in a block.
1580
1823
 
1581
1824
  Defining templates as classes is also a useful way for third-party gems to
1582
1825
  provide Toys integration. For example, suppose you are writing a code analysis
@@ -1588,7 +1831,7 @@ following in their Toys file:
1588
1831
  require "my_analysis"
1589
1832
  expand MyAnalysis::ToysTemplate
1590
1833
 
1591
- ### Preloading Ruby Files
1834
+ ### Preloading Ruby files
1592
1835
 
1593
1836
  For more complicated tools, you might want to write normal Ruby modules and
1594
1837
  classes as helpers. Toys provides a way to write Ruby code outside of its DSL
@@ -1599,7 +1842,7 @@ tools are defined. You can use such files to define Ruby classes, modules, and
1599
1842
  other code that may be used and shared by your tools.
1600
1843
 
1601
1844
  To use preloaded files, you must define your tools inside a
1602
- [Toys directory](#Toys_Directories). Before any tools inside a directory are
1845
+ [Toys directory](#Toys_directories). Before any tools inside a directory are
1603
1846
  loaded, any file named `.preload.rb` in the directory is automatically
1604
1847
  required. Additionally, any Ruby files inside a subdirectory called `.preload`
1605
1848
  are also automatically required.
@@ -1641,10 +1884,10 @@ first before loading any of the tools in the `test` subdirectory. Thus, any
1641
1884
  additional classes needed by `test unit` can be defined in these files.
1642
1885
 
1643
1886
  Either a single `.preload.rb` file or a `.preload` directory, or both, may be
1644
- used. If both are present, the `.preload.rb` file is loaded first before the
1645
- `.preload` directory contents.
1887
+ used. If both are present in the same directory, the `.preload.rb` file is
1888
+ loaded first before the `.preload` directory contents.
1646
1889
 
1647
- ## Using Third-Party Gems
1890
+ ## Using third-party gems
1648
1891
 
1649
1892
  The Ruby community has developed many resources for building command line
1650
1893
  tools, including a variety of gems that provide alternate command line parsing,
@@ -1654,12 +1897,17 @@ forth.
1654
1897
 
1655
1898
  This section describes how to use a third-party gem in your tool.
1656
1899
 
1657
- ### Activating Gems
1900
+ ### Activating gems
1658
1901
 
1659
- The toys binary itself uses only two gems: **toys** and **toys-core**. It has
1660
- no other gem dependencies. However, if you want to use a third-party gem in
1902
+ The toys executable itself uses only two gems: **toys** and **toys-core**. It
1903
+ has no other gem dependencies. However, if you want to use a third-party gem in
1661
1904
  your tool, Toys provides a convenient mechanism to ensure the gem is installed.
1662
1905
 
1906
+ (Note that you generally do not use bundler when running Toys; i.e. you do not
1907
+ normally run `bundle exec toys`. This is because Toys is intended as a
1908
+ general-purpose tool that can be run anywhere. It would be inconvenient to have
1909
+ to include Gemfiles in every directory where you might want to run it.)
1910
+
1663
1911
  To access the gem services, include the `:gems` mixin. This mixin adds a `gem`
1664
1912
  directive to ensure a gem is installed and activated when you're defining a
1665
1913
  tool, and a `gem` method to ensure a gem is available when you're running a
@@ -1686,6 +1934,8 @@ defined.
1686
1934
  end
1687
1935
  def run
1688
1936
  # ...
1937
+ end
1938
+ end
1689
1939
 
1690
1940
  Here's an example tool that just runs `rake`. Because it requires rake to be
1691
1941
  installed in order to *run* the tool, we call the
@@ -1708,8 +1958,13 @@ exception is raised.
1708
1958
  If you are not in the Toys DSL context—for example from a class-based
1709
1959
  mixin—you should use
1710
1960
  [Toys::Utils::Gems.activate](https://www.rubydoc.info/gems/toys-core/Toys%2FUtils%2FGems.activate)
1711
- instead. For example:
1961
+ instead. (Note that you must `require "toys/utils/gems"` explicitly before
1962
+ invoking the
1963
+ [Toys::Utils::Gems](https://www.rubydoc.info/gems/toys-core/Toys/Utils/Gems)
1964
+ class because, like all classes under `Toys::Utils`, Toys does not load it
1965
+ automatically.) For example:
1712
1966
 
1967
+ require "toys/utils/gems"
1713
1968
  Toys::Utils::Gems.activate("highline", "~> 2.0")
1714
1969
 
1715
1970
  Note these methods are a bit different from the
@@ -1717,7 +1972,7 @@ Note these methods are a bit different from the
1717
1972
  provided by Rubygems. The Toys version attempts to install a missing gem for
1718
1973
  you, whereas Rubygems will just throw an exception.
1719
1974
 
1720
- ### Useful Gems
1975
+ ### Useful gems
1721
1976
 
1722
1977
  Now that you know how to ensure a gem is installed, let's look at some third-
1723
1978
  party gems that you might find useful when writing tools.
@@ -1790,14 +2045,14 @@ non-deterministic.
1790
2045
  A variety of other useful gems can also be found in
1791
2046
  [this article](https://lab.hookops.com/ruby-cli-gems.html).
1792
2047
 
1793
- ## Toys as a Rake Replacement
2048
+ ## Toys as a Rake replacement
1794
2049
 
1795
2050
  Toys was designed to organize scripts that may be "scoped" to a project or
1796
2051
  directory. Rake is also commonly used for this purpose: you can write a
1797
2052
  "Rakefile" that defines rake tasks scoped to a directory. In many cases, Toys
1798
2053
  can be used as a replacement for Rake. Indeed, the Toys repository itself
1799
- contains a `.toys.rb` file instead of a Rakefile for running tests, builds, and
1800
- so forth.
2054
+ contains a `.toys.rb` file instead of a Rakefile, for running tests, builds,
2055
+ and so forth.
1801
2056
 
1802
2057
  This section will explore the differences between Toys and Rake, and describe
1803
2058
  how to use Toys for some of the things traditionally done with Rake.
@@ -1808,7 +2063,7 @@ Although Toys and Rake serve many of the same use cases, they have very
1808
2063
  different design goals, and it is useful to understand them.
1809
2064
 
1810
2065
  Rake's design is based on the classic "make" tool often provided in unix
1811
- development environments. This design focuses on _targets_ and _dependencies_,
2066
+ development environments. This design focuses on *targets* and *dependencies*,
1812
2067
  and is meant for a world where you invoke an external compiler tool whenever
1813
2068
  changes are made to an individual source file or any of its dependencies. This
1814
2069
  "declarative" approach expresses very well the build process for programs
@@ -1818,8 +2073,8 @@ Ruby, however, does not have an external compiler, and certainly not one that
1818
2073
  requires separate invocation for each source file as does the C compiler. So
1819
2074
  although Rake does support file dependencies, they are much less commonly used
1820
2075
  than in their Makefile cousins. Instead, in practice, most Rake tasks are not
1821
- connected to a dependency at all; they are simply standalone tasks, what would
1822
- be called "phony" targets in Makefile parlance. Such tasks are more imperative
2076
+ connected to a dependency at all; they are simply standalone scripts, what
2077
+ would be called "phony" targets in a Makefile. Such tasks are more imperative
1823
2078
  than declarative.
1824
2079
 
1825
2080
  The Toys approach to build tools simply embraces the fact that our build
@@ -1831,7 +2086,7 @@ For example, Rake provides a primitive mechanism for passing arguments to a
1831
2086
  task, but it is clumsy and quite different from most unix programs. However, to
1832
2087
  do otherwise would clash with Rake's design goal of treating tasks as targets
1833
2088
  and dependencies. Toys does not have those design goals, so it is able to
1834
- embrace the familiar ways to pass command line arguments.
2089
+ embrace the familiar unix conventions for command line arguments.
1835
2090
 
1836
2091
  Toys actually borrows some of its design from the "mix" build tool used for
1837
2092
  Elixir and Erlang programs. Unlike C, the Erlang and Elixir compilers do their
@@ -1844,7 +2099,7 @@ your build tasks. Rake will continue to be your friend in those cases. However,
1844
2099
  for imperative tasks such as "run my tests", "build my YARD documentation", or
1845
2100
  "release my gem", you may find Toys easier to use.
1846
2101
 
1847
- ### Using Toys to Invoke Rake Tasks
2102
+ ### Using Toys to invoke Rake tasks
1848
2103
 
1849
2104
  If you've already written a Rakefile for your project, Toys provides a
1850
2105
  convenient way to invoke your existing Rake tasks using Toys. The built-in
@@ -1857,16 +2112,16 @@ following contents:
1857
2112
  # In .toys.rb
1858
2113
  expand :rake
1859
2114
 
1860
- Now within that directory, if you had a task called `test`, you can invoke it
1861
- with:
2115
+ Now within that directory, if you had a Rake task called `test`, you can invoke
2116
+ it with:
1862
2117
 
1863
- toys test
2118
+ $ toys test
1864
2119
 
1865
- Similarly, a task named `test:integration` can be invoked with either of the
1866
- following:
2120
+ Similarly, a Rake task named `test:integration` can be invoked with either of
2121
+ the following:
1867
2122
 
1868
- toys test integration
1869
- toys test:integration
2123
+ $ toys test integration
2124
+ $ toys test:integration
1870
2125
 
1871
2126
  Rake tasks with arguments are mapped to tool arguments, making it easier to
1872
2127
  invoke those tasks using Toys. For example, consider a Rake task with two
@@ -1880,12 +2135,12 @@ arguments, defined as follows:
1880
2135
 
1881
2136
  would have to be invoked as follows using rake:
1882
2137
 
1883
- rake my_task[value1,value2]
2138
+ $ rake my_task[value1,value2]
1884
2139
 
1885
2140
  You may even need to escape the brackets if you are using a shell that treats
1886
2141
  them specially. Toys will let you pass them as normal command line arguments:
1887
2142
 
1888
- toys my_task value1 value2
2143
+ $ toys my_task value1 value2
1889
2144
 
1890
2145
  The `:rake` template provides several options. If your Rakefile is named
1891
2146
  something other than `Rakefile` or isn't in the current directory, you can
@@ -1903,9 +2158,9 @@ arguments. Set `:use_flags` when expanding the template:
1903
2158
  Now with this option, to pass arguments to the tool, use the argument names as
1904
2159
  flags:
1905
2160
 
1906
- toys my_task --first=value1 --second=value2
2161
+ $ toys my_task --first=value1 --second=value2
1907
2162
 
1908
- ### From Rakefiles to Toys Files
2163
+ ### From Rakefiles to Toys files
1909
2164
 
1910
2165
  Invoking Rake tasks using Toys is an easy first step, but eventually you will
1911
2166
  likely want to migrate some of your project's build tasks from Rake to Toys.
@@ -1933,7 +2188,7 @@ Toys to generate common build tools.
1933
2188
  Note that Rakefiles and Toys files can coexist in the same directory, so you
1934
2189
  can use either or both tools, depending on your needs.
1935
2190
 
1936
- ### Running Tests
2191
+ ### Running tests
1937
2192
 
1938
2193
  Toys provides a built-in template called `:minitest` for running unit tests
1939
2194
  with [minitest](https://github.com/seattlerb/minitest). The following example
@@ -1963,7 +2218,7 @@ tool called `rubocop`:
1963
2218
  See the {Toys::Templates::Rubocop} documentation for details on the available
1964
2219
  options.
1965
2220
 
1966
- ### Building and Releasing Gems
2221
+ ### Building and releasing gems
1967
2222
 
1968
2223
  The `:gem_build` built-in template can generate a variety of build and release
1969
2224
  tools for gems, and is a useful alternative to the Rake tasks provided by
@@ -1994,7 +2249,7 @@ example:
1994
2249
  See the {Toys::Templates::Clean} documentation for details on the various
1995
2250
  options for clean.
1996
2251
 
1997
- ### Building Documentation
2252
+ ### Building documentation
1998
2253
 
1999
2254
  Toys provides an `:rdoc` template for creating tools that generate RDoc
2000
2255
  documentation, and a `:yardoc` template for creating tools that generate YARD.
@@ -2006,7 +2261,7 @@ Here's an example for YARD, creating a tool called `yardoc`:
2006
2261
 
2007
2262
  expand :yardoc, protected: true, markup: "markdown"
2008
2263
 
2009
- ### Gem Example
2264
+ ### Gem example
2010
2265
 
2011
2266
  Let's look at a complete example that combines the techniques above to provide
2012
2267
  all the basic tools for a Ruby gem. It includes:
@@ -2021,9 +2276,9 @@ all the basic tools for a Ruby gem. It includes:
2021
2276
  actually build) the documentation for warnings and completeness.
2022
2277
 
2023
2278
  Below is the full annotated `.toys.rb` file. For many gems, you could drop this
2024
- into the gem source repo with minimal or no modifications. Indeed, it is
2025
- nearly identical to the Toys files provided for the **toys** and **toys-core**
2026
- gems themselves.
2279
+ into the gem source repo with minimal or no modifications. Indeed, it is very
2280
+ similar to the Toys files provided for the **toys** and **toys-core** gems
2281
+ themselves.
2027
2282
 
2028
2283
  # This file is .toys.rb
2029
2284
 
@@ -2051,14 +2306,16 @@ gems themselves.
2051
2306
  # The normal "build" tool that just builds a gem into the pkg directory.
2052
2307
  expand :gem_build
2053
2308
 
2309
+ # An "install" tool that builds the gem and installs it locally.
2310
+ expand :gem_build, name: "install", install_gem: true
2311
+
2054
2312
  # A full gem "release" tool that builds the gem, and pushes it to rubygems.
2055
2313
  # This assumes your local rubygems configuration is set up with the proper
2056
2314
  # credentials.
2057
2315
  expand :gem_build, name: "release", push_gem: true
2058
2316
 
2059
2317
  # Now we create a full CI tool. It runs the test, rubocop, and yardoc tools
2060
- # and checks for errors. This tool could be invoked from Travis-CI or
2061
- # similar CI system.
2318
+ # and checks for errors. This tool could be invoked from a CI system.
2062
2319
  tool "ci" do
2063
2320
  # The :exec mixin provides the exec_tool() method that we will use to run
2064
2321
  # other tools and check their exit status.
@@ -2088,7 +2345,7 @@ gems themselves.
2088
2345
  end
2089
2346
  end
2090
2347
 
2091
- ## Advanced Tool Definition Techniques
2348
+ ## Advanced tool definition techniques
2092
2349
 
2093
2350
  This section covers some additional features that are often useful for writing
2094
2351
  tools. I've labeled them "advanced", but all that really means is that this
@@ -2112,7 +2369,7 @@ To define an alias, use the `alias_tool` directive:
2112
2369
  alias_tool "t", "test"
2113
2370
 
2114
2371
  You may create an alias of a subtool, but the alias must have the same parent
2115
- (namespace) tool as the target tool. For example:
2372
+ (namespace) as the target tool. For example:
2116
2373
 
2117
2374
  tool "gem" do
2118
2375
  tool "test" do
@@ -2123,7 +2380,7 @@ You may create an alias of a subtool, but the alias must have the same parent
2123
2380
  alias_tool "t", "test"
2124
2381
  end
2125
2382
 
2126
- ### Custom Acceptors
2383
+ ### Custom acceptors
2127
2384
 
2128
2385
  We saw earlier that flags and positional arguments can have acceptors, which
2129
2386
  control the allowed format, and may also convert the string argument to a Ruby
@@ -2167,7 +2424,7 @@ A common technique, for example, would be to define an acceptor in the index
2167
2424
  file in a Toys directory. You can then include it from any subtools defined in
2168
2425
  other files in that same directory.
2169
2426
 
2170
- ### Controlling Built-in Flags
2427
+ ### Controlling built-in flags
2171
2428
 
2172
2429
  Earlier we saw that certain flags are added automatically to every tool:
2173
2430
  `--verbose`, `--quiet`, `--help`, and so forth. You may occasionally want to
@@ -2178,14 +2435,14 @@ the flag as you choose. Flags explicitly defined by your tool take precedence
2178
2435
  over the built-ins.
2179
2436
 
2180
2437
  For example, normally two built-in flags are provided to decrease the verbosity
2181
- level: `-q` and `--quiet`. If you define `-q` yourselffor example to activate
2182
- a "quick" modethen `-q` will be repurposed for your flag, but `--quiet` will
2438
+ level: `-q` and `--quiet`. If you define `-q` yourself (for example to activate
2439
+ a "quick" mode) then `-q` will be repurposed for your flag, but `--quiet` will
2183
2440
  still be present to decrease verbosity.
2184
2441
 
2185
2442
  # Repurposes -q to set the "quick" option instead of "quiet"
2186
2443
  flag :quick, "-q"
2187
2444
 
2188
- You may also completely disable a flag, and _not_ repurpose it, using the
2445
+ You may also completely disable a flag, and *not* repurpose it, using the
2189
2446
  `disable_flag` directive. It lets you mark one or more flags as "never use".
2190
2447
 
2191
2448
  For example, if you disable the `-q` flag, then `-q` will no longer be a
@@ -2198,7 +2455,83 @@ completely disable decreasing the verbosity, disable both `-q` and `--quiet`.
2198
2455
  # Completely disables decreasing verbosity
2199
2456
  disable_flag "-q", "--quiet"
2200
2457
 
2201
- ### Disabling Argument Parsing
2458
+ ### Enforcing flags before args
2459
+
2460
+ By default, tools allow flags and positional arguments to be interspersed when
2461
+ command line arguments are parsed. This matches the behavior of most common
2462
+ command line binaries.
2463
+
2464
+ However, some tools prefer to follow the convention that all flags must appear
2465
+ first, followed by positional arguments. In such a tool, once a non-flag
2466
+ argument appears on the command line, all remaining arguments are treated as
2467
+ positional, even if they look like a flag and start with a hyphen.
2468
+
2469
+ You may configure a tool to follow this alternate parsing strategy using the
2470
+ `enforce_flags_before_args` directive.
2471
+
2472
+ The built-in tool `toys do` is an example of a tool that does this. It
2473
+ recognizes its own flags (such as `--help` and `--delim`) but once positional
2474
+ arguments start appearing, it wants further flags to be treated as positional
2475
+ so it can pass them down to the different steps it is executing. Here is a
2476
+ simplified excerpt from the implementation that tool:
2477
+
2478
+ tool "do" do
2479
+ flag :delim, default: ","
2480
+ remaining_args :commands # the commands to execute
2481
+ enforce_flags_before_args
2482
+ def run
2483
+ # Now commands includes both the commands to run and
2484
+ # the "flags" to pass to them.
2485
+ commands.each do
2486
+ # ...
2487
+ end
2488
+ end
2489
+ end
2490
+
2491
+ ### Requiring exact flag matches
2492
+
2493
+ By default, tools will recognized "shortened" forms of long flags. For example,
2494
+ most suppose you are defining a tool with long flags:
2495
+
2496
+ tool "my-tool" do
2497
+ flag :long_flag_name, "--long-flag-name"
2498
+ flag :another_long_flag, "--another-long-flag"
2499
+ def run
2500
+ # ...
2501
+ end
2502
+ end
2503
+
2504
+ When you invoke this tool, you do not need to type the entire flag names.
2505
+ Abbreviations will also work:
2506
+
2507
+ $ toys my-tool --long --an
2508
+
2509
+ As long as the abbreviation is unambiguous (i.e. there is no other flag that
2510
+ begins with the same string), the Toys argument parser will recognize the flag.
2511
+ This is consistent with the behavior of most command line tools (and is also
2512
+ the behavior of Ruby's OptionParser library.)
2513
+
2514
+ However, it is possible to disable this behavior and require that flags be
2515
+ presented in their entirety, using the `require_exact_flag_match` directive.
2516
+
2517
+ tool "my-tool" do
2518
+ require_exact_flag_match
2519
+ flag :long_flag_name, "--long-flag-name"
2520
+ flag :another_long_flag, "--another-long-flag"
2521
+ def run
2522
+ # ...
2523
+ end
2524
+ end
2525
+
2526
+ Now, all flags for this tool must be presented in their entirety. Abbreviations
2527
+ are not allowed.
2528
+
2529
+ $ toys my-tool --long-flag-name --another-long-flag
2530
+
2531
+ Currently you can require exact flag matches only at the tool level, applied to
2532
+ all flags for that tool. You cannot set this option for individual flags.
2533
+
2534
+ ### Disabling argument parsing
2202
2535
 
2203
2536
  Normally Toys handles parsing command line arguments for you. This makes
2204
2537
  writing tools easier, and also allows Toys to generate documentation
@@ -2211,7 +2544,7 @@ To disable argument parsing, use the `disable_argument_parsing` directive. This
2211
2544
  directive disables parsing and validation of flags and positional arguments.
2212
2545
  (Thus, it is incompatible with specifying any flags or arguments for the tool.)
2213
2546
  Instead, you can retrieve the raw arguments using the
2214
- [Toys::Tool#args method](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:args).
2547
+ [Toys::Context#args method](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:args).
2215
2548
 
2216
2549
  Here is an example that wraps calls to git:
2217
2550
 
@@ -2224,24 +2557,123 @@ Here is an example that wraps calls to git:
2224
2557
  end
2225
2558
  end
2226
2559
 
2227
- ### Data Files
2560
+ ### Handling interrupts
2561
+
2562
+ If you interrupt a running tool, say, by hitting `CTRL`-`C`, Toys will normally
2563
+ terminate execution and display the message `INTERRUPTED` on the standard error
2564
+ stream.
2565
+
2566
+ If your tool needs to handle interrupts itself, you have several options. You
2567
+ can rescue the `Interrupt` exception or call `Signal.trap`. Or you can provide
2568
+ an *interrupt handler* in your tool using the `on_interrupt` directive. This
2569
+ directive either provides a block to handle interrupts, or designates a named
2570
+ method as the handler. If an interrupt handler is present, Toys will handle
2571
+ interrupts as follows:
2572
+
2573
+ 1. Toys will terminate the tool's `run` method by raising an `Interrupt`
2574
+ exception. Any `ensure` blocks will be called.
2575
+ 2. Toys will call the interrupt handler. If this method or block takes an
2576
+ argument, Toys will pass it the `Interrupt` exception object.
2577
+ 3. The interrupt handler is then responsible for tool execution from that
2578
+ point. It may terminate execution by returning or calling `exit`, or it may
2579
+ restart or resume processing (perhaps by calling the `run` method again).
2580
+ Or it may invoke the normal Toys interrupt handling (i.e. terminating
2581
+ execution, displaying the message `INTERRUPTED`) by re-raising *the same*
2582
+ interrupt exception object.
2583
+ 4. If another interrupt takes place during the execution of the interrupt
2584
+ handler, Toys will terminate it by raising a *second* `Interrupt` exception
2585
+ (calling any `ensure` blocks). Then, the interrupt handler will be called
2586
+ *again* and passed the new exception. Any additional interrupts will be
2587
+ handled similarly.
2588
+
2589
+ Because the interrupt handler is called again even if it is itself interrupted,
2590
+ you might consider detecting this case if your interrupt handler might be
2591
+ long-running. You can tell how many interrupts have taken place by looking at
2592
+ the `Exception#cause` property of the exception. The first interrupt will have
2593
+ a cause of `nil`. The second interrupt (i.e. the interrupt raised the first
2594
+ time the interrupt handler is itself interrupted) will have its cause point to
2595
+ the first interrupt (which in turn has a `nil` cause.) The third interrupt's
2596
+ cause will point to the second interrupt, and so on. So you can determine the
2597
+ interrupt "depth" by counting the length of the cause chain.
2598
+
2599
+ Here is an example that performs a long-running task. The first two times the
2600
+ task is interrupted, it is restarted. The third time, it is terminated.
2601
+
2602
+ tool "long-running" do
2603
+ def long_task(is_restart)
2604
+ puts "task #{is_restart ? 're' : ''}starting..."
2605
+ sleep 10
2606
+ puts "task finished!"
2607
+ end
2608
+
2609
+ def run
2610
+ long_task(false)
2611
+ end
2612
+
2613
+ on_interrupt do |ex|
2614
+ # The third interrupt will have a non-nil ex.cause.cause.
2615
+ # At that time, just give up and re-raise the exception, which causes
2616
+ # it to propagate out and invoke the standard Toys interrupt handler.
2617
+ raise ex if ex.cause&.cause
2618
+ # Otherwise, restart the long task.
2619
+ long_task(true)
2620
+ end
2621
+ end
2622
+
2623
+ ### Handling usage errors
2624
+
2625
+ Normally, if Toys detects a usage error (such as an unrecognized flag) while
2626
+ parsing arguments, it will respond by aborting the tool and displaying the
2627
+ usage error. It is possible to override this behavior by providing your own
2628
+ usage error handler using the `on_usage_error` directive. This directive either
2629
+ provides a block to handle usage errors, or designates a named method as the
2630
+ handler.
2631
+
2632
+ If your handler block or method takes a parameter, Toys will pass it the array
2633
+ of usage errors. Otherwise, you can get the array by calling
2634
+ [Toys::Context#usage_errors](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:usage_errors).
2635
+ This array will provide you with a list of the usage errors encountered.
2636
+
2637
+ You can also get information about the arguments that could not be parsed from
2638
+ the context. For example, the list of unrecognized flags is available from the
2639
+ context key `UNMATCHED_FLAGS`.
2640
+
2641
+ One common technique is to redirect usage errors back to the `run` method. In
2642
+ this way, `run` is called regardless of whether argument parsing succeeded or
2643
+ failed.
2644
+
2645
+ tool "lenient-parser" do
2646
+ flag :abc
2647
+
2648
+ on_usage_error :run
2649
+
2650
+ def run
2651
+ if usage_errors.empty?
2652
+ puts "Usage was correct"
2653
+ else
2654
+ puts "Usage was not correct"
2655
+ end
2656
+ end
2657
+ end
2658
+
2659
+ ### Data files
2228
2660
 
2229
2661
  If your tools require images, archives, keys, or other such static data, Toys
2230
2662
  provides a convenient place to put data files that can be looked up by tools
2231
2663
  either during definition or runtime.
2232
2664
 
2233
2665
  To use data files, you must define your tools inside a
2234
- [Toys directory](#Toys_Directories). Within the Toys directory, create a
2666
+ [Toys directory](#Toys_directories). Within the Toys directory, create a
2235
2667
  directory named `.data` and copy your data files there.
2236
2668
 
2237
2669
  You may then "find" a data file by providing the relative path to the file from
2238
2670
  the `.data` directory. When defining a tool, use the
2239
2671
  [Toys::DSL::Tool#find_data](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:find_data)
2240
2672
  directive in a Toys file. Or, at tool execution time, call
2241
- [Toys::Tool#find_data](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:find_data)
2673
+ [Toys::Context#find_data](https://www.rubydoc.info/gems/toys-core/Toys%2FContext:find_data)
2242
2674
  (which is a convenience method for getting the tool source object using the
2243
2675
  `TOOL_SOURCE` key, and calling
2244
- [Toys::Definition::SourceInfo#find_data](https://www.rubydoc.info/gems/toys-core/Toys%2FDefinition%2FSourceInfo:find_data)
2676
+ [Toys::SourceInfo#find_data](https://www.rubydoc.info/gems/toys-core/Toys%2FSourceInfo:find_data)
2245
2677
  on it). In either case, `find_data` locates a matching file (or directory)
2246
2678
  among the data files, and returns the full path to that file system object. You
2247
2679
  may then read the file or perform any other operation on it.
@@ -2321,7 +2753,7 @@ If, however, you find `greeting.txt` from a tool under `test`, it will still
2321
2753
  find the more general `.toys/.data/greeting.txt` file because there is no
2322
2754
  overriding file under `.toys/test/.data`.
2323
2755
 
2324
- ### The Context Directory
2756
+ ### The context directory
2325
2757
 
2326
2758
  The **context directory** for a tool is the directory containing the toplevel
2327
2759
  `.toys.rb` file or the `.toys` directory within which the tool is defined. It
@@ -2352,8 +2784,8 @@ This tool assumes it will be run from the main project directory (`my-project`
2352
2784
  in the above case). However, Toys lets you invoke tools even if you are in a
2353
2785
  subdirectory:
2354
2786
 
2355
- cd lib
2356
- toys list-tests # Does not work
2787
+ $ cd lib
2788
+ $ toys list-tests # Does not work
2357
2789
 
2358
2790
  Rake handles this by actually changing the current working directory to the
2359
2791
  directory containing the active Rakefile. Toys, however, does not change the
@@ -2388,10 +2820,10 @@ the entire toys directory structure. So if your tool definition is inside a
2388
2820
 
2389
2821
  This behavior is particularly useful for build tools. Indeed, all the build
2390
2822
  tools described in the section on
2391
- [Toys as a Rake Replacement](#Toys_as_a_Rake_Replacement) automatically move
2823
+ [Toys as a Rake Replacement](#Toys_as_a_Rake_replacement) automatically move
2392
2824
  into the context directory when they execute.
2393
2825
 
2394
- #### Changing the Context Directory
2826
+ #### Changing the context directory
2395
2827
 
2396
2828
  It is even possible to modify the context directory, causing tools that use the
2397
2829
  context directory (such as the standard build tools) to run in a different
@@ -2450,7 +2882,7 @@ context directory to `my-repo/gem1`. Here's what that could look like:
2450
2882
  # etc.
2451
2883
  end
2452
2884
 
2453
- ### Hidden Tools
2885
+ ### Hidden tools
2454
2886
 
2455
2887
  Tools whose name begins with an underscore (e.g. `_foo`) are called "hidden"
2456
2888
  tools. They can be executed the same as any other tool, but are normally
@@ -2461,12 +2893,12 @@ the implementation of other tools.
2461
2893
  If you pass the `--all` flag when displaying help, the help screen will include
2462
2894
  hidden tools in the subtools list.
2463
2895
 
2464
- ## Toys Administration Using the System Tools
2896
+ ## Toys administration using the system tools
2465
2897
 
2466
2898
  Toys comes with a few built-in tools, including some that let you administer
2467
2899
  Toys itself. These tools live in the `system` namespace.
2468
2900
 
2469
- ### Getting the Toys Version
2901
+ ### Getting the Toys version
2470
2902
 
2471
2903
  You can get the current version of Toys by running:
2472
2904
 
@@ -2489,39 +2921,69 @@ installation if it is not already current.
2489
2921
  Normall it asks you for confirmation before downloading. To disable interactive
2490
2922
  confirmation, pass the `--yes` flag.
2491
2923
 
2492
- A similar effect can of course be obtained simply by `gem install toys`.
2924
+ A similar effect can of course be obtained by running `gem install toys`.
2925
+
2926
+ ### Installing tab completion for Bash
2927
+
2928
+ Toys provides tab completion for the bash shell, and lets tools customize the
2929
+ completions for their arguments. However, you need to install the Toys
2930
+ completion tool into your shell. The following command sets up tab completion
2931
+ the current shell:
2932
+
2933
+ $(toys system bash-completion install)
2934
+
2935
+ Typically, you will want to include the above in your `.bashrc` or other bash
2936
+ initialization file.
2937
+
2938
+ By default, this associates the Toys tab completion logic with the `toys`
2939
+ executable. If you have other names or aliases for the executable, pass them as
2940
+ arguments. For example, I use `t` as an alias for `toys`, and I therefore
2941
+ install Toys's completion logic for `t`:
2942
+
2943
+ $(toys system bash-completion install t)
2944
+
2945
+ You can also remove the completion logic from the current shell:
2946
+
2947
+ $(toys system bash-completion remove)
2948
+ $(toys system bash-completion remove t)
2949
+
2950
+ At this time, bash is the only shell that is supported directly. If you are
2951
+ using zsh, however, you can use the `bashcompinit` function to load the toys
2952
+ bash completion (as well as other bash-based completions). This *mostly* works,
2953
+ with a few caveats. Native zsh completion is on the future roadmap.
2493
2954
 
2494
- ## Writing Your Own CLI Using Toys
2955
+ ## Writing your own CLI using Toys
2495
2956
 
2496
2957
  Although Toys is not primarily designed to help you write a custom command-line
2497
- binary, you can use it in that way. Toys is factored into two gems:
2958
+ executable, you can use it in that way. Toys is factored into two gems:
2498
2959
  **toys-core**, which includes all the underlying machinery for creating
2499
- command-line binaries, and **toys**, which is really just a wrapper that
2500
- provides the `toys` binary itself and its built-in commands and behavior. To
2501
- write your own command line binary based on the Toys system, just require the
2502
- **toys-core** gem and configure your binary the way you want.
2960
+ command-line executables, and **toys**, which is really just a wrapper that
2961
+ provides the `toys` executable itself and its built-in commands and behavior.
2962
+ To write your own command line executable based on the Toys system, just
2963
+ require the **toys-core** gem and configure your executable the way you want.
2503
2964
 
2504
2965
  Toys-Core is modular and lets you customize much of the behavior of a command
2505
- line binary. For example:
2966
+ line executable, simply by setting options or adding plugins. For example:
2506
2967
 
2507
2968
  * Toys itself automatically adds a number of flags, such as `--verbose` and
2508
- `--help`, to each tool. Toys-Core lets you customize what flags are
2509
- automatically added for your own command line binary.
2510
- * Toys itself provides a default way to run tools that have no `run` method:
2511
- it assumes such tools are namespaces, and displays the online help screen.
2969
+ `--help`, to each tool. Toys-Core lets you customize what flags (if any)
2970
+ are automatically added for your own command line executable.
2971
+ * Toys itself provides a default way to run tools that have no `run` method.
2972
+ It assumes such tools are namespaces, and displays the online help screen.
2512
2973
  Toys-Core lets you provide an alternate default run method for your own
2513
- command line binary.
2974
+ command line executable.
2514
2975
  * Toys itself provides several built-in tools, such as `do`, and `system`.
2515
- Toys-Core lets you write your own command line binary with its own built-in
2516
- tools.
2976
+ Toys-Core lets you write your own command line executable with its own
2977
+ built-in tools.
2517
2978
  * Toys itself implements a particular search path for user-provided Toys
2518
2979
  files, and looks for specific file and directory names such as `.toys.rb`.
2519
2980
  Toys-Core lets you change the search path, the file/directory names, or
2520
2981
  disable user-provided Toys files altogether for your own command line
2521
- binary. Indeed, most command line binaries do not need user-customizable
2522
- tools, and can ship with only built-in tools.
2523
- * Toys itself has a particular way of displaying online help and displaying
2524
- errors. Toys-Core lets your own command line binary customize these.
2982
+ executable. Indeed, most command line executables do not need
2983
+ user-customizable tools, and can ship with only built-in tools.
2984
+ * Toys itself has a particular way of displaying online help and reporting
2985
+ errors. Toys-Core lets your own command line executable customize these and
2986
+ many other features.
2525
2987
 
2526
2988
  For more information, see the
2527
2989
  [Toys-Core documentation](https://www.rubydoc.info/gems/toys-core/).