toys-core 0.15.6 → 0.17.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7afb8f468a42a9d5eb626646212238c656e9be93d7a29601631f4e3059975eaf
4
- data.tar.gz: d1b66149b911a8f4a9eab94c459f15cc7400ee871f8f3db1f473d7eddbd2ba61
3
+ metadata.gz: be1392e6cb8f49c19e9472449943cf873209b939d11cdc1e788bb58a1083c013
4
+ data.tar.gz: d78818495765389e99111032e863dc21d4fa982dfde07780a5b1ff9cc96743df
5
5
  SHA512:
6
- metadata.gz: ec09f204706004b5d6a914c1b2b1eabaaa0bd3d7accbbde8fe9e5d00aae3fba389676400b54abff33fb7cb79f5cb530577d099d0095838523ce9165b6659c52a
7
- data.tar.gz: f47170aecd0ffe9072a6c022a9def134e88114d52c8d8f57fdc4b11aeae68971bb7ee0ad7234ddc7df8f41d2c788e2f723a241f4fb0f0dd67c62281e3a2a6da4
6
+ metadata.gz: 63ca5e62ed30e068d7b75a0b08e3916fc19466d92ca165d52f8f333e9538f96358027fdd676690042c5eb55d2e2569c3c1a8b8d9c32dd33f7ec3d4036230bc81
7
+ data.tar.gz: 61821ef2ffde83d82469c6a8d38ba092f1efc2a3254a1f848d877fda09a888fc932274e27c742c53d0480a55abc1b49fc6266359ceeca31e8851e16dac3ce0e8
data/CHANGELOG.md CHANGED
@@ -1,8 +1,30 @@
1
1
  # Release History
2
2
 
3
+ ### v0.17.0 / 2025-11-07
4
+
5
+ Toys-Core 0.17 supports several significant new pieces of functionality:
6
+
7
+ * Support for loading tools from Rubygems. The load_gem directive loads tools from the "toys" directory in a gem, installing the gem if necessary. This makes it easy to distribute tools, securely and versioned, as gems.
8
+ * Flag handlers can now take an optional third argument, the entire options hash. This enables significantly more powerful behavior during flag parsing, such as letting flags affect the behavior of other flags.
9
+
10
+ Additional new features:
11
+
12
+ * When using the :gems mixin, you can now specify installation options such as on_missing not only when you include the mixin, but also when you declare the gem.
13
+ * Added support for an environment variable `TOYS_GIT_CACHE_WRITABLE` to disable the read-only behavior of git cache sources. This improves compatibility with environments that want to delete caches.
14
+
15
+ Other fixes and documentation:
16
+
17
+ * Added the standard logger gem to the toys-core dependencies to silence Ruby 3.5 warnings.
18
+ * Updated the user guide to cover new features and fix some internal links
19
+
20
+ ### v0.16.0 / 2025-10-31
21
+
22
+ * ADDED: Updated minimum Ruby version to 2.7
23
+ * FIXED: ToolDefinition#includes_arguments no longer returns true if only default data is set
24
+
3
25
  ### v0.15.6 / 2024-05-15
4
26
 
5
- * FIXED: Fixed argument parsing to allow a flag value with a newline delimited by =
27
+ * FIXED: Fixed argument parsing so flags with value delimited by "=" will support values containing newlines
6
28
 
7
29
  ### v0.15.5 / 2024-01-31
8
30
 
data/README.md CHANGED
@@ -338,7 +338,7 @@ Detailed usage information can be found in the
338
338
 
339
339
  ## System requirements
340
340
 
341
- Toys-Core requires Ruby 2.4 or later.
341
+ Toys-Core requires Ruby 2.7 or later.
342
342
 
343
343
  Most parts of Toys-Core work on JRuby. However, JRuby is not recommended
344
344
  because of JVM boot latency, lack of support for Kernel#fork, and other issues.
@@ -348,7 +348,7 @@ recommended because it has a few known bugs that affect Toys.
348
348
 
349
349
  ## License
350
350
 
