toys-core 0.11.5 → 0.13.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 +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
|