toys-core 0.3.7.1 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +1 -2
  4. data/lib/toys-core.rb +23 -8
  5. data/lib/toys/cli.rb +62 -23
  6. data/lib/toys/core_version.rb +1 -1
  7. data/lib/toys/definition/arg.rb +0 -2
  8. data/lib/toys/definition/flag.rb +2 -4
  9. data/lib/toys/definition/tool.rb +38 -36
  10. data/lib/toys/dsl/arg.rb +4 -0
  11. data/lib/toys/dsl/flag.rb +9 -5
  12. data/lib/toys/dsl/tool.rb +35 -28
  13. data/lib/toys/input_file.rb +2 -1
  14. data/lib/toys/loader.rb +97 -51
  15. data/lib/toys/middleware.rb +61 -87
  16. data/lib/toys/runner.rb +19 -2
  17. data/lib/toys/{middleware → standard_middleware}/add_verbosity_flags.rb +24 -8
  18. data/lib/toys/{middleware → standard_middleware}/handle_usage_errors.rb +4 -6
  19. data/lib/toys/{middleware → standard_middleware}/set_default_descriptions.rb +4 -4
  20. data/lib/toys/{middleware → standard_middleware}/show_help.rb +32 -16
  21. data/lib/toys/{middleware → standard_middleware}/show_root_version.rb +4 -5
  22. data/lib/toys/{helpers → standard_mixins}/exec.rb +8 -8
  23. data/lib/toys/{helpers → standard_mixins}/fileutils.rb +1 -1
  24. data/lib/toys/{helpers → standard_mixins}/highline.rb +2 -3
  25. data/lib/toys/{helpers → standard_mixins}/terminal.rb +2 -4
  26. data/lib/toys/tool.rb +3 -2
  27. data/lib/toys/utils/exec.rb +255 -82
  28. data/lib/toys/utils/gems.rb +3 -3
  29. data/lib/toys/utils/help_text.rb +0 -2
  30. data/lib/toys/utils/module_lookup.rb +60 -40
  31. data/lib/toys/utils/wrappable_string.rb +0 -2
  32. metadata +11 -19
  33. data/lib/toys/helpers.rb +0 -54
  34. data/lib/toys/middleware/base.rb +0 -99
  35. data/lib/toys/templates.rb +0 -55
  36. data/lib/toys/templates/clean.rb +0 -85
  37. data/lib/toys/templates/gem_build.rb +0 -125
  38. data/lib/toys/templates/minitest.rb +0 -125
  39. data/lib/toys/templates/rubocop.rb +0 -86
  40. data/lib/toys/templates/yardoc.rb +0 -101
data/lib/toys/dsl/flag.rb CHANGED
@@ -33,6 +33,9 @@ module Toys
33
33
  # DSL for a flag definition block. Lets you set flag attributes in a block
34
34
  # instead of a long series of keyword arguments.
35
35
  #
36
+ # These directives are available inside a block passed to
37
+ # {Toys::DSL::Tool#flag}.
38
+ #
36
39
  class Flag
37
40
  ## @private
38
41
  def initialize(flags, accept, default, handler, report_collisions, desc, long_desc)
@@ -75,14 +78,15 @@ module Toys
75
78
 
76
79
  ##
77
80
  # Set the optional handler for setting/updating the value when a flag is
78
- # parsed. It should be a Proc taking two arguments, the new given value
79
- # and the previous value, and it should return the new value that should
80
- # be set.
81
+ # parsed. A handler should be a Proc taking two arguments, the new given
82
+ # value and the previous value, and it should return the new value that
83
+ # should be set. You may pass the handler as a Proc (or an object
84
+ # responding to the `call` method) or you may pass a block.
81
85
  #
82
86
  # @param [Proc] handler
83
87
  #
84
- def handler(handler)
85
- @handler = handler
88
+ def handler(handler = nil, &block)
89
+ @handler = handler || block
86
90
  self
87
91
  end
88
92
 
data/lib/toys/dsl/tool.rb CHANGED
@@ -30,16 +30,13 @@
30
30
  module Toys
31
31
  module DSL
32
32
  ##
33
- # This class defines the DSL for a toys configuration file.
33
+ # This class defines the DSL for a Toys configuration file.
34
34
  #
35
- # A toys configuration defines one or more named tools. It provides syntax
35
+ # A Toys configuration defines one or more named tools. It provides syntax
36
36
  # for setting the description, defining flags and arguments, specifying
