toys-core 0.9.4 → 0.10.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/.yardopts +2 -1
- data/CHANGELOG.md +30 -0
- data/LICENSE.md +1 -1
- data/README.md +3 -3
- data/lib/toys-core.rb +11 -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 +135 -51
- data/lib/toys/errors.rb +0 -21
- 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 +41 -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 +124 -35
- 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 +1 -21
- data/lib/toys/utils/gems.rb +174 -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.0"
|
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
|
@@ -455,6 +438,7 @@ module Toys
|
|
455
438
|
#
|
456
439
|
def expand(template_class, *args, **kwargs)
|
457
440
|
cur_tool = DSL::Tool.current_tool(self, false)
|
441
|
+
return self if cur_tool.nil?
|
458
442
|
name = template_class.to_s
|
459
443
|
if template_class.is_a?(::String)
|
460
444
|
template_class = cur_tool.lookup_template(template_class)
|
@@ -464,15 +448,7 @@ module Toys
|
|
464
448
|
if template_class.nil?
|
465
449
|
raise ToolDefinitionError, "Template not found: #{name.inspect}"
|
466
450
|
end
|
467
|
-
|
468
|
-
# initialize will fail if there are no formal keyword args.
|
469
|
-
formals = template_class.instance_method(:initialize).parameters
|
470
|
-
template =
|
471
|
-
if kwargs.empty? && formals.all? { |(type, _name)| type != :key && type != :keyrest }
|
472
|
-
template_class.new(*args)
|
473
|
-
else
|
474
|
-
template_class.new(*args, **kwargs)
|
475
|
-
end
|
451
|
+
template = Compat.instantiate(template_class, args, kwargs, nil)
|
476
452
|
yield template if block_given?
|
477
453
|
class_exec(template, &template_class.expansion)
|
478
454
|
self
|
@@ -513,7 +489,8 @@ module Toys
|
|
513
489
|
#
|
514
490
|
def desc(str)
|
515
491
|
cur_tool = DSL::Tool.current_tool(self, true)
|
516
|
-
|
492
|
+
return self if cur_tool.nil?
|
493
|
+
cur_tool.desc = str
|
517
494
|
self
|
518
495
|
end
|
519
496
|
alias short_desc desc
|
@@ -539,10 +516,27 @@ module Toys
|
|
539
516
|
# long_desc "This line is appended to the description."
|
540
517
|
#
|
541
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`.
|
542
524
|
# @return [self]
|
543
525
|
#
|
544
|
-
def long_desc(*strs)
|
545
|
-
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)
|
546
540
|
self
|
547
541
|
end
|
548
542
|
|
@@ -1405,7 +1399,8 @@ module Toys
|
|
1405
1399
|
#
|
1406
1400
|
def on_interrupt(handler = nil, &block)
|
1407
1401
|
cur_tool = DSL::Tool.current_tool(self, true)
|
1408
|
-
|
1402
|
+
return self if cur_tool.nil?
|
1403
|
+
cur_tool.interrupt_handler = handler || block
|
1409
1404
|
self
|
1410
1405
|
end
|
1411
1406
|
|
@@ -1436,7 +1431,8 @@ module Toys
|
|
1436
1431
|
#
|
1437
1432
|
def on_usage_error(handler = nil, &block)
|
1438
1433
|
cur_tool = DSL::Tool.current_tool(self, true)
|
1439
|
-
|
1434
|
+
return self if cur_tool.nil?
|
1435
|
+
cur_tool.usage_error_handler = handler || block
|
1440
1436
|
self
|
1441
1437
|
end
|
1442
1438
|
|
@@ -1578,11 +1574,84 @@ module Toys
|
|
1578
1574
|
#
|
1579
1575
|
def set_context_directory(dir) # rubocop:disable Naming/AccessorMethodName
|
1580
1576
|
cur_tool = DSL::Tool.current_tool(self, false)
|
1581
|
-
return if cur_tool.nil?
|
1577
|
+
return self if cur_tool.nil?
|
1582
1578
|
cur_tool.custom_context_directory = dir
|
1583
1579
|
self
|
1584
1580
|
end
|
1585
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
|
+
|
1586
1655
|
## @private
|
1587
1656
|
def self.new_class(words, priority, loader)
|
1588
1657
|
tool_class = ::Class.new(::Toys::Context)
|
@@ -1599,7 +1668,7 @@ module Toys
|
|
1599
1668
|
def self.current_tool(tool_class, activate)
|
1600
1669
|
memoize_var = activate ? :@__active_tool : :@__cur_tool
|
1601
1670
|
if tool_class.instance_variable_defined?(memoize_var)
|
1602
|
-
|
1671
|
+
tool_class.instance_variable_get(memoize_var)
|
1603
1672
|
else
|
1604
1673
|
loader = tool_class.instance_variable_get(:@__loader)
|
1605
1674
|
words = tool_class.instance_variable_get(:@__words)
|
@@ -1610,13 +1679,12 @@ module Toys
|
|
1610
1679
|
else
|
1611
1680
|
loader.get_tool(words, priority)
|
1612
1681
|
end
|
1682
|
+
if cur_tool && activate
|
1683
|
+
source = tool_class.instance_variable_get(:@__source).last
|
1684
|
+
cur_tool.lock_source(source)
|
1685
|
+
end
|
1613
1686
|
tool_class.instance_variable_set(memoize_var, cur_tool)
|
1614
1687
|
end
|
1615
|
-
if cur_tool && activate
|
1616
|
-
source = tool_class.instance_variable_get(:@__source).last
|
1617
|
-
cur_tool.lock_source(source)
|
1618
|
-
end
|
1619
|
-
cur_tool
|
1620
1688
|
end
|
1621
1689
|
|
1622
1690
|
## @private
|
@@ -1654,6 +1722,22 @@ module Toys
|
|
1654
1722
|
end
|
1655
1723
|
mod
|
1656
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
|
1657
1741
|
end
|
1658
1742
|
end
|
1659
1743
|
end
|