toys-core 0.12.2 → 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 +22 -0
- data/LICENSE.md +1 -1
- data/README.md +4 -1
- data/docs/guide.md +1 -1
- data/lib/toys/acceptor.rb +10 -1
- data/lib/toys/arg_parser.rb +1 -0
- data/lib/toys/cli.rb +127 -107
- data/lib/toys/compat.rb +54 -3
- data/lib/toys/completion.rb +15 -5
- data/lib/toys/context.rb +22 -20
- data/lib/toys/core.rb +6 -2
- data/lib/toys/dsl/base.rb +2 -0
- data/lib/toys/dsl/flag.rb +23 -17
- data/lib/toys/dsl/flag_group.rb +11 -7
- data/lib/toys/dsl/positional_arg.rb +23 -13
- data/lib/toys/dsl/tool.rb +10 -6
- data/lib/toys/errors.rb +63 -8
- data/lib/toys/flag.rb +660 -651
- data/lib/toys/flag_group.rb +19 -6
- data/lib/toys/input_file.rb +9 -3
- data/lib/toys/loader.rb +129 -115
- data/lib/toys/middleware.rb +45 -21
- data/lib/toys/mixin.rb +8 -6
- data/lib/toys/positional_arg.rb +18 -17
- data/lib/toys/settings.rb +81 -67
- data/lib/toys/source_info.rb +33 -24
- data/lib/toys/standard_middleware/add_verbosity_flags.rb +2 -0
- data/lib/toys/standard_middleware/apply_config.rb +1 -0
- data/lib/toys/standard_middleware/handle_usage_errors.rb +1 -0
- data/lib/toys/standard_middleware/set_default_descriptions.rb +1 -0
- data/lib/toys/standard_middleware/show_help.rb +2 -0
- data/lib/toys/standard_middleware/show_root_version.rb +2 -0
- data/lib/toys/standard_mixins/bundler.rb +22 -14
- data/lib/toys/standard_mixins/exec.rb +31 -20
- 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 +5 -7
- 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 +5 -5
- data/lib/toys/template.rb +9 -7
- data/lib/toys/tool_definition.rb +209 -202
- data/lib/toys/utils/completion_engine.rb +7 -2
- data/lib/toys/utils/exec.rb +158 -127
- data/lib/toys/utils/gems.rb +81 -57
- data/lib/toys/utils/git_cache.rb +674 -45
- data/lib/toys/utils/help_text.rb +27 -3
- data/lib/toys/utils/terminal.rb +10 -2
- data/lib/toys/wrappable_string.rb +9 -2
- data/lib/toys-core.rb +14 -5
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68a552244c25e03216c7bf958a7ccd2a35bb7fb3795a02e77c4a839b7720e258
|
4
|
+
data.tar.gz: 58513ce7d5d60646a1b9e51235d04df470ee5d9317a9a72048a8e95872227da0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 299c193de07d0802046029c7b305a1e4cecac715eee32d259a917b6ecc2505975ba10a2aca90b510036076d9f32b58849a02381ae61837336eee5361cd2126ea
|
7
|
+
data.tar.gz: b42a4d81db4a71a136deafd4a62f0e7087325097a1c3e7473a5b7edda699b08ee1c8d81377765a70d8a18fd0a2693874781418f9953ca52f92cced670bec1421
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### v0.13.0 / 2022-02-08
|
4
|
+
|
5
|
+
Toys-Core 0.13.0 is a major release with significant improvements to the git cache, along with compatibility improvements and bug fixes.
|
6
|
+
|
7
|
+
New functionality:
|
8
|
+
|
9
|
+
* The `load_git` directive and the underlying `Toys::Utils::GitCache` class now support updating from git based on cache age.
|
10
|
+
* The `Toys::Utils::GitCache` class supports copying git content into a provided directory, querying repo information, and deleting cache data.
|
11
|
+
* The `Toys::Utils::GitCache` class makes files read-only, to help prevent clients from interfering with one another.
|
12
|
+
* The `:terminal` mixin and the underlying `Toys::Utils::Terminal` class now honor the `NO_COLOR` environment variable.
|
13
|
+
* Added `Toys::CLI#load_tool`, which is useful for testing tools.
|
14
|
+
|
15
|
+
Fixes and compatibility updates:
|
16
|
+
|
17
|
+
* Bundler install/updates are now spawned in subprocesses for compatibility with bundler 2.3. The bundler integration also now requires bundler 2.2 or later.
|
18
|
+
* The `exec_tool` and `exec_proc` methods in the `:exec` mixin now log their execution in the same way as other exec functions.
|
19
|
+
* Minor compatibility fixes to provide partial support for TruffleRuby.
|
20
|
+
|
21
|
+
Other notes:
|
22
|
+
|
23
|
+
* The internal GitCache representation has changed significantly to support additional features and improve robustness and performance. This will force existing caches to update, but should not break existing usage.
|
24
|
+
|
3
25
|
### v0.12.2 / 2021-08-30
|
4
26
|
|
5
27
|
* FIXED: Tool context inspect string is no longer overwhelmingly long
|
data/LICENSE.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# License
|
2
2
|
|
3
|
-
Copyright 2019-
|
3
|
+
Copyright 2019-2022 Daniel Azuma and the Toys contributors
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -39,6 +39,9 @@ Toys-Core requires Ruby 2.4 or later.
|
|
39
39
|
Most parts of Toys-Core work on JRuby. However, JRuby is not recommended
|
40
40
|
because of JVM boot latency, lack of support for Kernel#fork, and other issues.
|
41
41
|
|
42
|
+
Most parts of Toys-Core work on TruffleRuby. However, TruffleRuby is not
|
43
|
+
recommended because it has a few known bugs that affect Toys.
|
44
|
+
|
42
45
|
### Create a new executable
|
43
46
|
|
44
47
|
We'll start by creating an executable Ruby script. Using your favorite text
|
@@ -338,7 +341,7 @@ templates, and middleware, in the
|
|
338
341
|
|
339
342
|
## License
|
340
343
|
|
341
|
-
Copyright 2019-
|
344
|
+
Copyright 2019-2022 Daniel Azuma and the Toys contributors
|
342
345
|
|
343
346
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
344
347
|
of this software and associated documentation files (the "Software"), to deal
|
data/docs/guide.md
CHANGED
@@ -31,7 +31,7 @@ sophisticated command line tools.
|
|
31
31
|
|
32
32
|
Toys-Core is a command line *framework* in the traditional sense. It is
|
33
33
|
intended to be used to write custom command line executables in Ruby. The
|
34
|
-
framework provides common facilities such as
|
34
|
+
framework provides common facilities such as argument parsing and online help,
|
35
35
|
while your executable chooses and configures those facilities, and implements
|
36
36
|
the actual behavior.
|
37
37
|
|
data/lib/toys/acceptor.rb
CHANGED
@@ -178,6 +178,7 @@ module Toys
|
|
178
178
|
|
179
179
|
##
|
180
180
|
# Overrides {Toys::Acceptor::Base#match} to use the given function.
|
181
|
+
#
|
181
182
|
# @private
|
182
183
|
#
|
183
184
|
def match(str)
|
@@ -188,6 +189,7 @@ module Toys
|
|
188
189
|
##
|
189
190
|
# Overrides {Toys::Acceptor::Base#convert} to use the given function's
|
190
191
|
# result.
|
192
|
+
#
|
191
193
|
# @private
|
192
194
|
#
|
193
195
|
def convert(_str, result)
|
@@ -234,6 +236,7 @@ module Toys
|
|
234
236
|
|
235
237
|
##
|
236
238
|
# Overrides {Toys::Acceptor::Base#match} to use the given regex.
|
239
|
+
#
|
237
240
|
# @private
|
238
241
|
#
|
239
242
|
def match(str)
|
@@ -242,6 +245,7 @@ module Toys
|
|
242
245
|
|
243
246
|
##
|
244
247
|
# Overrides {Toys::Acceptor::Base#convert} to use the given converter.
|
248
|
+
#
|
245
249
|
# @private
|
246
250
|
#
|
247
251
|
def convert(str, *extra)
|
@@ -285,6 +289,7 @@ module Toys
|
|
285
289
|
|
286
290
|
##
|
287
291
|
# Overrides {Toys::Acceptor::Base#match} to find the value.
|
292
|
+
#
|
288
293
|
# @private
|
289
294
|
#
|
290
295
|
def match(str)
|
@@ -294,6 +299,7 @@ module Toys
|
|
294
299
|
##
|
295
300
|
# Overrides {Toys::Acceptor::Base#convert} to return the actual enum
|
296
301
|
# element.
|
302
|
+
#
|
297
303
|
# @private
|
298
304
|
#
|
299
305
|
def convert(_str, elem)
|
@@ -303,6 +309,7 @@ module Toys
|
|
303
309
|
##
|
304
310
|
# Overrides {Toys::Acceptor::Base#suggestions} to return close matches
|
305
311
|
# from the enum.
|
312
|
+
#
|
306
313
|
# @private
|
307
314
|
#
|
308
315
|
def suggestions(str)
|
@@ -513,7 +520,9 @@ module Toys
|
|
513
520
|
internal_create(spec, options, block)
|
514
521
|
end
|
515
522
|
|
516
|
-
##
|
523
|
+
##
|
524
|
+
# @private
|
525
|
+
#
|
517
526
|
def scalarize_spec(spec, options, block)
|
518
527
|
spec ||= block
|
519
528
|
if options.empty?
|
data/lib/toys/arg_parser.rb
CHANGED
@@ -417,6 +417,7 @@ module Toys
|
|
417
417
|
|
418
418
|
REMAINING_HANDLER = ->(val, prev) { prev.is_a?(::Array) ? prev << val : [val] }
|
419
419
|
ARG_HANDLER = ->(val, _prev) { val }
|
420
|
+
private_constant :REMAINING_HANDLER, :ARG_HANDLER
|
420
421
|
|
421
422
|
def initial_data(cli, tool, default_data)
|
422
423
|
data = {
|
data/lib/toys/cli.rb
CHANGED
@@ -175,26 +175,24 @@ module Toys
|
|
175
175
|
# Optional. If not provided, lib directories are disabled.
|
176
176
|
# Note: the standard toys executable sets this to `".lib"`.
|
177
177
|
#
|
178
|
-
def initialize( # rubocop:disable Metrics/MethodLength
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
completion: nil
|
197
|
-
)
|
178
|
+
def initialize(executable_name: nil, # rubocop:disable Metrics/MethodLength
|
179
|
+
middleware_stack: nil,
|
180
|
+
extra_delimiters: "",
|
181
|
+
config_dir_name: nil,
|
182
|
+
config_file_name: nil,
|
183
|
+
index_file_name: nil,
|
184
|
+
preload_file_name: nil,
|
185
|
+
preload_dir_name: nil,
|
186
|
+
data_dir_name: nil,
|
187
|
+
lib_dir_name: nil,
|
188
|
+
mixin_lookup: nil,
|
189
|
+
middleware_lookup: nil,
|
190
|
+
template_lookup: nil,
|
191
|
+
logger_factory: nil,
|
192
|
+
logger: nil,
|
193
|
+
base_level: nil,
|
194
|
+
error_handler: nil,
|
195
|
+
completion: nil)
|
198
196
|
@executable_name = executable_name || ::File.basename($PROGRAM_NAME)
|
199
197
|
@middleware_stack = middleware_stack || CLI.default_middleware_stack
|
200
198
|
@mixin_lookup = mixin_lookup || CLI.default_mixin_lookup
|
@@ -446,6 +444,9 @@ module Toys
|
|
446
444
|
# run and what arguments to pass to it. You may pass either a single
|
447
445
|
# array of strings, or a series of string arguments.
|
448
446
|
# @param verbosity [Integer] Initial verbosity. Default is 0.
|
447
|
+
# @param delegated_from [Toys::Context] The context from which this
|
448
|
+
# execution is delegated. Optional. Should be set only if this is a
|
449
|
+
# delegated execution.
|
449
450
|
#
|
450
451
|
# @return [Integer] The resulting process status code (i.e. 0 for success).
|
451
452
|
#
|
@@ -457,101 +458,32 @@ module Toys
|
|
457
458
|
"Error during tool execution!", tool.source_info&.source_path,
|
458
459
|
tool_name: tool.full_name, tool_args: remaining
|
459
460
|
) do
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
run_tool(tool, remaining, default_data)
|
461
|
+
context = build_context(tool, remaining,
|
462
|
+
verbosity: verbosity,
|
463
|
+
delegated_from: delegated_from)
|
464
|
+
execute_tool(tool, context, &:run)
|
465
465
|
end
|
466
466
|
rescue ContextualError, ::Interrupt => e
|
467
467
|
@error_handler.call(e).to_i
|
468
468
|
end
|
469
469
|
|
470
|
-
private
|
471
|
-
|
472
470
|
##
|
473
|
-
#
|
474
|
-
#
|
471
|
+
# Prepare a tool to be run, but just execute the given block rather than
|
472
|
+
# performing a full run of the tool. This is intended for testing tools.
|
473
|
+
# Unlike {#run}, this does not catch errors and perform error handling.
|
475
474
|
#
|
476
|
-
# @param
|
477
|
-
#
|
478
|
-
#
|
479
|
-
# @
|
475
|
+
# @param args [String...] Command line arguments specifying which tool to
|
476
|
+
# run and what arguments to pass to it. You may pass either a single
|
477
|
+
# array of strings, or a series of string arguments.
|
478
|
+
# @yieldparam context [Toys::Context] Yields the tool context.
|
480
479
|
#
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
context
|
487
|
-
|
488
|
-
tool.run_initializers(context)
|
489
|
-
|
490
|
-
cur_logger = context[Context::Key::LOGGER]
|
491
|
-
if cur_logger
|
492
|
-
original_level = cur_logger.level
|
493
|
-
cur_logger.level = (base_level || original_level) - context[Context::Key::VERBOSITY].to_i
|
494
|
-
end
|
495
|
-
begin
|
496
|
-
execute_tool_in_context(context, tool)
|
497
|
-
ensure
|
498
|
-
cur_logger.level = original_level if cur_logger
|
499
|
-
end
|
500
|
-
end
|
501
|
-
|
502
|
-
def execute_tool_in_context(context, tool)
|
503
|
-
executor = proc do
|
504
|
-
begin
|
505
|
-
if !context[Context::Key::USAGE_ERRORS].empty?
|
506
|
-
handle_usage_errors(context, tool)
|
507
|
-
elsif !tool.runnable?
|
508
|
-
raise NotRunnableError, "No implementation for tool #{tool.display_name.inspect}"
|
509
|
-
else
|
510
|
-
context.run
|
511
|
-
end
|
512
|
-
rescue ::Interrupt => e
|
513
|
-
raise e unless tool.handles_interrupts?
|
514
|
-
handle_interrupt(context, tool.interrupt_handler, e)
|
515
|
-
end
|
516
|
-
end
|
517
|
-
tool.built_middleware.reverse_each do |middleware|
|
518
|
-
executor = make_executor(middleware, context, executor)
|
519
|
-
end
|
520
|
-
catch(:result) do
|
521
|
-
executor.call
|
522
|
-
0
|
523
|
-
end
|
524
|
-
end
|
525
|
-
|
526
|
-
def handle_usage_errors(context, tool)
|
527
|
-
usage_errors = context[Context::Key::USAGE_ERRORS]
|
528
|
-
handler = tool.usage_error_handler
|
529
|
-
raise ArgParsingError, usage_errors if handler.nil?
|
530
|
-
handler = context.method(handler).to_proc if handler.is_a?(::Symbol)
|
531
|
-
if handler.arity.zero?
|
532
|
-
context.instance_exec(&handler)
|
533
|
-
else
|
534
|
-
context.instance_exec(usage_errors, &handler)
|
535
|
-
end
|
536
|
-
end
|
537
|
-
|
538
|
-
def handle_interrupt(context, handler, exception)
|
539
|
-
handler = context.method(handler).to_proc if handler.is_a?(::Symbol)
|
540
|
-
if handler.arity.zero?
|
541
|
-
context.instance_exec(&handler)
|
542
|
-
else
|
543
|
-
context.instance_exec(exception, &handler)
|
544
|
-
end
|
545
|
-
rescue ::Interrupt => e
|
546
|
-
raise e if e.equal?(exception)
|
547
|
-
handle_interrupt(context, handler, e)
|
548
|
-
end
|
549
|
-
|
550
|
-
def make_executor(middleware, context, next_executor)
|
551
|
-
if middleware.respond_to?(:run)
|
552
|
-
proc { middleware.run(context, &next_executor) }
|
553
|
-
else
|
554
|
-
next_executor
|
480
|
+
# @return [Object] The value returned from the block.
|
481
|
+
#
|
482
|
+
def load_tool(*args)
|
483
|
+
tool, remaining = @loader.lookup(args.flatten)
|
484
|
+
context = build_context(tool, remaining)
|
485
|
+
execute_tool(tool, context) do |ctx|
|
486
|
+
ctx.exit(yield ctx)
|
555
487
|
end
|
556
488
|
end
|
557
489
|
|
@@ -757,5 +689,93 @@ module Toys
|
|
757
689
|
"#{styled_header} #{msg}\n"
|
758
690
|
end
|
759
691
|
end
|
692
|
+
|
693
|
+
private
|
694
|
+
|
695
|
+
def build_context(tool, args, verbosity: 0, delegated_from: nil)
|
696
|
+
default_data = {
|
697
|
+
Context::Key::VERBOSITY => verbosity,
|
698
|
+
Context::Key::DELEGATED_FROM => delegated_from,
|
699
|
+
}
|
700
|
+
arg_parser = ArgParser.new(self, tool,
|
701
|
+
default_data: default_data,
|
702
|
+
require_exact_flag_match: tool.exact_flag_match_required?)
|
703
|
+
arg_parser.parse(args).finish
|
704
|
+
tool.tool_class.new(arg_parser.data)
|
705
|
+
end
|
706
|
+
|
707
|
+
def execute_tool(tool, context)
|
708
|
+
tool.source_info&.apply_lib_paths
|
709
|
+
tool.run_initializers(context)
|
710
|
+
cur_logger = context[Context::Key::LOGGER]
|
711
|
+
if cur_logger
|
712
|
+
original_level = cur_logger.level
|
713
|
+
cur_logger.level = (base_level || original_level) - context[Context::Key::VERBOSITY].to_i
|
714
|
+
end
|
715
|
+
begin
|
716
|
+
executor = build_executor(tool, context) do
|
717
|
+
yield context
|
718
|
+
end
|
719
|
+
catch(:result) do
|
720
|
+
executor.call
|
721
|
+
0
|
722
|
+
end
|
723
|
+
ensure
|
724
|
+
cur_logger.level = original_level if cur_logger
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
728
|
+
def build_executor(tool, context)
|
729
|
+
executor = proc do
|
730
|
+
begin
|
731
|
+
if !context[Context::Key::USAGE_ERRORS].empty?
|
732
|
+
handle_usage_errors(context, tool)
|
733
|
+
elsif !tool.runnable?
|
734
|
+
raise NotRunnableError, "No implementation for tool #{tool.display_name.inspect}"
|
735
|
+
else
|
736
|
+
yield
|
737
|
+
end
|
738
|
+
rescue ::Interrupt => e
|
739
|
+
raise e unless tool.handles_interrupts?
|
740
|
+
handle_interrupt(context, tool.interrupt_handler, e)
|
741
|
+
end
|
742
|
+
end
|
743
|
+
tool.built_middleware.reverse_each do |middleware|
|
744
|
+
executor = make_executor(middleware, context, executor)
|
745
|
+
end
|
746
|
+
executor
|
747
|
+
end
|
748
|
+
|
749
|
+
def handle_usage_errors(context, tool)
|
750
|
+
usage_errors = context[Context::Key::USAGE_ERRORS]
|
751
|
+
handler = tool.usage_error_handler
|
752
|
+
raise ArgParsingError, usage_errors if handler.nil?
|
753
|
+
handler = context.method(handler).to_proc if handler.is_a?(::Symbol)
|
754
|
+
if handler.arity.zero?
|
755
|
+
context.instance_exec(&handler)
|
756
|
+
else
|
757
|
+
context.instance_exec(usage_errors, &handler)
|
758
|
+
end
|
759
|
+
end
|
760
|
+
|
761
|
+
def handle_interrupt(context, handler, exception)
|
762
|
+
handler = context.method(handler).to_proc if handler.is_a?(::Symbol)
|
763
|
+
if handler.arity.zero?
|
764
|
+
context.instance_exec(&handler)
|
765
|
+
else
|
766
|
+
context.instance_exec(exception, &handler)
|
767
|
+
end
|
768
|
+
rescue ::Interrupt => e
|
769
|
+
raise e if e.equal?(exception)
|
770
|
+
handle_interrupt(context, handler, e)
|
771
|
+
end
|
772
|
+
|
773
|
+
def make_executor(middleware, context, next_executor)
|
774
|
+
if middleware.respond_to?(:run)
|
775
|
+
proc { middleware.run(context, &next_executor) }
|
776
|
+
else
|
777
|
+
next_executor
|
778
|
+
end
|
779
|
+
end
|
760
780
|
end
|
761
781
|
end
|
data/lib/toys/compat.rb
CHANGED
@@ -5,28 +5,44 @@ require "rbconfig"
|
|
5
5
|
module Toys
|
6
6
|
##
|
7
7
|
# Compatibility wrappers for older Ruby versions.
|
8
|
+
#
|
8
9
|
# @private
|
9
10
|
#
|
10
11
|
module Compat
|
11
12
|
parts = ::RUBY_VERSION.split(".")
|
12
13
|
ruby_version = parts[0].to_i * 10000 + parts[1].to_i * 100 + parts[2].to_i
|
13
14
|
|
15
|
+
##
|
14
16
|
# @private
|
17
|
+
#
|
15
18
|
def self.jruby?
|
16
|
-
::
|
19
|
+
::RUBY_ENGINE == "jruby"
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# @private
|
24
|
+
#
|
25
|
+
def self.truffleruby?
|
26
|
+
::RUBY_ENGINE == "truffleruby"
|
17
27
|
end
|
18
28
|
|
29
|
+
##
|
19
30
|
# @private
|
31
|
+
#
|
20
32
|
def self.windows?
|
21
33
|
::RbConfig::CONFIG["host_os"] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
22
34
|
end
|
23
35
|
|
36
|
+
##
|
24
37
|
# @private
|
38
|
+
#
|
25
39
|
def self.allow_fork?
|
26
|
-
!jruby? && !windows?
|
40
|
+
!jruby? && !truffleruby? && !windows?
|
27
41
|
end
|
28
42
|
|
43
|
+
##
|
29
44
|
# @private
|
45
|
+
#
|
30
46
|
def self.supports_suggestions?
|
31
47
|
unless defined?(@supports_suggestions)
|
32
48
|
begin
|
@@ -44,7 +60,9 @@ module Toys
|
|
44
60
|
@supports_suggestions
|
45
61
|
end
|
46
62
|
|
63
|
+
##
|
47
64
|
# @private
|
65
|
+
#
|
48
66
|
def self.suggestions(word, list)
|
49
67
|
if supports_suggestions?
|
50
68
|
::DidYouMean::SpellChecker.new(dictionary: list).correct(word)
|
@@ -55,26 +73,53 @@ module Toys
|
|
55
73
|
|
56
74
|
# The :base argument to Dir.glob requires Ruby 2.5 or later.
|
57
75
|
if ruby_version >= 20500
|
76
|
+
##
|
58
77
|
# @private
|
78
|
+
#
|
59
79
|
def self.glob_in_dir(glob, dir)
|
60
80
|
::Dir.glob(glob, base: dir)
|
61
81
|
end
|
62
82
|
else
|
83
|
+
##
|
63
84
|
# @private
|
85
|
+
#
|
64
86
|
def self.glob_in_dir(glob, dir)
|
65
87
|
::Dir.chdir(dir) { ::Dir.glob(glob) }
|
66
88
|
end
|
67
89
|
end
|
68
90
|
|
91
|
+
# Dir.children requires Ruby 2.5 or later.
|
92
|
+
if ruby_version >= 20500
|
93
|
+
##
|
94
|
+
# @private
|
95
|
+
#
|
96
|
+
def self.dir_children(dir)
|
97
|
+
::Dir.children(dir)
|
98
|
+
end
|
99
|
+
else
|
100
|
+
##
|
101
|
+
# @private
|
102
|
+
#
|
103
|
+
def self.dir_children(dir)
|
104
|
+
::Dir.entries(dir) - [".", ".."]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
69
108
|
# Due to a bug in Ruby < 2.7, passing an empty **kwargs splat to
|
70
109
|
# initialize will fail if there are no formal keyword args.
|
71
|
-
|
110
|
+
# This also hits TruffleRuby
|
111
|
+
# (see https://github.com/oracle/truffleruby/issues/2567)
|
112
|
+
if ruby_version >= 20700 && !truffleruby?
|
113
|
+
##
|
72
114
|
# @private
|
115
|
+
#
|
73
116
|
def self.instantiate(klass, args, kwargs, block)
|
74
117
|
klass.new(*args, **kwargs, &block)
|
75
118
|
end
|
76
119
|
else
|
120
|
+
##
|
77
121
|
# @private
|
122
|
+
#
|
78
123
|
def self.instantiate(klass, args, kwargs, block)
|
79
124
|
formals = klass.instance_method(:initialize).parameters
|
80
125
|
if kwargs.empty? && formals.all? { |arg| arg.first != :key && arg.first != :keyrest }
|
@@ -88,17 +133,23 @@ module Toys
|
|
88
133
|
# File.absolute_path? requires Ruby 2.7 or later. For earlier Rubies, use
|
89
134
|
# an ad-hoc mechanism.
|
90
135
|
if ruby_version >= 20700
|
136
|
+
##
|
91
137
|
# @private
|
138
|
+
#
|
92
139
|
def self.absolute_path?(path)
|
93
140
|
::File.absolute_path?(path)
|
94
141
|
end
|
95
142
|
elsif ::Dir.getwd =~ /^[a-zA-Z]:/
|
143
|
+
##
|
96
144
|
# @private
|
145
|
+
#
|
97
146
|
def self.absolute_path?(path)
|
98
147
|
/^[a-zA-Z]:/.match?(path)
|
99
148
|
end
|
100
149
|
else
|
150
|
+
##
|
101
151
|
# @private
|
152
|
+
#
|
102
153
|
def self.absolute_path?(path)
|
103
154
|
path.start_with?("/")
|
104
155
|
end
|
data/lib/toys/completion.rb
CHANGED
@@ -116,7 +116,9 @@ module Toys
|
|
116
116
|
@arg_parser ||= ArgParser.new(@cli, @tool).parse(@args)
|
117
117
|
end
|
118
118
|
|
119
|
-
##
|
119
|
+
##
|
120
|
+
# @private
|
121
|
+
#
|
120
122
|
def inspect
|
121
123
|
"<Toys::Completion::Context previous=#{previous_words.inspect}" \
|
122
124
|
" prefix=#{fragment_prefix.inspect} fragment=#{fragment.inspect}>"
|
@@ -175,17 +177,23 @@ module Toys
|
|
175
177
|
!@partial
|
176
178
|
end
|
177
179
|
|
178
|
-
##
|
180
|
+
##
|
181
|
+
# @private
|
182
|
+
#
|
179
183
|
def eql?(other)
|
180
184
|
other.is_a?(Candidate) && other.string.eql?(string) && other.partial? == @partial
|
181
185
|
end
|
182
186
|
|
183
|
-
##
|
187
|
+
##
|
188
|
+
# @private
|
189
|
+
#
|
184
190
|
def <=>(other)
|
185
191
|
string <=> other.string
|
186
192
|
end
|
187
193
|
|
188
|
-
##
|
194
|
+
##
|
195
|
+
# @private
|
196
|
+
#
|
189
197
|
def hash
|
190
198
|
string.hash ^ (partial? ? 1 : 0)
|
191
199
|
end
|
@@ -426,7 +434,9 @@ module Toys
|
|
426
434
|
end
|
427
435
|
end
|
428
436
|
|
429
|
-
##
|
437
|
+
##
|
438
|
+
# @private
|
439
|
+
#
|
430
440
|
def self.scalarize_spec(spec, options, block)
|
431
441
|
spec ||= block
|
432
442
|
if options.empty?
|
data/lib/toys/context.rb
CHANGED
@@ -133,26 +133,6 @@ module Toys
|
|
133
133
|
VERBOSITY = ::Object.new.freeze
|
134
134
|
end
|
135
135
|
|
136
|
-
##
|
137
|
-
# Create a Context object. Applications generally will not need to create
|
138
|
-
# these objects directly; they are created by the tool when it is preparing
|
139
|
-
# for execution.
|
140
|
-
#
|
141
|
-
# @private
|
142
|
-
#
|
143
|
-
# @param data [Hash]
|
144
|
-
#
|
145
|
-
def initialize(data)
|
146
|
-
@__data = data
|
147
|
-
end
|
148
|
-
|
149
|
-
# @private
|
150
|
-
def inspect
|
151
|
-
name = Array(@__data[Key::TOOL_NAME]).join(" ")
|
152
|
-
id = object_id.to_s(16)
|
153
|
-
"#<Toys::Context id=0x#{id} #{name}>"
|
154
|
-
end
|
155
|
-
|
156
136
|
##
|
157
137
|
# The raw arguments passed to the tool, as an array of strings.
|
158
138
|
# This does not include the tool name itself.
|
@@ -342,5 +322,27 @@ module Toys
|
|
342
322
|
def self.exit(code = 0)
|
343
323
|
throw :result, code
|
344
324
|
end
|
325
|
+
|
326
|
+
##
|
327
|
+
# Create a Context object. Applications generally will not need to create
|
328
|
+
# these objects directly; they are created by the tool when it is preparing
|
329
|
+
# for execution.
|
330
|
+
#
|
331
|
+
# @param data [Hash]
|
332
|
+
#
|
333
|
+
# @private
|
334
|
+
#
|
335
|
+
def initialize(data)
|
336
|
+
@__data = data
|
337
|
+
end
|
338
|
+
|
339
|
+
##
|
340
|
+
# @private
|
341
|
+
#
|
342
|
+
def inspect
|
343
|
+
name = Array(@__data[Key::TOOL_NAME]).join(" ")
|
344
|
+
id = object_id.to_s(16)
|
345
|
+
"#<Toys::Context id=0x#{id} #{name}>"
|
346
|
+
end
|
345
347
|
end
|
346
348
|
end
|
data/lib/toys/core.rb
CHANGED