37
- # how to execute the tool, and requesting helper modules and other services.
37
+ # how to execute the tool, and requesting mixin modules and other services.
38
38
  # It also lets you define subtools, nested arbitrarily deep, using blocks.
39
39
  #
40
- # Generally the DSL is invoked from the {Loader}. Applications should not
41
- # need to create instances of DSL::Tool directly.
42
- #
43
40
  # ## Simple example
44
41
  #
45
42
  # Create a file called `.toys.rb` in the current directory, with the
@@ -50,8 +47,8 @@ module Toys
50
47
  #
51
48
  # optional_arg :recipient, default: "world"
52
49
  #
53
- # script do
54
- # puts "Hello, #{self[:recipient]}!"
50
+ # def run
51
+ # puts "Hello, #{option(:recipient)}!"
55
52
  # end
56
53
  # end
57
54
  #
@@ -129,16 +126,16 @@ module Toys
129
126
  end
130
127
 
131
128
  ##
132
- # Create a named helper module.
129
+ # Create a named mixin module.
133
130
  # This module may be included by name in this tool or any subtool.
134
131
  #
135
132
  # You should pass a block and define methods in that block.
136
133
  #
137
- # @param [String] name Name of the helper
134
+ # @param [String] name Name of the mixin
138
135
  #
139
- def helper(name, &block)
136
+ def mixin(name, &block)
140
137
  cur_tool = DSL::Tool.activate_tool(self)
141
- cur_tool.add_helper(name, ::Module.new(&block)) if cur_tool
138
+ cur_tool.add_mixin(name, ::Module.new(&block)) if cur_tool
142
139
  self
143
140
  end
144
141
 
@@ -209,7 +206,10 @@ module Toys
209
206
  def expand(template_class, *args)
210
207
  unless template_class.is_a?(::Class)
211
208
  name = template_class.to_s
212
- template_class = Templates.lookup!(name)
209
+ template_class = @__loader.resolve_standard_template(name)
210
+ if template_class.nil?
211
+ raise ToolDefinitionError, "Template name not found: #{name.inspect}"
212
+ end
213
213
  end
214
214
  template = template_class.new(*args)
215
215
  yield template if block_given?
@@ -281,7 +281,7 @@ module Toys
281
281
  ##
282
282
  # Add a flag to the current tool. Each flag must specify a key which
283
283
  # the script may use to obtain the flag value from the context.
284
- # You may then provide the flags themselves in `OptionParser` form.
284
+ # You may then provide the flags themselves in OptionParser form.
285
285
  #
286
286
  # Attributes of the flag may be passed in as arguments to this method, or
287
287
  # set in a block passed to this method.
@@ -318,12 +318,13 @@ module Toys
318
318
  def flag(key, *flags,
319
319
  accept: nil, default: nil, handler: nil,
320
320
  report_collisions: true,
321
- desc: nil, long_desc: nil)
321
+ desc: nil, long_desc: nil,
322
+ &block)
322
323
  cur_tool = DSL::Tool.activate_tool(self)
323
324
  return self if cur_tool.nil?
324
325
  flag_dsl = DSL::Flag.new(flags, accept, default, handler, report_collisions,
325
326
  desc, long_desc)
326
- yield flag_dsl if block_given?
327
+ flag_dsl.instance_exec(flag_dsl, &block) if block
327
328
  flag_dsl._add_to(cur_tool, key)
328
329
  self
329
330
  end
@@ -352,11 +353,13 @@ module Toys
352
353
  # @yieldparam arg_dsl [Toys::DSL::Arg] An object that lets you configure
353
354
  # this argument in a block.
354
355
  #
355
- def required_arg(key, accept: nil, display_name: nil, desc: nil, long_desc: nil)
356
+ def required_arg(key,
357
+ accept: nil, display_name: nil, desc: nil, long_desc: nil,
358
+ &block)
356
359
  cur_tool = DSL::Tool.activate_tool(self)
357
360
  return self if cur_tool.nil?
358
361
  arg_dsl = DSL::Arg.new(accept, nil, display_name, desc, long_desc)
359
- yield arg_dsl if block_given?
362
+ arg_dsl.instance_exec(arg_dsl, &block) if block
360
363
  arg_dsl._add_required_to(cur_tool, key)
361
364
  self
362
365
  end
@@ -390,12 +393,14 @@ module Toys
390
393
  # @yieldparam arg_dsl [Toys::DSL::Arg] An object that lets you configure
391
394
  # this argument in a block.
392
395
  #
