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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +4 -1
  5. data/docs/guide.md +1 -1
  6. data/lib/toys/acceptor.rb +10 -1
  7. data/lib/toys/arg_parser.rb +1 -0
  8. data/lib/toys/cli.rb +127 -107
  9. data/lib/toys/compat.rb +54 -3
  10. data/lib/toys/completion.rb +15 -5
  11. data/lib/toys/context.rb +22 -20
  12. data/lib/toys/core.rb +6 -2
  13. data/lib/toys/dsl/base.rb +2 -0
  14. data/lib/toys/dsl/flag.rb +23 -17
  15. data/lib/toys/dsl/flag_group.rb +11 -7
  16. data/lib/toys/dsl/positional_arg.rb +23 -13
  17. data/lib/toys/dsl/tool.rb +10 -6
  18. data/lib/toys/errors.rb +63 -8
  19. data/lib/toys/flag.rb +660 -651
  20. data/lib/toys/flag_group.rb +19 -6
  21. data/lib/toys/input_file.rb +9 -3
  22. data/lib/toys/loader.rb +129 -115
  23. data/lib/toys/middleware.rb +45 -21
  24. data/lib/toys/mixin.rb +8 -6
  25. data/lib/toys/positional_arg.rb +18 -17
  26. data/lib/toys/settings.rb +81 -67
  27. data/lib/toys/source_info.rb +33 -24
  28. data/lib/toys/standard_middleware/add_verbosity_flags.rb +2 -0
  29. data/lib/toys/standard_middleware/apply_config.rb +1 -0
  30. data/lib/toys/standard_middleware/handle_usage_errors.rb +1 -0
  31. data/lib/toys/standard_middleware/set_default_descriptions.rb +1 -0
  32. data/lib/toys/standard_middleware/show_help.rb +2 -0
  33. data/lib/toys/standard_middleware/show_root_version.rb +2 -0
  34. data/lib/toys/standard_mixins/bundler.rb +22 -14
  35. data/lib/toys/standard_mixins/exec.rb +31 -20
  36. data/lib/toys/standard_mixins/fileutils.rb +3 -1
  37. data/lib/toys/standard_mixins/gems.rb +21 -17
  38. data/lib/toys/standard_mixins/git_cache.rb +5 -7
  39. data/lib/toys/standard_mixins/highline.rb +8 -8
  40. data/lib/toys/standard_mixins/terminal.rb +5 -5
  41. data/lib/toys/standard_mixins/xdg.rb +5 -5
  42. data/lib/toys/template.rb +9 -7
  43. data/lib/toys/tool_definition.rb +209 -202
  44. data/lib/toys/utils/completion_engine.rb +7 -2
  45. data/lib/toys/utils/exec.rb +158 -127
  46. data/lib/toys/utils/gems.rb +81 -57
  47. data/lib/toys/utils/git_cache.rb +674 -45
  48. data/lib/toys/utils/help_text.rb +27 -3
  49. data/lib/toys/utils/terminal.rb +10 -2
  50. data/lib/toys/wrappable_string.rb +9 -2
  51. data/lib/toys-core.rb +14 -5
  52. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5faba9107743469c7a7092eb483b103136dda81252fb7dbf4ed9d2abadc0c9cb
4
- data.tar.gz: 7c5898c2f6c5de58c73cc99b38a00537164ceeb7575b944df857ddbed75a8d86
3
+ metadata.gz: 68a552244c25e03216c7bf958a7ccd2a35bb7fb3795a02e77c4a839b7720e258
4
+ data.tar.gz: 58513ce7d5d60646a1b9e51235d04df470ee5d9317a9a72048a8e95872227da0
5
5
  SHA512:
6
- metadata.gz: 5d6552a6c22d948d28e90ccbd6690b8eafe82c1157f1b6fea3c8eec75b22e0b3e5d81862f93cb994ae63bbfdf234e6bcf97618da4835848c3a25ada8ca76dd80
7
- data.tar.gz: f2843e6e542612b0f22b1619a02d5a9b153bf85584065dce49f520d1e190b0e81bb071378a92f296bf6fb5d1768a1489ba97c856a0757b45ea89873fb30ab504
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-2020 Daniel Azuma and the Toys contributors
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-2020 Daniel Azuma and the Toys contributors
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 argumentparsing and online help,
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
- ## @private
523
+ ##
524
+ # @private
525
+ #
517
526
  def scalarize_spec(spec, options, block)
518
527
  spec ||= block
519
528
  if options.empty?
@@ -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
- executable_name: nil,
180
- middleware_stack: nil,
181
- extra_delimiters: "",
182
- config_dir_name: nil,
183
- config_file_name: nil,
184
- index_file_name: nil,
185
- preload_file_name: nil,
186
- preload_dir_name: nil,
187
- data_dir_name: nil,
188
- lib_dir_name: nil,
189
- mixin_lookup: nil,
190
- middleware_lookup: nil,
191
- template_lookup: nil,
192
- logger_factory: nil,
193
- logger: nil,
194
- base_level: nil,
195
- error_handler: nil,
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
- default_data = {
461
- Context::Key::VERBOSITY => verbosity,
462
- Context::Key::DELEGATED_FROM => delegated_from,
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
- # Run the given tool with the given arguments.
474
- # Does not handle exceptions.
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 tool [Toys::ToolDefinition] The tool to run.
477
- # @param args [Array<String>] Command line arguments passed to the tool.
478
- # @param default_data [Hash] Initial tool context data.
479
- # @return [Integer] The resulting status code
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
- def run_tool(tool, args, default_data)
482
- arg_parser = ArgParser.new(self, tool,
483
- default_data: default_data,
484
- require_exact_flag_match: tool.exact_flag_match_required?)
485
- arg_parser.parse(args).finish
486
- context = tool.tool_class.new(arg_parser.data)
487
- tool.source_info&.apply_lib_paths
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
- ::RUBY_PLATFORM == "java"
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
- if ruby_version >= 20700
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
@@ -116,7 +116,9 @@ module Toys
116
116
  @arg_parser ||= ArgParser.new(@cli, @tool).parse(@args)
117
117
  end
118
118
 
119
- ## @private
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
- ## @private
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
- ## @private
187
+ ##
188
+ # @private
189
+ #
184
190
  def <=>(other)
185
191
  string <=> other.string
186
192
  end
187
193
 
188
- ## @private
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
- ## @private
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
@@ -9,9 +9,13 @@ module Toys
9
9
  # Current version of Toys core.
10
10
  # @return [String]
11
11
  #
12
- VERSION = "0.12.2"
12
+ VERSION = "0.13.0"
13
13
  end
14
14
 
15
- ## @private deprecated
15
+ ##
16
+ # Deprecated
17
+ #
18
+ # @private
19
+ #
16
20
  CORE_VERSION = Core::VERSION
17
21
  end
data/lib/toys/dsl/base.rb CHANGED
@@ -75,7 +75,9 @@ module Toys
75
75
  # end
76
76
  #
77
77
  class Tool < Context
78
+ ##
78
79
  # @private
80
+ #
79
81
  def self.inherited(tool_class)
80
82
  DSL::Internal.configure_class(tool_class)
81
83
  super