toys-core 0.11.5 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +62 -0
- data/LICENSE.md +1 -1
- data/README.md +5 -2
- data/docs/guide.md +1 -1
- data/lib/toys/acceptor.rb +13 -4
- data/lib/toys/arg_parser.rb +7 -7
- data/lib/toys/cli.rb +170 -120
- data/lib/toys/compat.rb +71 -23
- data/lib/toys/completion.rb +18 -6
- data/lib/toys/context.rb +24 -15
- data/lib/toys/core.rb +6 -2
- data/lib/toys/dsl/base.rb +87 -0
- data/lib/toys/dsl/flag.rb +26 -20
- data/lib/toys/dsl/flag_group.rb +18 -14
- data/lib/toys/dsl/internal.rb +206 -0
- data/lib/toys/dsl/positional_arg.rb +26 -16
- data/lib/toys/dsl/tool.rb +180 -218
- data/lib/toys/errors.rb +64 -8
- data/lib/toys/flag.rb +662 -656
- data/lib/toys/flag_group.rb +24 -10
- data/lib/toys/input_file.rb +13 -7
- data/lib/toys/loader.rb +293 -140
- data/lib/toys/middleware.rb +46 -22
- data/lib/toys/mixin.rb +10 -8
- data/lib/toys/positional_arg.rb +21 -20
- data/lib/toys/settings.rb +914 -0
- data/lib/toys/source_info.rb +147 -35
- data/lib/toys/standard_middleware/add_verbosity_flags.rb +2 -0
- data/lib/toys/standard_middleware/apply_config.rb +6 -4
- data/lib/toys/standard_middleware/handle_usage_errors.rb +1 -0
- data/lib/toys/standard_middleware/set_default_descriptions.rb +19 -18
- data/lib/toys/standard_middleware/show_help.rb +19 -5
- data/lib/toys/standard_middleware/show_root_version.rb +2 -0
- data/lib/toys/standard_mixins/bundler.rb +24 -15
- data/lib/toys/standard_mixins/exec.rb +43 -34
- data/lib/toys/standard_mixins/fileutils.rb +3 -1
- data/lib/toys/standard_mixins/gems.rb +21 -17
- data/lib/toys/standard_mixins/git_cache.rb +46 -0
- data/lib/toys/standard_mixins/highline.rb +8 -8
- data/lib/toys/standard_mixins/terminal.rb +5 -5
- data/lib/toys/standard_mixins/xdg.rb +56 -0
- data/lib/toys/template.rb +11 -9
- data/lib/toys/{tool.rb → tool_definition.rb} +292 -226
- data/lib/toys/utils/completion_engine.rb +7 -2
- data/lib/toys/utils/exec.rb +162 -132
- data/lib/toys/utils/gems.rb +85 -60
- data/lib/toys/utils/git_cache.rb +813 -0
- data/lib/toys/utils/help_text.rb +117 -37
- data/lib/toys/utils/terminal.rb +11 -3
- data/lib/toys/utils/xdg.rb +293 -0
- data/lib/toys/wrappable_string.rb +9 -2
- data/lib/toys-core.rb +18 -6
- metadata +14 -7
@@ -16,8 +16,6 @@ module Toys
|
|
16
16
|
# This is a frontend for {Toys::Utils::Exec}. More information is
|
17
17
|
# available in that class's documentation.
|
18
18
|
#
|
19
|
-
# ## Features
|
20
|
-
#
|
21
19
|
# ### Controlling processes
|
22
20
|
#
|
23
21
|
# A process can be started in the *foreground* or the *background*. If you
|
@@ -149,7 +147,7 @@ module Toys
|
|
149
147
|
#
|
150
148
|
# include :exec, exit_on_nonzero_status: true
|
151
149
|
#
|
152
|
-
#
|
150
|
+
# ### Configuration Options
|
153
151
|
#
|
154
152
|
# A variety of options can be used to control subprocesses. These can be
|
155
153
|
# provided to any method that starts a subprocess. You can also set
|
@@ -231,20 +229,6 @@ module Toys
|
|
231
229
|
#
|
232
230
|
KEY = ::Object.new.freeze
|
233
231
|
|
234
|
-
on_initialize do |**opts|
|
235
|
-
require "toys/utils/exec"
|
236
|
-
context = self
|
237
|
-
opts = Exec._setup_exec_opts(opts, context)
|
238
|
-
context[KEY] = Utils::Exec.new(**opts) do |k|
|
239
|
-
case k
|
240
|
-
when :logger
|
241
|
-
context[Context::Key::LOGGER]
|
242
|
-
when :cli
|
243
|
-
context[Context::Key::CLI]
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
232
|
##
|
249
233
|
# Set default configuration options.
|
250
234
|
#
|
@@ -267,7 +251,7 @@ module Toys
|
|
267
251
|
# If the process is not set to run in the background, and a block is
|
268
252
|
# provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
|
269
253
|
#
|
270
|
-
#
|
254
|
+
# ### Examples
|
271
255
|
#
|
272
256
|
# Run a command without a shell, and print the exit code (0 for success):
|
273
257
|
#
|
@@ -303,11 +287,11 @@ module Toys
|
|
303
287
|
# If the process is not set to run in the background, and a block is
|
304
288
|
# provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
|
305
289
|
#
|
306
|
-
#
|
290
|
+
# ### Example
|
307
291
|
#
|
308
292
|
# Execute a small script with warnings
|
309
293
|
#
|
310
|
-
# exec_ruby("-w", "-e", "(1..10).each { |i| puts i }")
|
294
|
+
# exec_ruby(["-w", "-e", "(1..10).each { |i| puts i }"])
|
311
295
|
#
|
312
296
|
# @param args [String,Array<String>] The arguments to ruby.
|
313
297
|
# @param opts [keywords] The command options. See the section on
|
@@ -337,7 +321,7 @@ module Toys
|
|
337
321
|
# Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
|
338
322
|
# do not support this method because they do not support fork.
|
339
323
|
#
|
340
|
-
#
|
324
|
+
# ### Example
|
341
325
|
#
|
342
326
|
# Run a proc in a forked process.
|
343
327
|
#
|
@@ -377,7 +361,7 @@ module Toys
|
|
377
361
|
# Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
|
378
362
|
# do not support this method because they do not support fork.
|
379
363
|
#
|
380
|
-
#
|
364
|
+
# ### Example
|
381
365
|
#
|
382
366
|
# Run the "system update" tool and pass it an argument.
|
383
367
|
#
|
@@ -399,6 +383,7 @@ module Toys
|
|
399
383
|
def exec_tool(cmd, **opts, &block)
|
400
384
|
func = Exec._make_tool_caller(cmd)
|
401
385
|
opts = Exec._setup_exec_opts(opts, self)
|
386
|
+
opts = {log_cmd: "exec tool: #{cmd.inspect}"}.merge(opts)
|
402
387
|
self[KEY].exec_proc(func, **opts, &block)
|
403
388
|
end
|
404
389
|
|
@@ -424,7 +409,7 @@ module Toys
|
|
424
409
|
# run a tool that uses a different bundle. It may also be necessary on
|
425
410
|
# environments without "fork" (such as JRuby or Ruby on Windows).
|
426
411
|
#
|
427
|
-
#
|
412
|
+
# ### Example
|
428
413
|
#
|
429
414
|
# Run the "system update" tool and pass it an argument.
|
430
415
|
#
|
@@ -459,7 +444,7 @@ module Toys
|
|
459
444
|
# If a block is provided, a {Toys::Utils::Exec::Controller} will be
|
460
445
|
# yielded to it.
|
461
446
|
#
|
462
|
-
#
|
447
|
+
# ### Example
|
463
448
|
#
|
464
449
|
# Capture the output of an echo command
|
465
450
|
#
|
@@ -490,7 +475,7 @@ module Toys
|
|
490
475
|
# If a block is provided, a {Toys::Utils::Exec::Controller} will be
|
491
476
|
# yielded to it.
|
492
477
|
#
|
493
|
-
#
|
478
|
+
# ### Example
|
494
479
|
#
|
495
480
|
# Capture the output of a ruby script.
|
496
481
|
#
|
@@ -524,7 +509,7 @@ module Toys
|
|
524
509
|
# Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
|
525
510
|
# do not support this method because they do not support fork.
|
526
511
|
#
|
527
|
-
#
|
512
|
+
# ### Example
|
528
513
|
#
|
529
514
|
# Run a proc in a forked process and capture its output:
|
530
515
|
#
|
@@ -564,7 +549,7 @@ module Toys
|
|
564
549
|
# Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
|
565
550
|
# do not support this method because they do not support fork.
|
566
551
|
#
|
567
|
-
#
|
552
|
+
# ### Example
|
568
553
|
#
|
569
554
|
# Run the "system version" tool and capture its output.
|
570
555
|
#
|
@@ -612,7 +597,7 @@ module Toys
|
|
612
597
|
# run a tool that uses a different bundle. It may also be necessary on
|
613
598
|
# environments without "fork" (such as JRuby or Ruby on Windows).
|
614
599
|
#
|
615
|
-
#
|
600
|
+
# ### Example
|
616
601
|
#
|
617
602
|
# Run the "system version" tool and capture its output.
|
618
603
|
#
|
@@ -642,7 +627,7 @@ module Toys
|
|
642
627
|
# If a block is provided, a {Toys::Utils::Exec::Controller} will be
|
643
628
|
# yielded to it.
|
644
629
|
#
|
645
|
-
#
|
630
|
+
# ### Example
|
646
631
|
#
|
647
632
|
# Run a shell script
|
648
633
|
#
|
@@ -677,13 +662,17 @@ module Toys
|
|
677
662
|
0
|
678
663
|
end
|
679
664
|
|
680
|
-
##
|
665
|
+
##
|
666
|
+
# @private
|
667
|
+
#
|
681
668
|
def self._make_tool_caller(cmd)
|
682
669
|
cmd = ::Shellwords.split(cmd) if cmd.is_a?(::String)
|
683
670
|
proc { |config| ::Kernel.exit(config[:cli].run(*cmd)) }
|
684
671
|
end
|
685
672
|
|
686
|
-
##
|
673
|
+
##
|
674
|
+
# @private
|
675
|
+
#
|
687
676
|
def self._setup_exec_opts(opts, context)
|
688
677
|
count = 0
|
689
678
|
result_callback = nil
|
@@ -706,7 +695,9 @@ module Toys
|
|
706
695
|
opts
|
707
696
|
end
|
708
697
|
|
709
|
-
##
|
698
|
+
##
|
699
|
+
# @private
|
700
|
+
#
|
710
701
|
def self._interpret_e(value, context)
|
711
702
|
return nil unless value
|
712
703
|
proc do |result|
|
@@ -720,7 +711,9 @@ module Toys
|
|
720
711
|
end
|
721
712
|
end
|
722
713
|
|
723
|
-
##
|
714
|
+
##
|
715
|
+
# @private
|
716
|
+
#
|
724
717
|
def self._interpret_result_callback(value, context)
|
725
718
|
if value.is_a?(::Symbol)
|
726
719
|
context.method(value)
|
@@ -733,7 +726,9 @@ module Toys
|
|
733
726
|
end
|
734
727
|
end
|
735
728
|
|
736
|
-
##
|
729
|
+
##
|
730
|
+
# @private
|
731
|
+
#
|
737
732
|
def self._setup_clean_process(cmd)
|
738
733
|
raise ::ArgumentError, "Toys process is unknown" unless ::Toys.executable_path
|
739
734
|
cmd = ::Shellwords.split(cmd) if cmd.is_a?(::String)
|
@@ -748,6 +743,20 @@ module Toys
|
|
748
743
|
yield(cmd)
|
749
744
|
end
|
750
745
|
end
|
746
|
+
|
747
|
+
on_initialize do |**opts|
|
748
|
+
require "toys/utils/exec"
|
749
|
+
context = self
|
750
|
+
opts = Exec._setup_exec_opts(opts, context)
|
751
|
+
context[KEY] = Utils::Exec.new(**opts) do |k|
|
752
|
+
case k
|
753
|
+
when :logger
|
754
|
+
context[Context::Key::LOGGER]
|
755
|
+
when :cli
|
756
|
+
context[Context::Key::CLI]
|
757
|
+
end
|
758
|
+
end
|
759
|
+
end
|
751
760
|
end
|
752
761
|
end
|
753
762
|
end
|
@@ -25,23 +25,6 @@ module Toys
|
|
25
25
|
module Gems
|
26
26
|
include Mixin
|
27
27
|
|
28
|
-
on_include do |**opts|
|
29
|
-
@__gems_opts = opts
|
30
|
-
|
31
|
-
## @private
|
32
|
-
def self.gems
|
33
|
-
require "toys/utils/gems"
|
34
|
-
# rubocop:disable Naming/MemoizedInstanceVariableName
|
35
|
-
@__gems ||= Utils::Gems.new(**@__gems_opts)
|
36
|
-
# rubocop:enable Naming/MemoizedInstanceVariableName
|
37
|
-
end
|
38
|
-
|
39
|
-
## @private
|
40
|
-
def self.gem(name, *requirements)
|
41
|
-
gems.activate(name, *requirements)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
28
|
##
|
46
29
|
# A tool-wide instance of {Toys::Utils::Gems}.
|
47
30
|
# @return [Toys::Utils::Gems]
|
@@ -60,6 +43,27 @@ module Toys
|
|
60
43
|
def gem(name, *requirements)
|
61
44
|
self.class.gems.activate(name, *requirements)
|
62
45
|
end
|
46
|
+
|
47
|
+
on_include do |**opts|
|
48
|
+
@__gems_opts = opts
|
49
|
+
|
50
|
+
##
|
51
|
+
# @private
|
52
|
+
#
|
53
|
+
def self.gems
|
54
|
+
require "toys/utils/gems"
|
55
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
56
|
+
@__gems ||= Utils::Gems.new(**@__gems_opts)
|
57
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# @private
|
62
|
+
#
|
63
|
+
def self.gem(name, *requirements)
|
64
|
+
gems.activate(name, *requirements)
|
65
|
+
end
|
66
|
+
end
|
63
67
|
end
|
64
68
|
end
|
65
69
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Toys
|
4
|
+
module StandardMixins
|
5
|
+
##
|
6
|
+
# A mixin that provides a git cache.
|
7
|
+
#
|
8
|
+
# This mixin provides an instance of {Toys::Utils::GitCache}, providing
|
9
|
+
# cached access to files from a remote git repo.
|
10
|
+
#
|
11
|
+
# Example usage:
|
12
|
+
#
|
13
|
+
# include :git_cache
|
14
|
+
#
|
15
|
+
# def run
|
16
|
+
# # Pull and cache the HEAD commit from the Toys repo.
|
17
|
+
# dir = git_cache.find("https://github.com/dazuma/toys.git")
|
18
|
+
# # Display the contents of the readme file.
|
19
|
+
# puts File.read(File.join(dir, "README.md"))
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
module GitCache
|
23
|
+
include Mixin
|
24
|
+
|
25
|
+
##
|
26
|
+
# Context key for the GitCache object.
|
27
|
+
# @return [Object]
|
28
|
+
#
|
29
|
+
KEY = ::Object.new.freeze
|
30
|
+
|
31
|
+
##
|
32
|
+
# Access the builtin GitCache.
|
33
|
+
#
|
34
|
+
# @return [Toys::Utils::GitCache]
|
35
|
+
#
|
36
|
+
def git_cache
|
37
|
+
self[KEY]
|
38
|
+
end
|
39
|
+
|
40
|
+
on_initialize do
|
41
|
+
require "toys/utils/git_cache"
|
42
|
+
self[KEY] = Utils::GitCache.new
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -36,14 +36,6 @@ module Toys
|
|
36
36
|
#
|
37
37
|
KEY = ::Object.new.freeze
|
38
38
|
|
39
|
-
on_initialize do |*args|
|
40
|
-
require "toys/utils/gems"
|
41
|
-
Toys::Utils::Gems.activate("highline", "~> 2.0")
|
42
|
-
require "highline"
|
43
|
-
self[KEY] = ::HighLine.new(*args)
|
44
|
-
self[KEY].use_color = $stdout.tty?
|
45
|
-
end
|
46
|
-
|
47
39
|
##
|
48
40
|
# A tool-wide [HighLine](https://www.rubydoc.info/gems/highline/HighLine)
|
49
41
|
# instance
|
@@ -136,6 +128,14 @@ module Toys
|
|
136
128
|
def new_scope
|
137
129
|
highline.new_scope
|
138
130
|
end
|
131
|
+
|
132
|
+
on_initialize do |*args|
|
133
|
+
require "toys/utils/gems"
|
134
|
+
Toys::Utils::Gems.activate("highline", "~> 2.0")
|
135
|
+
require "highline"
|
136
|
+
self[KEY] = ::HighLine.new(*args)
|
137
|
+
self[KEY].use_color = $stdout.tty?
|
138
|
+
end
|
139
139
|
end
|
140
140
|
end
|
141
141
|
end
|
@@ -35,11 +35,6 @@ module Toys
|
|
35
35
|
#
|
36
36
|
KEY = ::Object.new.freeze
|
37
37
|
|
38
|
-
on_initialize do |**opts|
|
39
|
-
require "toys/utils/terminal"
|
40
|
-
self[KEY] = Utils::Terminal.new(**opts)
|
41
|
-
end
|
42
|
-
|
43
38
|
##
|
44
39
|
# A tool-wide terminal instance
|
45
40
|
# @return [Toys::Utils::Terminal]
|
@@ -139,6 +134,11 @@ module Toys
|
|
139
134
|
frame_length: frame_length, frames: frames, style: style,
|
140
135
|
&block)
|
141
136
|
end
|
137
|
+
|
138
|
+
on_initialize do |**opts|
|
139
|
+
require "toys/utils/terminal"
|
140
|
+
self[KEY] = Utils::Terminal.new(**opts)
|
141
|
+
end
|
142
142
|
end
|
143
143
|
end
|
144
144
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module Toys
|
6
|
+
module StandardMixins
|
7
|
+
##
|
8
|
+
# A mixin that provides tools for working with the XDG Base Directory
|
9
|
+
# Specification.
|
10
|
+
#
|
11
|
+
# This mixin provides an instance of {Toys::Utils::XDG}, which includes
|
12
|
+
# utility methods that locate base directories and search paths for
|
13
|
+
# application state, configuration, caches, and other data, according to
|
14
|
+
# the [XDG Base Directory Spec version
|
15
|
+
# 0.8](https://specifications.freedesktop.org/basedir-spec/0.8/).
|
16
|
+
#
|
17
|
+
# Example usage:
|
18
|
+
#
|
19
|
+
# include :xdg
|
20
|
+
#
|
21
|
+
# def run
|
22
|
+
# # Get config file paths, in order from most to least inportant
|
23
|
+
# config_files = xdg.lookup_config("my-config.toml")
|
24
|
+
# config_files.each { |path| read_my_config(path) }
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
module XDG
|
28
|
+
include Mixin
|
29
|
+
|
30
|
+
##
|
31
|
+
# Context key for the XDG object.
|
32
|
+
# @return [Object]
|
33
|
+
#
|
34
|
+
KEY = ::Object.new.freeze
|
35
|
+
|
36
|
+
##
|
37
|
+
# Access XDG utility methods.
|
38
|
+
#
|
39
|
+
# @return [Toys::Utils::XDG]
|
40
|
+
#
|
41
|
+
def xdg
|
42
|
+
self[KEY]
|
43
|
+
end
|
44
|
+
|
45
|
+
on_initialize do
|
46
|
+
require "toys/utils/xdg"
|
47
|
+
self[KEY] = Utils::XDG.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# An alternate name for the {XDG} module
|
53
|
+
#
|
54
|
+
Xdg = XDG
|
55
|
+
end
|
56
|
+
end
|
data/lib/toys/template.rb
CHANGED
@@ -10,7 +10,7 @@ module Toys
|
|
10
10
|
# Templates will often support configuration; for example the minitest
|
11
11
|
# template lets you configure the paths to the test files.
|
12
12
|
#
|
13
|
-
#
|
13
|
+
# ### Usage
|
14
14
|
#
|
15
15
|
# To create a template, define a class and include this module.
|
16
16
|
# The class defines the "configuration" of the template. If your template
|
@@ -25,7 +25,7 @@ module Toys
|
|
25
25
|
# this block are "inserted" into the user's configuration. The template
|
26
26
|
# object is passed to the block so you have access to the template options.
|
27
27
|
#
|
28
|
-
#
|
28
|
+
# ### Example
|
29
29
|
#
|
30
30
|
# This is a simple template that generates a "hello" tool. The tool simply
|
31
31
|
# prints a `"Hello, #{name}!"` greeting. The name is set as a template
|
@@ -84,13 +84,6 @@ module Toys
|
|
84
84
|
template_class
|
85
85
|
end
|
86
86
|
|
87
|
-
## @private
|
88
|
-
def self.included(mod)
|
89
|
-
return if mod.respond_to?(:on_expand)
|
90
|
-
mod.extend(ClassMethods)
|
91
|
-
mod.include(Context::Key)
|
92
|
-
end
|
93
|
-
|
94
87
|
##
|
95
88
|
# Class methods that will be added to a template class.
|
96
89
|
#
|
@@ -118,5 +111,14 @@ module Toys
|
|
118
111
|
#
|
119
112
|
attr_accessor :expansion
|
120
113
|
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# @private
|
117
|
+
#
|
118
|
+
def self.included(mod)
|
119
|
+
return if mod.respond_to?(:on_expand)
|
120
|
+
mod.extend(ClassMethods)
|
121
|
+
mod.include(Context::Key)
|
122
|
+
end
|
121
123
|
end
|
122
124
|
end
|