393
- def optional_arg(key, default: nil, accept: nil, display_name: nil,
394
- desc: nil, long_desc: nil)
396
+ def optional_arg(key,
397
+ default: nil, accept: nil, display_name: nil,
398
+ desc: nil, long_desc: nil,
399
+ &block)
395
400
  cur_tool = DSL::Tool.activate_tool(self)
396
401
  return self if cur_tool.nil?
397
402
  arg_dsl = DSL::Arg.new(accept, default, display_name, desc, long_desc)
398
- yield arg_dsl if block_given?
403
+ arg_dsl.instance_exec(arg_dsl, &block) if block
399
404
  arg_dsl._add_optional_to(cur_tool, key)
400
405
  self
401
406
  end
@@ -428,12 +433,14 @@ module Toys
428
433
  # @yieldparam arg_dsl [Toys::DSL::Arg] An object that lets you configure
429
434
  # this argument in a block.
430
435
  #
431
- def remaining_args(key, default: [], accept: nil, display_name: nil,
432
- desc: nil, long_desc: nil)
436
+ def remaining_args(key,
437
+ default: [], accept: nil, display_name: nil,
438
+ desc: nil, long_desc: nil,
439
+ &block)
433
440
  cur_tool = DSL::Tool.activate_tool(self)
434
441
  return self if cur_tool.nil?
435
442
  arg_dsl = DSL::Arg.new(accept, default, display_name, desc, long_desc)
436
- yield arg_dsl if block_given?
443
+ arg_dsl.instance_exec(arg_dsl, &block) if block
437
444
  arg_dsl._set_remaining_on(cur_tool, key)
438
445
  self
439
446
  end
@@ -452,9 +459,9 @@ module Toys
452
459
  # Specify that the given module should be mixed into this tool, and its
453
460
  # methods made available when running the tool.
454
461
  #
455
- # You may provide either a module, the string name of a helper that you
462
+ # You may provide either a module, the string name of a mixin that you
456
463
  # have defined in this tool or one of its ancestors, or the symbol name
457
- # of a well-known helper.
464
+ # of a well-known mixin.
458
465
  #
459
466
  # @param [Module,Symbol,String] mod Module or module name.
460
467
  #
@@ -463,9 +470,9 @@ module Toys
463
470
  return if cur_tool.nil?
464
471
  name = mod.to_s
465
472
  if mod.is_a?(::String)
466
- mod = cur_tool.resolve_helper(mod)
473
+ mod = cur_tool.resolve_mixin(mod)
467
474
  elsif mod.is_a?(::Symbol)
468
- mod = Helpers.lookup!(name)
475
+ mod = @__loader.resolve_standard_mixin(name)
469
476
  end
470
477
  if mod.nil?
471
478
  raise ToolDefinitionError, "Module not found: #{name.inspect}"
@@ -28,7 +28,8 @@
28
28
  ;
29
29
 
30
30
  ##
31
- # Internal modules providing constant namespaces for config files.
31
+ # This module is a namespace for constant scopes. Whenever a configuration file
32
+ # is parsed, a module is created under this parent for that file's constants.
32
33
  #
33
34
  module Toys::InputFile # rubocop:disable Style/ClassAndModuleChildren
34
35
  ## @private
data/lib/toys/loader.rb CHANGED
@@ -59,14 +59,24 @@ module Toys
59
59
  # used by the tools defined in that directory.
60
60
  # @param [Array] middleware_stack An array of middleware that will be used
61
61
  # by default for all tools loaded by this loader.
62
- #
63
- def initialize(index_file_name: nil, preload_file_name: nil, middleware_stack: [])
62
+ # @param [Toys::Utils::ModuleLookup] mixin_lookup A lookup for well-known
63
+ # mixin modules. Defaults to an empty lookup.
64
+ # @param [Toys::Utils::ModuleLookup] middleware_lookup A lookup for
65
+ # well-known middleware classes. Defaults to an empty lookup.
66
+ # @param [Toys::Utils::ModuleLookup] template_lookup A lookup for
67
+ # well-known template classes. Defaults to an empty lookup.
68
+ #
69
+ def initialize(index_file_name: nil, preload_file_name: nil, middleware_stack: [],
70
+ mixin_lookup: nil, middleware_lookup: nil, template_lookup: nil)
64
71
  if index_file_name && ::File.extname(index_file_name) != ".rb"
65
72
  raise ::ArgumentError, "Illegal index file name #{index_file_name.inspect}"
66
73
  end
67
74
  if preload_file_name && ::File.extname(preload_file_name) != ".rb"