351
- Copyright 2019-2023 Daniel Azuma and the Toys contributors
351
+ Copyright 2019-2025 Daniel Azuma and the Toys contributors
352
352
 
353
353
  Permission is hereby granted, free of charge, to any person obtaining a copy
354
354
  of this software and associated documentation files (the "Software"), to deal
data/docs/guide.md CHANGED
@@ -159,7 +159,7 @@ If only `foo` is requested, the loader will execute the `tool "foo" do` block
159
159
  to get that tool definition, but will not execute the `tool "bar" do` block.
160
160
 
161
161
  We will discuss more about the features of the loader below in the section on
162
- [defining functionality](#Defining_functionality).
162
+ [defining functionality](#defining-functionality).
163
163
 
164
164
  #### Building context
165
165
 
@@ -209,16 +209,16 @@ Generally, you control CLI features by passing arguments to its constructor.
209
209
  These features include:
210
210
 
211
211
  * How to find toys files and related code and data. See the section on
212
- [defining functionality](#Defining_functionality).
212
+ [defining functionality](#defining-functionality).
213
213
  * Middleware, providing common behavior for all tools. See the section on
214
- [customizing the middleware stack](#Customizing_default_behavior).
214
+ [customizing the middleware stack](#customizing-default-behavior).
215
215
  * Common mixins and templates available to all tools. See the section on
216
- [how to define mixins and templates](#Defining_mixins_and_templates).
216
+ [how to define mixins and templates](#defining-mixins-and-templates).
217
217
  * How logs, errors, and signals are reported. See the section on
218
- [customizing tool output](#Customizing_tool_output).
218
+ [customizing tool output](#customizing-tool-output).
219
219
  * How the executable interacts with the shell, including setting up tab
220
220
  completion. See the
221
- [corresponding section](#Shell_and_command_line_integration).
221
+ [corresponding section](#shell-and-command-line-integration).
222
222
 
223
223
  Each of the actual parameters is covered in detail in the documentation for
224
224
  {Toys::CLI#initialize}. The configuration of a CLI cannot be changed once the
@@ -663,7 +663,7 @@ execute.
663
663
  # This is a context key that will be used to store the "--show-timing"
664
664
  # flag state. We can use `Object.new` to ensure that the key is unique
665
665
  # across other middlewares and tool definitions.
666
- KEY = Object.new
666
+ KEY = Object.new.freeze
667
667
 
668
668
  # This method intercepts tool configuration. We use it to add a flag that
669
669
  # enables timing display.
@@ -416,7 +416,7 @@ module Toys
416
416
  private
417
417
 
418
418
  REMAINING_HANDLER = ->(val, prev) { prev.is_a?(::Array) ? prev << val : [val] }
419
- ARG_HANDLER = ->(val, _prev) { val }
419
+ ARG_HANDLER = ->(val) { val }
420
420
  private_constant :REMAINING_HANDLER, :ARG_HANDLER
421
421
 
422
422
  def initial_data(cli, tool, default_data)
@@ -465,7 +465,7 @@ module Toys
465
465
 
466
466
  def handle_single_flags(str)
467
467
  until str.empty?
468
- str = handle_plain_flag("-#{str[0]}", str[1..-1])
468
+ str = handle_plain_flag("-#{str[0]}", str[1..])
469
469
  end
470
470
  end
471
471
 
@@ -521,7 +521,7 @@ module Toys
521
521
 
522
522
  def find_flag(name)
523
523
  flag_result = @tool.resolve_flag(name)
524
- if flag_result.not_found? || @require_exact_flag_match && !flag_result.found_exact?
524
+ if flag_result.not_found? || (@require_exact_flag_match && !flag_result.found_exact?)
525
525
  @errors << FlagUnrecognizedError.new(
526
526
  value: name, suggestions: Compat.suggestions(name, @tool.used_flags)
527
527
  )
@@ -551,7 +551,12 @@ module Toys
551
551
  value = accept.convert(*Array(match))
552
552
  end
553
553
  if handler
554
- value = handler.call(value, @data[key])
554
+ args = [value, @data[key], @data]
555
+ if handler.lambda?
556
+ limit = handler.arity.negative? ? -handler.arity - 1 : handler.arity
557
+ args = args[...limit]
558
+ end
559
+ value = handler.call(*args)
555
560
  end
556
561
  @data[key] = value
557
562
  end
data/lib/toys/cli.rb CHANGED
@@ -628,17 +628,15 @@ module Toys
628
628
 
629
629
  def build_executor(tool, context)
630
630
  executor = proc do
631
- begin
632
- if !context[Context::Key::USAGE_ERRORS].empty?
633
- handle_usage_errors(context, tool)
634
- elsif !tool.runnable?
635
- raise NotRunnableError, "No implementation for tool #{tool.display_name.inspect}"
636
- else
637
- yield context
638
- end
639
- rescue ::SignalException => e
640
- handle_signal_by_tool(context, tool, e)
631
+ if !context[Context::Key::USAGE_ERRORS].empty?
632
+ handle_usage_errors(context, tool)
633
+ elsif !tool.runnable?
634
+ raise NotRunnableError, "No implementation for tool #{tool.display_name.inspect}"
635
+ else
636
+ yield context
641
637
  end
638
+ rescue ::SignalException => e
639
+ handle_signal_by_tool(context, tool, e)
642
640
  end
643
641
  tool.built_middleware.reverse_each do |middleware|
644
642
  executor = make_executor(middleware, context, executor)
data/lib/toys/compat.rb CHANGED
@@ -4,13 +4,17 @@ require "rbconfig"
4
4
 
5
5
  module Toys
6
6
  ##
7
- # Compatibility wrappers for older Ruby versions.
7
+ # Compatibility wrappers for certain Ruby implementations and versions, and
8
+ # other environment differences.
8
9
  #
9
10
  # @private
10
11
  #
11
12
  module Compat
12
13
  parts = ::RUBY_VERSION.split(".")
13
- ruby_version = parts[0].to_i * 10000 + parts[1].to_i * 100 + parts[2].to_i
14
+ ruby_version = (parts[0].to_i * 10000) + (parts[1].to_i * 100) + parts[2].to_i
15
+
16
+ # @private
17
+ RUBY_VERSION_CODE = ruby_version
14
18
 
15
19
  # @private
16
20
  def self.jruby?
@@ -27,6 +31,11 @@ module Toys
27
31
  ::RbConfig::CONFIG["host_os"] =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/
28
32
  end
29
33
 
34
+ # @private
35
+ def self.macos?
36
+ ::RbConfig::CONFIG["host_os"] =~ /darwin/
37
+ end
38
+
30
39
  # @private
31
40
  def self.allow_fork?
32
41
  !jruby? && !truffleruby? && !windows?
@@ -58,86 +67,5 @@ module Toys
58
67
  []
59
68
  end
60
69
  end
61
-
62
- # The :base argument to Dir.glob requires Ruby 2.5 or later.
63
- if ruby_version >= 20500
64
- # @private
65
- def self.glob_in_dir(glob, dir)
66
- ::Dir.glob(glob, base: dir)
67
- end
68
- else
69
- # @private
70
- def self.glob_in_dir(glob, dir)
71
- ::Dir.chdir(dir) { ::Dir.glob(glob) }
72
- end
73
- end
74
-
75
- # Dir.children requires Ruby 2.5 or later.
76
- if ruby_version >= 20500
77
- # @private
78
- def self.dir_children(dir)
79
- ::Dir.children(dir)
80
- end
81
- else
82
- # @private
83
- def self.dir_children(dir)
84
- ::Dir.entries(dir) - [".", ".."]
85
- end
86
- end
87
-
88
- # Due to a bug in Ruby < 2.7, passing an empty **kwargs splat to
89
- # initialize will fail if there are no formal keyword args.
90
- # This also hits TruffleRuby
91
- # (see https://github.com/oracle/truffleruby/issues/2567)
92
- if ruby_version >= 20700 && !truffleruby?
93
- # @private
94
- def self.instantiate(klass, args, kwargs, block)
95
- klass.new(*args, **kwargs, &block)
96
- end
97
- else
98
- # @private
99
- def self.instantiate(klass, args, kwargs, block)
100
- formals = klass.instance_method(:initialize).parameters
101
- if kwargs.empty? && formals.all? { |arg| arg.first != :key && arg.first != :keyrest }
102
- klass.new(*args, &block)
103
- else
104
- klass.new(*args, **kwargs, &block)
105
- end
106
- end
107
- end
108
-
109
- # File.absolute_path? requires Ruby 2.7 or later. For earlier Rubies, use
110
- # an ad-hoc mechanism.
111
- if ruby_version >= 20700
112
- # @private
113
- def self.absolute_path?(path)
114
- ::File.absolute_path?(path)
115
- end
116
- elsif ::Dir.getwd =~ /^[a-zA-Z]:/
117
- # @private
118
- def self.absolute_path?(path)
119
- /^[a-zA-Z]:/.match?(path)
120
- end
121
- else
122
- # @private
123
- def self.absolute_path?(path)
124
- path.start_with?("/")
125
- end
126
- end
127
-
128
- # The second argument to method_defined? and private_method_defined?
129
- # requires Ruby 2.6 or later.
130
- if ruby_version >= 20600
131
- # @private
132
- def self.method_defined_without_ancestors?(klass, name)
133
- klass.method_defined?(name, false) || klass.private_method_defined?(name, false)
134
- end
135
- else
136
- # @private
137
- def self.method_defined_without_ancestors?(klass, name)
138
- klass.instance_methods(false).include?(name) ||
139
- klass.private_instance_methods(false).include?(name)
140
- end
141
- end
142
70
  end
143
71
  end
@@ -49,7 +49,7 @@ module Toys
49
49
  # @return [Toys::Completion::Context]
50
50
  #
51
51
  def with(**delta_params)
52
- Context.new(**@params.merge(delta_params))
52
+ Context.new(**@params, **delta_params)
53
53
  end
54
54
 
55
55
  ##
@@ -195,7 +195,7 @@ module Toys
195
195
  # @private
196
196
  #
197
197
  def hash
198
- string.hash ^ (partial? ? 1 : 0)
198
+ [@string, @partial].hash
199
199
  end
200
200
 
201
201
  ##
@@ -295,7 +295,7 @@ module Toys
295
295
  return [] unless ::File.directory?(dir)
296
296
  prefix = nil if [".", ""].include?(prefix)
297
297
  omits = [".", "..", ""]
298
- children = Compat.glob_in_dir(name, dir).find_all do |child|
298
+ children = ::Dir.glob(name, base: dir).find_all do |child|
299
299
  !omits.include?(child)
300
300
  end
301
301
  children += ::Dir.entries(dir).find_all do |child|
data/lib/toys/core.rb CHANGED
@@ -9,7 +9,7 @@ module Toys
9
9
  # Current version of Toys core.
10
10
  # @return [String]
11
11
  #
12
- VERSION = "0.15.6"
12
+ VERSION = "0.17.0"
13
13
  end
14
14
 
15
15
  ##
data/lib/toys/dsl/flag.rb CHANGED
@@ -114,17 +114,20 @@ module Toys
114
114
  end
115
115
 
116
116
  ##
117
- # Set the optional handler for setting/updating the value when a flag is
118
- # parsed. A handler should be a Proc taking two arguments, the new given
119
- # value and the previous value, and it should return the new value that
120
- # should be set. You may pass the handler as a Proc (or an object
121
- # responding to the `call` method) or you may pass a block.
122
- #
123
- # You can also pass one of the special values `:set` or `:push` as the
124
- # handler. The `:set` handler replaces the previous value (equivalent to
125
- # `-> (val, _prev) { val }`.) The `:push` handler expects the previous
126
- # value to be an array and pushes the given value onto it; it should be
127
- # combined with setting the default value to `[]` and is intended for
117
+ # Set the optional handler that customizes how a value is set or updated
118
+ # when the flag is parsed.
119
+ #
120
+ # A handler is a proc that takes up to three arguments: the given value,
121
+ # the previous value, and a hash containing all the data collected so far
122
+ # during argument parsing. It must return the new value for the flag. You
123
+ # You may pass the handler as a Proc (or an object responding to the
124
+ # `call` method) or you may provide a block.
125
+ #
126
+ # You may also specify a predefined named handler. The `:set` handler
127
+ # (the default) replaces the previous value (effectively
128
+ # `-> (val) { val }`). The `:push` handler expects the previous value to
129
+ # be an array and pushes the given value onto it; it should be combined
130
+ # with setting the default value to `[]` and is intended for
128
131
  # "multi-valued" flags.
129
132
  #
130
133
  # @param handler [Proc,:set,:push]
@@ -147,15 +147,18 @@ module Toys
147
147
  # @param default [Object] The default value. This is the value that will
148
148
  # be set in the context if this flag is not provided on the command
149
149
  # line. Defaults to `nil`.
150
- # @param handler [Proc,nil,:set,:push] An optional handler for
151
- # setting/updating the value. A handler is a proc taking two
152
- # arguments, the given value and the previous value, returning the
153
- # new value that should be set. You may also specify a predefined
154
- # named handler. The `:set` handler (the default) replaces the
155
- # previous value (effectively `-> (val, _prev) { val }`). The
156
- # `:push` handler expects the previous value to be an array and
157
- # pushes the given value onto it; it should be combined with setting
158
- # `default: []` and is intended for "multi-valued" flags.
150
+ # @param handler [Proc,nil,:set,:push] An optional handler that
151
+ # customizes how a value is set or updated when the flag is parsed.
152
+ # A handler is a proc that takes up to three arguments: the given
153
+ # value, the previous value, and a hash containing all the data
154
+ # collected so far during argument parsing. The proc must return the
155
+ # new value for the flag.
156
+ # You may also specify a predefined named handler. The `:set` handler
157
+ # (the default) replaces the previous value (effectively
158
+ # `-> (val) { val }`). The `:push` handler expects the previous value
159
+ # to be an array and pushes the given value onto it; it should be
160
+ # combined with setting the default value to `[]` and is intended for
161
+ # "multi-valued" flags.
159
162
  # @param complete_flags [Object] A specifier for shell tab completion
160
163
  # for flag names associated with this flag. By default, a
161
164
  # {Toys::Flag::DefaultCompletion} is used, which provides the flag's
@@ -12,8 +12,8 @@ module Toys
12
12
  # @private A list of method names to avoid using as getters
13
13
  #
14
14
  AVOID_GETTERS = (::Object.instance_methods + [:run, :initialize])
15
- .find_all { |name| /^[a-z]\w*$/.match?(name) }
16
- .map { |name| [name, true] }.to_h
15
+ .grep(/^[a-z]\w*$/)
16
+ .to_h { |name| [name, true] }
17
17
  .freeze
18
18
 
19
19
  class << self
@@ -109,7 +109,8 @@ module Toys
109
109
  when nil
110
110
  return if !/^[a-zA-Z]\w*[!?]?$/.match?(key.to_s) ||
111
111
  AVOID_GETTERS.key?(key) ||
112
- Compat.method_defined_without_ancestors?(tool_class, key)
112
+ tool_class.method_defined?(key, false) ||
113
+ tool_class.private_method_defined?(key, false)
113
114
  end
114
115
  tool_class.class_eval do
115
116
  define_method(key) do
data/lib/toys/dsl/tool.rb CHANGED
@@ -436,9 +436,12 @@ module Toys
436
436
  # current commit if already loading from git, or to `HEAD`.
437
437
  # @param as [String] Load into the given tool/namespace. If omitted,
438
438
  # configuration will be loaded into the current namespace.
439
- # @param update [Boolean] Force-fetch from the remote (unless the commit
440
- # is a SHA). This will ensure that symbolic commits, such as branch
441
- # names, are up to date. Default is false.
439
+ # @param update [Boolean,Integer] Whether and when to force-fetch from
440
+ # the remote (unless the commit is a SHA). Force-fetching will ensure
441
+ # that symbolic commits, such as branch names or HEAD, are up to date.
442
+ # You can pass `true` or `false` to specify whether to update, or an
443
+ # integer to update if the last update was done at least that many
444
+ # seconds ago. Default is false.
442
445
  #
443
446
  # @return [self]
444
447
  #
@@ -453,9 +456,35 @@ module Toys
453
456
  raise ToolDefinitionError, "Git remote not specified" unless remote
454
457
  path ||= ""
455
458
  commit ||= source_info.git_commit || "HEAD"
456
- @__loader.load_git(source_info, remote, path, commit,
457
- @__words, @__remaining_words, @__priority,
458
- update: update)
459
+ @__loader.load_git(source_info, remote, path, commit, update,
460
+ @__words, @__remaining_words, @__priority)
461
+ self
462
+ end
463
+
464
+ ##
465
+ # Load configuration from a gem, as if its contents were inserted at the
466
+ # current location.
467
+ #
468
+ # @param name [String] Name of the gem
469
+ # @param version [String,Array<String>] Version requirements for the gem.
470
+ # @param path [String] Optional path within the gem to the file or
471
+ # directory to load. Defaults to the root of the gem's toys directory.
472
+ # @param toys_dir [String] Optional override for the gem's toys
473
+ # directory name. If not specified, the default specified by the gem
474
+ # will be used.
475
+ # @param as [String] Load into the given tool/namespace. If omitted,
476
+ # configuration will be loaded into the current namespace.
477
+ #
478
+ def load_gem(name, version: nil, path: nil, toys_dir: nil, as: nil)
479
+ if as
480
+ tool(as) do
481
+ load_gem(name, version: version, path: path, toys_dir: toys_dir)
482
+ end
483
+ return self
484
+ end
485
+ path ||= ""
486
+ @__loader.load_gem(source_info, name, version, toys_dir, path,
487
+ @__words, @__remaining_words, @__priority)
459
488
  self
460
489
  end
461
490
 
@@ -504,7 +533,7 @@ module Toys
504
533
  if template_class.nil?
505
534
  raise ToolDefinitionError, "Template not found: #{name.inspect}"
506
535
  end
507
- template = Compat.instantiate(template_class, args, kwargs, nil)
536
+ template = template_class.new(*args, **kwargs)
508
537
  yield template if block_given?
509
538
  class_exec(template, &template_class.expansion)
510
539
  self
@@ -946,15 +975,18 @@ module Toys
946
975
  # @param default [Object] The default value. This is the value that will
947
976
  # be set in the context if this flag is not provided on the command
948
977
  # line. Defaults to `nil`.
949
- # @param handler [Proc,nil,:set,:push] An optional handler for
950
- # setting/updating the value. A handler is a proc taking two
951
- # arguments, the given value and the previous value, returning the
952
- # new value that should be set. You may also specify a predefined
953
- # named handler. The `:set` handler (the default) replaces the
954
- # previous value (effectively `-> (val, _prev) { val }`). The
955
- # `:push` handler expects the previous value to be an array and
956
- # pushes the given value onto it; it should be combined with setting
957
- # `default: []` and is intended for "multi-valued" flags.
978
+ # @param handler [Proc,nil,:set,:push] An optional handler that
979
+ # customizes how a value is set or updated when the flag is parsed.
980
+ # A handler is a proc that takes up to three arguments: the given
981
+ # value, the previous value, and a hash containing all the data
982
+ # collected so far during argument parsing. The proc must return the
983
+ # new value for the flag.
984
+ # You may also specify a predefined named handler. The `:set` handler
985
+ # (the default) replaces the previous value (effectively
986
+ # `-> (val) { val }`). The `:push` handler expects the previous value
987
+ # to be an array and pushes the given value onto it; it should be
988
+ # combined with setting the default value to `[]` and is intended for
989
+ # "multi-valued" flags.
958
990
  # @param complete_flags [Object] A specifier for shell tab completion
959
991
  # for flag names associated with this flag. By default, a
960
992
  # {Toys::Flag::DefaultCompletion} is used, which provides the flag's
data/lib/toys/flag.rb CHANGED
@@ -374,16 +374,16 @@ module Toys
374
374
  # The set handler replaces the previous value.
375
375
  # @return [Proc]
376
376
  #
377
- SET_HANDLER = ->(val, _prev) { val }
377
+ SET_HANDLER = proc { |val| val }
378
378
 
379
379
  ##
380
380
  # The push handler pushes the given value using the `<<` operator.
381
381
  # @return [Proc]
382
382
  #
383
- PUSH_HANDLER = ->(val, prev) { prev.nil? ? [val] : prev << val }
383
+ PUSH_HANDLER = proc { |val, prev| prev.nil? ? [val] : prev << val }
384
384
 
385
385
  ##
386
- # The default handler is the set handler, replacing the previous value.
386
+ # The default handler is the set handler, which replaces the previous value.
387
387
  # @return [Proc]
388
388
  #
389
389
  DEFAULT_HANDLER = SET_HANDLER
@@ -401,15 +401,18 @@ module Toys
401
401
  # @param default [Object] The default value. This is the value that will
402
402
  # be set in the context if this flag is not provided on the command
403
403
  # line. Defaults to `nil`.
404
- # @param handler [Proc,nil,:set,:push] An optional handler for
405
- # setting/updating the value. A handler is a proc taking two
406
- # arguments, the given value and the previous value, returning the
407
- # new value that should be set. You may also specify a predefined
408
- # named handler. The `:set` handler (the default) replaces the
409
- # previous value (effectively `-> (val, _prev) { val }`). The
410
- # `:push` handler expects the previous value to be an array and
411
- # pushes the given value onto it; it should be combined with setting
412
- # `default: []` and is intended for "multi-valued" flags.
404
+ # @param handler [Proc,nil,:set,:push] An optional handler that customizes
405
+ # how a value is set or updated when the flag is parsed.
406
+ # A handler is a proc that takes up to three arguments: the given
407
+ # value, the previous value, and a hash containing all the data
408
+ # collected so far during argument parsing. The proc must return the
409
+ # new value for the flag.
410
+ # You may also specify a predefined named handler. The `:set` handler
411
+ # (the default) replaces the previous value (effectively
412
+ # `-> (val) { val }`). The `:push` handler expects the previous value
413
+ # to be an array and pushes the given value onto it; it should be
414
+ # combined with setting `default: []` and is intended for
415
+ # "multi-valued" flags.
413
416
  # @param complete_flags [Object] A specifier for shell tab completion for
414
417
  # flag names associated with this flag. By default, a
415
418
  # {Toys::Flag::DefaultCompletion} is used, which provides the flag's
@@ -14,7 +14,7 @@ module Toys::InputFile # rubocop:disable Style/ClassAndModuleChildren
14
14
  def self.evaluate(tool_class, words, priority, remaining_words, source, loader)
15
15
  namespace = ::Module.new
16
16
  namespace.module_eval do
17
- include ::Toys::Context::Key
17
+ include ::Toys::Context::Key # rubocop:disable Layout/EmptyLinesAfterModuleInclusion
18
18
  @__tool_class = tool_class
19
19
  end
20
20
  path = source.source_path
@@ -25,9 +25,7 @@ module Toys::InputFile # rubocop:disable Style/ClassAndModuleChildren
25
25
  const_set(name, namespace)
26
26
  ::Toys::DSL::Internal.prepare(tool_class, words, priority, remaining_words, source, loader) do
27
27
  ::Toys::ContextualError.capture_path("Error while loading Toys config!", path) do
28
- # rubocop:disable Security/Eval
29
- eval(str, __binding, path)
30
- # rubocop:enable Security/Eval
28
+ eval(str, __binding, path) # rubocop:disable Security/Eval
31
29
  end
32
30
  end
33
31
  end
@@ -48,7 +46,7 @@ module Toys::InputFile # rubocop:disable Style/ClassAndModuleChildren
48
46
  return nil if index.nil?
49
47
  "#{string[0, index]}" \
50
48
  "module #{module_name}; @__tool_class.class_eval do; " \
51
- "#{string[index..-1]}\n" \
49
+ "#{string[index..]}\n" \
52
50
  "end; end\n"
53
51
  end
54
52
  end