toys-core 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +98 -0
- data/LICENSE.md +16 -24
- data/README.md +307 -59
- data/docs/guide.md +44 -4
- data/lib/toys-core.rb +58 -49
- data/lib/toys/acceptor.rb +672 -0
- data/lib/toys/alias.rb +106 -0
- data/lib/toys/arg_parser.rb +624 -0
- data/lib/toys/cli.rb +422 -181
- data/lib/toys/compat.rb +83 -0
- data/lib/toys/completion.rb +442 -0
- data/lib/toys/context.rb +354 -0
- data/lib/toys/core_version.rb +18 -26
- data/lib/toys/dsl/flag.rb +213 -56
- data/lib/toys/dsl/flag_group.rb +237 -51
- data/lib/toys/dsl/positional_arg.rb +210 -0
- data/lib/toys/dsl/tool.rb +968 -317
- data/lib/toys/errors.rb +46 -28
- data/lib/toys/flag.rb +821 -0
- data/lib/toys/flag_group.rb +282 -0
- data/lib/toys/input_file.rb +18 -26
- data/lib/toys/loader.rb +110 -100
- data/lib/toys/middleware.rb +24 -31
- data/lib/toys/mixin.rb +90 -59
- data/lib/toys/module_lookup.rb +125 -0
- data/lib/toys/positional_arg.rb +184 -0
- data/lib/toys/source_info.rb +192 -0
- data/lib/toys/standard_middleware/add_verbosity_flags.rb +38 -43
- data/lib/toys/standard_middleware/handle_usage_errors.rb +39 -40
- data/lib/toys/standard_middleware/set_default_descriptions.rb +111 -89
- data/lib/toys/standard_middleware/show_help.rb +130 -113
- data/lib/toys/standard_middleware/show_root_version.rb +29 -35
- data/lib/toys/standard_mixins/exec.rb +116 -78
- data/lib/toys/standard_mixins/fileutils.rb +16 -24
- data/lib/toys/standard_mixins/gems.rb +29 -30
- data/lib/toys/standard_mixins/highline.rb +34 -41
- data/lib/toys/standard_mixins/terminal.rb +72 -26
- data/lib/toys/template.rb +51 -35
- data/lib/toys/tool.rb +1161 -206
- data/lib/toys/utils/completion_engine.rb +171 -0
- data/lib/toys/utils/exec.rb +279 -182
- data/lib/toys/utils/gems.rb +58 -49
- data/lib/toys/utils/help_text.rb +117 -111
- data/lib/toys/utils/terminal.rb +69 -62
- data/lib/toys/wrappable_string.rb +162 -0
- metadata +24 -22
- data/lib/toys/definition/acceptor.rb +0 -191
- data/lib/toys/definition/alias.rb +0 -112
- data/lib/toys/definition/arg.rb +0 -140
- data/lib/toys/definition/flag.rb +0 -370
- data/lib/toys/definition/flag_group.rb +0 -205
- data/lib/toys/definition/source_info.rb +0 -190
- data/lib/toys/definition/tool.rb +0 -842
- data/lib/toys/dsl/arg.rb +0 -132
- data/lib/toys/runner.rb +0 -188
- data/lib/toys/standard_middleware.rb +0 -47
- data/lib/toys/utils/module_lookup.rb +0 -135
- data/lib/toys/utils/wrappable_string.rb +0 -165
data/lib/toys/dsl/tool.rb
CHANGED
@@ -1,32 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright
|
3
|
+
# Copyright 2019 Daniel Azuma
|
4
4
|
#
|
5
|
-
#
|
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
|
-
#
|
8
|
-
#
|
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
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
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.
|
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.
|
30
22
|
;
|
31
23
|
|
32
24
|
module Toys
|
@@ -69,121 +61,251 @@ module Toys
|
|
69
61
|
end
|
70
62
|
|
71
63
|
##
|
72
|
-
# Create
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
64
|
+
# Create a named acceptor that can be referenced by name from any flag or
|
65
|
+
# positional argument in this tool or its subtools.
|
66
|
+
#
|
67
|
+
# An acceptor validates the string parameter passed to a flag or
|
68
|
+
# positional argument. It also optionally converts the string to a
|
69
|
+
# different object before storing it in your tool's data.
|
70
|
+
#
|
71
|
+
# Acceptors can be defined in one of four ways.
|
72
|
+
#
|
73
|
+
# * You can provide a **regular expression**. This acceptor validates
|
74
|
+
# only if the regex matches the *entire string parameter*.
|
75
|
+
#
|
76
|
+
# You can also provide an optional conversion function as a block. If
|
77
|
+
# provided, function must take a variable number of arguments, the
|
78
|
+
# first being the matched string and the remainder being the captures
|
79
|
+
# from the regular expression. It should return the converted object
|
80
|
+
# that will be stored in the context data. If you do not provide a
|
81
|
+
# block, the original string will be used.
|
82
|
+
#
|
83
|
+
# * You can provide an **array** of possible values. The acceptor
|
84
|
+
# validates if the string parameter matches the *string form* of one
|
85
|
+
# of the array elements (i.e. the results of calling `to_s` on the
|
86
|
+
# array elements.)
|
87
|
+
#
|
88
|
+
# An array acceptor automatically converts the string parameter to
|
89
|
+
# the actual array element that it matched. For example, if the
|
90
|
+
# symbol `:foo` is in the array, it will match the string `"foo"`,
|
91
|
+
# and then store the symbol `:foo` in the tool data.
|
92
|
+
#
|
93
|
+
# * You can provide a **range** of possible values, along with a
|
94
|
+
# conversion function that converts a string parameter to a type
|
95
|
+
# comparable by the range. (See the "function" spec below for a
|
96
|
+
# detailed description of conversion functions.) If the range has
|
97
|
+
# numeric endpoints, the conversion function is optional because a
|
98
|
+
# default will be provided.
|
99
|
+
#
|
100
|
+
# * You can provide a **function** by passing it as a proc or a block.
|
101
|
+
# This function performs *both* validation and conversion. It should
|
102
|
+
# take the string parameter as its argument, and it must either
|
103
|
+
# return the object that should be stored in the tool data, or raise
|
104
|
+
# an exception (descended from `StandardError`) to indicate that the
|
105
|
+
# string parameter is invalid.
|
106
|
+
#
|
107
|
+
# ## Example
|
108
|
+
#
|
109
|
+
# The following example creates an acceptor named "hex" that is defined
|
110
|
+
# via a regular expression. It then uses it to validate values passed to
|
111
|
+
# a flag.
|
112
|
+
#
|
113
|
+
# tool "example" do
|
114
|
+
# acceptor "hex", /[0-9a-fA-F]+/, type_desc: "hex numbers"
|
115
|
+
# flag :number, accept: "hex"
|
116
|
+
# def run
|
117
|
+
# puts "number was #{number}"
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# @param name [String] The acceptor name.
|
122
|
+
# @param spec [Object] See the description for recognized values.
|
123
|
+
# @param type_desc [String] Type description string, shown in help.
|
124
|
+
# Defaults to the acceptor name.
|
125
|
+
# @param block [Proc] See the description for recognized forms.
|
126
|
+
# @return [self]
|
127
|
+
#
|
128
|
+
def acceptor(name, spec = nil, type_desc: nil, &block)
|
129
|
+
cur_tool = DSL::Tool.current_tool(self, false)
|
130
|
+
cur_tool&.add_acceptor(name, spec, type_desc: type_desc || name.to_s, &block)
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# Create a named mixin module that can be included by name from this tool
|
136
|
+
# or its subtools.
|
76
137
|
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
138
|
+
# A mixin is a module that defines methods that can be called from a
|
139
|
+
# tool. It is commonly used to provide "utility" methods, implementing
|
140
|
+
# common functionality and allowing tools to share code.
|
80
141
|
#
|
81
|
-
#
|
82
|
-
#
|
142
|
+
# Normally you provide a block and define the mixin's methods in that
|
143
|
+
# block. Alternatively, you can create a module separately and pass it
|
144
|
+
# directly to this directive.
|
83
145
|
#
|
84
|
-
#
|
85
|
-
# argument string and succeeds only if the expression covers the *entire*
|
86
|
-
# string. The elements of the MatchData (i.e. the string matched, plus any
|
87
|
-
# captures) are then passed into the conversion function.
|
146
|
+
# ## Example
|
88
147
|
#
|
89
|
-
#
|
90
|
-
# (i.e. the results of calling to_s on each element) are considered the
|
91
|
-
# valid values for the argument. This is useful for enums, for example.
|
92
|
-
# In this case, the input is converted to the original array element, and
|
93
|
-
# any converter function you provide is ignored.
|
148
|
+
# The following example creates a named mixin and uses it in a tool.
|
94
149
|
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
150
|
+
# mixin "error-reporter" do
|
151
|
+
# def error message
|
152
|
+
# logger.error "An error occurred: #{message}"
|
153
|
+
# exit 1
|
154
|
+
# end
|
155
|
+
# end
|
98
156
|
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
157
|
+
# tool "build" do
|
158
|
+
# include "error-reporter"
|
159
|
+
# def run
|
160
|
+
# puts "Building..."
|
161
|
+
# error "Build failed!"
|
162
|
+
# end
|
163
|
+
# end
|
106
164
|
#
|
107
|
-
# @param [String]
|
108
|
-
# @param [
|
109
|
-
#
|
110
|
-
#
|
165
|
+
# @param name [String] Name of the mixin
|
166
|
+
# @param mixin_module [Module] Module to use as the mixin. Optional.
|
167
|
+
# Either pass a module here, *or* provide a block and define the
|
168
|
+
# mixin within the block.
|
169
|
+
# @param block [Proc] Defines the mixin module.
|
170
|
+
# @return [self]
|
111
171
|
#
|
112
|
-
def
|
172
|
+
def mixin(name, mixin_module = nil, &block)
|
113
173
|
cur_tool = DSL::Tool.current_tool(self, false)
|
114
|
-
|
115
|
-
accept =
|
116
|
-
case validator
|
117
|
-
when ::Regexp
|
118
|
-
Definition::PatternAcceptor.new(name, validator, converter, &block)
|
119
|
-
when ::Array
|
120
|
-
Definition::EnumAcceptor.new(name, validator)
|
121
|
-
when nil
|
122
|
-
Definition::Acceptor.new(name, converter, &block)
|
123
|
-
else
|
124
|
-
raise ToolDefinitionError, "Illegal validator: #{validator.inspect}"
|
125
|
-
end
|
126
|
-
cur_tool.add_acceptor(accept)
|
174
|
+
cur_tool&.add_mixin(name, mixin_module, &block)
|
127
175
|
self
|
128
176
|
end
|
129
177
|
|
130
178
|
##
|
131
|
-
# Create a named
|
132
|
-
#
|
179
|
+
# Create a named template that can be expanded by name from this tool
|
180
|
+
# or its subtools.
|
181
|
+
#
|
182
|
+
# A template is an object that generates DSL directives. You can use it
|
183
|
+
# to build "prefabricated" tools, and then instantiate them in your Toys
|
184
|
+
# files. Generally, a template is a class with an associated `expansion`
|
185
|
+
# procedure. The class defines parameters for the template expansion,
|
186
|
+
# and `expansion` includes DSL directives that should be run based on
|
187
|
+
# those parameters.
|
188
|
+
#
|
189
|
+
# Normally, you provide a block and define the template class in that
|
190
|
+
# block. Most templates will define an `initialize` method that takes any
|
191
|
+
# arguments passed into the template expansion. The template must also
|
192
|
+
# provide an `expansion` block showing how to use the template object to
|
193
|
+
# produce DSL directives.
|
194
|
+
#
|
195
|
+
# Alternately, you can create a template class separately and pass it
|
196
|
+
# directly. See {Toys::Template} for details on creating a template
|
197
|
+
# class.
|
198
|
+
#
|
199
|
+
# ## Example
|
200
|
+
#
|
201
|
+
# The following example creates and uses a simple template.
|
202
|
+
#
|
203
|
+
# template "hello-generator" do
|
204
|
+
# def initialize(name, message)
|
205
|
+
# @name = name
|
206
|
+
# @message = message
|
207
|
+
# end
|
208
|
+
# attr_reader :name, :message
|
209
|
+
# expansion do |template|
|
210
|
+
# tool template.name do
|
211
|
+
# to_run do
|
212
|
+
# puts template.message
|
213
|
+
# end
|
214
|
+
# end
|
215
|
+
# end
|
216
|
+
# end
|
133
217
|
#
|
134
|
-
#
|
218
|
+
# expand "hello-generator", "mytool", "mytool is running!"
|
135
219
|
#
|
136
|
-
# @param [String]
|
137
|
-
# @
|
220
|
+
# @param name [String] Name of the template
|
221
|
+
# @param template_class [Class] Module to use as the mixin. Optional.
|
222
|
+
# Either pass a module here, *or* provide a block and define the
|
223
|
+
# mixin within the block.
|
224
|
+
# @param block [Proc] Defines the template class.
|
225
|
+
# @return [self]
|
138
226
|
#
|
139
|
-
def
|
227
|
+
def template(name, template_class = nil, &block)
|
140
228
|
cur_tool = DSL::Tool.current_tool(self, false)
|
141
|
-
|
142
|
-
mixin_mod = ::Module.new do
|
143
|
-
include ::Toys::Mixin
|
144
|
-
end
|
145
|
-
mixin_mod.module_eval(&block)
|
146
|
-
cur_tool.add_mixin(name, mixin_mod)
|
147
|
-
end
|
229
|
+
cur_tool&.add_template(name, template_class, &block)
|
148
230
|
self
|
149
231
|
end
|
150
232
|
|
151
233
|
##
|
152
|
-
# Create a named
|
153
|
-
#
|
234
|
+
# Create a named completion procedure that may be used by name by any
|
235
|
+
# flag or positional arg in this tool or any subtool.
|
236
|
+
#
|
237
|
+
# A completion controls tab completion for the value of a flag or
|
238
|
+
# positional argument. In general, it is a Ruby `Proc` that takes a
|
239
|
+
# context object (of type {Toys::Completion::Context}) and returns an
|
240
|
+
# array of completion candidate strings.
|
241
|
+
#
|
242
|
+
# Completions can be specified in one of three ways.
|
243
|
+
#
|
244
|
+
# * A Proc object itself, either passed directly to this directive or
|
245
|
+
# provided as a block.
|
246
|
+
# * A static array of strings, indicating the completion candidates
|
247
|
+
# independent of context.
|
248
|
+
# * The symbol `:file_system` which indicates that paths in the file
|
249
|
+
# system should serve as completion candidates.
|
250
|
+
#
|
251
|
+
# ## Example
|
154
252
|
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
158
|
-
#
|
159
|
-
# define how to expand the template.
|
253
|
+
# The following example defines a completion that uses only the immediate
|
254
|
+
# files in the current directory as candidates. (This is different from
|
255
|
+
# the `:file_system` completion which will descend into subdirectories
|
256
|
+
# similar to how bash completes most of its file system commands.)
|
160
257
|
#
|
161
|
-
#
|
162
|
-
#
|
258
|
+
# completion "local-files" do |_context|
|
259
|
+
# `/bin/ls`.split("\n")
|
260
|
+
# end
|
261
|
+
# tool "example" do
|
262
|
+
# flag :file, complete_values: "local-files"
|
263
|
+
# def run
|
264
|
+
# puts "selected file #{file}"
|
265
|
+
# end
|
266
|
+
# end
|
267
|
+
#
|
268
|
+
# @param name [String] Name of the completion
|
269
|
+
# @param spec [Object] See the description for recognized values.
|
270
|
+
# @param options [Hash] Additional options to pass to the completion.
|
271
|
+
# @param block [Proc] See the description for recognized forms.
|
272
|
+
# @return [self]
|
163
273
|
#
|
164
|
-
def
|
274
|
+
def completion(name, spec = nil, **options, &block)
|
165
275
|
cur_tool = DSL::Tool.current_tool(self, false)
|
166
|
-
|
167
|
-
template_class = ::Class.new do
|
168
|
-
include ::Toys::Template
|
169
|
-
end
|
170
|
-
template_class.class_eval(&block)
|
171
|
-
cur_tool.add_template(name, template_class)
|
172
|
-
end
|
276
|
+
cur_tool&.add_completion(name, spec, options, &block)
|
173
277
|
self
|
174
278
|
end
|
175
279
|
|
176
280
|
##
|
177
281
|
# Create a subtool. You must provide a block defining the subtool.
|
178
282
|
#
|
179
|
-
#
|
180
|
-
#
|
283
|
+
# ## Example
|
284
|
+
#
|
285
|
+
# The following example defines a tool and two subtools within it.
|
286
|
+
#
|
287
|
+
# tool "build" do
|
288
|
+
# tool "staging" do
|
289
|
+
# def run
|
290
|
+
# puts "Building staging"
|
291
|
+
# end
|
292
|
+
# end
|
293
|
+
# tool "staging" do
|
294
|
+
# def run
|
295
|
+
# puts "Building staging"
|
296
|
+
# end
|
297
|
+
# end
|
298
|
+
# end
|
299
|
+
#
|
300
|
+
# @param words [String,Array<String>] The name of the subtool
|
301
|
+
# @param if_defined [:combine,:reset,:ignore] What to do if a definition
|
181
302
|
# already exists for this tool. Possible values are `:combine` (the
|
182
303
|
# default) indicating the definition should be combined with the
|
183
304
|
# existing definition, `:reset` indicating the earlier definition
|
184
305
|
# should be reset and the new definition applied instead, or
|
185
306
|
# `:ignore` indicating the new definition should be ignored.
|
186
|
-
# @
|
307
|
+
# @param block [Proc] Defines the subtool.
|
308
|
+
# @return [self]
|
187
309
|
#
|
188
310
|
def tool(words, if_defined: :combine, &block)
|
189
311
|
subtool_words = @__words
|
@@ -193,7 +315,7 @@ module Toys
|
|
193
315
|
subtool_words += [word]
|
194
316
|
next_remaining = Loader.next_remaining_words(next_remaining, word)
|
195
317
|
end
|
196
|
-
subtool = @__loader.
|
318
|
+
subtool = @__loader.get_tool(subtool_words, @__priority)
|
197
319
|
if subtool.includes_definition?
|
198
320
|
case if_defined
|
199
321
|
when :ignore
|
@@ -213,9 +335,24 @@ module Toys
|
|
213
335
|
##
|
214
336
|
# Create an alias in the current namespace.
|
215
337
|
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
338
|
+
# An alias is an alternate name for a tool. The referenced tool must be
|
339
|
+
# in the same namespace.
|
340
|
+
#
|
341
|
+
# ## Example
|
342
|
+
#
|
343
|
+
# This example defines a tool and an alias pointing to it. Both the tool
|
344
|
+
# name `test` and the alias `t` will then refer to the same tool.
|
345
|
+
#
|
346
|
+
# tool "test" do
|
347
|
+
# def run
|
348
|
+
# puts "Running tests..."
|
349
|
+
# end
|
350
|
+
# end
|
351
|
+
# alias_tool "t", "test"
|
352
|
+
#
|
353
|
+
# @param word [String] The name of the alias
|
354
|
+
# @param target [String] The target of the alias
|
355
|
+
# @return [self]
|
219
356
|
#
|
220
357
|
def alias_tool(word, target)
|
221
358
|
@__loader.make_alias(@__words + [word.to_s], @__words + [target.to_s], @__priority)
|
@@ -226,8 +363,8 @@ module Toys
|
|
226
363
|
# Load another config file or directory, as if its contents were inserted
|
227
364
|
# at the current location.
|
228
365
|
#
|
229
|
-
# @param [String]
|
230
|
-
# @return [
|
366
|
+
# @param path [String] The file or directory to load.
|
367
|
+
# @return [self]
|
231
368
|
#
|
232
369
|
def load(path)
|
233
370
|
@__loader.load_path(source_info, path, @__words, @__remaining_words, @__priority)
|
@@ -240,16 +377,37 @@ module Toys
|
|
240
377
|
# The template may be specified as a class or a well-known template name.
|
241
378
|
# You may also provide arguments to pass to the template.
|
242
379
|
#
|
243
|
-
#
|
380
|
+
# ## Example
|
381
|
+
#
|
382
|
+
# The following example creates and uses a simple template.
|
383
|
+
#
|
384
|
+
# template "hello-generator" do
|
385
|
+
# def initialize(name, message)
|
386
|
+
# @name = name
|
387
|
+
# @message = message
|
388
|
+
# end
|
389
|
+
# attr_reader :name, :message
|
390
|
+
# expansion do |template|
|
391
|
+
# tool template.name do
|
392
|
+
# to_run do
|
393
|
+
# puts template.message
|
394
|
+
# end
|
395
|
+
# end
|
396
|
+
# end
|
397
|
+
# end
|
398
|
+
#
|
399
|
+
# expand "hello-generator", "mytool", "mytool is running!"
|
400
|
+
#
|
401
|
+
# @param template_class [Class,String,Symbol] The template, either as a
|
244
402
|
# class or a well-known name.
|
245
|
-
# @param [Object...]
|
246
|
-
# @return [
|
403
|
+
# @param args [Object...] Template arguments
|
404
|
+
# @return [self]
|
247
405
|
#
|
248
406
|
def expand(template_class, *args)
|
249
407
|
cur_tool = DSL::Tool.current_tool(self, false)
|
250
408
|
name = template_class.to_s
|
251
409
|
if template_class.is_a?(::String)
|
252
|
-
template_class = cur_tool.
|
410
|
+
template_class = cur_tool.lookup_template(template_class)
|
253
411
|
elsif template_class.is_a?(::Symbol)
|
254
412
|
template_class = @__loader.resolve_standard_template(name)
|
255
413
|
end
|
@@ -258,29 +416,32 @@ module Toys
|
|
258
416
|
end
|
259
417
|
template = template_class.new(*args)
|
260
418
|
yield template if block_given?
|
261
|
-
class_exec(template, &template_class.
|
419
|
+
class_exec(template, &template_class.expansion)
|
262
420
|
self
|
263
421
|
end
|
264
422
|
|
265
423
|
##
|
266
|
-
# Set the short description for the current tool. The short description
|
267
|
-
# displayed with the tool in a subtool list. You may also use the
|
424
|
+
# Set the short description for the current tool. The short description
|
425
|
+
# is displayed with the tool in a subtool list. You may also use the
|
268
426
|
# equivalent method `short_desc`.
|
269
427
|
#
|
270
|
-
# The description is a {Toys::
|
271
|
-
#
|
272
|
-
#
|
273
|
-
#
|
428
|
+
# The description is a {Toys::WrappableString}, which may be word-wrapped
|
429
|
+
# when displayed in a help screen. You may pass a {Toys::WrappableString}
|
430
|
+
# directly to this method, or you may pass any input that can be used to
|
431
|
+
# construct a wrappable string:
|
274
432
|
#
|
275
|
-
#
|
433
|
+
# * If you pass a String, its whitespace will be compacted (i.e. tabs,
|
276
434
|
# newlines, and multiple consecutive whitespace will be turned into a
|
277
435
|
# single space), and it will be word-wrapped on whitespace.
|
278
|
-
#
|
279
|
-
# literal word that cannot be broken, and wrapping will be done
|
280
|
-
# the strings in the array. In this case, whitespace is not
|
436
|
+
# * If you pass an Array of Strings, each string will be considered a
|
437
|
+
# literal word that cannot be broken, and wrapping will be done
|
438
|
+
# across the strings in the array. In this case, whitespace is not
|
439
|
+
# compacted.
|
281
440
|
#
|
282
|
-
#
|
283
|
-
#
|
441
|
+
# ## Examples
|
442
|
+
#
|
443
|
+
# If you pass in a sentence as a simple string, it may be word wrapped
|
444
|
+
# when displayed:
|
284
445
|
#
|
285
446
|
# desc "This sentence may be wrapped."
|
286
447
|
#
|
@@ -289,8 +450,8 @@ module Toys
|
|
289
450
|
#
|
290
451
|
# desc ["This sentence will not be wrapped."]
|
291
452
|
#
|
292
|
-
# @param [Toys::
|
293
|
-
# @return [
|
453
|
+
# @param str [Toys::WrappableString,String,Array<String>]
|
454
|
+
# @return [self]
|
294
455
|
#
|
295
456
|
def desc(str)
|
296
457
|
cur_tool = DSL::Tool.current_tool(self, true)
|
@@ -300,24 +461,27 @@ module Toys
|
|
300
461
|
alias short_desc desc
|
301
462
|
|
302
463
|
##
|
303
|
-
#
|
304
|
-
# displayed in the usage documentation for the tool itself.
|
464
|
+
# Add to the long description for the current tool. The long description
|
465
|
+
# is displayed in the usage documentation for the tool itself. This
|
466
|
+
# directive may be given multiple times, and the results are cumulative.
|
305
467
|
#
|
306
468
|
# A long description is a series of descriptions, which are generally
|
307
469
|
# displayed in a series of lines/paragraphs. Each individual description
|
308
|
-
# uses the form described in the {
|
309
|
-
#
|
310
|
-
#
|
470
|
+
# uses the form described in the {#desc} documentation, and may be
|
471
|
+
# word-wrapped when displayed. To insert a blank line, include an empty
|
472
|
+
# string as one of the descriptions.
|
311
473
|
#
|
312
|
-
# Example
|
474
|
+
# ## Example
|
313
475
|
#
|
314
|
-
# long_desc "This
|
476
|
+
# long_desc "This initial paragraph might get word wrapped.",
|
315
477
|
# "This next paragraph is followed by a blank line.",
|
316
478
|
# "",
|
317
|
-
# ["This line will not be wrapped."]
|
479
|
+
# ["This line will not be wrapped."],
|
480
|
+
# [" This indent is preserved."]
|
481
|
+
# long_desc "This line is appended to the description."
|
318
482
|
#
|
319
|
-
# @param [Toys::
|
320
|
-
# @return [
|
483
|
+
# @param strs [Toys::WrappableString,String,Array<String>...]
|
484
|
+
# @return [self]
|
321
485
|
#
|
322
486
|
def long_desc(*strs)
|
323
487
|
DSL::Tool.current_tool(self, true)&.append_long_desc(strs)
|
@@ -329,33 +493,39 @@ module Toys
|
|
329
493
|
# belong to the group. The flags in the group are listed together in
|
330
494
|
# help screens.
|
331
495
|
#
|
332
|
-
# Example
|
496
|
+
# ## Example
|
497
|
+
#
|
498
|
+
# The following example creates a flag group in which all flags are
|
499
|
+
# optional.
|
333
500
|
#
|
334
|
-
#
|
335
|
-
#
|
336
|
-
#
|
501
|
+
# tool "execute" do
|
502
|
+
# flag_group desc: "Debug Flags" do
|
503
|
+
# flag :debug, "-D", desc: "Enable debugger"
|
504
|
+
# flag :warnings, "-W[VAL]", desc: "Enable warnings"
|
505
|
+
# end
|
506
|
+
# # ...
|
337
507
|
# end
|
338
508
|
#
|
339
|
-
# @param [Symbol]
|
509
|
+
# @param type [Symbol] The type of group. Allowed values: `:required`,
|
340
510
|
# `:optional`, `:exactly_one`, `:at_most_one`, `:at_least_one`.
|
341
511
|
# Default is `:optional`.
|
342
|
-
# @param [String,Array<String>,Toys::
|
343
|
-
# description for the group. See {Toys::
|
344
|
-
#
|
345
|
-
# @param [Array<String,Array<String>,Toys::
|
512
|
+
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
513
|
+
# description for the group. See {Toys::Tool#desc=} for a description
|
514
|
+
# of allowed formats. Defaults to `"Flags"`.
|
515
|
+
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
346
516
|
# Long description for the flag group. See
|
347
|
-
# {Toys::
|
348
|
-
#
|
349
|
-
# @param [String,Symbol,nil]
|
517
|
+
# {Toys::Tool#long_desc=} for a description of allowed formats.
|
518
|
+
# Defaults to the empty array.
|
519
|
+
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
350
520
|
# name.
|
351
|
-
# @param [Boolean]
|
521
|
+
# @param report_collisions [Boolean] If `true`, raise an exception if a
|
352
522
|
# the given name is already taken. If `false`, ignore. Default is
|
353
523
|
# `true`.
|
354
|
-
# @param [Boolean]
|
524
|
+
# @param prepend [Boolean] If `true`, prepend rather than append the
|
355
525
|
# group to the list. Default is `false`.
|
356
|
-
# @
|
357
|
-
#
|
358
|
-
# @return [
|
526
|
+
# @param block [Proc] Adds flags to the group. See {Toys::DSL::FlagGroup}
|
527
|
+
# for the directives that can be called in this block.
|
528
|
+
# @return [self]
|
359
529
|
#
|
360
530
|
def flag_group(type: :optional, desc: nil, long_desc: nil, name: nil,
|
361
531
|
report_collisions: true, prepend: false, &block)
|
@@ -374,30 +544,35 @@ module Toys
|
|
374
544
|
# defined in the block belong to the group. All flags in this group are
|
375
545
|
# required.
|
376
546
|
#
|
377
|
-
# Example
|
547
|
+
# ## Example
|
548
|
+
#
|
549
|
+
# The following example creates a group of required flags.
|
378
550
|
#
|
379
|
-
#
|
380
|
-
#
|
381
|
-
#
|
551
|
+
# tool "login" do
|
552
|
+
# all_required do
|
553
|
+
# flag :username, "--username=VAL", desc: "Set username (required)"
|
554
|
+
# flag :password, "--password=VAL", desc: "Set password (required)"
|
555
|
+
# end
|
556
|
+
# # ...
|
382
557
|
# end
|
383
558
|
#
|
384
|
-
# @param [String,Array<String>,Toys::
|
385
|
-
# description for the group. See {Toys::
|
386
|
-
#
|
387
|
-
# @param [Array<String,Array<String>,Toys::
|
559
|
+
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
560
|
+
# description for the group. See {Toys::Tool#desc=} for a description
|
561
|
+
# of allowed formats. Defaults to `"Flags"`.
|
562
|
+
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
388
563
|
# Long description for the flag group. See
|
389
|
-
# {Toys::
|
390
|
-
#
|
391
|
-
# @param [String,Symbol,nil]
|
564
|
+
# {Toys::Tool#long_desc=} for a description of allowed formats.
|
565
|
+
# Defaults to the empty array.
|
566
|
+
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
392
567
|
# name.
|
393
|
-
# @param [Boolean]
|
568
|
+
# @param report_collisions [Boolean] If `true`, raise an exception if a
|
394
569
|
# the given name is already taken. If `false`, ignore. Default is
|
395
570
|
# `true`.
|
396
|
-
# @param [Boolean]
|
571
|
+
# @param prepend [Boolean] If `true`, prepend rather than append the
|
397
572
|
# group to the list. Default is `false`.
|
398
|
-
# @
|
399
|
-
#
|
400
|
-
# @return [
|
573
|
+
# @param block [Proc] Adds flags to the group. See {Toys::DSL::FlagGroup}
|
574
|
+
# for the directives that can be called in this block.
|
575
|
+
# @return [self]
|
401
576
|
#
|
402
577
|
def all_required(desc: nil, long_desc: nil, name: nil, report_collisions: true,
|
403
578
|
prepend: false, &block)
|
@@ -410,87 +585,132 @@ module Toys
|
|
410
585
|
# defined in the block belong to the group. At most one flag in this
|
411
586
|
# group must be provided on the command line.
|
412
587
|
#
|
413
|
-
#
|
414
|
-
#
|
415
|
-
#
|
416
|
-
#
|
588
|
+
# ## Example
|
589
|
+
#
|
590
|
+
# The following example creates a group of flags in which either one or
|
591
|
+
# none may be set, but not more than one.
|
592
|
+
#
|
593
|
+
# tool "provision-server" do
|
594
|
+
# at_most_one do
|
595
|
+
# flag :restore_from_backup, "--restore-from-backup=VAL"
|
596
|
+
# flag :restore_from_image, "--restore-from-image=VAL"
|
597
|
+
# flag :clone_existing, "--clone-existing=VAL"
|
598
|
+
# end
|
599
|
+
# # ...
|
600
|
+
# end
|
601
|
+
#
|
602
|
+
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
603
|
+
# description for the group. See {Toys::Tool#desc=} for a description
|
604
|
+
# of allowed formats. Defaults to `"Flags"`.
|
605
|
+
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
417
606
|
# Long description for the flag group. See
|
418
|
-
# {Toys::
|
419
|
-
#
|
420
|
-
# @param [String,Symbol,nil]
|
607
|
+
# {Toys::Tool#long_desc=} for a description of allowed formats.
|
608
|
+
# Defaults to the empty array.
|
609
|
+
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
421
610
|
# name.
|
422
|
-
# @param [Boolean]
|
611
|
+
# @param report_collisions [Boolean] If `true`, raise an exception if a
|
423
612
|
# the given name is already taken. If `false`, ignore. Default is
|
424
613
|
# `true`.
|
425
|
-
# @param [Boolean]
|
614
|
+
# @param prepend [Boolean] If `true`, prepend rather than append the
|
426
615
|
# group to the list. Default is `false`.
|
427
|
-
# @
|
428
|
-
#
|
429
|
-
# @return [
|
616
|
+
# @param block [Proc] Adds flags to the group. See {Toys::DSL::FlagGroup}
|
617
|
+
# for the directives that can be called in this block.
|
618
|
+
# @return [self]
|
430
619
|
#
|
431
|
-
def
|
432
|
-
|
620
|
+
def at_most_one(desc: nil, long_desc: nil, name: nil, report_collisions: true,
|
621
|
+
prepend: false, &block)
|
433
622
|
flag_group(type: :at_most_one, desc: desc, long_desc: long_desc,
|
434
623
|
name: name, report_collisions: report_collisions, prepend: prepend, &block)
|
435
624
|
end
|
625
|
+
alias at_most_one_required at_most_one
|
436
626
|
|
437
627
|
##
|
438
628
|
# Create a flag group of type `:at_least_one`. If a block is given, flags
|
439
629
|
# defined in the block belong to the group. At least one flag in this
|
440
630
|
# group must be provided on the command line.
|
441
631
|
#
|
442
|
-
#
|
443
|
-
#
|
444
|
-
#
|
445
|
-
#
|
632
|
+
# ## Example
|
633
|
+
#
|
634
|
+
# The following example creates a group of flags in which one or more
|
635
|
+
# may be set.
|
636
|
+
#
|
637
|
+
# tool "run-tests" do
|
638
|
+
# at_least_one do
|
639
|
+
# flag :unit, desc: "Run unit tests"
|
640
|
+
# flag :integration, desc: "Run integration tests"
|
641
|
+
# flag :performance, desc: "Run performance tests"
|
642
|
+
# end
|
643
|
+
# # ...
|
644
|
+
# end
|
645
|
+
#
|
646
|
+
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
647
|
+
# description for the group. See {Toys::Tool#desc=} for a description
|
648
|
+
# of allowed formats. Defaults to `"Flags"`.
|
649
|
+
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
446
650
|
# Long description for the flag group. See
|
447
|
-
# {Toys::
|
448
|
-
#
|
449
|
-
# @param [String,Symbol,nil]
|
651
|
+
# {Toys::Tool#long_desc=} for a description of allowed formats.
|
652
|
+
# Defaults to the empty array.
|
653
|
+
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
450
654
|
# name.
|
451
|
-
# @param [Boolean]
|
655
|
+
# @param report_collisions [Boolean] If `true`, raise an exception if a
|
452
656
|
# the given name is already taken. If `false`, ignore. Default is
|
453
657
|
# `true`.
|
454
|
-
# @param [Boolean]
|
658
|
+
# @param prepend [Boolean] If `true`, prepend rather than append the
|
455
659
|
# group to the list. Default is `false`.
|
456
|
-
# @
|
457
|
-
#
|
458
|
-
# @return [
|
660
|
+
# @param block [Proc] Adds flags to the group. See {Toys::DSL::FlagGroup}
|
661
|
+
# for the directives that can be called in this block.
|
662
|
+
# @return [self]
|
459
663
|
#
|
460
|
-
def
|
461
|
-
|
664
|
+
def at_least_one(desc: nil, long_desc: nil, name: nil, report_collisions: true,
|
665
|
+
prepend: false, &block)
|
462
666
|
flag_group(type: :at_least_one, desc: desc, long_desc: long_desc,
|
463
667
|
name: name, report_collisions: report_collisions, prepend: prepend, &block)
|
464
668
|
end
|
669
|
+
alias at_least_one_required at_least_one
|
465
670
|
|
466
671
|
##
|
467
672
|
# Create a flag group of type `:exactly_one`. If a block is given, flags
|
468
673
|
# defined in the block belong to the group. Exactly one flag in this
|
469
674
|
# group must be provided on the command line.
|
470
675
|
#
|
471
|
-
#
|
472
|
-
#
|
473
|
-
#
|
474
|
-
#
|
676
|
+
# ## Example
|
677
|
+
#
|
678
|
+
# The following example creates a group of flags in which exactly one
|
679
|
+
# must be set.
|
680
|
+
#
|
681
|
+
# tool "deploy" do
|
682
|
+
# exactly_one do
|
683
|
+
# flag :server, "--server=IP_ADDR", desc: "Deploy to server"
|
684
|
+
# flag :vm, "--vm=ID", desc: "Deploy to a VM"
|
685
|
+
# flag :container, "--container=ID", desc: "Deploy to a container"
|
686
|
+
# end
|
687
|
+
# # ...
|
688
|
+
# end
|
689
|
+
#
|
690
|
+
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
691
|
+
# description for the group. See {Toys::Tool#desc=} for a description
|
692
|
+
# of allowed formats. Defaults to `"Flags"`.
|
693
|
+
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
475
694
|
# Long description for the flag group. See
|
476
|
-
# {Toys::
|
477
|
-
#
|
478
|
-
# @param [String,Symbol,nil]
|
695
|
+
# {Toys::Tool#long_desc=} for a description of allowed formats.
|
696
|
+
# Defaults to the empty array.
|
697
|
+
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
479
698
|
# name.
|
480
|
-
# @param [Boolean]
|
699
|
+
# @param report_collisions [Boolean] If `true`, raise an exception if a
|
481
700
|
# the given name is already taken. If `false`, ignore. Default is
|
482
701
|
# `true`.
|
483
|
-
# @param [Boolean]
|
702
|
+
# @param prepend [Boolean] If `true`, prepend rather than append the
|
484
703
|
# group to the list. Default is `false`.
|
485
|
-
# @
|
486
|
-
#
|
487
|
-
# @return [
|
704
|
+
# @param block [Proc] Adds flags to the group. See {Toys::DSL::FlagGroup}
|
705
|
+
# for the directives that can be called in this block.
|
706
|
+
# @return [self]
|
488
707
|
#
|
489
|
-
def
|
490
|
-
|
708
|
+
def exactly_one(desc: nil, long_desc: nil, name: nil, report_collisions: true,
|
709
|
+
prepend: false, &block)
|
491
710
|
flag_group(type: :exactly_one, desc: desc, long_desc: long_desc,
|
492
711
|
name: name, report_collisions: report_collisions, prepend: prepend, &block)
|
493
712
|
end
|
713
|
+
alias exactly_one_required exactly_one
|
494
714
|
|
495
715
|
##
|
496
716
|
# Add a flag to the current tool. Each flag must specify a key which
|
@@ -500,56 +720,176 @@ module Toys
|
|
500
720
|
# If the given key is a symbol representing a valid method name, then a
|
501
721
|
# helper method is automatically added to retrieve the value. Otherwise,
|
502
722
|
# if the key is a string or does not represent a valid method name, the
|
503
|
-
# tool can retrieve the value by calling {Toys::
|
723
|
+
# tool can retrieve the value by calling {Toys::Context#get}.
|
504
724
|
#
|
505
725
|
# Attributes of the flag may be passed in as arguments to this method, or
|
506
726
|
# set in a block passed to this method. If you provide a block, you can
|
507
727
|
# use directives in {Toys::DSL::Flag} within the block.
|
508
728
|
#
|
509
|
-
#
|
729
|
+
# ## Flag syntax
|
730
|
+
#
|
731
|
+
# The flags themselves should be provided in OptionParser form. Following
|
732
|
+
# are examples of valid syntax.
|
733
|
+
#
|
734
|
+
# * `-a` : A short boolean switch. When this appears as an argument,
|
735
|
+
# the value is set to `true`.
|
736
|
+
# * `--abc` : A long boolean switch. When this appears as an argument,
|
737
|
+
# the value is set to `true`.
|
738
|
+
# * `-aVAL` or `-a VAL` : A short flag that takes a required value.
|
739
|
+
# These two forms are treated identically. If this argument appears
|
740
|
+
# with a value attached (e.g. `-afoo`), the attached string (e.g.
|
741
|
+
# `"foo"`) is taken as the value. Otherwise, the following argument
|
742
|
+
# is taken as the value (e.g. for `-a foo`, the value is set to
|
743
|
+
# `"foo"`.) The following argument is treated as the value even if it
|
744
|
+
# looks like a flag (e.g. `-a -a` causes the string `"-a"` to be
|
745
|
+
# taken as the value.)
|
746
|
+
# * `-a[VAL]` : A short flag that takes an optional value. If this
|
747
|
+
# argument appears with a value attached (e.g. `-afoo`), the attached
|
748
|
+
# string (e.g. `"foo"`) is taken as the value. Otherwise, the value
|
749
|
+
# is set to `true`. The following argument is never interpreted as
|
750
|
+
# the value. (Compare with `-a [VAL]`.)
|
751
|
+
# * `-a [VAL]` : A short flag that takes an optional value. If this
|
752
|
+
# argument appears with a value attached (e.g. `-afoo`), the attached
|
753
|
+
# string (e.g. `"foo"`) is taken as the value. Otherwise, if the
|
754
|
+
# following argument does not look like a flag (i.e. it does not
|
755
|
+
# begin with a hyphen), it is taken as the value. (e.g. `-a foo`
|
756
|
+
# causes the string `"foo"` to be taken as the value.). If there is
|
757
|
+
# no following argument, or the following argument looks like a flag,
|
758
|
+
# the value is set to `true`. (Compare with `-a[VAL]`.)
|
759
|
+
# * `--abc=VAL` or `--abc VAL` : A long flag that takes a required
|
760
|
+
# value. These two forms are treated identically. If this argument
|
761
|
+
# appears with a value attached (e.g. `--abc=foo`), the attached
|
762
|
+
# string (e.g. `"foo"`) is taken as the value. Otherwise, the
|
763
|
+
# following argument is taken as the value (e.g. for `--abc foo`, the
|
764
|
+
# value is set to `"foo"`.) The following argument is treated as the
|
765
|
+
# value even if it looks like a flag (e.g. `--abc --abc` causes the
|
766
|
+
# string `"--abc"` to be taken as the value.)
|
767
|
+
# * `--abc[=VAL]` : A long flag that takes an optional value. If this
|
768
|
+
# argument appears with a value attached (e.g. `--abc=foo`), the
|
769
|
+
# attached string (e.g. `"foo"`) is taken as the value. Otherwise,
|
770
|
+
# the value is set to `true`. The following argument is never
|
771
|
+
# interpreted as the value. (Compare with `--abc [VAL]`.)
|
772
|
+
# * `--abc [VAL]` : A long flag that takes an optional value. If this
|
773
|
+
# argument appears with a value attached (e.g. `--abc=foo`), the
|
774
|
+
# attached string (e.g. `"foo"`) is taken as the value. Otherwise, if
|
775
|
+
# the following argument does not look like a flag (i.e. it does not
|
776
|
+
# begin with a hyphen), it is taken as the value. (e.g. `--abc foo`
|
777
|
+
# causes the string `"foo"` to be taken as the value.). If there is
|
778
|
+
# no following argument, or the following argument looks like a flag,
|
779
|
+
# the value is set to `true`. (Compare with `--abc=[VAL]`.)
|
780
|
+
# * `--[no-]abc` : A long boolean switch that can be turned either on
|
781
|
+
# or off. This effectively creates two flags, `--abc` which sets the
|
782
|
+
# value to `true`, and `--no-abc` which sets the falue to `false`.
|
783
|
+
#
|
784
|
+
# ## Default flag syntax
|
785
|
+
#
|
786
|
+
# If no flag syntax strings are provided, a default syntax will be
|
787
|
+
# inferred based on the key and other options.
|
788
|
+
#
|
789
|
+
# Specifically, if the key has one character, then that character will be
|
790
|
+
# chosen as a short flag. If the key has multiple characters, a long flag
|
791
|
+
# will be generated.
|
792
|
+
#
|
793
|
+
# Furthermore, if a custom completion, a non-boolean acceptor, or a
|
794
|
+
# non-boolean default value is provided in the options, then the flag
|
795
|
+
# will be considered to take a value. Otherwise, it will be considered to
|
796
|
+
# be a boolean switch.
|
797
|
+
#
|
798
|
+
# For example, the following pairs of flags are identical:
|
799
|
+
#
|
800
|
+
# flag :a
|
801
|
+
# flag :a, "-a"
|
802
|
+
#
|
803
|
+
# flag :abc_def
|
804
|
+
# flag :abc_def, "--abc-def"
|
805
|
+
#
|
806
|
+
# flag :number, accept: Integer
|
807
|
+
# flag :number, "--number=VAL", accept: Integer
|
808
|
+
#
|
809
|
+
# ## More examples
|
810
|
+
#
|
811
|
+
# A flag that sets its value to the number of times it appears on the
|
812
|
+
# command line:
|
813
|
+
#
|
814
|
+
# flag :verbose, "-v", "--verbose",
|
815
|
+
# default: 0, handler: ->(_val, count) { count + 1 }
|
816
|
+
#
|
817
|
+
# An example using block form:
|
818
|
+
#
|
819
|
+
# flag :shout do
|
820
|
+
# flags "-s", "--shout"
|
821
|
+
# default false
|
822
|
+
# desc "Say it louder"
|
823
|
+
# long_desc "This flag says it lowder.",
|
824
|
+
# "You might use this when people can't hear you.",
|
825
|
+
# "",
|
826
|
+
# "Example:",
|
827
|
+
# [" toys say --shout hello"]
|
828
|
+
# end
|
829
|
+
#
|
830
|
+
# @param key [String,Symbol] The key to use to retrieve the value from
|
510
831
|
# the execution context.
|
511
|
-
# @param [String...]
|
512
|
-
# @param [Object]
|
832
|
+
# @param flags [String...] The flags in OptionParser format.
|
833
|
+
# @param accept [Object] An acceptor that validates and/or converts the
|
513
834
|
# value. You may provide either the name of an acceptor you have
|
514
835
|
# defined, or one of the default acceptors provided by OptionParser.
|
515
836
|
# Optional. If not specified, accepts any value as a string.
|
516
|
-
# @param [Object]
|
837
|
+
# @param default [Object] The default value. This is the value that will
|
517
838
|
# be set in the context if this flag is not provided on the command
|
518
839
|
# line. Defaults to `nil`.
|
519
|
-
# @param [Proc,nil]
|
520
|
-
# value.
|
521
|
-
#
|
522
|
-
# should be set.
|
523
|
-
#
|
524
|
-
#
|
840
|
+
# @param handler [Proc,nil,:set,:push] An optional handler for
|
841
|
+
# setting/updating the value. A handler is a proc taking two
|
842
|
+
# arguments, the given value and the previous value, returning the
|
843
|
+
# new value that should be set. You may also specify a predefined
|
844
|
+
# named handler. The `:set` handler (the default) replaces the
|
845
|
+
# previous value (effectively `-> (val, _prev) { val }`). The
|
846
|
+
# `:push` handler expects the previous value to be an array and
|
847
|
+
# pushes the given value onto it; it should be combined with setting
|
848
|
+
# `default: []` and is intended for "multi-valued" flags.
|
849
|
+
# @param complete_flags [Object] A specifier for shell tab completion
|
850
|
+
# for flag names associated with this flag. By default, a
|
851
|
+
# {Toys::Flag::DefaultCompletion} is used, which provides the flag's
|
852
|
+
# names as completion candidates. To customize completion, set this
|
853
|
+
# to the name of a previously defined completion, a hash of options
|
854
|
+
# to pass to the constructor for {Toys::Flag::DefaultCompletion}, or
|
855
|
+
# any other spec recognized by {Toys::Completion.create}.
|
856
|
+
# @param complete_values [Object] A specifier for shell tab completion
|
857
|
+
# for flag values associated with this flag. This is the empty
|
858
|
+
# completion by default. To customize completion, set this to the
|
859
|
+
# name of a previously defined completion, or any spec recognized by
|
860
|
+
# {Toys::Completion.create}.
|
861
|
+
# @param report_collisions [Boolean] Raise an exception if a flag is
|
525
862
|
# requested that is already in use or marked as unusable. Default is
|
526
863
|
# true.
|
527
|
-
# @param [Toys::
|
528
|
-
#
|
529
|
-
#
|
530
|
-
# @param [String,Array<String>,Toys::
|
864
|
+
# @param group [Toys::FlagGroup,String,Symbol,nil] Group for this flag.
|
865
|
+
# You may provide a group name, a FlagGroup object, or `nil` which
|
866
|
+
# denotes the default group.
|
867
|
+
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
531
868
|
# description for the flag. See {Toys::DSL::Tool#desc} for a
|
532
869
|
# description of the allowed formats. Defaults to the empty string.
|
533
|
-
# @param [Array<String,Array<String>,Toys::
|
870
|
+
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
534
871
|
# Long description for the flag. See {Toys::DSL::Tool#long_desc} for
|
535
872
|
# a description of the allowed formats. (But note that this param
|
536
873
|
# takes an Array of description lines, rather than a series of
|
537
874
|
# arguments.) Defaults to the empty array.
|
538
|
-
# @param [String]
|
875
|
+
# @param display_name [String] A display name for this flag, used in help
|
539
876
|
# text and error messages.
|
540
|
-
# @
|
541
|
-
#
|
542
|
-
# @return [
|
877
|
+
# @param block [Proc] Configures the flag. See {Toys::DSL::Flag} for the
|
878
|
+
# directives that can be called in this block.
|
879
|
+
# @return [self]
|
543
880
|
#
|
544
881
|
def flag(key, *flags,
|
545
882
|
accept: nil, default: nil, handler: nil,
|
883
|
+
complete_flags: nil, complete_values: nil,
|
546
884
|
report_collisions: true, group: nil,
|
547
885
|
desc: nil, long_desc: nil, display_name: nil,
|
548
886
|
&block)
|
549
887
|
cur_tool = DSL::Tool.current_tool(self, true)
|
550
888
|
return self if cur_tool.nil?
|
551
|
-
flag_dsl = DSL::Flag.new(
|
552
|
-
|
889
|
+
flag_dsl = DSL::Flag.new(
|
890
|
+
flags.flatten, accept, default, handler, complete_flags, complete_values,
|
891
|
+
report_collisions, group, desc, long_desc, display_name
|
892
|
+
)
|
553
893
|
flag_dsl.instance_exec(flag_dsl, &block) if block
|
554
894
|
flag_dsl._add_to(cur_tool, key)
|
555
895
|
DSL::Tool.maybe_add_getter(self, key)
|
@@ -564,39 +904,57 @@ module Toys
|
|
564
904
|
# If the given key is a symbol representing a valid method name, then a
|
565
905
|
# helper method is automatically added to retrieve the value. Otherwise,
|
566
906
|
# if the key is a string or does not represent a valid method name, the
|
567
|
-
# tool can retrieve the value by calling {Toys::
|
907
|
+
# tool can retrieve the value by calling {Toys::Context#get}.
|
568
908
|
#
|
569
909
|
# Attributes of the arg may be passed in as arguments to this method, or
|
570
910
|
# set in a block passed to this method. If you provide a block, you can
|
571
|
-
# use directives in {Toys::DSL::
|
911
|
+
# use directives in {Toys::DSL::PositionalArg} within the block.
|
912
|
+
#
|
913
|
+
# ## Example
|
914
|
+
#
|
915
|
+
# This tool "moves" something from a source to destination, and takes two
|
916
|
+
# required arguments:
|
572
917
|
#
|
573
|
-
#
|
918
|
+
# tool "mv" do
|
919
|
+
# required_arg :source
|
920
|
+
# required_arg :dest
|
921
|
+
# def run
|
922
|
+
# puts "moving from #{source} to #{dest}..."
|
923
|
+
# end
|
924
|
+
# end
|
925
|
+
#
|
926
|
+
# @param key [String,Symbol] The key to use to retrieve the value from
|
574
927
|
# the execution context.
|
575
|
-
# @param [Object]
|
928
|
+
# @param accept [Object] An acceptor that validates and/or converts the
|
576
929
|
# value. You may provide either the name of an acceptor you have
|
577
930
|
# defined, or one of the default acceptors provided by OptionParser.
|
578
931
|
# Optional. If not specified, accepts any value as a string.
|
579
|
-
# @param [
|
932
|
+
# @param complete [Object] A specifier for shell tab completion for
|
933
|
+
# values of this arg. This is the empty completion by default. To
|
934
|
+
# customize completion, set this to the name of a previously defined
|
935
|
+
# completion, or any spec recognized by {Toys::Completion.create}.
|
936
|
+
# @param display_name [String] A name to use for display (in help text and
|
580
937
|
# error reports). Defaults to the key in upper case.
|
581
|
-
# @param [String,Array<String>,Toys::
|
938
|
+
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
582
939
|
# description for the flag. See {Toys::DSL::Tool#desc} for a
|
583
940
|
# description of the allowed formats. Defaults to the empty string.
|
584
|
-
# @param [Array<String,Array<String>,Toys::
|
941
|
+
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
585
942
|
# Long description for the flag. See {Toys::DSL::Tool#long_desc} for
|
586
943
|
# a description of the allowed formats. (But note that this param
|
587
944
|
# takes an Array of description lines, rather than a series of
|
588
945
|
# arguments.) Defaults to the empty array.
|
589
|
-
# @
|
590
|
-
#
|
591
|
-
#
|
946
|
+
# @param block [Proc] Configures the positional argument. See
|
947
|
+
# {Toys::DSL::PositionalArg} for the directives that can be called in
|
948
|
+
# this block.
|
949
|
+
# @return [self]
|
592
950
|
#
|
593
951
|
def required_arg(key,
|
594
|
-
accept: nil, display_name: nil,
|
952
|
+
accept: nil, complete: nil, display_name: nil,
|
595
953
|
desc: nil, long_desc: nil,
|
596
954
|
&block)
|
597
955
|
cur_tool = DSL::Tool.current_tool(self, true)
|
598
956
|
return self if cur_tool.nil?
|
599
|
-
arg_dsl = DSL::
|
957
|
+
arg_dsl = DSL::PositionalArg.new(accept, nil, complete, display_name, desc, long_desc)
|
600
958
|
arg_dsl.instance_exec(arg_dsl, &block) if block
|
601
959
|
arg_dsl._add_required_to(cur_tool, key)
|
602
960
|
DSL::Tool.maybe_add_getter(self, key)
|
@@ -613,42 +971,61 @@ module Toys
|
|
613
971
|
# If the given key is a symbol representing a valid method name, then a
|
614
972
|
# helper method is automatically added to retrieve the value. Otherwise,
|
615
973
|
# if the key is a string or does not represent a valid method name, the
|
616
|
-
# tool can retrieve the value by calling {Toys::
|
974
|
+
# tool can retrieve the value by calling {Toys::Context#get}.
|
617
975
|
#
|
618
976
|
# Attributes of the arg may be passed in as arguments to this method, or
|
619
977
|
# set in a block passed to this method. If you provide a block, you can
|
620
|
-
# use directives in {Toys::DSL::
|
978
|
+
# use directives in {Toys::DSL::PositionalArg} within the block.
|
979
|
+
#
|
980
|
+
# ## Example
|
981
|
+
#
|
982
|
+
# This tool creates a "link" to a given target. The link location is
|
983
|
+
# optional; if it is not given, it is inferred from the target.
|
984
|
+
#
|
985
|
+
# tool "ln" do
|
986
|
+
# required_arg :target
|
987
|
+
# optional_arg :location
|
988
|
+
# def run
|
989
|
+
# loc = location || File.basename(target)
|
990
|
+
# puts "linking to #{target} from #{loc}..."
|
991
|
+
# end
|
992
|
+
# end
|
621
993
|
#
|
622
|
-
# @param [String,Symbol]
|
994
|
+
# @param key [String,Symbol] The key to use to retrieve the value from
|
623
995
|
# the execution context.
|
624
|
-
# @param [Object]
|
996
|
+
# @param default [Object] The default value. This is the value that will
|
625
997
|
# be set in the context if this argument is not provided on the command
|
626
998
|
# line. Defaults to `nil`.
|
627
|
-
# @param [Object]
|
999
|
+
# @param accept [Object] An acceptor that validates and/or converts the
|
628
1000
|
# value. You may provide either the name of an acceptor you have
|
629
1001
|
# defined, or one of the default acceptors provided by OptionParser.
|
630
1002
|
# Optional. If not specified, accepts any value as a string.
|
631
|
-
# @param [
|
1003
|
+
# @param complete [Object] A specifier for shell tab completion for
|
1004
|
+
# values of this arg. This is the empty completion by default. To
|
1005
|
+
# customize completion, set this to the name of a previously defined
|
1006
|
+
# completion, or any spec recognized by {Toys::Completion.create}.
|
1007
|
+
# @param display_name [String] A name to use for display (in help text and
|
632
1008
|
# error reports). Defaults to the key in upper case.
|
633
|
-
# @param [String,Array<String>,Toys::
|
1009
|
+
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
634
1010
|
# description for the flag. See {Toys::DSL::Tool#desc} for a
|
635
1011
|
# description of the allowed formats. Defaults to the empty string.
|
636
|
-
# @param [Array<String,Array<String>,Toys::
|
1012
|
+
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
637
1013
|
# Long description for the flag. See {Toys::DSL::Tool#long_desc} for
|
638
1014
|
# a description of the allowed formats. (But note that this param
|
639
1015
|
# takes an Array of description lines, rather than a series of
|
640
1016
|
# arguments.) Defaults to the empty array.
|
641
|
-
# @
|
642
|
-
#
|
643
|
-
#
|
1017
|
+
# @param block [Proc] Configures the positional argument. See
|
1018
|
+
# {Toys::DSL::PositionalArg} for the directives that can be called in
|
1019
|
+
# this block.
|
1020
|
+
# @return [self]
|
644
1021
|
#
|
645
1022
|
def optional_arg(key,
|
646
|
-
default: nil, accept: nil, display_name: nil,
|
1023
|
+
default: nil, accept: nil, complete: nil, display_name: nil,
|
647
1024
|
desc: nil, long_desc: nil,
|
648
1025
|
&block)
|
649
1026
|
cur_tool = DSL::Tool.current_tool(self, true)
|
650
1027
|
return self if cur_tool.nil?
|
651
|
-
arg_dsl = DSL::
|
1028
|
+
arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name, desc, long_desc)
|
652
1029
|
arg_dsl.instance_exec(arg_dsl, &block) if block
|
653
1030
|
arg_dsl._add_optional_to(cur_tool, key)
|
654
1031
|
DSL::Tool.maybe_add_getter(self, key)
|
@@ -664,42 +1041,62 @@ module Toys
|
|
664
1041
|
# If the given key is a symbol representing a valid method name, then a
|
665
1042
|
# helper method is automatically added to retrieve the value. Otherwise,
|
666
1043
|
# if the key is a string or does not represent a valid method name, the
|
667
|
-
# tool can retrieve the value by calling {Toys::
|
1044
|
+
# tool can retrieve the value by calling {Toys::Context#get}.
|
668
1045
|
#
|
669
1046
|
# Attributes of the arg may be passed in as arguments to this method, or
|
670
1047
|
# set in a block passed to this method. If you provide a block, you can
|
671
|
-
# use directives in {Toys::DSL::
|
1048
|
+
# use directives in {Toys::DSL::PositionalArg} within the block.
|
1049
|
+
#
|
1050
|
+
# ## Example
|
1051
|
+
#
|
1052
|
+
# This tool displays a "list" of the given directories. If no directories
|
1053
|
+
# ar given, lists the current directory.
|
1054
|
+
#
|
1055
|
+
# tool "ln" do
|
1056
|
+
# remaining_args :directories
|
1057
|
+
# def run
|
1058
|
+
# dirs = directories.empty? ? [Dir.pwd] : directories
|
1059
|
+
# dirs.each do |dir|
|
1060
|
+
# puts "Listing directory #{dir}..."
|
1061
|
+
# end
|
1062
|
+
# end
|
1063
|
+
# end
|
672
1064
|
#
|
673
|
-
# @param [String,Symbol]
|
1065
|
+
# @param key [String,Symbol] The key to use to retrieve the value from
|
674
1066
|
# the execution context.
|
675
|
-
# @param [Object]
|
1067
|
+
# @param default [Object] The default value. This is the value that will
|
676
1068
|
# be set in the context if no unmatched arguments are provided on the
|
677
1069
|
# command line. Defaults to the empty array `[]`.
|
678
|
-
# @param [Object]
|
1070
|
+
# @param accept [Object] An acceptor that validates and/or converts the
|
679
1071
|
# value. You may provide either the name of an acceptor you have
|
680
1072
|
# defined, or one of the default acceptors provided by OptionParser.
|
681
1073
|
# Optional. If not specified, accepts any value as a string.
|
682
|
-
# @param [
|
1074
|
+
# @param complete [Object] A specifier for shell tab completion for
|
1075
|
+
# values of this arg. This is the empty completion by default. To
|
1076
|
+
# customize completion, set this to the name of a previously defined
|
1077
|
+
# completion, or any spec recognized by {Toys::Completion.create}.
|
1078
|
+
# @param display_name [String] A name to use for display (in help text and
|
683
1079
|
# error reports). Defaults to the key in upper case.
|
684
|
-
# @param [String,Array<String>,Toys::
|
1080
|
+
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
685
1081
|
# description for the flag. See {Toys::DSL::Tool#desc} for a
|
686
1082
|
# description of the allowed formats. Defaults to the empty string.
|
687
|
-
# @param [Array<String,Array<String>,Toys::
|
1083
|
+
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
688
1084
|
# Long description for the flag. See {Toys::DSL::Tool#long_desc} for
|
689
1085
|
# a description of the allowed formats. (But note that this param
|
690
1086
|
# takes an Array of description lines, rather than a series of
|
691
1087
|
# arguments.) Defaults to the empty array.
|
692
|
-
# @
|
693
|
-
#
|
694
|
-
#
|
1088
|
+
# @param block [Proc] Configures the positional argument. See
|
1089
|
+
# {Toys::DSL::PositionalArg} for the directives that can be called in
|
1090
|
+
# this block.
|
1091
|
+
# @return [self]
|
695
1092
|
#
|
696
1093
|
def remaining_args(key,
|
697
|
-
default: [], accept: nil, display_name: nil,
|
1094
|
+
default: [], accept: nil, complete: nil, display_name: nil,
|
698
1095
|
desc: nil, long_desc: nil,
|
699
1096
|
&block)
|
700
1097
|
cur_tool = DSL::Tool.current_tool(self, true)
|
701
1098
|
return self if cur_tool.nil?
|
702
|
-
arg_dsl = DSL::
|
1099
|
+
arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name, desc, long_desc)
|
703
1100
|
arg_dsl.instance_exec(arg_dsl, &block) if block
|
704
1101
|
arg_dsl._set_remaining_on(cur_tool, key)
|
705
1102
|
DSL::Tool.maybe_add_getter(self, key)
|
@@ -708,17 +1105,35 @@ module Toys
|
|
708
1105
|
alias remaining remaining_args
|
709
1106
|
|
710
1107
|
##
|
711
|
-
# Set
|
1108
|
+
# Set a option values statically and create a helper method.
|
712
1109
|
#
|
713
|
-
# If
|
1110
|
+
# If any given key is a symbol representing a valid method name, then a
|
714
1111
|
# helper method is automatically added to retrieve the value. Otherwise,
|
715
1112
|
# if the key is a string or does not represent a valid method name, the
|
716
|
-
# tool can retrieve the value by calling {Toys::
|
1113
|
+
# tool can retrieve the value by calling {Toys::Context#get}.
|
717
1114
|
#
|
718
|
-
#
|
719
|
-
#
|
720
|
-
#
|
721
|
-
#
|
1115
|
+
# ## Example
|
1116
|
+
#
|
1117
|
+
# tool "hello" do
|
1118
|
+
# static :greeting, "Hi there"
|
1119
|
+
# def run
|
1120
|
+
# puts "#{greeting}, world!"
|
1121
|
+
# end
|
1122
|
+
# end
|
1123
|
+
#
|
1124
|
+
# @return [self]
|
1125
|
+
#
|
1126
|
+
# @overload static(key, value)
|
1127
|
+
# Set a single value by key.
|
1128
|
+
# @param key [String,Symbol] The key to use to retrieve the value from
|
1129
|
+
# the execution context.
|
1130
|
+
# @param value [Object] The value to set.
|
1131
|
+
# @return [self]
|
1132
|
+
#
|
1133
|
+
# @overload static(hash)
|
1134
|
+
# Set multiple keys and values
|
1135
|
+
# @param hash [Hash] The keys and values to set
|
1136
|
+
# @return [self]
|
722
1137
|
#
|
723
1138
|
def static(key, value = nil)
|
724
1139
|
cur_tool = DSL::Tool.current_tool(self, true)
|
@@ -735,15 +1150,84 @@ module Toys
|
|
735
1150
|
self
|
736
1151
|
end
|
737
1152
|
|
1153
|
+
##
|
1154
|
+
# Set a option values statically without creating helper methods.
|
1155
|
+
#
|
1156
|
+
# ## Example
|
1157
|
+
#
|
1158
|
+
# tool "hello" do
|
1159
|
+
# set :greeting, "Hi there"
|
1160
|
+
# def run
|
1161
|
+
# puts "#{get(:greeting)}, world!"
|
1162
|
+
# end
|
1163
|
+
# end
|
1164
|
+
#
|
1165
|
+
# @return [self]
|
1166
|
+
#
|
1167
|
+
# @overload set(key, value)
|
1168
|
+
# Set a single value by key.
|
1169
|
+
# @param key [String,Symbol] The key to use to retrieve the value from
|
1170
|
+
# the execution context.
|
1171
|
+
# @param value [Object] The value to set.
|
1172
|
+
# @return [self]
|
1173
|
+
#
|
1174
|
+
# @overload set(hash)
|
1175
|
+
# Set multiple keys and values
|
1176
|
+
# @param hash [Hash] The keys and values to set
|
1177
|
+
# @return [self]
|
1178
|
+
#
|
1179
|
+
def set(key, value = nil)
|
1180
|
+
cur_tool = DSL::Tool.current_tool(self, true)
|
1181
|
+
return self if cur_tool.nil?
|
1182
|
+
if key.is_a?(::Hash)
|
1183
|
+
cur_tool.default_data.merge!(key)
|
1184
|
+
else
|
1185
|
+
cur_tool.default_data[key] = value
|
1186
|
+
end
|
1187
|
+
self
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
##
|
1191
|
+
# Enforce that all flags must be provided before any positional args.
|
1192
|
+
# That is, as soon as the first positional arg appears in the command
|
1193
|
+
# line arguments, flag parsing is disabled as if `--` had appeared.
|
1194
|
+
#
|
1195
|
+
# Issuing this directive by itself turns on enforcement. You may turn it
|
1196
|
+
# off by passsing `false` as the parameter.
|
1197
|
+
#
|
1198
|
+
# @param state [Boolean]
|
1199
|
+
# @return [self]
|
1200
|
+
#
|
1201
|
+
def enforce_flags_before_args(state = true)
|
1202
|
+
DSL::Tool.current_tool(self, true)&.enforce_flags_before_args(state)
|
1203
|
+
self
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
##
|
1207
|
+
# Require that flags must match exactly. That is, flags must appear in
|
1208
|
+
# their entirety on the command line. (If false, substrings of flags are
|
1209
|
+
# accepted as long as they are unambiguous.)
|
1210
|
+
#
|
1211
|
+
# Issuing this directive by itself turns on exact match. You may turn it
|
1212
|
+
# off by passsing `false` as the parameter.
|
1213
|
+
#
|
1214
|
+
# @param state [Boolean]
|
1215
|
+
# @return [self]
|
1216
|
+
#
|
1217
|
+
def require_exact_flag_match(state = true)
|
1218
|
+
DSL::Tool.current_tool(self, true)&.require_exact_flag_match(state)
|
1219
|
+
self
|
1220
|
+
end
|
1221
|
+
|
738
1222
|
##
|
739
1223
|
# Disable argument parsing for this tool. Arguments will not be parsed
|
740
1224
|
# and the options will not be populated. Instead, tools can retrieve the
|
741
|
-
# full unparsed argument list by calling {Toys::
|
1225
|
+
# full unparsed argument list by calling {Toys::Context#args}.
|
742
1226
|
#
|
743
1227
|
# This directive is mutually exclusive with any of the directives that
|
744
1228
|
# declare arguments or flags.
|
745
1229
|
#
|
746
|
-
# @return [
|
1230
|
+
# @return [self]
|
747
1231
|
#
|
748
1232
|
def disable_argument_parsing
|
749
1233
|
DSL::Tool.current_tool(self, true)&.disable_argument_parsing
|
@@ -755,26 +1239,152 @@ module Toys
|
|
755
1239
|
# subsequent flag definition. This can be used to prevent middleware from
|
756
1240
|
# defining a particular flag.
|
757
1241
|
#
|
758
|
-
#
|
759
|
-
#
|
1242
|
+
# ## Example
|
1243
|
+
#
|
1244
|
+
# This tool does not support the `-v` and `-q` short forms for the two
|
1245
|
+
# verbosity flags (although it still supports the long forms `--verbose`
|
1246
|
+
# and `--quiet`.)
|
1247
|
+
#
|
1248
|
+
# tool "mytool" do
|
1249
|
+
# disable_flag "-v", "-q"
|
1250
|
+
# def run
|
1251
|
+
# # ...
|
1252
|
+
# end
|
1253
|
+
# end
|
1254
|
+
#
|
1255
|
+
# @param flags [String...] The flags to disable
|
1256
|
+
# @return [self]
|
760
1257
|
#
|
761
1258
|
def disable_flag(*flags)
|
762
1259
|
DSL::Tool.current_tool(self, true)&.disable_flag(*flags)
|
763
1260
|
self
|
764
1261
|
end
|
765
1262
|
|
1263
|
+
##
|
1264
|
+
# Set the shell completion strategy for this tool's arguments.
|
1265
|
+
# You can pass one of the following:
|
1266
|
+
#
|
1267
|
+
# * The string name of a completion defined in this tool or any of its
|
1268
|
+
# its ancestors.
|
1269
|
+
# * A hash of options to pass to the constructor of
|
1270
|
+
# {Toys::Tool::DefaultCompletion}.
|
1271
|
+
# * `nil` or `:default` to select the standard completion strategy
|
1272
|
+
# (which is {Toys::Tool::DefaultCompletion} with no extra options).
|
1273
|
+
# * Any other specification recognized by {Toys::Completion.create}.
|
1274
|
+
#
|
1275
|
+
# ## Example
|
1276
|
+
#
|
1277
|
+
# The namespace "foo" supports completion only of subtool names. It does
|
1278
|
+
# not complete the standard flags (like --help).
|
1279
|
+
#
|
1280
|
+
# tool "foo" do
|
1281
|
+
# complete_tool_args complete_args: false, complete_flags: false,
|
1282
|
+
# complete_flag_values: false
|
1283
|
+
# tool "bar" do
|
1284
|
+
# def run
|
1285
|
+
# puts "in foo bar"
|
1286
|
+
# end
|
1287
|
+
# end
|
1288
|
+
# end
|
1289
|
+
#
|
1290
|
+
# @param spec [Object]
|
1291
|
+
# @param options [Hash]
|
1292
|
+
# @param block [Proc]
|
1293
|
+
# @return [self]
|
1294
|
+
#
|
1295
|
+
def complete_tool_args(spec = nil, **options, &block)
|
1296
|
+
cur_tool = DSL::Tool.current_tool(self, true)
|
1297
|
+
return self if cur_tool.nil?
|
1298
|
+
cur_tool.completion = cur_tool.scalar_completion(spec, options, &block)
|
1299
|
+
self
|
1300
|
+
end
|
1301
|
+
|
766
1302
|
##
|
767
1303
|
# Specify how to run this tool. Typically you do this by defining a
|
768
|
-
# method namd `run`. Alternatively, you can pass a block to
|
1304
|
+
# method namd `run`. Alternatively, however, you can pass a block to the
|
1305
|
+
# `to_run` method.
|
1306
|
+
#
|
769
1307
|
# You may want to do this if your method needs access to local variables
|
770
|
-
# in the lexical scope.
|
1308
|
+
# in the lexical scope. However, it is often more convenient to use
|
1309
|
+
# {#static} to set the value in the context.)
|
1310
|
+
#
|
1311
|
+
# ## Example
|
1312
|
+
#
|
1313
|
+
# tool "foo" do
|
1314
|
+
# cur_time = Time.new
|
1315
|
+
# to_run do
|
1316
|
+
# puts "The time at tool definition was #{cur_time}"
|
1317
|
+
# end
|
1318
|
+
# end
|
771
1319
|
#
|
772
|
-
# @
|
1320
|
+
# @param block [Proc] The run method.
|
1321
|
+
# @return [self]
|
773
1322
|
#
|
774
1323
|
def to_run(&block)
|
775
1324
|
define_method(:run, &block)
|
776
1325
|
self
|
777
1326
|
end
|
1327
|
+
alias on_run to_run
|
1328
|
+
|
1329
|
+
##
|
1330
|
+
# Specify how to handle interrupts.
|
1331
|
+
#
|
1332
|
+
# You may pass a block to be called, or the name of a method to call. In
|
1333
|
+
# either case, the block or method should take one argument, the
|
1334
|
+
# Interrupt exception that was raised.
|
1335
|
+
#
|
1336
|
+
# ## Example
|
1337
|
+
#
|
1338
|
+
# tool "foo" do
|
1339
|
+
# def run
|
1340
|
+
# sleep 10
|
1341
|
+
# end
|
1342
|
+
# on_interrupt do |e|
|
1343
|
+
# puts "I was interrupted."
|
1344
|
+
# end
|
1345
|
+
# end
|
1346
|
+
#
|
1347
|
+
# @param handler [Proc,Symbol,nil] The interrupt callback proc or method
|
1348
|
+
# name. Pass nil to disable interrupt handling.
|
1349
|
+
# @param block [Proc] The interrupt callback as a block.
|
1350
|
+
# @return [self]
|
1351
|
+
#
|
1352
|
+
def on_interrupt(handler = nil, &block)
|
1353
|
+
cur_tool = DSL::Tool.current_tool(self, true)
|
1354
|
+
cur_tool.interrupt_handler = handler || block unless cur_tool.nil?
|
1355
|
+
self
|
1356
|
+
end
|
1357
|
+
|
1358
|
+
##
|
1359
|
+
# Specify how to handle usage errors.
|
1360
|
+
#
|
1361
|
+
# You may pass a block to be called, or the name of a method to call. In
|
1362
|
+
# either case, the block or method should take one argument, the array of
|
1363
|
+
# usage errors reported.
|
1364
|
+
#
|
1365
|
+
# ## Example
|
1366
|
+
#
|
1367
|
+
# This tool runs even if a usage error is encountered. You can find info
|
1368
|
+
# on the errors from {Toys::Context::Key::USAGE_ERRORS},
|
1369
|
+
# {Toys::Context::Key::UNMATCHED_ARGS}, and similar keys.
|
1370
|
+
#
|
1371
|
+
# tool "foo" do
|
1372
|
+
# def run
|
1373
|
+
# puts "Errors: #{usage_errors.join("\n")}"
|
1374
|
+
# end
|
1375
|
+
# on_usage_error :run
|
1376
|
+
# end
|
1377
|
+
#
|
1378
|
+
# @param handler [Proc,Symbol,nil] The interrupt callback proc or method
|
1379
|
+
# name. Pass nil to disable interrupt handling.
|
1380
|
+
# @param block [Proc] The interrupt callback as a block.
|
1381
|
+
# @return [self]
|
1382
|
+
#
|
1383
|
+
def on_usage_error(handler = nil, &block)
|
1384
|
+
cur_tool = DSL::Tool.current_tool(self, true)
|
1385
|
+
cur_tool.usage_error_handler = handler || block unless cur_tool.nil?
|
1386
|
+
self
|
1387
|
+
end
|
778
1388
|
|
779
1389
|
##
|
780
1390
|
# Specify that the given module should be mixed into this tool, and its
|
@@ -784,26 +1394,43 @@ module Toys
|
|
784
1394
|
# have defined in this tool or one of its ancestors, or the symbol name
|
785
1395
|
# of a well-known mixin.
|
786
1396
|
#
|
787
|
-
#
|
788
|
-
#
|
1397
|
+
# ## Example
|
1398
|
+
#
|
1399
|
+
# Include the well-known mixin `:terminal` and perform some terminal
|
1400
|
+
# magic.
|
1401
|
+
#
|
1402
|
+
# tool "spin" do
|
1403
|
+
# include :terminal
|
1404
|
+
# def run
|
1405
|
+
# # The spinner method is defined by the :terminal mixin.
|
1406
|
+
# spinner(leading_text: "Waiting...", final_text: "\n") do
|
1407
|
+
# sleep 5
|
1408
|
+
# end
|
1409
|
+
# end
|
1410
|
+
# end
|
1411
|
+
#
|
1412
|
+
# @param mod [Module,Symbol,String] Module or module name.
|
1413
|
+
# @param args [Object...] Arguments to pass to the initializer
|
1414
|
+
# @return [self]
|
789
1415
|
#
|
790
1416
|
def include(mod, *args)
|
791
1417
|
cur_tool = DSL::Tool.current_tool(self, true)
|
792
|
-
return if cur_tool.nil?
|
1418
|
+
return self if cur_tool.nil?
|
793
1419
|
mod = DSL::Tool.resolve_mixin(mod, cur_tool, @__loader)
|
794
1420
|
if included_modules.include?(mod)
|
795
1421
|
raise ToolDefinitionError, "Mixin already included: #{mod.name}"
|
796
1422
|
end
|
797
1423
|
cur_tool.mark_includes_modules
|
798
|
-
|
799
|
-
|
1424
|
+
super(mod)
|
1425
|
+
if mod.respond_to?(:initializer)
|
1426
|
+
callback = mod.initializer
|
800
1427
|
cur_tool.add_initializer(callback, *args) if callback
|
801
1428
|
end
|
802
|
-
if mod.respond_to?(:
|
803
|
-
callback = mod.
|
1429
|
+
if mod.respond_to?(:inclusion)
|
1430
|
+
callback = mod.inclusion
|
804
1431
|
class_exec(*args, &callback) if callback
|
805
1432
|
end
|
806
|
-
|
1433
|
+
self
|
807
1434
|
end
|
808
1435
|
|
809
1436
|
##
|
@@ -813,9 +1440,10 @@ module Toys
|
|
813
1440
|
# have defined in this tool or one of its ancestors, or the symbol name
|
814
1441
|
# of a well-known mixin.
|
815
1442
|
#
|
816
|
-
# @param [Module,Symbol,String]
|
817
|
-
#
|
818
|
-
#
|
1443
|
+
# @param mod [Module,Symbol,String] Module or module name.
|
1444
|
+
#
|
1445
|
+
# @return [Boolean] Whether the mixin is included
|
1446
|
+
# @return [nil] if the current tool is not active.
|
819
1447
|
#
|
820
1448
|
def include?(mod)
|
821
1449
|
cur_tool = DSL::Tool.current_tool(self, false)
|
@@ -826,19 +1454,39 @@ module Toys
|
|
826
1454
|
##
|
827
1455
|
# Return the current source info object.
|
828
1456
|
#
|
829
|
-
# @return [Toys::
|
1457
|
+
# @return [Toys::SourceInfo] Source info.
|
830
1458
|
#
|
831
1459
|
def source_info
|
832
1460
|
@__source.last
|
833
1461
|
end
|
834
1462
|
|
835
1463
|
##
|
836
|
-
# Find the given data path (file or directory)
|
1464
|
+
# Find the given data path (file or directory).
|
1465
|
+
#
|
1466
|
+
# Data directories are a convenient place to put images, archives, keys,
|
1467
|
+
# or other such static data needed by your tools. Data files are located
|
1468
|
+
# in a directory called `.data` inside a Toys directory. This directive
|
1469
|
+
# locates a data file during tool definition.
|
1470
|
+
#
|
1471
|
+
# ## Example
|
1472
|
+
#
|
1473
|
+
# This tool reads its description from a text file in the `.data`
|
1474
|
+
# directory.
|
1475
|
+
#
|
1476
|
+
# tool "mytool" do
|
1477
|
+
# path = find_data("mytool-desc.txt", type: :file)
|
1478
|
+
# desc IO.read(path) if path
|
1479
|
+
# def run
|
1480
|
+
# # ...
|
1481
|
+
# end
|
1482
|
+
# end
|
1483
|
+
#
|
1484
|
+
# @param path [String] The path to find
|
1485
|
+
# @param type [nil,:file,:directory] Type of file system object to find.
|
1486
|
+
# Default is `nil`, indicating any type.
|
837
1487
|
#
|
838
|
-
# @
|
839
|
-
# @
|
840
|
-
# or nil to return any type.
|
841
|
-
# @return [String,nil] Absolute path of the result, or nil if not found.
|
1488
|
+
# @return [String] Absolute path of the data.
|
1489
|
+
# @return [nil] if the given data path is not found.
|
842
1490
|
#
|
843
1491
|
def find_data(path, type: nil)
|
844
1492
|
source_info.find_data(path, type: type)
|
@@ -849,9 +1497,9 @@ module Toys
|
|
849
1497
|
# to the directory containing the toys config directory structure being
|
850
1498
|
# read, but it may be changed by setting a different context directory
|
851
1499
|
# for the tool.
|
852
|
-
# May return nil if there is no context.
|
853
1500
|
#
|
854
|
-
# @return [String
|
1501
|
+
# @return [String] Context directory path
|
1502
|
+
# @return [nil] if there is no context.
|
855
1503
|
#
|
856
1504
|
def context_directory
|
857
1505
|
DSL::Tool.current_tool(self, false)&.context_directory || source_info.context_directory
|
@@ -860,9 +1508,10 @@ module Toys
|
|
860
1508
|
##
|
861
1509
|
# Set a custom context directory for this tool.
|
862
1510
|
#
|
863
|
-
# @param [String]
|
1511
|
+
# @param dir [String] Context directory
|
1512
|
+
# @return [self]
|
864
1513
|
#
|
865
|
-
def set_context_directory(dir)
|
1514
|
+
def set_context_directory(dir) # rubocop:disable Naming/AccessorMethodName
|
866
1515
|
cur_tool = DSL::Tool.current_tool(self, false)
|
867
1516
|
return if cur_tool.nil?
|
868
1517
|
cur_tool.custom_context_directory = dir
|
@@ -871,7 +1520,7 @@ module Toys
|
|
871
1520
|
|
872
1521
|
## @private
|
873
1522
|
def self.new_class(words, priority, loader)
|
874
|
-
tool_class = ::Class.new(::Toys::
|
1523
|
+
tool_class = ::Class.new(::Toys::Context)
|
875
1524
|
tool_class.extend(DSL::Tool)
|
876
1525
|
tool_class.instance_variable_set(:@__words, words)
|
877
1526
|
tool_class.instance_variable_set(:@__priority, priority)
|
@@ -892,11 +1541,11 @@ module Toys
|
|
892
1541
|
priority = tool_class.instance_variable_get(:@__priority)
|
893
1542
|
cur_tool =
|
894
1543
|
if activate
|
895
|
-
loader.
|
1544
|
+
loader.activate_tool(words, priority)
|
896
1545
|
else
|
897
|
-
loader.
|
1546
|
+
loader.get_tool(words, priority)
|
898
1547
|
end
|
899
|
-
if cur_tool.is_a?(
|
1548
|
+
if cur_tool.is_a?(Alias)
|
900
1549
|
raise ToolDefinitionError,
|
901
1550
|
"Cannot configure #{words.join(' ').inspect} because it is an alias"
|
902
1551
|
end
|
@@ -920,10 +1569,12 @@ module Toys
|
|
920
1569
|
|
921
1570
|
## @private
|
922
1571
|
def self.maybe_add_getter(tool_class, key)
|
923
|
-
if key.is_a?(::Symbol) && key.to_s =~ /^[_a-zA-Z]\w*[!\?]?$/
|
924
|
-
tool_class.
|
925
|
-
|
926
|
-
|
1572
|
+
if key.is_a?(::Symbol) && key.to_s =~ /^[_a-zA-Z]\w*[!\?]?$/ && key != :run
|
1573
|
+
unless tool_class.public_method_defined?(key)
|
1574
|
+
tool_class.class_eval do
|
1575
|
+
define_method(key) do
|
1576
|
+
self[key]
|
1577
|
+
end
|
927
1578
|
end
|
928
1579
|
end
|
929
1580
|
end
|
@@ -933,7 +1584,7 @@ module Toys
|
|
933
1584
|
def self.resolve_mixin(mod, cur_tool, loader)
|
934
1585
|
name = mod.to_s
|
935
1586
|
if mod.is_a?(::String)
|
936
|
-
mod = cur_tool.
|
1587
|
+
mod = cur_tool.lookup_mixin(mod)
|
937
1588
|
elsif mod.is_a?(::Symbol)
|
938
1589
|
mod = loader.resolve_standard_mixin(name)
|
939
1590
|
end
|