68
75
  raise ::ArgumentError, "Illegal preload file name #{preload_file_name.inspect}"
69
76
  end
77
+ @mixin_lookup = mixin_lookup || Utils::ModuleLookup.new
78
+ @middleware_lookup = middleware_lookup || Utils::ModuleLookup.new
79
+ @template_lookup = template_lookup || Utils::ModuleLookup.new
70
80
  @index_file_name = index_file_name
71
81
  @preload_file_name = preload_file_name
72
82
  @middleware_stack = middleware_stack
@@ -133,7 +143,7 @@ module Toys
133
143
  # @param [Array<String>] words The name of the parent tool
134
144
  # @param [Boolean] recursive If true, return all subtools recursively
135
145
  # rather than just the immediate children (the default)
136
- # @return [Array<Toys::Definition::Tool,Tool::Definition::Alias>]
146
+ # @return [Array<Toys::Definition::Tool,Toys::Definition::Alias>]
137
147
  #
138
148
  def list_subtools(words, recursive: false)
139
149
  load_for_prefix(words)
@@ -168,23 +178,6 @@ module Toys
168
178
  false
169
179
  end
170
180
 
171
- ##
172
- # Finishes all tool definitions under the given path. This generally means
173
- # installing middleware.
174
- #
175
- # @param [Array<String>] words The path to the tool under which all
176
- # definitions should be finished.
177
- #
178
- def finish_definitions_in_tree(words)
179
- load_for_prefix(words)
180
- len = words.length
181
- @tool_data.each do |n, td|
182
- next if n.length < len || n.slice(0, len) != words
183
- tool = td.active_definition || td.top_definition
184
- tool.finish_definition(self) if tool.is_a?(Definition::Tool)
185
- end
186
- end
187
-
188
181
  ##
189
182
  # Returns a tool specified by the given words, with the given priority.
190
183
  # Does not do any loading. If the tool is not present, creates it.
@@ -241,36 +234,8 @@ module Toys
241
234
  end
242
235
 
243
236
  ##
244
- # Returns a tool given a name. Resolves any aliases.
245
- #
246
- # @param [Array<String>] words Name of the tool
247
- # @param [Array<Array<String>>] looked_up List of names that have already
248
- # been traversed during alias resolution. Used to detect circular
249
- # alias references.
250
- # @return [Toys::Definition::Tool,nil] The tool, or `nil` if not found
251
- #
252
- # @private
253
- #
254
- def get_active_tool(words, looked_up = [])
255
- tool_data = get_tool_data(words)
256
- result = tool_data.active_definition
257
- case result
258
- when Definition::Alias
259
- words = result.target_name
260
- if looked_up.include?(words)
261
- raise ToolDefinitionError, "Circular alias references: #{looked_up.inspect}"
262
- end
263
- looked_up << words
264
- get_active_tool(words, looked_up)
265
- when Definition::Tool
266
- result
267
- else
268
- tool_data.top_definition
269
- end
270
- end
271
-
272
- ##
273
- # Get the tool definition for the given name and priority.
237
+ # Get or create the tool definition for the given name and priority.
238
+ # May return either a tool or alias definition.
274
239
  #
275
240
  # @private
276
241
  #
@@ -284,8 +249,29 @@ module Toys
284
249
  if tool_data.top_priority.nil? || tool_data.top_priority < priority
285
250
  tool_data.top_priority = priority
286
251
  end
252
+ middlewares = @middleware_stack.map { |m| resolve_middleware(m) }
287
253
  tool_data.definitions[priority] ||=
288
- Definition::Tool.new(self, parent, words, priority, @middleware_stack)
254
+ Definition::Tool.new(self, parent, words, priority, middlewares)
255
+ end
256
+
257
+ ##
258
+ # Attempt to get a well-known mixin module for the given symbolic name.
259
+ #
260
+ # @param [Symbol] name Mixin name
261
+ # @return [Module,nil] The mixin, or `nil` if not found.
262
+ #
263
+ def resolve_standard_mixin(name)
264
+ @mixin_lookup.lookup(name)
265
+ end
266
+
267
+ ##
268
+ # Attempt to get a well-known template class for the given symbolic name.
269
+ #
270
+ # @param [Symbol] name Template name
271
+ # @return [Class,nil] The template, or `nil` if not found.
272
+ #
273
+ def resolve_standard_template(name)
274
+ @template_lookup.lookup(name)
289
275
  end
290
276
 
291
277
  ##
