toys-core 0.11.2 → 0.12.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 +46 -1
- data/README.md +1 -1
- data/lib/toys-core.rb +4 -1
- data/lib/toys/acceptor.rb +3 -3
- data/lib/toys/arg_parser.rb +6 -7
- data/lib/toys/cli.rb +44 -14
- data/lib/toys/compat.rb +19 -22
- data/lib/toys/completion.rb +3 -1
- data/lib/toys/context.rb +2 -2
- data/lib/toys/core.rb +1 -1
- data/lib/toys/dsl/base.rb +85 -0
- data/lib/toys/dsl/flag.rb +3 -3
- data/lib/toys/dsl/flag_group.rb +7 -7
- data/lib/toys/dsl/internal.rb +206 -0
- data/lib/toys/dsl/positional_arg.rb +3 -3
- data/lib/toys/dsl/tool.rb +174 -216
- data/lib/toys/errors.rb +1 -0
- data/lib/toys/flag.rb +15 -18
- data/lib/toys/flag_group.rb +5 -4
- data/lib/toys/input_file.rb +4 -4
- data/lib/toys/loader.rb +189 -50
- data/lib/toys/middleware.rb +1 -1
- data/lib/toys/mixin.rb +2 -2
- data/lib/toys/positional_arg.rb +3 -3
- data/lib/toys/settings.rb +900 -0
- data/lib/toys/source_info.rb +121 -18
- data/lib/toys/standard_middleware/apply_config.rb +5 -4
- data/lib/toys/standard_middleware/set_default_descriptions.rb +18 -18
- data/lib/toys/standard_middleware/show_help.rb +17 -5
- data/lib/toys/standard_mixins/bundler.rb +5 -1
- data/lib/toys/standard_mixins/exec.rb +22 -15
- data/lib/toys/standard_mixins/git_cache.rb +48 -0
- data/lib/toys/standard_mixins/xdg.rb +56 -0
- data/lib/toys/template.rb +2 -2
- data/lib/toys/{tool.rb → tool_definition.rb} +100 -41
- data/lib/toys/utils/exec.rb +37 -16
- data/lib/toys/utils/gems.rb +48 -14
- data/lib/toys/utils/git_cache.rb +184 -0
- data/lib/toys/utils/help_text.rb +90 -34
- data/lib/toys/utils/terminal.rb +1 -1
- data/lib/toys/utils/xdg.rb +293 -0
- metadata +15 -8
data/lib/toys/dsl/flag.rb
CHANGED
@@ -9,7 +9,7 @@ module Toys
|
|
9
9
|
# These directives are available inside a block passed to
|
10
10
|
# {Toys::DSL::Tool#flag}.
|
11
11
|
#
|
12
|
-
#
|
12
|
+
# ### Example
|
13
13
|
#
|
14
14
|
# tool "mytool" do
|
15
15
|
# flag :value do
|
@@ -212,7 +212,7 @@ module Toys
|
|
212
212
|
# across the strings in the array. In this case, whitespace is not
|
213
213
|
# compacted.
|
214
214
|
#
|
215
|
-
#
|
215
|
+
# ### Examples
|
216
216
|
#
|
217
217
|
# If you pass in a sentence as a simple string, it may be word wrapped
|
218
218
|
# when displayed:
|
@@ -243,7 +243,7 @@ module Toys
|
|
243
243
|
# word-wrapped when displayed. To insert a blank line, include an empty
|
244
244
|
# string as one of the descriptions.
|
245
245
|
#
|
246
|
-
#
|
246
|
+
# ### Example
|
247
247
|
#
|
248
248
|
# long_desc "This initial paragraph might get word wrapped.",
|
249
249
|
# "This next paragraph is followed by a blank line.",
|
data/lib/toys/dsl/flag_group.rb
CHANGED
@@ -10,7 +10,7 @@ module Toys
|
|
10
10
|
# {Toys::DSL::Tool#at_most_one}, {Toys::DSL::Tool#at_least_one}, or
|
11
11
|
# {Toys::DSL::Tool#exactly_one}.
|
12
12
|
#
|
13
|
-
#
|
13
|
+
# ### Example
|
14
14
|
#
|
15
15
|
# tool "login" do
|
16
16
|
# all_required do
|
@@ -43,7 +43,7 @@ module Toys
|
|
43
43
|
# set in a block passed to this method. If you provide a block, you can
|
44
44
|
# use directives in {Toys::DSL::Flag} within the block.
|
45
45
|
#
|
46
|
-
#
|
46
|
+
# ### Flag syntax
|
47
47
|
#
|
48
48
|
# The flags themselves should be provided in OptionParser form. Following
|
49
49
|
# are examples of valid syntax.
|
@@ -98,7 +98,7 @@ module Toys
|
|
98
98
|
# or off. This effectively creates two flags, `--abc` which sets the
|
99
99
|
# value to `true`, and `--no-abc` which sets the falue to `false`.
|
100
100
|
#
|
101
|
-
#
|
101
|
+
# ### Default flag syntax
|
102
102
|
#
|
103
103
|
# If no flag syntax strings are provided, a default syntax will be
|
104
104
|
# inferred based on the key and other options.
|
@@ -123,7 +123,7 @@ module Toys
|
|
123
123
|
# flag :number, accept: Integer
|
124
124
|
# flag :number, "--number=VAL", accept: Integer
|
125
125
|
#
|
126
|
-
#
|
126
|
+
# ### More examples
|
127
127
|
#
|
128
128
|
# A flag that sets its value to the number of times it appears on the
|
129
129
|
# command line:
|
@@ -200,7 +200,7 @@ module Toys
|
|
200
200
|
report_collisions, @flag_group, desc, long_desc, display_name)
|
201
201
|
flag_dsl.instance_exec(flag_dsl, &block) if block
|
202
202
|
flag_dsl._add_to(@tool, key)
|
203
|
-
DSL::
|
203
|
+
DSL::Internal.maybe_add_getter(@tool_dsl, key)
|
204
204
|
self
|
205
205
|
end
|
206
206
|
|
@@ -221,7 +221,7 @@ module Toys
|
|
221
221
|
# across the strings in the array. In this case, whitespace is not
|
222
222
|
# compacted.
|
223
223
|
#
|
224
|
-
#
|
224
|
+
# ### Examples
|
225
225
|
#
|
226
226
|
# If you pass in a sentence as a simple string, it may be word wrapped
|
227
227
|
# when displayed:
|
@@ -252,7 +252,7 @@ module Toys
|
|
252
252
|
# word-wrapped when displayed. To insert a blank line, include an empty
|
253
253
|
# string as one of the descriptions.
|
254
254
|
#
|
255
|
-
#
|
255
|
+
# ### Example
|
256
256
|
#
|
257
257
|
# long_desc "This initial paragraph might get word wrapped.",
|
258
258
|
# "This next paragraph is followed by a blank line.",
|
@@ -0,0 +1,206 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Toys
|
4
|
+
module DSL
|
5
|
+
##
|
6
|
+
# Internal utility calls used by the DSL.
|
7
|
+
#
|
8
|
+
# @private
|
9
|
+
#
|
10
|
+
module Internal
|
11
|
+
class << self
|
12
|
+
##
|
13
|
+
# Called by the Loader and InputFile to prepare a tool class for running
|
14
|
+
# the DSL.
|
15
|
+
#
|
16
|
+
# @private
|
17
|
+
#
|
18
|
+
def prepare(tool_class, words, priority, remaining_words, source, loader)
|
19
|
+
unless tool_class.is_a?(DSL::Tool)
|
20
|
+
class << tool_class
|
21
|
+
alias_method :super_include, :include
|
22
|
+
end
|
23
|
+
tool_class.extend(DSL::Tool)
|
24
|
+
end
|
25
|
+
unless tool_class.instance_variable_defined?(:@__words)
|
26
|
+
tool_class.instance_variable_set(:@__words, words)
|
27
|
+
tool_class.instance_variable_set(:@__priority, priority)
|
28
|
+
tool_class.instance_variable_set(:@__loader, loader)
|
29
|
+
tool_class.instance_variable_set(:@__source, [])
|
30
|
+
end
|
31
|
+
tool_class.instance_variable_set(:@__remaining_words, remaining_words)
|
32
|
+
tool_class.instance_variable_get(:@__source).push(source)
|
33
|
+
old_source = ::Thread.current[:__toys_current_source]
|
34
|
+
begin
|
35
|
+
::Thread.current[:__toys_current_source] = source
|
36
|
+
yield
|
37
|
+
ensure
|
38
|
+
tool_class.instance_variable_get(:@__source).pop
|
39
|
+
::Thread.current[:__toys_current_source] = old_source
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Called by the DSL implementation to get, and optionally activate, the
|
45
|
+
# current tool.
|
46
|
+
#
|
47
|
+
# @private
|
48
|
+
#
|
49
|
+
def current_tool(tool_class, activate)
|
50
|
+
memoize_var = activate ? :@__active_tool : :@__cur_tool
|
51
|
+
if tool_class.instance_variable_defined?(memoize_var)
|
52
|
+
tool_class.instance_variable_get(memoize_var)
|
53
|
+
else
|
54
|
+
loader = tool_class.instance_variable_get(:@__loader)
|
55
|
+
words = tool_class.instance_variable_get(:@__words)
|
56
|
+
priority = tool_class.instance_variable_get(:@__priority)
|
57
|
+
cur_tool =
|
58
|
+
if activate
|
59
|
+
loader.activate_tool(words, priority)
|
60
|
+
else
|
61
|
+
loader.get_tool(words, priority)
|
62
|
+
end
|
63
|
+
if cur_tool && activate
|
64
|
+
source = tool_class.instance_variable_get(:@__source).last
|
65
|
+
cur_tool.lock_source(source)
|
66
|
+
end
|
67
|
+
tool_class.instance_variable_set(memoize_var, cur_tool)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Called by the DSL implementation to add a getter to the tool class.
|
73
|
+
#
|
74
|
+
# @private
|
75
|
+
#
|
76
|
+
def maybe_add_getter(tool_class, key)
|
77
|
+
if key.is_a?(::Symbol) && key.to_s =~ /^[_a-zA-Z]\w*[!?]?$/ && key != :run
|
78
|
+
unless tool_class.public_method_defined?(key)
|
79
|
+
tool_class.class_eval do
|
80
|
+
define_method(key) do
|
81
|
+
self[key]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# Called by the DSL implementation to find a named mixin.
|
90
|
+
#
|
91
|
+
# @private
|
92
|
+
#
|
93
|
+
def resolve_mixin(mixin, cur_tool, loader)
|
94
|
+
mod =
|
95
|
+
case mixin
|
96
|
+
when ::String
|
97
|
+
cur_tool.lookup_mixin(mixin)
|
98
|
+
when ::Symbol
|
99
|
+
loader.resolve_standard_mixin(mixin.to_s)
|
100
|
+
when ::Module
|
101
|
+
mixin
|
102
|
+
end
|
103
|
+
raise ToolDefinitionError, "Mixin not found: #{mixin.inspect}" unless mod
|
104
|
+
mod
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Called by the DSL implementation to load a long description from a
|
109
|
+
# file.
|
110
|
+
#
|
111
|
+
# @private
|
112
|
+
#
|
113
|
+
def load_long_desc_file(path)
|
114
|
+
if ::File.extname(path) == ".txt"
|
115
|
+
begin
|
116
|
+
::File.readlines(path).map do |line|
|
117
|
+
line = line.chomp
|
118
|
+
line =~ /^\s/ ? [line] : line
|
119
|
+
end
|
120
|
+
rescue ::SystemCallError => e
|
121
|
+
raise Toys::ToolDefinitionError, e.to_s
|
122
|
+
end
|
123
|
+
else
|
124
|
+
raise Toys::ToolDefinitionError, "Cannot load long desc from file type: #{path}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Called by the Tool base class to set config values for a subclass.
|
130
|
+
#
|
131
|
+
# @private
|
132
|
+
#
|
133
|
+
def configure_class(tool_class, given_name = nil)
|
134
|
+
return if tool_class.name.nil? || tool_class.instance_variable_defined?(:@__loader)
|
135
|
+
|
136
|
+
mod_names = tool_class.name.split("::")
|
137
|
+
class_name = mod_names.pop
|
138
|
+
parent = parent_from_mod_name_segments(mod_names)
|
139
|
+
loader = parent.instance_variable_get(:@__loader)
|
140
|
+
name = given_name ? loader.split_path(given_name) : class_name_to_tool_name(class_name)
|
141
|
+
|
142
|
+
priority = parent.instance_variable_get(:@__priority)
|
143
|
+
words = parent.instance_variable_get(:@__words) + name
|
144
|
+
subtool = loader.get_tool(words, priority, tool_class)
|
145
|
+
|
146
|
+
remaining_words = parent.instance_variable_get(:@__remaining_words)
|
147
|
+
next_remaining = name.reduce(remaining_words) do |running_words, word|
|
148
|
+
Loader.next_remaining_words(running_words, word)
|
149
|
+
end
|
150
|
+
|
151
|
+
tool_class.instance_variable_set(:@__words, words)
|
152
|
+
tool_class.instance_variable_set(:@__priority, priority)
|
153
|
+
tool_class.instance_variable_set(:@__loader, loader)
|
154
|
+
tool_class.instance_variable_set(:@__source, [current_source_from_context])
|
155
|
+
tool_class.instance_variable_set(:@__remaining_words, next_remaining)
|
156
|
+
tool_class.instance_variable_set(:@__cur_tool, subtool)
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# Called by the Tool base class to add the DSL to a subclass.
|
161
|
+
#
|
162
|
+
# @private
|
163
|
+
#
|
164
|
+
def setup_class_dsl(tool_class)
|
165
|
+
return if tool_class.name.nil? || tool_class.is_a?(DSL::Tool)
|
166
|
+
class << tool_class
|
167
|
+
alias_method :super_include, :include
|
168
|
+
end
|
169
|
+
tool_class.extend(DSL::Tool)
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def class_name_to_tool_name(class_name)
|
175
|
+
name = class_name.to_s.sub(/^_+/, "").sub(/_+$/, "").gsub(/_+/, "-")
|
176
|
+
while name.sub!(/([^-])([A-Z])/, "\\1-\\2") do end
|
177
|
+
[name.downcase!]
|
178
|
+
end
|
179
|
+
|
180
|
+
def parent_from_mod_name_segments(mod_names)
|
181
|
+
parent = mod_names.reduce(::Object) do |running_mod, seg|
|
182
|
+
running_mod.const_get(seg)
|
183
|
+
end
|
184
|
+
if !parent.is_a?(::Toys::Tool) && parent.instance_variable_defined?(:@__tool_class)
|
185
|
+
parent = parent.instance_variable_get(:@__tool_class)
|
186
|
+
end
|
187
|
+
unless parent.ancestors.include?(::Toys::Context)
|
188
|
+
raise ToolDefinitionError, "Toys::Tool can be subclassed only from the Toys DSL"
|
189
|
+
end
|
190
|
+
parent
|
191
|
+
end
|
192
|
+
|
193
|
+
def current_source_from_context
|
194
|
+
source = ::Thread.current[:__toys_current_source]
|
195
|
+
if source.nil?
|
196
|
+
raise ToolDefinitionError, "Toys::Tool can be subclassed only from a Toys config file"
|
197
|
+
end
|
198
|
+
unless source.source_type == :file
|
199
|
+
raise ToolDefinitionError, "Toys::Tool cannot be subclassed inside a tool block"
|
200
|
+
end
|
201
|
+
source
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
@@ -10,7 +10,7 @@ module Toys
|
|
10
10
|
# {Toys::DSL::Tool#required_arg}, {Toys::DSL::Tool#optional_arg}, or
|
11
11
|
# {Toys::DSL::Tool#remaining_args}.
|
12
12
|
#
|
13
|
-
#
|
13
|
+
# ### Example
|
14
14
|
#
|
15
15
|
# tool "mytool" do
|
16
16
|
# optional_arg :value do
|
@@ -103,7 +103,7 @@ module Toys
|
|
103
103
|
# across the strings in the array. In this case, whitespace is not
|
104
104
|
# compacted.
|
105
105
|
#
|
106
|
-
#
|
106
|
+
# ### Examples
|
107
107
|
#
|
108
108
|
# If you pass in a sentence as a simple string, it may be word wrapped
|
109
109
|
# when displayed:
|
@@ -134,7 +134,7 @@ module Toys
|
|
134
134
|
# word-wrapped when displayed. To insert a blank line, include an empty
|
135
135
|
# string as one of the descriptions.
|
136
136
|
#
|
137
|
-
#
|
137
|
+
# ### Example
|
138
138
|
#
|
139
139
|
# long_desc "This initial paragraph might get word wrapped.",
|
140
140
|
# "This next paragraph is followed by a blank line.",
|
data/lib/toys/dsl/tool.rb
CHANGED
@@ -10,7 +10,7 @@ module Toys
|
|
10
10
|
# how to execute the tool, and requesting mixin modules and other services.
|
11
11
|
# It also lets you define subtools, nested arbitrarily deep, using blocks.
|
12
12
|
#
|
13
|
-
#
|
13
|
+
# ### Simple example
|
14
14
|
#
|
15
15
|
# Create a file called `.toys.rb` in the current directory, with the
|
16
16
|
# following contents:
|
@@ -36,7 +36,8 @@ module Toys
|
|
36
36
|
module Tool
|
37
37
|
## @private
|
38
38
|
def method_added(_meth)
|
39
|
-
|
39
|
+
super
|
40
|
+
DSL::Internal.current_tool(self, true)&.check_definition_state(is_method: true)
|
40
41
|
end
|
41
42
|
|
42
43
|
##
|
@@ -83,7 +84,7 @@ module Toys
|
|
83
84
|
# an exception (descended from `StandardError`) to indicate that the
|
84
85
|
# string parameter is invalid.
|
85
86
|
#
|
86
|
-
#
|
87
|
+
# ### Example
|
87
88
|
#
|
88
89
|
# The following example creates an acceptor named "hex" that is defined
|
89
90
|
# via a regular expression. It then uses it to validate values passed to
|
@@ -105,7 +106,7 @@ module Toys
|
|
105
106
|
# @return [self]
|
106
107
|
#
|
107
108
|
def acceptor(name, spec = nil, type_desc: nil, &block)
|
108
|
-
cur_tool = DSL::
|
109
|
+
cur_tool = DSL::Internal.current_tool(self, false)
|
109
110
|
cur_tool&.add_acceptor(name, spec, type_desc: type_desc || name.to_s, &block)
|
110
111
|
self
|
111
112
|
end
|
@@ -122,7 +123,7 @@ module Toys
|
|
122
123
|
# block. Alternatively, you can create a module separately and pass it
|
123
124
|
# directly to this directive.
|
124
125
|
#
|
125
|
-
#
|
126
|
+
# ### Example
|
126
127
|
#
|
127
128
|
# The following example creates a named mixin and uses it in a tool.
|
128
129
|
#
|
@@ -149,7 +150,7 @@ module Toys
|
|
149
150
|
# @return [self]
|
150
151
|
#
|
151
152
|
def mixin(name, mixin_module = nil, &block)
|
152
|
-
cur_tool = DSL::
|
153
|
+
cur_tool = DSL::Internal.current_tool(self, false)
|
153
154
|
cur_tool&.add_mixin(name, mixin_module, &block)
|
154
155
|
self
|
155
156
|
end
|
@@ -175,7 +176,7 @@ module Toys
|
|
175
176
|
# directly. See {Toys::Template} for details on creating a template
|
176
177
|
# class.
|
177
178
|
#
|
178
|
-
#
|
179
|
+
# ### Example
|
179
180
|
#
|
180
181
|
# The following example creates and uses a simple template.
|
181
182
|
#
|
@@ -204,7 +205,7 @@ module Toys
|
|
204
205
|
# @return [self]
|
205
206
|
#
|
206
207
|
def template(name, template_class = nil, &block)
|
207
|
-
cur_tool = DSL::
|
208
|
+
cur_tool = DSL::Internal.current_tool(self, false)
|
208
209
|
return self if cur_tool.nil?
|
209
210
|
cur_tool.add_template(name, template_class, &block)
|
210
211
|
self
|
@@ -228,7 +229,7 @@ module Toys
|
|
228
229
|
# * The symbol `:file_system` which indicates that paths in the file
|
229
230
|
# system should serve as completion candidates.
|
230
231
|
#
|
231
|
-
#
|
232
|
+
# ### Example
|
232
233
|
#
|
233
234
|
# The following example defines a completion that uses only the immediate
|
234
235
|
# files in the current directory as candidates. (This is different from
|
@@ -252,7 +253,7 @@ module Toys
|
|
252
253
|
# @return [self]
|
253
254
|
#
|
254
255
|
def completion(name, spec = nil, **options, &block)
|
255
|
-
cur_tool = DSL::
|
256
|
+
cur_tool = DSL::Internal.current_tool(self, false)
|
256
257
|
return self if cur_tool.nil?
|
257
258
|
cur_tool.add_completion(name, spec, **options, &block)
|
258
259
|
self
|
@@ -261,7 +262,7 @@ module Toys
|
|
261
262
|
##
|
262
263
|
# Create a subtool. You must provide a block defining the subtool.
|
263
264
|
#
|
264
|
-
#
|
265
|
+
# ### Example
|
265
266
|
#
|
266
267
|
# The following example defines a tool and two subtools within it.
|
267
268
|
#
|
@@ -280,7 +281,7 @@ module Toys
|
|
280
281
|
#
|
281
282
|
# The following example defines a tool that runs one of its subtools.
|
282
283
|
#
|
283
|
-
# tool "test",
|
284
|
+
# tool "test", delegate_to: ["test", "unit"] do
|
284
285
|
# tool "unit" do
|
285
286
|
# def run
|
286
287
|
# puts "Running unit tests"
|
@@ -316,7 +317,7 @@ module Toys
|
|
316
317
|
when :ignore
|
317
318
|
return self
|
318
319
|
when :reset
|
319
|
-
subtool.reset_definition
|
320
|
+
subtool.reset_definition
|
320
321
|
end
|
321
322
|
end
|
322
323
|
if delegate_to
|
@@ -328,7 +329,6 @@ module Toys
|
|
328
329
|
end
|
329
330
|
self
|
330
331
|
end
|
331
|
-
alias name tool
|
332
332
|
|
333
333
|
##
|
334
334
|
# Create an alias, representing an "alternate name" for a tool.
|
@@ -337,7 +337,7 @@ module Toys
|
|
337
337
|
# `delegate_to` option, except that `alias_tool` takes a _relative_ name
|
338
338
|
# for the delegate.
|
339
339
|
#
|
340
|
-
#
|
340
|
+
# ### Example
|
341
341
|
#
|
342
342
|
# This example defines a tool and an alias pointing to it. Both the tool
|
343
343
|
# name `test` and the alias `t` will then refer to the same tool.
|
@@ -364,7 +364,7 @@ module Toys
|
|
364
364
|
# Causes the current tool to delegate to another tool. When run, it
|
365
365
|
# simply invokes the target tool with the same arguments.
|
366
366
|
#
|
367
|
-
#
|
367
|
+
# ### Example
|
368
368
|
#
|
369
369
|
# This example defines a tool that runs one of its subtools. Running the
|
370
370
|
# `test` tool will have the same effect (and recognize the same args) as
|
@@ -386,7 +386,7 @@ module Toys
|
|
386
386
|
# @return [self]
|
387
387
|
#
|
388
388
|
def delegate_to(target)
|
389
|
-
cur_tool = DSL::
|
389
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
390
390
|
return self if cur_tool.nil?
|
391
391
|
cur_tool.delegate_to(@__loader.split_path(target))
|
392
392
|
self
|
@@ -397,20 +397,64 @@ module Toys
|
|
397
397
|
# at the current location.
|
398
398
|
#
|
399
399
|
# @param path [String] The file or directory to load.
|
400
|
+
# @param as [String] Load into the given tool/namespace. If omitted,
|
401
|
+
# configuration will be loaded into the current namespace.
|
402
|
+
#
|
400
403
|
# @return [self]
|
401
404
|
#
|
402
|
-
def load(path)
|
405
|
+
def load(path, as: nil)
|
406
|
+
if as
|
407
|
+
tool(as) do
|
408
|
+
load(path)
|
409
|
+
end
|
410
|
+
return self
|
411
|
+
end
|
403
412
|
@__loader.load_path(source_info, path, @__words, @__remaining_words, @__priority)
|
404
413
|
self
|
405
414
|
end
|
406
415
|
|
416
|
+
##
|
417
|
+
# Load configuration from a public git repository, as if its contents
|
418
|
+
# were inserted at the current location.
|
419
|
+
#
|
420
|
+
# @param remote [String] The URL of the git repository. Defaults to the
|
421
|
+
# current repository if already loading from git.
|
422
|
+
# @param path [String] The path within the repo to the file or directory
|
423
|
+
# to load. Defaults to the root of the repo.
|
424
|
+
# @param commit [String] The commit branch, tag, or sha. Defaults to the
|
425
|
+
# current commit if already loading from git, or to `HEAD`.
|
426
|
+
# @param as [String] Load into the given tool/namespace. If omitted,
|
427
|
+
# configuration will be loaded into the current namespace.
|
428
|
+
# @param update [Boolean] Force-fetch from the remote (unless the commit
|
429
|
+
# is a SHA). This will ensure that symbolic commits, such as branch
|
430
|
+
# names, are up to date. Default is false.
|
431
|
+
#
|
432
|
+
# @return [self]
|
433
|
+
#
|
434
|
+
def load_git(remote: nil, path: nil, commit: nil, as: nil, update: false)
|
435
|
+
if as
|
436
|
+
tool(as) do
|
437
|
+
load_git(remote: remote, path: path, commit: commit)
|
438
|
+
end
|
439
|
+
return self
|
440
|
+
end
|
441
|
+
remote ||= source_info.git_remote
|
442
|
+
raise ToolDefinitionError, "Git remote not specified" unless remote
|
443
|
+
path ||= ""
|
444
|
+
commit ||= source_info.git_commit || "HEAD"
|
445
|
+
@__loader.load_git(source_info, remote, path, commit,
|
446
|
+
@__words, @__remaining_words, @__priority,
|
447
|
+
update: update)
|
448
|
+
self
|
449
|
+
end
|
450
|
+
|
407
451
|
##
|
408
452
|
# Expand the given template in the current location.
|
409
453
|
#
|
410
454
|
# The template may be specified as a class or a well-known template name.
|
411
455
|
# You may also provide arguments to pass to the template.
|
412
456
|
#
|
413
|
-
#
|
457
|
+
# ### Example
|
414
458
|
#
|
415
459
|
# The following example creates and uses a simple template.
|
416
460
|
#
|
@@ -437,12 +481,13 @@ module Toys
|
|
437
481
|
# @return [self]
|
438
482
|
#
|
439
483
|
def expand(template_class, *args, **kwargs)
|
440
|
-
cur_tool = DSL::
|
484
|
+
cur_tool = DSL::Internal.current_tool(self, false)
|
441
485
|
return self if cur_tool.nil?
|
442
486
|
name = template_class.to_s
|
443
|
-
|
487
|
+
case template_class
|
488
|
+
when ::String
|
444
489
|
template_class = cur_tool.lookup_template(template_class)
|
445
|
-
|
490
|
+
when ::Symbol
|
446
491
|
template_class = @__loader.resolve_standard_template(name)
|
447
492
|
end
|
448
493
|
if template_class.nil?
|
@@ -472,7 +517,7 @@ module Toys
|
|
472
517
|
# across the strings in the array. In this case, whitespace is not
|
473
518
|
# compacted.
|
474
519
|
#
|
475
|
-
#
|
520
|
+
# ### Examples
|
476
521
|
#
|
477
522
|
# If you pass in a sentence as a simple string, it may be word wrapped
|
478
523
|
# when displayed:
|
@@ -488,7 +533,7 @@ module Toys
|
|
488
533
|
# @return [self]
|
489
534
|
#
|
490
535
|
def desc(str)
|
491
|
-
cur_tool = DSL::
|
536
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
492
537
|
return self if cur_tool.nil?
|
493
538
|
cur_tool.desc = str
|
494
539
|
self
|
@@ -506,7 +551,7 @@ module Toys
|
|
506
551
|
# word-wrapped when displayed. To insert a blank line, include an empty
|
507
552
|
# string as one of the descriptions.
|
508
553
|
#
|
509
|
-
#
|
554
|
+
# ### Example
|
510
555
|
#
|
511
556
|
# long_desc "This initial paragraph might get word wrapped.",
|
512
557
|
# "This next paragraph is followed by a blank line.",
|
@@ -524,7 +569,7 @@ module Toys
|
|
524
569
|
# @return [self]
|
525
570
|
#
|
526
571
|
def long_desc(*strs, file: nil, data: nil)
|
527
|
-
cur_tool = DSL::
|
572
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
528
573
|
return self if cur_tool.nil?
|
529
574
|
if file
|
530
575
|
unless source_info.source_path
|
@@ -535,7 +580,7 @@ module Toys
|
|
535
580
|
elsif data
|
536
581
|
file = source_info.find_data(data, type: :file)
|
537
582
|
end
|
538
|
-
strs += DSL::
|
583
|
+
strs += DSL::Internal.load_long_desc_file(file) if file
|
539
584
|
cur_tool.append_long_desc(strs)
|
540
585
|
self
|
541
586
|
end
|
@@ -545,7 +590,7 @@ module Toys
|
|
545
590
|
# belong to the group. The flags in the group are listed together in
|
546
591
|
# help screens.
|
547
592
|
#
|
548
|
-
#
|
593
|
+
# ### Example
|
549
594
|
#
|
550
595
|
# The following example creates a flag group in which all flags are
|
551
596
|
# optional.
|
@@ -562,11 +607,11 @@ module Toys
|
|
562
607
|
# `:optional`, `:exactly_one`, `:at_most_one`, `:at_least_one`.
|
563
608
|
# Default is `:optional`.
|
564
609
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
565
|
-
# description for the group. See {Toys::Tool#desc
|
566
|
-
# of allowed formats. Defaults to `"Flags"`.
|
610
|
+
# description for the group. See {Toys::DSL::Tool#desc} for a
|
611
|
+
# description of allowed formats. Defaults to `"Flags"`.
|
567
612
|
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
568
613
|
# Long description for the flag group. See
|
569
|
-
# {Toys::Tool#long_desc
|
614
|
+
# {Toys::DSL::Tool#long_desc} for a description of allowed formats.
|
570
615
|
# Defaults to the empty array.
|
571
616
|
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
572
617
|
# name.
|
@@ -581,7 +626,7 @@ module Toys
|
|
581
626
|
#
|
582
627
|
def flag_group(type: :optional, desc: nil, long_desc: nil, name: nil,
|
583
628
|
report_collisions: true, prepend: false, &block)
|
584
|
-
cur_tool = DSL::
|
629
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
585
630
|
return self if cur_tool.nil?
|
586
631
|
cur_tool.add_flag_group(type: type, desc: desc, long_desc: long_desc, name: name,
|
587
632
|
report_collisions: report_collisions, prepend: prepend)
|
@@ -596,7 +641,7 @@ module Toys
|
|
596
641
|
# defined in the block belong to the group. All flags in this group are
|
597
642
|
# required.
|
598
643
|
#
|
599
|
-
#
|
644
|
+
# ### Example
|
600
645
|
#
|
601
646
|
# The following example creates a group of required flags.
|
602
647
|
#
|
@@ -609,11 +654,11 @@ module Toys
|
|
609
654
|
# end
|
610
655
|
#
|
611
656
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
612
|
-
# description for the group. See {Toys::Tool#desc
|
613
|
-
# of allowed formats. Defaults to `"Flags"`.
|
657
|
+
# description for the group. See {Toys::DSL::Tool#desc} for a
|
658
|
+
# description of allowed formats. Defaults to `"Flags"`.
|
614
659
|
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
615
660
|
# Long description for the flag group. See
|
616
|
-
# {Toys::Tool#long_desc
|
661
|
+
# {Toys::DSL::Tool#long_desc} for a description of allowed formats.
|
617
662
|
# Defaults to the empty array.
|
618
663
|
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
619
664
|
# name.
|
@@ -637,7 +682,7 @@ module Toys
|
|
637
682
|
# defined in the block belong to the group. At most one flag in this
|
638
683
|
# group must be provided on the command line.
|
639
684
|
#
|
640
|
-
#
|
685
|
+
# ### Example
|
641
686
|
#
|
642
687
|
# The following example creates a group of flags in which either one or
|
643
688
|
# none may be set, but not more than one.
|
@@ -652,11 +697,11 @@ module Toys
|
|
652
697
|
# end
|
653
698
|
#
|
654
699
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
655
|
-
# description for the group. See {Toys::Tool#desc
|
656
|
-
# of allowed formats. Defaults to `"Flags"`.
|
700
|
+
# description for the group. See {Toys::DSL::Tool#desc} for a
|
701
|
+
# description of allowed formats. Defaults to `"Flags"`.
|
657
702
|
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
658
703
|
# Long description for the flag group. See
|
659
|
-
# {Toys::Tool#long_desc
|
704
|
+
# {Toys::DSL::Tool#long_desc} for a description of allowed formats.
|
660
705
|
# Defaults to the empty array.
|
661
706
|
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
662
707
|
# name.
|
@@ -681,7 +726,7 @@ module Toys
|
|
681
726
|
# defined in the block belong to the group. At least one flag in this
|
682
727
|
# group must be provided on the command line.
|
683
728
|
#
|
684
|
-
#
|
729
|
+
# ### Example
|
685
730
|
#
|
686
731
|
# The following example creates a group of flags in which one or more
|
687
732
|
# may be set.
|
@@ -696,11 +741,11 @@ module Toys
|
|
696
741
|
# end
|
697
742
|
#
|
698
743
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
699
|
-
# description for the group. See {Toys::Tool#desc
|
700
|
-
# of allowed formats. Defaults to `"Flags"`.
|
744
|
+
# description for the group. See {Toys::DSL::Tool#desc} for a
|
745
|
+
# description of allowed formats. Defaults to `"Flags"`.
|
701
746
|
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
702
747
|
# Long description for the flag group. See
|
703
|
-
# {Toys::Tool#long_desc
|
748
|
+
# {Toys::DSL::Tool#long_desc} for a description of allowed formats.
|
704
749
|
# Defaults to the empty array.
|
705
750
|
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
706
751
|
# name.
|
@@ -725,7 +770,7 @@ module Toys
|
|
725
770
|
# defined in the block belong to the group. Exactly one flag in this
|
726
771
|
# group must be provided on the command line.
|
727
772
|
#
|
728
|
-
#
|
773
|
+
# ### Example
|
729
774
|
#
|
730
775
|
# The following example creates a group of flags in which exactly one
|
731
776
|
# must be set.
|
@@ -740,11 +785,11 @@ module Toys
|
|
740
785
|
# end
|
741
786
|
#
|
742
787
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
743
|
-
# description for the group. See {Toys::Tool#desc
|
744
|
-
# of allowed formats. Defaults to `"Flags"`.
|
788
|
+
# description for the group. See {Toys::DSL::Tool#desc} for a
|
789
|
+
# description of allowed formats. Defaults to `"Flags"`.
|
745
790
|
# @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
|
746
791
|
# Long description for the flag group. See
|
747
|
-
# {Toys::Tool#long_desc
|
792
|
+
# {Toys::DSL::Tool#long_desc} for a description of allowed formats.
|
748
793
|
# Defaults to the empty array.
|
749
794
|
# @param name [String,Symbol,nil] The name of the group, or nil for no
|
750
795
|
# name.
|
@@ -778,7 +823,7 @@ module Toys
|
|
778
823
|
# set in a block passed to this method. If you provide a block, you can
|
779
824
|
# use directives in {Toys::DSL::Flag} within the block.
|
780
825
|
#
|
781
|
-
#
|
826
|
+
# ### Flag syntax
|
782
827
|
#
|
783
828
|
# The flags themselves should be provided in OptionParser form. Following
|
784
829
|
# are examples of valid syntax.
|
@@ -833,7 +878,7 @@ module Toys
|
|
833
878
|
# or off. This effectively creates two flags, `--abc` which sets the
|
834
879
|
# value to `true`, and `--no-abc` which sets the falue to `false`.
|
835
880
|
#
|
836
|
-
#
|
881
|
+
# ### Default flag syntax
|
837
882
|
#
|
838
883
|
# If no flag syntax strings are provided, a default syntax will be
|
839
884
|
# inferred based on the key and other options.
|
@@ -858,7 +903,7 @@ module Toys
|
|
858
903
|
# flag :number, accept: Integer
|
859
904
|
# flag :number, "--number=VAL", accept: Integer
|
860
905
|
#
|
861
|
-
#
|
906
|
+
# ### More examples
|
862
907
|
#
|
863
908
|
# A flag that sets its value to the number of times it appears on the
|
864
909
|
# command line:
|
@@ -937,7 +982,7 @@ module Toys
|
|
937
982
|
report_collisions: true, group: nil,
|
938
983
|
desc: nil, long_desc: nil, display_name: nil,
|
939
984
|
&block)
|
940
|
-
cur_tool = DSL::
|
985
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
941
986
|
return self if cur_tool.nil?
|
942
987
|
flag_dsl = DSL::Flag.new(
|
943
988
|
flags.flatten, accept, default, handler, complete_flags, complete_values,
|
@@ -945,14 +990,14 @@ module Toys
|
|
945
990
|
)
|
946
991
|
flag_dsl.instance_exec(flag_dsl, &block) if block
|
947
992
|
flag_dsl._add_to(cur_tool, key)
|
948
|
-
DSL::
|
993
|
+
DSL::Internal.maybe_add_getter(self, key)
|
949
994
|
self
|
950
995
|
end
|
951
996
|
|
952
997
|
##
|
953
|
-
# Add a required positional argument to the current tool. You must
|
954
|
-
# a key which the script may use to obtain the argument value
|
955
|
-
# context.
|
998
|
+
# Add a required positional argument to the current tool. You must
|
999
|
+
# specify a key which the script may use to obtain the argument value
|
1000
|
+
# from the context.
|
956
1001
|
#
|
957
1002
|
# If the given key is a symbol representing a valid method name, then a
|
958
1003
|
# helper method is automatically added to retrieve the value. Otherwise,
|
@@ -963,7 +1008,7 @@ module Toys
|
|
963
1008
|
# set in a block passed to this method. If you provide a block, you can
|
964
1009
|
# use directives in {Toys::DSL::PositionalArg} within the block.
|
965
1010
|
#
|
966
|
-
#
|
1011
|
+
# ### Example
|
967
1012
|
#
|
968
1013
|
# This tool "moves" something from a source to destination, and takes two
|
969
1014
|
# required arguments:
|
@@ -987,8 +1032,8 @@ module Toys
|
|
987
1032
|
# values of this arg. This is the empty completion by default. To
|
988
1033
|
# customize completion, set this to the name of a previously defined
|
989
1034
|
# completion, or any spec recognized by {Toys::Completion.create}.
|
990
|
-
# @param display_name [String] A name to use for display (in help text
|
991
|
-
# error reports). Defaults to the key in upper case.
|
1035
|
+
# @param display_name [String] A name to use for display (in help text
|
1036
|
+
# and error reports). Defaults to the key in upper case.
|
992
1037
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
993
1038
|
# description for the flag. See {Toys::DSL::Tool#desc} for a
|
994
1039
|
# description of the allowed formats. Defaults to the empty string.
|
@@ -1006,21 +1051,21 @@ module Toys
|
|
1006
1051
|
accept: nil, complete: nil, display_name: nil,
|
1007
1052
|
desc: nil, long_desc: nil,
|
1008
1053
|
&block)
|
1009
|
-
cur_tool = DSL::
|
1054
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1010
1055
|
return self if cur_tool.nil?
|
1011
1056
|
arg_dsl = DSL::PositionalArg.new(accept, nil, complete, display_name, desc, long_desc)
|
1012
1057
|
arg_dsl.instance_exec(arg_dsl, &block) if block
|
1013
1058
|
arg_dsl._add_required_to(cur_tool, key)
|
1014
|
-
DSL::
|
1059
|
+
DSL::Internal.maybe_add_getter(self, key)
|
1015
1060
|
self
|
1016
1061
|
end
|
1017
1062
|
alias required required_arg
|
1018
1063
|
|
1019
1064
|
##
|
1020
|
-
# Add an optional positional argument to the current tool. You must
|
1021
|
-
# a key which the script may use to obtain the argument value
|
1022
|
-
# context. If an optional argument is not given on the command
|
1023
|
-
# value is set to the given default.
|
1065
|
+
# Add an optional positional argument to the current tool. You must
|
1066
|
+
# specify a key which the script may use to obtain the argument value
|
1067
|
+
# from the context. If an optional argument is not given on the command
|
1068
|
+
# line, the value is set to the given default.
|
1024
1069
|
#
|
1025
1070
|
# If the given key is a symbol representing a valid method name, then a
|
1026
1071
|
# helper method is automatically added to retrieve the value. Otherwise,
|
@@ -1031,7 +1076,7 @@ module Toys
|
|
1031
1076
|
# set in a block passed to this method. If you provide a block, you can
|
1032
1077
|
# use directives in {Toys::DSL::PositionalArg} within the block.
|
1033
1078
|
#
|
1034
|
-
#
|
1079
|
+
# ### Example
|
1035
1080
|
#
|
1036
1081
|
# This tool creates a "link" to a given target. The link location is
|
1037
1082
|
# optional; if it is not given, it is inferred from the target.
|
@@ -1048,8 +1093,8 @@ module Toys
|
|
1048
1093
|
# @param key [String,Symbol] The key to use to retrieve the value from
|
1049
1094
|
# the execution context.
|
1050
1095
|
# @param default [Object] The default value. This is the value that will
|
1051
|
-
# be set in the context if this argument is not provided on the
|
1052
|
-
# line. Defaults to `nil`.
|
1096
|
+
# be set in the context if this argument is not provided on the
|
1097
|
+
# command line. Defaults to `nil`.
|
1053
1098
|
# @param accept [Object] An acceptor that validates and/or converts the
|
1054
1099
|
# value. You may provide either the name of an acceptor you have
|
1055
1100
|
# defined, one of the default acceptors provided by OptionParser, or
|
@@ -1059,8 +1104,8 @@ module Toys
|
|
1059
1104
|
# values of this arg. This is the empty completion by default. To
|
1060
1105
|
# customize completion, set this to the name of a previously defined
|
1061
1106
|
# completion, or any spec recognized by {Toys::Completion.create}.
|
1062
|
-
# @param display_name [String] A name to use for display (in help text
|
1063
|
-
# error reports). Defaults to the key in upper case.
|
1107
|
+
# @param display_name [String] A name to use for display (in help text
|
1108
|
+
# and error reports). Defaults to the key in upper case.
|
1064
1109
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
1065
1110
|
# description for the flag. See {Toys::DSL::Tool#desc} for a
|
1066
1111
|
# description of the allowed formats. Defaults to the empty string.
|
@@ -1078,20 +1123,20 @@ module Toys
|
|
1078
1123
|
default: nil, accept: nil, complete: nil, display_name: nil,
|
1079
1124
|
desc: nil, long_desc: nil,
|
1080
1125
|
&block)
|
1081
|
-
cur_tool = DSL::
|
1126
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1082
1127
|
return self if cur_tool.nil?
|
1083
1128
|
arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name, desc, long_desc)
|
1084
1129
|
arg_dsl.instance_exec(arg_dsl, &block) if block
|
1085
1130
|
arg_dsl._add_optional_to(cur_tool, key)
|
1086
|
-
DSL::
|
1131
|
+
DSL::Internal.maybe_add_getter(self, key)
|
1087
1132
|
self
|
1088
1133
|
end
|
1089
1134
|
alias optional optional_arg
|
1090
1135
|
|
1091
1136
|
##
|
1092
|
-
# Specify what should be done with unmatched positional arguments. You
|
1093
|
-
# specify a key which the script may use to obtain the remaining
|
1094
|
-
# the context.
|
1137
|
+
# Specify what should be done with unmatched positional arguments. You
|
1138
|
+
# must specify a key which the script may use to obtain the remaining
|
1139
|
+
# args from the context.
|
1095
1140
|
#
|
1096
1141
|
# If the given key is a symbol representing a valid method name, then a
|
1097
1142
|
# helper method is automatically added to retrieve the value. Otherwise,
|
@@ -1102,7 +1147,7 @@ module Toys
|
|
1102
1147
|
# set in a block passed to this method. If you provide a block, you can
|
1103
1148
|
# use directives in {Toys::DSL::PositionalArg} within the block.
|
1104
1149
|
#
|
1105
|
-
#
|
1150
|
+
# ### Example
|
1106
1151
|
#
|
1107
1152
|
# This tool displays a "list" of the given directories. If no directories
|
1108
1153
|
# ar given, lists the current directory.
|
@@ -1131,8 +1176,8 @@ module Toys
|
|
1131
1176
|
# values of this arg. This is the empty completion by default. To
|
1132
1177
|
# customize completion, set this to the name of a previously defined
|
1133
1178
|
# completion, or any spec recognized by {Toys::Completion.create}.
|
1134
|
-
# @param display_name [String] A name to use for display (in help text
|
1135
|
-
# error reports). Defaults to the key in upper case.
|
1179
|
+
# @param display_name [String] A name to use for display (in help text
|
1180
|
+
# and error reports). Defaults to the key in upper case.
|
1136
1181
|
# @param desc [String,Array<String>,Toys::WrappableString] Short
|
1137
1182
|
# description for the flag. See {Toys::DSL::Tool#desc} for a
|
1138
1183
|
# description of the allowed formats. Defaults to the empty string.
|
@@ -1150,12 +1195,12 @@ module Toys
|
|
1150
1195
|
default: [], accept: nil, complete: nil, display_name: nil,
|
1151
1196
|
desc: nil, long_desc: nil,
|
1152
1197
|
&block)
|
1153
|
-
cur_tool = DSL::
|
1198
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1154
1199
|
return self if cur_tool.nil?
|
1155
1200
|
arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name, desc, long_desc)
|
1156
1201
|
arg_dsl.instance_exec(arg_dsl, &block) if block
|
1157
1202
|
arg_dsl._set_remaining_on(cur_tool, key)
|
1158
|
-
DSL::
|
1203
|
+
DSL::Internal.maybe_add_getter(self, key)
|
1159
1204
|
self
|
1160
1205
|
end
|
1161
1206
|
alias remaining remaining_args
|
@@ -1168,7 +1213,7 @@ module Toys
|
|
1168
1213
|
# if the key is a string or does not represent a valid method name, the
|
1169
1214
|
# tool can retrieve the value by calling {Toys::Context#get}.
|
1170
1215
|
#
|
1171
|
-
#
|
1216
|
+
# ### Example
|
1172
1217
|
#
|
1173
1218
|
# tool "hello" do
|
1174
1219
|
# static :greeting, "Hi there"
|
@@ -1190,16 +1235,16 @@ module Toys
|
|
1190
1235
|
# @return [self]
|
1191
1236
|
#
|
1192
1237
|
def static(key, value = nil)
|
1193
|
-
cur_tool = DSL::
|
1238
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1194
1239
|
return self if cur_tool.nil?
|
1195
1240
|
if key.is_a?(::Hash)
|
1196
1241
|
cur_tool.default_data.merge!(key)
|
1197
1242
|
key.each_key do |k|
|
1198
|
-
DSL::
|
1243
|
+
DSL::Internal.maybe_add_getter(self, k)
|
1199
1244
|
end
|
1200
1245
|
else
|
1201
1246
|
cur_tool.default_data[key] = value
|
1202
|
-
DSL::
|
1247
|
+
DSL::Internal.maybe_add_getter(self, key)
|
1203
1248
|
end
|
1204
1249
|
self
|
1205
1250
|
end
|
@@ -1207,7 +1252,7 @@ module Toys
|
|
1207
1252
|
##
|
1208
1253
|
# Set a option values statically without creating helper methods.
|
1209
1254
|
#
|
1210
|
-
#
|
1255
|
+
# ### Example
|
1211
1256
|
#
|
1212
1257
|
# tool "hello" do
|
1213
1258
|
# set :greeting, "Hi there"
|
@@ -1229,7 +1274,7 @@ module Toys
|
|
1229
1274
|
# @return [self]
|
1230
1275
|
#
|
1231
1276
|
def set(key, value = nil)
|
1232
|
-
cur_tool = DSL::
|
1277
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1233
1278
|
return self if cur_tool.nil?
|
1234
1279
|
if key.is_a?(::Hash)
|
1235
1280
|
cur_tool.default_data.merge!(key)
|
@@ -1251,7 +1296,7 @@ module Toys
|
|
1251
1296
|
# @return [self]
|
1252
1297
|
#
|
1253
1298
|
def enforce_flags_before_args(state = true)
|
1254
|
-
DSL::
|
1299
|
+
DSL::Internal.current_tool(self, true)&.enforce_flags_before_args(state)
|
1255
1300
|
self
|
1256
1301
|
end
|
1257
1302
|
|
@@ -1267,7 +1312,7 @@ module Toys
|
|
1267
1312
|
# @return [self]
|
1268
1313
|
#
|
1269
1314
|
def require_exact_flag_match(state = true)
|
1270
|
-
DSL::
|
1315
|
+
DSL::Internal.current_tool(self, true)&.require_exact_flag_match(state)
|
1271
1316
|
self
|
1272
1317
|
end
|
1273
1318
|
|
@@ -1282,7 +1327,7 @@ module Toys
|
|
1282
1327
|
# @return [self]
|
1283
1328
|
#
|
1284
1329
|
def disable_argument_parsing
|
1285
|
-
DSL::
|
1330
|
+
DSL::Internal.current_tool(self, true)&.disable_argument_parsing
|
1286
1331
|
self
|
1287
1332
|
end
|
1288
1333
|
|
@@ -1291,7 +1336,7 @@ module Toys
|
|
1291
1336
|
# subsequent flag definition. This can be used to prevent middleware from
|
1292
1337
|
# defining a particular flag.
|
1293
1338
|
#
|
1294
|
-
#
|
1339
|
+
# ### Example
|
1295
1340
|
#
|
1296
1341
|
# This tool does not support the `-v` and `-q` short forms for the two
|
1297
1342
|
# verbosity flags (although it still supports the long forms `--verbose`
|
@@ -1308,7 +1353,7 @@ module Toys
|
|
1308
1353
|
# @return [self]
|
1309
1354
|
#
|
1310
1355
|
def disable_flag(*flags)
|
1311
|
-
DSL::
|
1356
|
+
DSL::Internal.current_tool(self, true)&.disable_flag(*flags)
|
1312
1357
|
self
|
1313
1358
|
end
|
1314
1359
|
|
@@ -1319,12 +1364,13 @@ module Toys
|
|
1319
1364
|
# * The string name of a completion defined in this tool or any of its
|
1320
1365
|
# its ancestors.
|
1321
1366
|
# * A hash of options to pass to the constructor of
|
1322
|
-
# {Toys::
|
1367
|
+
# {Toys::ToolDefinition::DefaultCompletion}.
|
1323
1368
|
# * `nil` or `:default` to select the standard completion strategy
|
1324
|
-
# (which is {Toys::
|
1369
|
+
# (which is {Toys::ToolDefinition::DefaultCompletion} with no extra
|
1370
|
+
# options).
|
1325
1371
|
# * Any other specification recognized by {Toys::Completion.create}.
|
1326
1372
|
#
|
1327
|
-
#
|
1373
|
+
# ### Example
|
1328
1374
|
#
|
1329
1375
|
# The namespace "foo" supports completion only of subtool names. It does
|
1330
1376
|
# not complete the standard flags (like --help).
|
@@ -1345,7 +1391,7 @@ module Toys
|
|
1345
1391
|
# @return [self]
|
1346
1392
|
#
|
1347
1393
|
def complete_tool_args(spec = nil, **options, &block)
|
1348
|
-
cur_tool = DSL::
|
1394
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1349
1395
|
return self if cur_tool.nil?
|
1350
1396
|
cur_tool.completion = Completion.scalarize_spec(spec, options, block)
|
1351
1397
|
self
|
@@ -1360,7 +1406,7 @@ module Toys
|
|
1360
1406
|
# in the lexical scope. However, it is often more convenient to use
|
1361
1407
|
# {#static} to set the value in the context.)
|
1362
1408
|
#
|
1363
|
-
#
|
1409
|
+
# ### Example
|
1364
1410
|
#
|
1365
1411
|
# tool "foo" do
|
1366
1412
|
# cur_time = Time.new
|
@@ -1373,7 +1419,9 @@ module Toys
|
|
1373
1419
|
# @return [self]
|
1374
1420
|
#
|
1375
1421
|
def to_run(&block)
|
1376
|
-
|
1422
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1423
|
+
return self if cur_tool.nil?
|
1424
|
+
cur_tool.run_handler = block
|
1377
1425
|
self
|
1378
1426
|
end
|
1379
1427
|
alias on_run to_run
|
@@ -1385,7 +1433,7 @@ module Toys
|
|
1385
1433
|
# either case, the block or method should take one argument, the
|
1386
1434
|
# Interrupt exception that was raised.
|
1387
1435
|
#
|
1388
|
-
#
|
1436
|
+
# ### Example
|
1389
1437
|
#
|
1390
1438
|
# tool "foo" do
|
1391
1439
|
# def run
|
@@ -1402,7 +1450,7 @@ module Toys
|
|
1402
1450
|
# @return [self]
|
1403
1451
|
#
|
1404
1452
|
def on_interrupt(handler = nil, &block)
|
1405
|
-
cur_tool = DSL::
|
1453
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1406
1454
|
return self if cur_tool.nil?
|
1407
1455
|
cur_tool.interrupt_handler = handler || block
|
1408
1456
|
self
|
@@ -1415,7 +1463,7 @@ module Toys
|
|
1415
1463
|
# either case, the block or method should take one argument, the array of
|
1416
1464
|
# usage errors reported.
|
1417
1465
|
#
|
1418
|
-
#
|
1466
|
+
# ### Example
|
1419
1467
|
#
|
1420
1468
|
# This tool runs even if a usage error is encountered. You can find info
|
1421
1469
|
# on the errors from {Toys::Context::Key::USAGE_ERRORS},
|
@@ -1434,7 +1482,7 @@ module Toys
|
|
1434
1482
|
# @return [self]
|
1435
1483
|
#
|
1436
1484
|
def on_usage_error(handler = nil, &block)
|
1437
|
-
cur_tool = DSL::
|
1485
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1438
1486
|
return self if cur_tool.nil?
|
1439
1487
|
cur_tool.usage_error_handler = handler || block
|
1440
1488
|
self
|
@@ -1448,7 +1496,7 @@ module Toys
|
|
1448
1496
|
# have defined in this tool or one of its ancestors, or the symbol name
|
1449
1497
|
# of a well-known mixin.
|
1450
1498
|
#
|
1451
|
-
#
|
1499
|
+
# ### Example
|
1452
1500
|
#
|
1453
1501
|
# Include the well-known mixin `:terminal` and perform some terminal
|
1454
1502
|
# magic.
|
@@ -1463,28 +1511,16 @@ module Toys
|
|
1463
1511
|
# end
|
1464
1512
|
# end
|
1465
1513
|
#
|
1466
|
-
# @param
|
1514
|
+
# @param mixin [Module,Symbol,String] Module or module name.
|
1467
1515
|
# @param args [Object...] Arguments to pass to the initializer
|
1468
1516
|
# @param kwargs [keywords] Keyword arguments to pass to the initializer
|
1469
1517
|
# @return [self]
|
1470
1518
|
#
|
1471
|
-
def include(
|
1472
|
-
cur_tool = DSL::
|
1519
|
+
def include(mixin, *args, **kwargs)
|
1520
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1473
1521
|
return self if cur_tool.nil?
|
1474
|
-
mod = DSL::
|
1475
|
-
|
1476
|
-
raise ToolDefinitionError, "Mixin already included: #{mod.name}"
|
1477
|
-
end
|
1478
|
-
cur_tool.mark_includes_modules
|
1479
|
-
super(mod)
|
1480
|
-
if mod.respond_to?(:initializer)
|
1481
|
-
callback = mod.initializer
|
1482
|
-
cur_tool.add_initializer(callback, *args, **kwargs) if callback
|
1483
|
-
end
|
1484
|
-
if mod.respond_to?(:inclusion)
|
1485
|
-
callback = mod.inclusion
|
1486
|
-
class_exec(*args, **kwargs, &callback) if callback
|
1487
|
-
end
|
1522
|
+
mod = DSL::Internal.resolve_mixin(mixin, cur_tool, @__loader)
|
1523
|
+
cur_tool.include_mixin(mod, *args, **kwargs)
|
1488
1524
|
self
|
1489
1525
|
end
|
1490
1526
|
|
@@ -1501,9 +1537,9 @@ module Toys
|
|
1501
1537
|
# @return [nil] if the current tool is not active.
|
1502
1538
|
#
|
1503
1539
|
def include?(mod)
|
1504
|
-
cur_tool = DSL::
|
1540
|
+
cur_tool = DSL::Internal.current_tool(self, false)
|
1505
1541
|
return if cur_tool.nil?
|
1506
|
-
super(DSL::
|
1542
|
+
super(DSL::Internal.resolve_mixin(mod, cur_tool, @__loader))
|
1507
1543
|
end
|
1508
1544
|
|
1509
1545
|
##
|
@@ -1523,7 +1559,7 @@ module Toys
|
|
1523
1559
|
# in a directory called `.data` inside a Toys directory. This directive
|
1524
1560
|
# locates a data file during tool definition.
|
1525
1561
|
#
|
1526
|
-
#
|
1562
|
+
# ### Example
|
1527
1563
|
#
|
1528
1564
|
# This tool reads its description from a text file in the `.data`
|
1529
1565
|
# directory.
|
@@ -1557,17 +1593,17 @@ module Toys
|
|
1557
1593
|
# @return [nil] if there is no context.
|
1558
1594
|
#
|
1559
1595
|
def context_directory
|
1560
|
-
DSL::
|
1596
|
+
DSL::Internal.current_tool(self, false)&.context_directory || source_info.context_directory
|
1561
1597
|
end
|
1562
1598
|
|
1563
1599
|
##
|
1564
|
-
# Return the current tool
|
1600
|
+
# Return the current tool config. This object can be queried to determine
|
1565
1601
|
# such information as the name, but it should not be altered.
|
1566
1602
|
#
|
1567
|
-
# @return [Toys::
|
1603
|
+
# @return [Toys::ToolDefinition]
|
1568
1604
|
#
|
1569
1605
|
def current_tool
|
1570
|
-
DSL::
|
1606
|
+
DSL::Internal.current_tool(self, false)
|
1571
1607
|
end
|
1572
1608
|
|
1573
1609
|
##
|
@@ -1577,7 +1613,7 @@ module Toys
|
|
1577
1613
|
# @return [self]
|
1578
1614
|
#
|
1579
1615
|
def set_context_directory(dir) # rubocop:disable Naming/AccessorMethodName
|
1580
|
-
cur_tool = DSL::
|
1616
|
+
cur_tool = DSL::Internal.current_tool(self, false)
|
1581
1617
|
return self if cur_tool.nil?
|
1582
1618
|
cur_tool.custom_context_directory = dir
|
1583
1619
|
self
|
@@ -1591,7 +1627,7 @@ module Toys
|
|
1591
1627
|
# The block is applied only to subtools defined *after* the block
|
1592
1628
|
# appears. Subtools defined before the block appears are not affected.
|
1593
1629
|
#
|
1594
|
-
#
|
1630
|
+
# ### Example
|
1595
1631
|
#
|
1596
1632
|
# It is common for tools to use the `:exec` mixin to invoke external
|
1597
1633
|
# programs. This example automatically includes the exec mixin in all
|
@@ -1616,7 +1652,7 @@ module Toys
|
|
1616
1652
|
# end
|
1617
1653
|
#
|
1618
1654
|
def subtool_apply(&block)
|
1619
|
-
cur_tool = DSL::
|
1655
|
+
cur_tool = DSL::Internal.current_tool(self, false)
|
1620
1656
|
return self if cur_tool.nil?
|
1621
1657
|
cur_tool.subtool_middleware_stack.add(:apply_config,
|
1622
1658
|
parent_source: source_info, &block)
|
@@ -1640,6 +1676,15 @@ module Toys
|
|
1640
1676
|
end
|
1641
1677
|
end
|
1642
1678
|
|
1679
|
+
##
|
1680
|
+
# Get the settings for this tool.
|
1681
|
+
#
|
1682
|
+
# @return [Toys::ToolDefinition::Settings] Tool-specific settings.
|
1683
|
+
#
|
1684
|
+
def settings
|
1685
|
+
DSL::Internal.current_tool(self, false)&.settings
|
1686
|
+
end
|
1687
|
+
|
1643
1688
|
##
|
1644
1689
|
# Determines whether the current Toys version satisfies the given
|
1645
1690
|
# requirements.
|
@@ -1672,93 +1717,6 @@ module Toys
|
|
1672
1717
|
end
|
1673
1718
|
self
|
1674
1719
|
end
|
1675
|
-
|
1676
|
-
## @private
|
1677
|
-
def self.new_class(words, priority, loader)
|
1678
|
-
tool_class = ::Class.new(::Toys::Context)
|
1679
|
-
tool_class.extend(DSL::Tool)
|
1680
|
-
tool_class.instance_variable_set(:@__words, words)
|
1681
|
-
tool_class.instance_variable_set(:@__priority, priority)
|
1682
|
-
tool_class.instance_variable_set(:@__loader, loader)
|
1683
|
-
tool_class.instance_variable_set(:@__remaining_words, nil)
|
1684
|
-
tool_class.instance_variable_set(:@__source, [])
|
1685
|
-
tool_class
|
1686
|
-
end
|
1687
|
-
|
1688
|
-
## @private
|
1689
|
-
def self.current_tool(tool_class, activate)
|
1690
|
-
memoize_var = activate ? :@__active_tool : :@__cur_tool
|
1691
|
-
if tool_class.instance_variable_defined?(memoize_var)
|
1692
|
-
tool_class.instance_variable_get(memoize_var)
|
1693
|
-
else
|
1694
|
-
loader = tool_class.instance_variable_get(:@__loader)
|
1695
|
-
words = tool_class.instance_variable_get(:@__words)
|
1696
|
-
priority = tool_class.instance_variable_get(:@__priority)
|
1697
|
-
cur_tool =
|
1698
|
-
if activate
|
1699
|
-
loader.activate_tool(words, priority)
|
1700
|
-
else
|
1701
|
-
loader.get_tool(words, priority)
|
1702
|
-
end
|
1703
|
-
if cur_tool && activate
|
1704
|
-
source = tool_class.instance_variable_get(:@__source).last
|
1705
|
-
cur_tool.lock_source(source)
|
1706
|
-
end
|
1707
|
-
tool_class.instance_variable_set(memoize_var, cur_tool)
|
1708
|
-
end
|
1709
|
-
end
|
1710
|
-
|
1711
|
-
## @private
|
1712
|
-
def self.prepare(tool_class, remaining_words, source)
|
1713
|
-
tool_class.instance_variable_set(:@__remaining_words, remaining_words)
|
1714
|
-
tool_class.instance_variable_get(:@__source).push(source)
|
1715
|
-
yield
|
1716
|
-
ensure
|
1717
|
-
tool_class.instance_variable_get(:@__source).pop
|
1718
|
-
end
|
1719
|
-
|
1720
|
-
## @private
|
1721
|
-
def self.maybe_add_getter(tool_class, key)
|
1722
|
-
if key.is_a?(::Symbol) && key.to_s =~ /^[_a-zA-Z]\w*[!\?]?$/ && key != :run
|
1723
|
-
unless tool_class.public_method_defined?(key)
|
1724
|
-
tool_class.class_eval do
|
1725
|
-
define_method(key) do
|
1726
|
-
self[key]
|
1727
|
-
end
|
1728
|
-
end
|
1729
|
-
end
|
1730
|
-
end
|
1731
|
-
end
|
1732
|
-
|
1733
|
-
## @private
|
1734
|
-
def self.resolve_mixin(mod, cur_tool, loader)
|
1735
|
-
name = mod.to_s
|
1736
|
-
if mod.is_a?(::String)
|
1737
|
-
mod = cur_tool.lookup_mixin(mod)
|
1738
|
-
elsif mod.is_a?(::Symbol)
|
1739
|
-
mod = loader.resolve_standard_mixin(name)
|
1740
|
-
end
|
1741
|
-
unless mod.is_a?(::Module)
|
1742
|
-
raise ToolDefinitionError, "Module not found: #{name.inspect}"
|
1743
|
-
end
|
1744
|
-
mod
|
1745
|
-
end
|
1746
|
-
|
1747
|
-
## @private
|
1748
|
-
def self.load_long_desc_file(path)
|
1749
|
-
if ::File.extname(path) == ".txt"
|
1750
|
-
begin
|
1751
|
-
::File.readlines(path).map do |line|
|
1752
|
-
line = line.chomp
|
1753
|
-
line =~ /^\s/ ? [line] : line
|
1754
|
-
end
|
1755
|
-
rescue ::SystemCallError => e
|
1756
|
-
raise Toys::ToolDefinitionError, e.to_s
|
1757
|
-
end
|
1758
|
-
else
|
1759
|
-
raise Toys::ToolDefinitionError, "Cannot load long desc from file type: #{path}"
|
1760
|
-
end
|
1761
|
-
end
|
1762
1720
|
end
|
1763
1721
|
end
|
1764
1722
|
end
|