toys-core 0.9.2 → 0.10.2
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/.yardopts +2 -1
- data/CHANGELOG.md +47 -0
- data/LICENSE.md +1 -1
- data/README.md +3 -3
- data/lib/toys-core.rb +14 -21
- data/lib/toys/acceptor.rb +0 -21
- data/lib/toys/arg_parser.rb +1 -22
- data/lib/toys/cli.rb +102 -70
- data/lib/toys/compat.rb +49 -41
- data/lib/toys/completion.rb +0 -21
- data/lib/toys/context.rb +0 -23
- data/lib/toys/core.rb +1 -22
- data/lib/toys/dsl/flag.rb +0 -21
- data/lib/toys/dsl/flag_group.rb +0 -21
- data/lib/toys/dsl/positional_arg.rb +0 -21
- data/lib/toys/dsl/tool.rb +136 -51
- data/lib/toys/errors.rb +1 -22
- data/lib/toys/flag.rb +0 -21
- data/lib/toys/flag_group.rb +0 -21
- data/lib/toys/input_file.rb +0 -21
- data/lib/toys/loader.rb +42 -78
- data/lib/toys/middleware.rb +146 -77
- data/lib/toys/mixin.rb +0 -21
- data/lib/toys/module_lookup.rb +3 -26
- data/lib/toys/positional_arg.rb +0 -21
- data/lib/toys/source_info.rb +49 -38
- data/lib/toys/standard_middleware/add_verbosity_flags.rb +0 -23
- data/lib/toys/standard_middleware/apply_config.rb +42 -0
- data/lib/toys/standard_middleware/handle_usage_errors.rb +7 -28
- data/lib/toys/standard_middleware/set_default_descriptions.rb +0 -23
- data/lib/toys/standard_middleware/show_help.rb +0 -23
- data/lib/toys/standard_middleware/show_root_version.rb +0 -23
- data/lib/toys/standard_mixins/bundler.rb +89 -0
- data/lib/toys/standard_mixins/exec.rb +478 -128
- data/lib/toys/standard_mixins/fileutils.rb +0 -21
- data/lib/toys/standard_mixins/gems.rb +2 -24
- data/lib/toys/standard_mixins/highline.rb +0 -21
- data/lib/toys/standard_mixins/terminal.rb +0 -21
- data/lib/toys/template.rb +0 -21
- data/lib/toys/tool.rb +22 -34
- data/lib/toys/utils/completion_engine.rb +0 -21
- data/lib/toys/utils/exec.rb +142 -71
- data/lib/toys/utils/gems.rb +181 -63
- data/lib/toys/utils/help_text.rb +0 -21
- data/lib/toys/utils/terminal.rb +46 -37
- data/lib/toys/wrappable_string.rb +0 -21
- metadata +25 -9
data/lib/toys/compat.rb
CHANGED
@@ -1,25 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
#
|
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:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
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.
|
22
|
-
;
|
3
|
+
require "rbconfig"
|
23
4
|
|
24
5
|
module Toys
|
25
6
|
##
|
@@ -27,44 +8,51 @@ module Toys
|
|
27
8
|
# @private
|
28
9
|
#
|
29
10
|
module Compat
|
30
|
-
|
31
|
-
|
11
|
+
parts = ::RUBY_VERSION.split(".")
|
12
|
+
ruby_version = parts[0].to_i * 10000 + parts[1].to_i * 100 + parts[2].to_i
|
32
13
|
|
33
|
-
|
14
|
+
# @private
|
34
15
|
def self.jruby?
|
35
16
|
::RUBY_PLATFORM == "java"
|
36
17
|
end
|
37
18
|
|
38
|
-
|
19
|
+
# @private
|
39
20
|
def self.allow_fork?
|
40
|
-
!jruby? && RbConfig::CONFIG["host_os"] !~ /mswin/
|
21
|
+
!jruby? && ::RbConfig::CONFIG["host_os"] !~ /mswin/
|
41
22
|
end
|
42
23
|
|
43
|
-
|
44
|
-
def self.
|
45
|
-
|
24
|
+
# @private
|
25
|
+
def self.supports_suggestions?
|
26
|
+
unless defined?(@supports_suggestions)
|
27
|
+
require "rubygems"
|
28
|
+
begin
|
29
|
+
require "did_you_mean"
|
30
|
+
@supports_suggestions = defined?(::DidYouMean::SpellChecker)
|
31
|
+
rescue ::LoadError
|
32
|
+
@supports_suggestions = false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
@supports_suggestions
|
46
36
|
end
|
47
37
|
|
48
|
-
|
49
|
-
|
50
|
-
|
38
|
+
# @private
|
39
|
+
def self.suggestions(word, list)
|
40
|
+
if supports_suggestions?
|
51
41
|
::DidYouMean::SpellChecker.new(dictionary: list).correct(word)
|
52
|
-
|
53
|
-
else
|
54
|
-
## @private
|
55
|
-
def self.suggestions(_word, _list)
|
42
|
+
else
|
56
43
|
[]
|
57
44
|
end
|
58
45
|
end
|
59
46
|
|
60
|
-
|
61
|
-
|
47
|
+
# In Ruby < 2.4, some objects such as nil cannot be cloned.
|
48
|
+
if ruby_version >= 20400
|
49
|
+
# @private
|
62
50
|
def self.merge_clones(hash, orig)
|
63
51
|
orig.each { |k, v| hash[k] = v.clone }
|
64
52
|
hash
|
65
53
|
end
|
66
54
|
else
|
67
|
-
|
55
|
+
# @private
|
68
56
|
def self.merge_clones(hash, orig)
|
69
57
|
orig.each do |k, v|
|
70
58
|
hash[k] =
|
@@ -78,16 +66,36 @@ module Toys
|
|
78
66
|
end
|
79
67
|
end
|
80
68
|
|
81
|
-
|
82
|
-
|
69
|
+
# The :base argument to Dir.glob requires Ruby 2.5 or later.
|
70
|
+
if ruby_version >= 20500
|
71
|
+
# @private
|
83
72
|
def self.glob_in_dir(glob, dir)
|
84
73
|
::Dir.glob(glob, base: dir)
|
85
74
|
end
|
86
75
|
else
|
87
|
-
|
76
|
+
# @private
|
88
77
|
def self.glob_in_dir(glob, dir)
|
89
78
|
::Dir.chdir(dir) { ::Dir.glob(glob) }
|
90
79
|
end
|
91
80
|
end
|
81
|
+
|
82
|
+
# Due to a bug in Ruby < 2.7, passing an empty **kwargs splat to
|
83
|
+
# initialize will fail if there are no formal keyword args.
|
84
|
+
if ruby_version >= 20700
|
85
|
+
# @private
|
86
|
+
def self.instantiate(klass, args, kwargs, block)
|
87
|
+
klass.new(*args, **kwargs, &block)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
# @private
|
91
|
+
def self.instantiate(klass, args, kwargs, block)
|
92
|
+
formals = klass.instance_method(:initialize).parameters
|
93
|
+
if kwargs.empty? && formals.all? { |arg| arg.first != :key && arg.first != :keyrest }
|
94
|
+
klass.new(*args, &block)
|
95
|
+
else
|
96
|
+
klass.new(*args, **kwargs, &block)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
92
100
|
end
|
93
101
|
end
|
data/lib/toys/completion.rb
CHANGED
@@ -1,26 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
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:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
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.
|
22
|
-
;
|
23
|
-
|
24
3
|
module Toys
|
25
4
|
##
|
26
5
|
# A Completion is a callable Proc that determines candidates for shell tab
|
data/lib/toys/context.rb
CHANGED
@@ -1,28 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
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:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
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.
|
22
|
-
;
|
23
|
-
|
24
|
-
require "logger"
|
25
|
-
|
26
3
|
module Toys
|
27
4
|
##
|
28
5
|
# This is the base class for tool execution. It represents `self` when your
|
data/lib/toys/core.rb
CHANGED
@@ -1,26 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
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:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
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.
|
22
|
-
;
|
23
|
-
|
24
3
|
module Toys
|
25
4
|
##
|
26
5
|
# The core Toys classes.
|
@@ -30,7 +9,7 @@ module Toys
|
|
30
9
|
# Current version of Toys core.
|
31
10
|
# @return [String]
|
32
11
|
#
|
33
|
-
VERSION = "0.
|
12
|
+
VERSION = "0.10.2"
|
34
13
|
end
|
35
14
|
|
36
15
|
## @private deprecated
|
data/lib/toys/dsl/flag.rb
CHANGED
@@ -1,26 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
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:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
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.
|
22
|
-
;
|
23
|
-
|
24
3
|
module Toys
|
25
4
|
module DSL
|
26
5
|
##
|
data/lib/toys/dsl/flag_group.rb
CHANGED
@@ -1,26 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
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:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
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.
|
22
|
-
;
|
23
|
-
|
24
3
|
module Toys
|
25
4
|
module DSL
|
26
5
|
##
|
@@ -1,26 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
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:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
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.
|
22
|
-
;
|
23
|
-
|
24
3
|
module Toys
|
25
4
|
module DSL
|
26
5
|
##
|
data/lib/toys/dsl/tool.rb
CHANGED
@@ -1,26 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright 2019 Daniel Azuma
|
4
|
-
#
|
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:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
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.
|
22
|
-
;
|
23
|
-
|
24
3
|
module Toys
|
25
4
|
module DSL
|
26
5
|
##
|
@@ -226,7 +205,8 @@ module Toys
|
|
226
205
|
#
|
227
206
|
def template(name, template_class = nil, &block)
|
228
207
|
cur_tool = DSL::Tool.current_tool(self, false)
|
229
|
-
|
208
|
+
return self if cur_tool.nil?
|
209
|
+
cur_tool.add_template(name, template_class, &block)
|
230
210
|
self
|
231
211
|
end
|
232
212
|
|
@@ -273,7 +253,8 @@ module Toys
|
|
273
253
|
#
|
274
254
|
def completion(name, spec = nil, **options, &block)
|
275
255
|
cur_tool = DSL::Tool.current_tool(self, false)
|
276
|
-
|
256
|
+
return self if cur_tool.nil?
|
257
|
+
cur_tool.add_completion(name, spec, **options, &block)
|
277
258
|
self
|
278
259
|
end
|
279
260
|
|
@@ -322,11 +303,11 @@ module Toys
|
|
322
303
|
# @return [self]
|
323
304
|
#
|
324
305
|
def tool(words, if_defined: :combine, delegate_to: nil, &block)
|
325
|
-
subtool_words = @__words
|
306
|
+
subtool_words = @__words.dup
|
326
307
|
next_remaining = @__remaining_words
|
327
|
-
|
308
|
+
@__loader.split_path(words).each do |word|
|
328
309
|
word = word.to_s
|
329
|
-
subtool_words
|
310
|
+
subtool_words << word
|
330
311
|
next_remaining = Loader.next_remaining_words(next_remaining, word)
|
331
312
|
end
|
332
313
|
subtool = @__loader.get_tool(subtool_words, @__priority)
|
@@ -338,10 +319,12 @@ module Toys
|
|
338
319
|
subtool.reset_definition(@__loader)
|
339
320
|
end
|
340
321
|
end
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
322
|
+
if delegate_to
|
323
|
+
delegator = proc { self.delegate_to(delegate_to) }
|
324
|
+
@__loader.load_block(source_info, delegator, subtool_words, next_remaining, @__priority)
|
325
|
+
end
|
326
|
+
if block
|
327
|
+
@__loader.load_block(source_info, block, subtool_words, next_remaining, @__priority)
|
345
328
|
end
|
346
329
|
self
|
347
330
|
end
|
@@ -404,6 +387,7 @@ module Toys
|
|
404
387
|
#
|
405
388
|
def delegate_to(target)
|
406
389
|
cur_tool = DSL::Tool.current_tool(self, true)
|
390
|
+
return self if cur_tool.nil?
|
407
391
|
cur_tool.delegate_to(@__loader.split_path(target))
|
408
392
|
self
|
409
393
|
end
|
@@ -454,6 +438,7 @@ module Toys
|
|
454
438
|
#
|
455
439
|
def expand(template_class, *args, **kwargs)
|
456
440
|
cur_tool = DSL::Tool.current_tool(self, false)
|
441
|
+
return self if cur_tool.nil?
|
457
442
|
name = template_class.to_s
|
458
443
|
if template_class.is_a?(::String)
|
459
444
|
template_class = cur_tool.lookup_template(template_class)
|
@@ -463,15 +448,7 @@ module Toys
|
|
463
448
|
if template_class.nil?
|
464
449
|
raise ToolDefinitionError, "Template not found: #{name.inspect}"
|
465
450
|
end
|
466
|
-
|
467
|
-
# initialize will fail if there are no formal keyword args.
|
468
|
-
formals = template_class.instance_method(:initialize).parameters
|
469
|
-
template =
|
470
|
-
if kwargs.empty? && formals.all? { |(type, _name)| type != :key && type != :keyrest }
|
471
|
-
template_class.new(*args)
|
472
|
-
else
|
473
|
-
template_class.new(*args, **kwargs)
|
474
|
-
end
|
451
|
+
template = Compat.instantiate(template_class, args, kwargs, nil)
|
475
452
|
yield template if block_given?
|
476
453
|
class_exec(template, &template_class.expansion)
|
477
454
|
self
|
@@ -512,7 +489,8 @@ module Toys
|
|
512
489
|
#
|
513
490
|
def desc(str)
|
514
491
|
cur_tool = DSL::Tool.current_tool(self, true)
|
515
|
-
|
492
|
+
return self if cur_tool.nil?
|
493
|
+
cur_tool.desc = str
|
516
494
|
self
|
517
495
|
end
|
518
496
|
alias short_desc desc
|
@@ -538,10 +516,27 @@ module Toys
|
|
538
516
|
# long_desc "This line is appended to the description."
|
539
517
|
#
|
540
518
|
# @param strs [Toys::WrappableString,String,Array<String>...]
|
519
|
+
# @param file [String] Optional. Read the description from the given file
|
520
|
+
# provided relative to the current toys file. The file must be a
|
521
|
+
# plain text file whose suffix is `.txt`.
|
522
|
+
# @param data [String] Optional. Read the description from the given data
|
523
|
+
# file. The file must be a plain text file whose suffix is `.txt`.
|
541
524
|
# @return [self]
|
542
525
|
#
|
543
|
-
def long_desc(*strs)
|
544
|
-
DSL::Tool.current_tool(self, true)
|
526
|
+
def long_desc(*strs, file: nil, data: nil)
|
527
|
+
cur_tool = DSL::Tool.current_tool(self, true)
|
528
|
+
return self if cur_tool.nil?
|
529
|
+
if file
|
530
|
+
unless source_info.source_path
|
531
|
+
raise ::Toys::ToolDefinitionError,
|
532
|
+
"Cannot set long_desc from a file because the tool is not defined in a file"
|
533
|
+
end
|
534
|
+
file = ::File.join(::File.dirname(source_info.source_path), file)
|
535
|
+
elsif data
|
536
|
+
file = source_info.find_data(data, type: :file)
|
537
|
+
end
|
538
|
+
strs += DSL::Tool.load_long_desc_file(file) if file
|
539
|
+
cur_tool.append_long_desc(strs)
|
545
540
|
self
|
546
541
|
end
|
547
542
|
|
@@ -1404,7 +1399,8 @@ module Toys
|
|
1404
1399
|
#
|
1405
1400
|
def on_interrupt(handler = nil, &block)
|
1406
1401
|
cur_tool = DSL::Tool.current_tool(self, true)
|
1407
|
-
|
1402
|
+
return self if cur_tool.nil?
|
1403
|
+
cur_tool.interrupt_handler = handler || block
|
1408
1404
|
self
|
1409
1405
|
end
|
1410
1406
|
|
@@ -1435,7 +1431,8 @@ module Toys
|
|
1435
1431
|
#
|
1436
1432
|
def on_usage_error(handler = nil, &block)
|
1437
1433
|
cur_tool = DSL::Tool.current_tool(self, true)
|
1438
|
-
|
1434
|
+
return self if cur_tool.nil?
|
1435
|
+
cur_tool.usage_error_handler = handler || block
|
1439
1436
|
self
|
1440
1437
|
end
|
1441
1438
|
|
@@ -1577,11 +1574,84 @@ module Toys
|
|
1577
1574
|
#
|
1578
1575
|
def set_context_directory(dir) # rubocop:disable Naming/AccessorMethodName
|
1579
1576
|
cur_tool = DSL::Tool.current_tool(self, false)
|
1580
|
-
return if cur_tool.nil?
|
1577
|
+
return self if cur_tool.nil?
|
1581
1578
|
cur_tool.custom_context_directory = dir
|
1582
1579
|
self
|
1583
1580
|
end
|
1584
1581
|
|
1582
|
+
##
|
1583
|
+
# Applies the given block to all subtools, recursively. Effectively, the
|
1584
|
+
# given block is run at the *end* of every tool block. This can be used,
|
1585
|
+
# for example, to provide some shared configuration for all tools.
|
1586
|
+
#
|
1587
|
+
# The block is applied only to subtools defined *after* the block
|
1588
|
+
# appears. Subtools defined before the block appears are not affected.
|
1589
|
+
#
|
1590
|
+
# ## Example
|
1591
|
+
#
|
1592
|
+
# It is common for tools to use the `:exec` mixin to invoke external
|
1593
|
+
# programs. This example automatically includes the exec mixin in all
|
1594
|
+
# subtools, recursively, so you do not have to repeat the `include`
|
1595
|
+
# directive in every tool.
|
1596
|
+
#
|
1597
|
+
# # .toys.rb
|
1598
|
+
#
|
1599
|
+
# subtool_apply do
|
1600
|
+
# # Include the mixin only if the tool hasn't already done so
|
1601
|
+
# unless include?(:exec)
|
1602
|
+
# include :exec, exit_on_nonzero_status: true
|
1603
|
+
# end
|
1604
|
+
# end
|
1605
|
+
#
|
1606
|
+
# tool "foo" do
|
1607
|
+
# def run
|
1608
|
+
# # This tool has access to methods defined by the :exec mixin
|
1609
|
+
# # because the above block is applied to the tool.
|
1610
|
+
# sh "echo hello"
|
1611
|
+
# end
|
1612
|
+
# end
|
1613
|
+
#
|
1614
|
+
def subtool_apply(&block)
|
1615
|
+
cur_tool = DSL::Tool.current_tool(self, false)
|
1616
|
+
return self if cur_tool.nil?
|
1617
|
+
cur_tool.subtool_middleware_stack.add(:apply_config,
|
1618
|
+
parent_source: source_info, &block)
|
1619
|
+
self
|
1620
|
+
end
|
1621
|
+
|
1622
|
+
##
|
1623
|
+
# Determines whether the current Toys version satisfies the given
|
1624
|
+
# requirements.
|
1625
|
+
#
|
1626
|
+
# @return [Boolean] whether or not the requirements are satisfied
|
1627
|
+
#
|
1628
|
+
def toys_version?(*requirements)
|
1629
|
+
require "rubygems"
|
1630
|
+
version = ::Gem::Version.new(Core::VERSION)
|
1631
|
+
requirement = ::Gem::Requirement.new(*requirements)
|
1632
|
+
requirement.satisfied_by?(version)
|
1633
|
+
end
|
1634
|
+
|
1635
|
+
##
|
1636
|
+
# Asserts that the current Toys version against the given requirements,
|
1637
|
+
# raising an exception if not.
|
1638
|
+
#
|
1639
|
+
# @return [self]
|
1640
|
+
#
|
1641
|
+
# @raise [Toys::ToolDefinitionError] if the current Toys version does not
|
1642
|
+
# satisfy the requirements.
|
1643
|
+
#
|
1644
|
+
def toys_version!(*requirements)
|
1645
|
+
require "rubygems"
|
1646
|
+
version = ::Gem::Version.new(Core::VERSION)
|
1647
|
+
requirement = ::Gem::Requirement.new(*requirements)
|
1648
|
+
unless requirement.satisfied_by?(version)
|
1649
|
+
raise Toys::ToolDefinitionError,
|
1650
|
+
"Toys version requirements #{requirement} not satisfied by {version}"
|
1651
|
+
end
|
1652
|
+
self
|
1653
|
+
end
|
1654
|
+
|
1585
1655
|
## @private
|
1586
1656
|
def self.new_class(words, priority, loader)
|
1587
1657
|
tool_class = ::Class.new(::Toys::Context)
|
@@ -1598,7 +1668,7 @@ module Toys
|
|
1598
1668
|
def self.current_tool(tool_class, activate)
|
1599
1669
|
memoize_var = activate ? :@__active_tool : :@__cur_tool
|
1600
1670
|
if tool_class.instance_variable_defined?(memoize_var)
|
1601
|
-
|
1671
|
+
tool_class.instance_variable_get(memoize_var)
|
1602
1672
|
else
|
1603
1673
|
loader = tool_class.instance_variable_get(:@__loader)
|
1604
1674
|
words = tool_class.instance_variable_get(:@__words)
|
@@ -1609,13 +1679,12 @@ module Toys
|
|
1609
1679
|
else
|
1610
1680
|
loader.get_tool(words, priority)
|
1611
1681
|
end
|
1682
|
+
if cur_tool && activate
|
1683
|
+
source = tool_class.instance_variable_get(:@__source).last
|
1684
|
+
cur_tool.lock_source(source)
|
1685
|
+
end
|
1612
1686
|
tool_class.instance_variable_set(memoize_var, cur_tool)
|
1613
1687
|
end
|
1614
|
-
if cur_tool && activate
|
1615
|
-
source = tool_class.instance_variable_get(:@__source).last
|
1616
|
-
cur_tool.lock_source(source)
|
1617
|
-
end
|
1618
|
-
cur_tool
|
1619
1688
|
end
|
1620
1689
|
|
1621
1690
|
## @private
|
@@ -1653,6 +1722,22 @@ module Toys
|
|
1653
1722
|
end
|
1654
1723
|
mod
|
1655
1724
|
end
|
1725
|
+
|
1726
|
+
## @private
|
1727
|
+
def self.load_long_desc_file(path)
|
1728
|
+
if ::File.extname(path) == ".txt"
|
1729
|
+
begin
|
1730
|
+
::File.readlines(path).map do |line|
|
1731
|
+
line = line.chomp
|
1732
|
+
line =~ /^\s/ ? [line] : line
|
1733
|
+
end
|
1734
|
+
rescue ::SystemCallError => e
|
1735
|
+
raise Toys::ToolDefinitionError, e.to_s
|
1736
|
+
end
|
1737
|
+
else
|
1738
|
+
raise Toys::ToolDefinitionError, "Cannot load long desc from file type: #{path}"
|
1739
|
+
end
|
1740
|
+
end
|
1656
1741
|
end
|
1657
1742
|
end
|
1658
1743
|
end
|