@@ -318,6 +304,66 @@ module Toys
318
304
  @tool_data[words] ||= ToolData.new({}, nil, nil)
319
305
  end
320
306
 
307
+ ##
308
+ # Returns the current effective tool given a name. Resolves any aliases.
309
+ #
310
+ # If there is an active tool, returns it; otherwise, returns the highest
311
+ # priority tool that has been defined. If no tool has been defined with
312
+ # the given name, returns `nil`.
313
+ #
314
+ # @private
315
+ #
316
+ def get_active_tool(words, looked_up = [])
317
+ tool_data = get_tool_data(words)
318
+ result = tool_data.active_definition
319
+ case result
320
+ when Definition::Alias
321
+ words = result.target_name
322
+ if looked_up.include?(words)
323
+ raise ToolDefinitionError, "Circular alias references: #{looked_up.inspect}"
324
+ end
325
+ looked_up << words
326
+ get_active_tool(words, looked_up)
327
+ when Definition::Tool
328
+ result
329
+ else
330
+ tool_data.top_definition
331
+ end
332
+ end
333
+
334
+ def resolve_middleware(input)
335
+ input = Array(input)
336
+ cls = input.first
337
+ args = input[1..-1]
338
+ if cls.is_a?(::String) || cls.is_a?(::Symbol)
339
+ cls = @middleware_lookup.lookup(cls)
340
+ if cls.nil?
341
+ raise ::ArgumentError, "Unrecognized middleware name #{input.first.inspect}"
342
+ end
343
+ end
344
+ if cls.is_a?(::Class)
345
+ cls.new(*args)
346
+ elsif !args.empty?
347
+ raise ::ArgumentError, "Unrecognized middleware object of class #{cls.class}"
348
+ else
349
+ cls
350
+ end
351
+ end
352
+
353
+ ##
354
+ # Finishes all tool definitions under the given path. This generally means
355
+ # installing middleware.
356
+ #
357
+ def finish_definitions_in_tree(words)
358
+ load_for_prefix(words)
359
+ len = words.length
360
+ @tool_data.each do |n, td|
361
+ next if n.length < len || n.slice(0, len) != words
362
+ tool = td.active_definition || td.top_definition
363
+ tool.finish_definition(self) if tool.is_a?(Definition::Tool)
364
+ end
365
+ end
366
+
321
367
  def load_for_prefix(prefix)
322
368
  cur_worklist = @load_worklist
323
369
  @load_worklist = []
@@ -27,98 +27,72 @@
27
27
  # POSSIBILITY OF SUCH DAMAGE.
28
28
  ;
29
29
 
30
- require "toys/utils/module_lookup"
31
-
32
30
  module Toys
33
31
  ##
34
- # Middleware lets you define common behavior across many tools.
32
+ # A middleware is an object that has the opportunity to alter the
33
+ # configuration and runtime behavior of each tool in a Toys CLI. A CLI
34
+ # contains an ordered list of middleware, known as the *middleware stack*,
35
+ # that together define the CLI's default behavior.
36
+ #
37
+ # Specifically, a middleware can perform two functions.
38
+ #
39
+ # First, it can modify the configuration of a tool. After tools are defined
40
+ # from configuration, the middleware stack can make modifications to each
41
+ # tool. A middleware can add flags and arguments to the tool, modify the
42
+ # description, or make any other changes to how the tool is set up.
43
+ #
44
+ # Second, a middleware can intercept and change tool execution. Like a Rack
45
+ # middleware, a Toys middleware can wrap execution with its own code,
46
+ # replace it outright, or leave it unmodified.
47
+ #
48
+ # Generally, a middleware is a class that implements the two methods defined
49
+ # in this module: {Toys::Middleware#config} and {Toys::Middleware#run}. A
50
+ # middleware can include this module to get default implementations that do
51
+ # nothing, but this is not required.
35
52
  #
36
53
  module Middleware
