toys-core 0.3.7.1 → 0.3.8

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.
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