toys-core 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|