37
- class << self
38
- ##
39
- # Return a well-known middleware class by name.
40
- #
41
- # Currently recognized middleware names are:
42
- #
43
- # * `:add_verbosity_flags` : Adds flags for affecting verbosity.
44
- # * `:handle_usage_errors` : Displays the usage error if one occurs.
45
- # * `:set_default_descriptions` : Sets default descriptions for tools
46
- # that do not have them set explicitly.
47
- # * `:show_help` : Teaches tools to print their usage documentation.
48
- # * `:show_version` : Teaches tools to print their version.
49
- #
50
- # @param [String,Symbol] name Name of the middleware class to return
51
- # @return [Class,nil] The class, or `nil` if not found
52
- #
53
- def lookup!(name)
54
- Utils::ModuleLookup.lookup!(:middleware, name)
55
- end
56
-
57
- ##
58
- # Resolves a single middleware. You may pass an instance already
59
- # constructed, a middleware class, the name of a well-known middleware
60
- # class, or an array where the first element is the lookup name or class,
61
- # and subsequent elements are arguments to be passed to the constructor.
62
- #
63
- # @param [String,Symbol,Array,Object] input The middleware spec
64
- # @return [Object] Constructed middleware
65
- #
66
- def resolve(input)
67
- input = Array(input)
68
- raise "No middleware found" if input.empty?
69
- cls = input.first
70
- args = input[1..-1]
71
- if cls.is_a?(::String) || cls.is_a?(::Symbol)
72
- cls = lookup!(cls)
73
- end
74
- if cls.is_a?(::Class)
75
- cls.new(*args)
76
- else
77
- raise "Unrecognized middleware class #{cls.class}" unless args.empty?
78
- cls
79
- end
80
- end
81
-
82
- ##
83
- # Resolves an array of middleware specs. See {Toys::Middleware.resolve}.
84
- #
85
- # @param [Array] input An array of middleware specs
86
- # @return [Array] An array of constructed middleware
87
- #
88
- def resolve_stack(input)
89
- input.map { |e| resolve(e) }
90
- end
54
+ ##
55
+ # This method is called after a tool has been defined, and gives this
56
+ # middleware the opportunity to modify the tool definition. It is passed
57
+ # the tool definition object and the loader, and can make any changes to
58
+ # the tool definition. In most cases, this method should also call
59
+ # `yield`, which passes control to the next middleware in the stack. A
60
+ # middleware can disable modifications done by subsequent middleware by
61
+ # omitting the `yield` call, but this is uncommon.
62
+ #
63
+ # This basic implementation does nothing and simply yields to the next
64
+ # middleware.
65
+ #
66
+ # @param [Toys::Definition::Tool] _tool_definition The tool definition
67
+ # to modify.
68
+ # @param [Toys::Loader] _loader The loader that loaded this tool.
69
+ #
70
+ def config(_tool_definition, _loader)
71
+ yield
72
+ end
91
73
 
92
- ##
93
- # Resolves a typical flags specification. Used often in middleware.
94
- #
95
- # You may provide any of the following for the `flags` parameter:
96
- # * A string, which becomes the single flag
97
- # * An array of strings
98
- # * The value `false` or `nil` which resolves to no flags
99
- # * The value `true` or `:default` which resolves to the given defaults
100
- # * A proc that takes a tool as argument and returns any of the above.
101
- #
102
- # Always returns an array of flag strings, even if empty.
103
- #
104
- # @param [Boolean,String,Array<String>,Proc] flags Flag spec
105
- # @param [Toys::Tool] tool The tool
106
- # @param [Array<String>] defaults The defaults to use for `true`.
107
- # @return [Array<String>] An array of flags
108
- #
109
- def resolve_flags_spec(flags, tool, defaults)
110
- flags = flags.call(tool) if flags.respond_to?(:call)
111
- case flags
112
- when true, :default
113
- Array(defaults)
114
- when ::String
115
- [flags]
116
- when ::Array
117
- flags
118
- else
119
- []
120
- end
121
- end
74
+ ##
75
+ # This method is called when the tool is run. It gives the middleware an
76
+ # opportunity to modify the runtime behavior of the tool. It is passed
77
+ # the tool instance (i.e. the object that hosts a tool's `run` method),
78
+ # and you can use this object to access the tool's options and other
79
+ # context data. In most cases, this method should also call `yield`,
80
+ # which passes control to the next middleware in the stack. A middleware
81
+ # can "wrap" normal execution by calling `yield` somewhere in its
82
+ # implementation of this method, or it can completely replace the
83
+ # execution behavior by not calling `yield` at all.
84
+ #
85
+ # Like a tool's `run` method, this method's return value is unused. If
86
+ # you want to output from a tool, write to stdout or stderr. If you want
87
+ # to set the exit status code, call {Toys::Tool#exit} on the tool object.
88
+ #
89
+ # This basic implementation does nothing and simply yields to the next
90
+ # middleware.
91
+ #
92
+ # @param [Toys::Tool] _tool The tool execution instance.
93
+ #
94
+ def run(_tool)
95
+ yield
122
96
  end
123
97
  end
124
98
  end