toys-core 0.3.9.1 → 0.3.10

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: 3ddc8eac1d584a35898abadd2c8ef601c6fa4c98fc6854e0bd5578e47f46b6ae
4
- data.tar.gz: e15d35d38f56128bb8d5cdef467db338b6e813f88df5be5cbe4a44b9698703fd
3
+ metadata.gz: 7bfede9155648ae5e0b3766dfad5b5165f80fa865eca0e91d390706616372c6e
4
+ data.tar.gz: 78ba80645b891e5382049153d47168ef69f18e7e762efe553a0f77ad14aa178a
5
5
  SHA512:
6
- metadata.gz: 0ff220cbdc9fca5b657d7f4924ad5ac263984ece39be6ed267c2d1f1989004ebcba2cb00f69c3427c890c45341fe0829852987ff324e02d2915abe9a58b4d380
7
- data.tar.gz: 20bc712ca5414341e309178d7367f7d4bdc506a8bd1d7f0fda3fa01f4f9f4d64e8c733f0879060d610626a760b6f5db3bb8279ffe096bc50b35f79d99f1a0f29
6
+ metadata.gz: f0f9533b044b056ea6ea46d121a18fd0a9966b1aadacc845c36651c258bf7bdf8ba8851ccd0f00770a27da67697dcf1fe003804e94b720f87efab4a348cb9cab
7
+ data.tar.gz: c010707f7452adf31bdbe1d4bd692f39a285091e899c46d6cd964c686ba1aa3df7e119df3888da0f2f660732409c96b1768604f0af48768efa90c188c8497d22
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Release History
2
2
 
3
+ ### 0.3.10 / 2018-06-30
4
+
5
+ * CHANGED: Dropped Tool#option. Use Tool#get instead.
6
+ * CHANGED: "run" directive renamed to "to_run"
7
+ * CHANGED: Highline mixin now uses Highline 2.0
8
+ * CHANGED: Middleware-added keys no longer show up in the options hash
9
+ * ADDED: Mixins can provide initializers
10
+ * ADDED: Loader can load an inline block
11
+
3
12
  ### 0.3.9.1 / 2018-06-24
4
13
 
5
14
  * FIXED: Built-in flags were interfering with disable_argument_parsing
data/lib/toys/cli.rb CHANGED
@@ -151,6 +151,20 @@ module Toys
151
151
  self
152
152
  end
153
153
 
154
+ ##
155
+ # Add a configuration block to the loader.
156
+ #
157
+ # @param [Boolean] high_priority Add the config at the head of the priority
158
+ # list rather than the tail.
159
+ # @param [String] path The "path" that will be shown in documentation for
160
+ # tools defined in this block. If omitted, a default unique string will
161
+ # be generated.
162
+ #
163
+ def add_config_block(high_priority: false, path: nil, &block)
164
+ @loader.add_block(high_priority: high_priority, path: path, &block)
165
+ self
166
+ end
167
+
154
168
  ##
155
169
  # Searches the given directory for a well-known config directory and/or
156
170
  # config file. If found, these are added to the loader.
@@ -32,5 +32,5 @@ module Toys
32
32
  # Current version of Toys core
33
33
  # @return [String]
34
34
  #
35
- CORE_VERSION = "0.3.9.1".freeze
35
+ CORE_VERSION = "0.3.10".freeze
36
36
  end
@@ -39,7 +39,7 @@ module Toys
39
39
  # Create an Arg definition
40
40
  # @private
41
41
  #
42
- def initialize(key, type, accept, default, desc, long_desc, display_name)
42
+ def initialize(key, type, accept, default, desc, long_desc, display_name = nil)
43
43
  @key = key
44
44
  @type = type
45
45
  @accept = accept
@@ -103,7 +103,7 @@ module Toys
103
103
  result = input
104
104
  optparse = ::OptionParser.new
105
105
  optparse.accept(accept) if accept.is_a?(Acceptor)
106
- optparse.on("--abc=VALUE", accept) { |v| result = v }
106
+ optparse.on("--abc VALUE", accept) { |v| result = v }
107
107
  optparse.parse(["--abc", input])
108
108
  result
109
109
  end
@@ -43,6 +43,8 @@ module Toys
43
43
  setup(str, [$1], $1, "-", nil, nil, nil, nil)
44
44
  when /^(-[\?\w])( ?)\[(\w+)\]$/
45
45
  setup(str, [$1], $1, "-", :value, :optional, $2, $3)
46
+ when /^(-[\?\w])\[( )(\w+)\]$/
47
+ setup(str, [$1], $1, "-", :value, :optional, $2, $3)
46
48
  when /^(-[\?\w])( ?)(\w+)$/
47
49
  setup(str, [$1], $1, "-", :value, :required, $2, $3)
48
50
  when /^--\[no-\](\w[\?\w-]*)$/
@@ -305,6 +307,7 @@ module Toys
305
307
  analyze_flag_syntax(flag)
306
308
  end
307
309
  @flag_type ||= :boolean
310
+ @value_type ||= :required if @flag_type == :value
308
311
  flag_syntax.each do |flag|
309
312
  flag.configure_canonical(@flag_type, @value_type, @value_label, @value_delim)
310
313
  end
@@ -82,6 +82,7 @@ module Toys
82
82
 
83
83
  @default_data = {}
84
84
  @used_flags = []
85
+ @initializers = []
85
86
 
86
87
  @acceptors = {}
87
88
  @mixins = {}
@@ -381,6 +382,20 @@ module Toys
381
382
  @long_desc = Utils::WrappableString.make_array(long_desc)
382
383
  end
383
384
 
385
+ ##
386
+ # Append long description strings.
387
+ #
388
+ # Each string may be provided as a {Toys::Utils::WrappableString}, a single
389
+ # string (which will be wrapped), or an array of strings, which will be
390
+ # interpreted as string fragments that will be concatenated and wrapped.
391
+ #
392
+ # @param [Array<Toys::Utils::WrappableString,String,Array<String>>] long_desc
393
+ #
394
+ def append_long_desc(long_desc)
395
+ check_definition_state
396
+ @long_desc += Utils::WrappableString.make_array(long_desc)
397
+ end
398
+
384
399
  ##
385
400
  # Add an acceptor to the tool. This acceptor may be refereneced by name
386
401
  # when adding a flag or an arg.
@@ -615,7 +630,19 @@ module Toys
615
630
  # @param [Proc] proc The runnable block
616
631
  #
617
632
  def runnable=(proc)
618
- @tool_class.run(&proc)
633
+ @tool_class.to_run(&proc)
634
+ end
635
+
636
+ ##
637
+ # Add an initializer.
638
+ #
639
+ # @param [Proc] proc The initializer block
640
+ # @param [Object...] args Arguments to pass to the initializer
641
+ #
642
+ def add_initializer(proc, *args)
643
+ check_definition_state
644
+ @initializers << [proc, args]
645
+ self
619
646
  end
620
647
 
621
648
  ##
@@ -647,6 +674,17 @@ module Toys
647
674
  self
648
675
  end
649
676
 
677
+ ##
678
+ # Run all initializers against a tool. Should be called from the Runner
679
+ # only.
680
+ # @private
681
+ #
682
+ def run_initializers(tool)
683
+ @initializers.each do |func, args|
684
+ tool.instance_exec(*args, &func)
685
+ end
686
+ end
687
+
650
688
  private
651
689
 
652
690
  def make_config_proc(middleware, loader, next_config)
data/lib/toys/dsl/arg.rb CHANGED
@@ -44,7 +44,7 @@ module Toys
44
44
  @default = default
45
45
  @display_name = display_name
46
46
  @desc = desc
47
- @long_desc = long_desc
47
+ @long_desc = long_desc || []
48
48
  end
49
49
 
50
50
  ##
@@ -70,7 +70,7 @@ module Toys
70
70
  # @param [String] display_name
71
71
  #
72
72
  def display_name(display_name)
73
- @handler = display_name
73
+ @display_name = display_name
74
74
  self
75
75
  end
76
76
 
data/lib/toys/dsl/flag.rb CHANGED
@@ -45,7 +45,7 @@ module Toys
45
45
  @handler = handler
46
46
  @report_collisions = report_collisions
47
47
  @desc = desc
48
- @long_desc = long_desc
48
+ @long_desc = long_desc || []
49
49
  end
50
50
 
51
51
  ##
data/lib/toys/dsl/tool.rb CHANGED
@@ -48,7 +48,7 @@ module Toys
48
48
  # optional_arg :recipient, default: "world"
49
49
  #
50
50
  # def run
51
- # puts "Hello, #{option(:recipient)}!"
51
+ # puts "Hello, #{get(:recipient)}!"
52
52
  # end
53
53
  # end
54
54
  #
@@ -63,7 +63,7 @@ module Toys
63
63
  module Tool
64
64
  ## @private
65
65
  def method_added(meth)
66
- cur_tool = DSL::Tool.activate_tool(self)
66
+ cur_tool = DSL::Tool.current_tool(self, true)
67
67
  cur_tool.mark_runnable if cur_tool && meth == :run
68
68
  end
69
69
 
@@ -108,7 +108,7 @@ module Toys
108
108
  # @param [Proc,nil] converter The validator.
109
109
  #
110
110
  def acceptor(name, validator = nil, converter = nil, &block)
111
- cur_tool = DSL::Tool.activate_tool(self)
111
+ cur_tool = DSL::Tool.current_tool(self, false)
112
112
  return self if cur_tool.nil?
113
113
  accept =
114
114
  case validator
@@ -134,8 +134,14 @@ module Toys
134
134
  # @param [String] name Name of the mixin
135
135
  #
136
136
  def mixin(name, &block)
137
- cur_tool = DSL::Tool.activate_tool(self)
138
- cur_tool.add_mixin(name, ::Module.new(&block)) if cur_tool
137
+ cur_tool = DSL::Tool.current_tool(self, false)
138
+ if cur_tool
139
+ mixin_mod = ::Module.new do
140
+ include ::Toys::Mixin
141
+ end
142
+ mixin_mod.module_eval(&block)
143
+ cur_tool.add_mixin(name, mixin_mod)
144
+ end
139
145
  self
140
146
  end
141
147
 
@@ -152,7 +158,7 @@ module Toys
152
158
  # @param [String] name Name of the template
153
159
  #
154
160
  def template(name, &block)
155
- cur_tool = DSL::Tool.activate_tool(self)
161
+ cur_tool = DSL::Tool.current_tool(self, false)
156
162
  if cur_tool
157
163
  template_class = ::Class.new do
158
164
  include ::Toys::Template
@@ -200,7 +206,7 @@ module Toys
200
206
  # @param [String] path The file or directory to include.
201
207
  #
202
208
  def load(path)
203
- @__loader.include_path(path, @__words, @__remaining_words, @__priority)
209
+ @__loader.load_path(path, @__words, @__remaining_words, @__priority)
204
210
  self
205
211
  end
206
212
 
@@ -215,6 +221,8 @@ module Toys
215
221
  # @param [Object...] args Template arguments
216
222
  #
217
223
  def expand(template_class, *args)
224
+ cur_tool = DSL::Tool.current_tool(self, true)
225
+ return self if cur_tool.nil?
218
226
  name = template_class.to_s
219
227
  if template_class.is_a?(::String)
220
228
  template_class = cur_tool.resolve_template(template_class)
@@ -260,7 +268,7 @@ module Toys
260
268
  # @param [Toys::Utils::WrappableString,String,Array<String>] str
261
269
  #
262
270
  def desc(str)
263
- cur_tool = DSL::Tool.activate_tool(self)
271
+ cur_tool = DSL::Tool.current_tool(self, true)
264
272
  cur_tool.desc = str if cur_tool
265
273
  self
266
274
  end
@@ -286,8 +294,8 @@ module Toys
286
294
  # @param [Toys::Utils::WrappableString,String,Array<String>...] strs
287
295
  #
288
296
  def long_desc(*strs)
289
- cur_tool = DSL::Tool.activate_tool(self)
290
- cur_tool.long_desc = strs if cur_tool
297
+ cur_tool = DSL::Tool.current_tool(self, true)
298
+ cur_tool.append_long_desc(strs) if cur_tool
291
299
  self
292
300
  end
293
301
 
@@ -333,7 +341,7 @@ module Toys
333
341
  report_collisions: true,
334
342
  desc: nil, long_desc: nil,
335
343
  &block)
336
- cur_tool = DSL::Tool.activate_tool(self)
344
+ cur_tool = DSL::Tool.current_tool(self, true)
337
345
  return self if cur_tool.nil?
338
346
  flag_dsl = DSL::Flag.new(flags, accept, default, handler, report_collisions,
339
347
  desc, long_desc)
@@ -369,7 +377,7 @@ module Toys
369
377
  def required_arg(key,
370
378
  accept: nil, display_name: nil, desc: nil, long_desc: nil,
371
379
  &block)
372
- cur_tool = DSL::Tool.activate_tool(self)
380
+ cur_tool = DSL::Tool.current_tool(self, true)
373
381
  return self if cur_tool.nil?
374
382
  arg_dsl = DSL::Arg.new(accept, nil, display_name, desc, long_desc)
375
383
  arg_dsl.instance_exec(arg_dsl, &block) if block
@@ -410,7 +418,7 @@ module Toys
410
418
  default: nil, accept: nil, display_name: nil,
411
419
  desc: nil, long_desc: nil,
412
420
  &block)
413
- cur_tool = DSL::Tool.activate_tool(self)
421
+ cur_tool = DSL::Tool.current_tool(self, true)
414
422
  return self if cur_tool.nil?
415
423
  arg_dsl = DSL::Arg.new(accept, default, display_name, desc, long_desc)
416
424
  arg_dsl.instance_exec(arg_dsl, &block) if block
@@ -450,7 +458,7 @@ module Toys
450
458
  default: [], accept: nil, display_name: nil,
451
459
  desc: nil, long_desc: nil,
452
460
  &block)
453
- cur_tool = DSL::Tool.activate_tool(self)
461
+ cur_tool = DSL::Tool.current_tool(self, true)
454
462
  return self if cur_tool.nil?
455
463
  arg_dsl = DSL::Arg.new(accept, default, display_name, desc, long_desc)
456
464
  arg_dsl.instance_exec(arg_dsl, &block) if block
@@ -466,10 +474,14 @@ module Toys
466
474
  # execution context.
467
475
  # @param [Object] value The value to set.
468
476
  #
469
- def set(key, value)
470
- cur_tool = DSL::Tool.activate_tool(self)
477
+ def set(key, value = nil)
478
+ cur_tool = DSL::Tool.current_tool(self, true)
471
479
  return self if cur_tool.nil?
472
- cur_tool.default_data[key] = value
480
+ if key.is_a?(::Hash)
481
+ cur_tool.default_data.merge!(key)
482
+ else
483
+ cur_tool.default_data[key] = value
484
+ end
473
485
  self
474
486
  end
475
487
 
@@ -482,29 +494,29 @@ module Toys
482
494
  # declare arguments or flags.
483
495
  #
484
496
  def disable_argument_parsing
485
- cur_tool = DSL::Tool.activate_tool(self)
497
+ cur_tool = DSL::Tool.current_tool(self, true)
486
498
  cur_tool.disable_argument_parsing unless cur_tool.nil?
487
499
  self
488
500
  end
489
501
 
490
502
  ##
491
503
  # Mark one or more flags as disabled, preventing their use by any
492
- # subsequent flag definition. This may be used to prevent middleware from
504
+ # subsequent flag definition. This can be used to prevent middleware from
493
505
  # defining a particular flag.
494
506
  #
495
507
  # @param [String...] flags The flags to disable
496
508
  #
497
509
  def disable_flag(*flags)
498
- cur_tool = DSL::Tool.activate_tool(self)
510
+ cur_tool = DSL::Tool.current_tool(self, true)
499
511
  cur_tool.disable_flag(*flags) unless cur_tool.nil?
500
512
  self
501
513
  end
502
514
 
503
515
  ##
504
- # Specify how to run this tool. You may do this by providing a block to
516
+ # Specify how to run this tool. You can do this by providing a block to
505
517
  # this directive, or by defining the `run` method in the tool.
506
518
  #
507
- def run(&block)
519
+ def to_run(&block)
508
520
  define_method(:run, &block)
509
521
  self
510
522
  end
@@ -518,9 +530,10 @@ module Toys
518
530
  # of a well-known mixin.
519
531
  #
520
532
  # @param [Module,Symbol,String] mod Module or module name.
533
+ # @param [Object...] args Arguments to pass to the initializer
521
534
  #
522
- def include(mod)
523
- cur_tool = DSL::Tool.activate_tool(self)
535
+ def include(mod, *args)
536
+ cur_tool = DSL::Tool.current_tool(self, true)
524
537
  return if cur_tool.nil?
525
538
  name = mod.to_s
526
539
  if mod.is_a?(::String)
@@ -531,6 +544,9 @@ module Toys
531
544
  if mod.nil?
532
545
  raise ToolDefinitionError, "Module not found: #{name.inspect}"
533
546
  end
547
+ if mod.respond_to?(:initializer)
548
+ cur_tool.add_initializer(mod.initializer, *args) if mod.initializer
549
+ end
534
550
  super(mod)
535
551
  end
536
552
 
@@ -558,24 +574,28 @@ module Toys
558
574
  end
559
575
 
560
576
  ## @private
561
- def self.activate_tool(tool_class)
577
+ def self.current_tool(tool_class, activate)
578
+ memoize_var = activate ? :@__active_tool : :@__cur_tool
562
579
  path = tool_class.instance_variable_get(:@__path)
563
- cur_tool =
564
- if tool_class.instance_variable_defined?(:@__cur_tool)
565
- tool_class.instance_variable_get(:@__cur_tool)
566
- else
567
- loader = tool_class.instance_variable_get(:@__loader)
568
- words = tool_class.instance_variable_get(:@__words)
569
- priority = tool_class.instance_variable_get(:@__priority)
570
- cur_tool = loader.activate_tool_definition(words, priority)
571
- if cur_tool.is_a?(Definition::Alias)
572
- raise ToolDefinitionError,
573
- "Cannot configure #{words.join(' ').inspect} because it is an alias"
580
+ if tool_class.instance_variable_defined?(memoize_var)
581
+ cur_tool = tool_class.instance_variable_get(memoize_var)
582
+ else
583
+ loader = tool_class.instance_variable_get(:@__loader)
584
+ words = tool_class.instance_variable_get(:@__words)
585
+ priority = tool_class.instance_variable_get(:@__priority)
586
+ cur_tool =
587
+ if activate
588
+ loader.activate_tool_definition(words, priority)
589
+ else
590
+ loader.get_tool_definition(words, priority)
574
591
  end
575
- tool_class.instance_variable_set(:@__cur_tool, cur_tool)
576
- cur_tool
592
+ if cur_tool.is_a?(Definition::Alias)
593
+ raise ToolDefinitionError,
594
+ "Cannot configure #{words.join(' ').inspect} because it is an alias"
577
595
  end
578
- cur_tool.lock_source_path(path) if cur_tool
596
+ tool_class.instance_variable_set(memoize_var, cur_tool)
597
+ end
598
+ cur_tool.lock_source_path(path) if cur_tool && activate
579
599
  cur_tool
580
600
  end
581
601
 
data/lib/toys/loader.rb CHANGED
@@ -44,6 +44,9 @@ module Toys
44
44
  end
45
45
  end
46
46
 
47
+ ## @private
48
+ LOW_PRIORITY = -999_999
49
+
47
50
  ##
48
51
  # Create a Loader
49
52
  #
@@ -80,7 +83,7 @@ module Toys
80
83
  @index_file_name = index_file_name
81
84
  @preload_file_name = preload_file_name
82
85
  @middleware_stack = middleware_stack
83
- @load_worklist = []
86
+ @worklist = []
84
87
  @tool_data = {}
85
88
  @max_priority = @min_priority = 0
86
89
  end
@@ -97,11 +100,28 @@ module Toys
97
100
  paths = Array(path)
98
101
  priority = high_priority ? (@max_priority += 1) : (@min_priority -= 1)
99
102
  paths.each do |p|
100
- @load_worklist << [check_path(p), [], priority]
103
+ @worklist << [:file, check_path(p), [], priority]
101
104
  end
102
105
  self
103
106
  end
104
107
 
108
+ ##
109
+ # Add a configuration block to the loader.
110
+ #
111
+ # @param [Boolean] high_priority If true, add this block at the top of the
112
+ # priority list. Defaults to false, indicating the block should be at
113
+ # the bottom of the priority list.
114
+ # @param [String] path The "path" that will be shown in documentation for
115
+ # tools defined in this block. If omitted, a default unique string will
116
+ # be generated.
117
+ #
118
+ def add_block(high_priority: false, path: nil, &block)
119
+ path ||= "(Block #{block.object_id})"
120
+ priority = high_priority ? (@max_priority += 1) : (@min_priority -= 1)
121
+ @worklist << [block, path, [], priority]
122
+ self
123
+ end
124
+
105
125
  ##
106
126
  # Given a list of command line arguments, find the appropriate tool to
107
127
  # handle the command, loading it from the configuration if necessary, and
@@ -131,7 +151,7 @@ module Toys
131
151
  break if p.empty? || p.length <= cur_prefix.length
132
152
  p = p.slice(0..-2)
133
153
  end
134
- return nil if cur_prefix.empty?
154
+ return get_tool_definition([], LOW_PRIORITY) if cur_prefix.empty?
135
155
  cur_prefix = cur_prefix.slice(0..-2)
136
156
  end
137
157
  end
@@ -279,8 +299,26 @@ module Toys
279
299
  #
280
300
  # @private
281
301
  #
282
- def include_path(path, words, remaining_words, priority)
283
- handle_path(check_path(path), words, remaining_words, priority)
302
+ def load_path(path, words, remaining_words, priority)
303
+ load_validated_path(check_path(path), words, remaining_words, priority)
304
+ end
305
+
306
+ ##
307
+ # Load configuration from the given proc.
308
+ #
309
+ # @private
310
+ #
311
+ def load_proc(proc, words, remaining_words, priority, path)
312
+ if remaining_words
313
+ tool_class = get_tool_definition(words, priority).tool_class
314
+ ::Toys::DSL::Tool.prepare(tool_class, remaining_words, path) do
315
+ ::Toys::ContextualError.capture("Error while loading Toys config!") do
316
+ tool_class.class_eval(&proc)
317
+ end
318
+ end
319
+ else
320
+ @worklist << [proc, path, words, priority]
321
+ end
284
322
  end
285
323
 
286
324
  ##
@@ -365,22 +403,27 @@ module Toys
365
403
  end
366
404
 
367
405
  def load_for_prefix(prefix)
368
- cur_worklist = @load_worklist
369
- @load_worklist = []
370
- cur_worklist.each do |path, words, priority|
371
- handle_path(path, words, calc_remaining_words(prefix, words), priority)
406
+ cur_worklist = @worklist
407
+ @worklist = []
408
+ cur_worklist.each do |source, path, words, priority|
409
+ remaining_words = calc_remaining_words(prefix, words)
410
+ if source.respond_to?(:call)
411
+ load_proc(source, words, remaining_words, priority, path)
412
+ elsif source == :file
413
+ load_validated_path(path, words, remaining_words, priority)
414
+ end
372
415
  end
373
416
  end
374
417
 
375
- def handle_path(path, words, remaining_words, priority)
418
+ def load_validated_path(path, words, remaining_words, priority)
376
419
  if remaining_words
377
- load_path(path, words, remaining_words, priority)
420
+ load_relevant_path(path, words, remaining_words, priority)
378
421
  else
379
- @load_worklist << [path, words, priority]
422
+ @worklist << [:file, path, words, priority]
380
423
  end
381
424
  end
382
425
 
383
- def load_path(path, words, remaining_words, priority)
426
+ def load_relevant_path(path, words, remaining_words, priority)
384
427
  if ::File.extname(path) == ".rb"
385
428
  tool_class = get_tool_definition(words, priority).tool_class
386
429
  Toys::InputFile.evaluate(tool_class, remaining_words, path)
@@ -404,7 +447,7 @@ module Toys
404
447
  return unless @index_file_name
405
448
  index_path = ::File.join(path, @index_file_name)
406
449
  index_path = check_path(index_path, type: :file, lenient: true)
407
- load_path(index_path, words, remaining_words, priority) if index_path
450
+ load_relevant_path(index_path, words, remaining_words, priority) if index_path
408
451
  end
409
452
 
410
453
  def load_child_in(path, child, words, remaining_words, priority)
@@ -414,7 +457,7 @@ module Toys
414
457
  child_word = ::File.basename(child, ".rb")
415
458
  next_words = words + [child_word]
416
459
  next_remaining = Loader.next_remaining_words(remaining_words, child_word)
417
- handle_path(child_path, next_words, next_remaining, priority)
460
+ load_validated_path(child_path, next_words, next_remaining, priority)
418
461
  end
419
462
 
420
463
  def check_path(path, lenient: false, type: nil)
data/lib/toys/mixin.rb ADDED
@@ -0,0 +1,112 @@
1
+ # Copyright 2018 Daniel Azuma
2
+ #
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of the copyright holder, nor the names of any other
14
+ # contributors to this software, may be used to endorse or promote products
15
+ # derived from this software without specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
+ # POSSIBILITY OF SUCH DAMAGE.
28
+ ;
29
+
30
+ module Toys
31
+ ##
32
+ # A mixin definition. Mixin modules should include this module.
33
+ #
34
+ # A mixin is a collection of methods that are available to be called from a
35
+ # tool implementation (i.e. its run method). The mixin is added to the tool
36
+ # class, so it has access to the same methods that can be called by the tool,
37
+ # such as {Toys::Tool#option}.
38
+ #
39
+ # ## Usage
40
+ #
41
+ # To create a mixin, define a module, and include this module. Then define
42
+ # the methods you want to be available.
43
+ #
44
+ # If you want to perform some initialization specific to the mixin, use a
45
+ # `to_initialize` block. This block is passed any extra arguments that were
46
+ # passed to the `include` directive. It is called in the context of the tool,
47
+ # so it also has access to tool methods such as {Toys::Tool#option}. It can
48
+ # perform any setup required, which often involves initializing some
49
+ # persistent state and storing it in the tool using {Toys::Tool#set}.
50
+ #
51
+ # ## Example
52
+ #
53
+ # This is an example that implements a simple counter. Whenever the counter
54
+ # is incremented, a log message is emitted. The tool can also retrieve the
55
+ # final counter value.
56
+ #
57
+ # # Define a mixin by creating a module that includes Toys::Mixin
58
+ # module MyCounterMixin
59
+ # include Toys::Mixin
60
+ #
61
+ # # Initialize the counter. Called with self set to the tool so it can
62
+ # # affect the tool state.
63
+ # to_initialize do |start = 0|
64
+ # set(:counter_value, start)
65
+ # end
66
+ #
67
+ # # Mixin methods are called with self set to the tool and can affect
68
+ # # the tool state.
69
+ # def increment
70
+ # self[:counter_value] += 1
71
+ # logger.info("Incremented counter")
72
+ # end
73
+ # end
74
+ #
75
+ # Now we can use it from a tool:
76
+ #
77
+ # tool "count-up" do
78
+ # # Pass 1 as an extra argument to the mixin initializer
79
+ # include MyCounterMixin, 1
80
+ #
81
+ # def run
82
+ # 5.times { increment }
83
+ # puts "Final value is #{get(:counter_value)}"
84
+ # end
85
+ # end
86
+ #
87
+ module Mixin
88
+ ## @private
89
+ def self.included(mod)
90
+ return if mod.respond_to?(:to_initialize)
91
+ mod.extend(ClassMethods)
92
+ end
93
+
94
+ ##
95
+ # Class methods that will be added to a mixin module.
96
+ #
97
+ module ClassMethods
98
+ ##
99
+ # Provide the block that initializes this mixin.
100
+ #
101
+ def to_initialize(&block)
102
+ self.initializer = block
103
+ end
104
+
105
+ ##
106
+ # You may alternately set the initializer block using this accessor.
107
+ # @return [Proc]
108
+ #
109
+ attr_accessor :initializer
110
+ end
111
+ end
112
+ end
data/lib/toys/runner.rb CHANGED
@@ -61,6 +61,7 @@ module Toys
61
61
  data = create_data(args, verbosity)
62
62
  parse_args(args, data) unless @tool_definition.argument_parsing_disabled?
63
63
  tool = @tool_definition.tool_class.new(@cli, data)
64
+ @tool_definition.run_initializers(tool)
64
65
 
65
66
  original_level = @cli.logger.level
66
67
  @cli.logger.level = @cli.base_level - data[Tool::Keys::VERBOSITY]
@@ -66,6 +66,36 @@ module Toys
66
66
  #
67
67
  DEFAULT_SEARCH_FLAGS = ["-s WORD", "--search=WORD"].freeze
68
68
 
69
+ ##
70
+ # Key set when the show help flag is present
71
+ # @return [Object]
72
+ #
73
+ SHOW_HELP_KEY = Object.new.freeze
74
+
75
+ ##
76
+ # Key set when the show usage flag is present
77
+ # @return [Object]
78
+ #
79
+ SHOW_USAGE_KEY = Object.new.freeze
80
+
81
+ ##
82
+ # Key for the recursive setting
83
+ # @return [Object]
84
+ #
85
+ RECURSIVE_SUBTOOLS_KEY = Object.new.freeze
86
+
87
+ ##
88
+ # Key for the search string
89
+ # @return [Object]
90
+ #
91
+ SEARCH_STRING_KEY = Object.new.freeze
92
+
93
+ ##
94
+ # Key for the tool name
95
+ # @return [Object]
96
+ #
97
+ TOOL_NAME_KEY = Object.new.freeze
98
+
69
99
  ##
70
100
  # Create a ShowHelp middleware.
71
101
  #
@@ -155,7 +185,7 @@ module Toys
155
185
  usage_flags = add_usage_flags(tool_definition)
156
186
  if @allow_root_args && (!help_flags.empty? || !usage_flags.empty?)
157
187
  if tool_definition.root? && tool_definition.arg_definitions.empty?
158
- tool_definition.set_remaining_args(:_tool_name,
188
+ tool_definition.set_remaining_args(TOOL_NAME_KEY,
159
189
  display_name: "TOOL_NAME",
160
190
  desc: "The tool for which to display help")
161
191
  end
@@ -173,15 +203,15 @@ module Toys
173
203
  # Display help text if requested.
174
204
  #
175
205
  def run(tool)
176
- if tool[:_show_usage]
206
+ if tool[SHOW_USAGE_KEY]
177
207
  help_text = get_help_text(tool)
178
208
  str = help_text.usage_string(wrap_width: terminal.width)
179
209
  terminal.puts(str)
180
210
  elsif @fallback_execution && !tool[Tool::Keys::TOOL_DEFINITION].runnable? ||
181
- tool[:_show_help]
211
+ tool[SHOW_HELP_KEY]
182
212
  help_text = get_help_text(tool)
183
- str = help_text.help_string(recursive: tool[:_recursive_subtools],
184
- search: tool[:_search_subtools],
213
+ str = help_text.help_string(recursive: tool[RECURSIVE_SUBTOOLS_KEY],
214
+ search: tool[SEARCH_STRING_KEY],
185
215
  show_source_path: @show_source_path,
186
216
  wrap_width: terminal.width)
187
217
  output_help(str)
@@ -216,7 +246,7 @@ module Toys
216
246
  end
217
247
 
218
248
  def get_help_text(tool)
219
- tool_name = tool[:_tool_name]
249
+ tool_name = tool[TOOL_NAME_KEY]
220
250
  return Utils::HelpText.from_tool(tool) if tool_name.nil? || tool_name.empty?
221
251
  loader = tool[Tool::Keys::LOADER]
222
252
  tool_definition, rest = loader.lookup(tool_name)
@@ -236,7 +266,7 @@ module Toys
236
266
  help_flags = resolve_flags_spec(@help_flags, tool_definition, DEFAULT_HELP_FLAGS)
237
267
  unless help_flags.empty?
238
268
  tool_definition.add_flag(
239
- :_show_help, help_flags,
269
+ SHOW_HELP_KEY, help_flags,
240
270
  report_collisions: false,
241
271
  desc: "Display help for this tool"
242
272
  )
@@ -248,7 +278,7 @@ module Toys
248
278
  usage_flags = resolve_flags_spec(@usage_flags, tool_definition, DEFAULT_USAGE_FLAGS)
249
279
  unless usage_flags.empty?
250
280
  tool_definition.add_flag(
251
- :_show_usage, usage_flags,
281
+ SHOW_USAGE_KEY, usage_flags,
252
282
  report_collisions: false,
253
283
  desc: "Display a brief usage string for this tool"
254
284
  )
@@ -261,7 +291,7 @@ module Toys
261
291
  DEFAULT_RECURSIVE_FLAGS)
262
292
  unless recursive_flags.empty?
263
293
  tool_definition.add_flag(
264
- :_recursive_subtools, recursive_flags,
294
+ RECURSIVE_SUBTOOLS_KEY, recursive_flags,
265
295
  report_collisions: false, default: @default_recursive,
266
296
  desc: "Show all subtools recursively (default is #{@default_recursive})"
267
297
  )
@@ -272,7 +302,7 @@ module Toys
272
302
  search_flags = resolve_flags_spec(@search_flags, tool_definition, DEFAULT_SEARCH_FLAGS)
273
303
  unless search_flags.empty?
274
304
  tool_definition.add_flag(
275
- :_search_subtools, search_flags,
305
+ SEARCH_STRING_KEY, search_flags,
276
306
  report_collisions: false,
277
307
  desc: "Search subtools for the given regular expression"
278
308
  )
@@ -48,6 +48,12 @@ module Toys
48
48
  #
49
49
  DEFAULT_VERSION_FLAG_DESC = "Display the version".freeze
50
50
 
51
+ ##
52
+ # Key set when the version flag is present
53
+ # @return [Object]
54
+ #
55
+ SHOW_VERSION_KEY = Object.new.freeze
56
+
51
57
  ##
52
58
  # Create a ShowVersion middleware
53
59
  #
@@ -72,7 +78,7 @@ module Toys
72
78
  #
73
79
  def config(tool_definition, _loader)
74
80
  if @version_string && tool_definition.root?
75
- tool_definition.add_flag(:_show_version, @version_flags,
81
+ tool_definition.add_flag(SHOW_VERSION_KEY, @version_flags,
76
82
  report_collisions: false, desc: @version_flag_desc)
77
83
  end
78
84
  yield
@@ -82,7 +88,7 @@ module Toys
82
88
  # This middleware displays the version.
83
89
  #
84
90
  def run(tool)
85
- if tool[:_show_version]
91
+ if tool[SHOW_VERSION_KEY]
86
92
  @terminal.puts(@version_string)
87
93
  else
88
94
  yield
@@ -44,6 +44,26 @@ module Toys
44
44
  # available in that class's documentation.
45
45
  #
46
46
  module Exec
47
+ include Mixin
48
+
49
+ ##
50
+ # Context key for the executor object.
51
+ # @return [Object]
52
+ #
53
+ KEY = ::Object.new.freeze
54
+
55
+ to_initialize do |opts = {}|
56
+ tool = self
57
+ tool[KEY] = Utils::Exec.new(opts) do |k|
58
+ case k
59
+ when :logger
60
+ tool[Tool::Keys::LOGGER]
61
+ when :cli
62
+ tool[Tool::Keys::CLI]
63
+ end
64
+ end
65
+ end
66
+
47
67
  ##
48
68
  # Set default configuration keys.
49
69
  #
@@ -51,7 +71,7 @@ module Toys
51
71
  # configuration options in the {Toys::Utils::Exec} docs.
52
72
  #
53
73
  def configure_exec(opts = {})
54
- Exec._exec(self).configure_defaults(Exec._setup_exec_opts(opts, self))
74
+ self[KEY].configure_defaults(Exec._setup_exec_opts(opts, self))
55
75
  end
56
76
 
57
77
  ##
@@ -71,7 +91,7 @@ module Toys
71
91
  # the exit code and any captured output.
72
92
  #
73
93
  def exec(cmd, opts = {}, &block)
74
- Exec._exec(self).exec(cmd, Exec._setup_exec_opts(opts, self), &block)
94
+ self[KEY].exec(cmd, Exec._setup_exec_opts(opts, self), &block)
75
95
  end
76
96
 
77
97
  ##
@@ -90,7 +110,7 @@ module Toys
90
110
  # the exit code and any captured output.
91
111
  #
92
112
  def exec_ruby(args, opts = {}, &block)
93
- Exec._exec(self).exec_ruby(args, Exec._setup_exec_opts(opts, self), &block)
113
+ self[KEY].exec_ruby(args, Exec._setup_exec_opts(opts, self), &block)
94
114
  end
95
115
  alias ruby exec_ruby
96
116
 
@@ -110,7 +130,7 @@ module Toys
110
130
  # exit code and any captured output.
111
131
  #
112
132
  def exec_proc(func, opts = {}, &block)
113
- Exec._exec(self).exec_proc(func, Exec._setup_exec_opts(opts, self), &block)
133
+ self[KEY].exec_proc(func, Exec._setup_exec_opts(opts, self), &block)
114
134
  end
115
135
 
116
136
  ##
@@ -131,7 +151,7 @@ module Toys
131
151
  #
132
152
  def exec_tool(cmd, opts = {}, &block)
133
153
  func = Exec._make_tool_caller(cmd)
134
- Exec._exec(self).exec_proc(func, Exec._setup_exec_opts(opts, self), &block)
154
+ self[KEY].exec_proc(func, Exec._setup_exec_opts(opts, self), &block)
135
155
  end
136
156
 
137
157
  ##
@@ -147,7 +167,7 @@ module Toys
147
167
  # @return [String] What was written to standard out.
148
168
  #
149
169
  def capture(cmd, opts = {})
150
- Exec._exec(self).capture(cmd, Exec._setup_exec_opts(opts, self))
170
+ self[KEY].capture(cmd, Exec._setup_exec_opts(opts, self))
151
171
  end
152
172
 
153
173
  ##
@@ -162,7 +182,7 @@ module Toys
162
182
  # @return [String] What was written to standard out.
163
183
  #
164
184
  def capture_ruby(args, opts = {})
165
- Exec._exec(self).capture_ruby(args, Exec._setup_exec_opts(opts, self))
185
+ self[KEY].capture_ruby(args, Exec._setup_exec_opts(opts, self))
166
186
  end
167
187
 
168
188
  ##
@@ -177,7 +197,7 @@ module Toys
177
197
  # @return [String] What was written to standard out.
178
198
  #
179
199
  def capture_proc(func, opts = {})
180
- Exec._exec(self).capture_proc(func, Exec._setup_exec_opts(opts, self))
200
+ self[KEY].capture_proc(func, Exec._setup_exec_opts(opts, self))
181
201
  end
182
202
 
183
203
  ##
@@ -194,7 +214,7 @@ module Toys
194
214
  #
195
215
  def capture_tool(cmd, opts = {})
196
216
  func = Exec._make_tool_caller(cmd)
197
- Exec._exec(self).capture_proc(func, Exec._setup_exec_opts(opts, self))
217
+ self[KEY].capture_proc(func, Exec._setup_exec_opts(opts, self))
198
218
  end
199
219
 
200
220
  ##
@@ -207,7 +227,7 @@ module Toys
207
227
  # @return [Integer] The exit code
208
228
  #
209
229
  def sh(cmd, opts = {})
210
- Exec._exec(self).sh(cmd, Exec._setup_exec_opts(opts, self))
230
+ self[KEY].sh(cmd, Exec._setup_exec_opts(opts, self))
211
231
  end
212
232
 
213
233
  ##
@@ -222,18 +242,6 @@ module Toys
222
242
  0
223
243
  end
224
244
 
225
- ## @private
226
- def self._exec(tool)
227
- tool[Exec] ||= Utils::Exec.new do |k|
228
- case k
229
- when :logger
230
- tool[Tool::Keys::LOGGER]
231
- when :cli
232
- tool[Tool::Keys::CLI]
233
- end
234
- end
235
- end
236
-
237
245
  ## @private
238
246
  def self._make_tool_caller(cmd)
239
247
  cmd = ::Shellwords.split(cmd) if cmd.is_a?(::String)
@@ -41,6 +41,8 @@ module Toys
41
41
  # include :fileutils
42
42
  #
43
43
  module Fileutils
44
+ include Mixin
45
+
44
46
  ## @private
45
47
  def self.included(mod)
46
48
  mod.include(::FileUtils)
@@ -27,7 +27,7 @@
27
27
  # POSSIBILITY OF SUCH DAMAGE.
28
28
  ;
29
29
 
30
- Toys::Utils::Gems.activate("highline", "~> 1.7")
30
+ Toys::Utils::Gems.activate("highline", "~> 2.0")
31
31
  require "highline"
32
32
 
33
33
  module Toys
@@ -41,15 +41,25 @@ module Toys
41
41
  # include :highline
42
42
  #
43
43
  module Highline
44
+ include Mixin
45
+
46
+ ##
47
+ # Context key for the executor object.
48
+ # @return [Object]
49
+ #
50
+ KEY = ::Object.new.freeze
51
+
52
+ to_initialize do |*args|
53
+ self[KEY] = ::HighLine.new(*args)
54
+ self[KEY].use_color = $stdout.tty?
55
+ end
56
+
44
57
  ##
45
58
  # Returns a global highline instance
46
59
  # @return [::HighLine]
47
60
  #
48
61
  def highline
49
- self[Highline] ||= begin
50
- ::HighLine.use_color = $stdout.tty?
51
- ::HighLine.new
52
- end
62
+ self[KEY]
53
63
  end
54
64
 
55
65
  ##
@@ -88,38 +98,52 @@ module Toys
88
98
  end
89
99
 
90
100
  ##
91
- # @see https://www.rubydoc.info/gems/highline/HighLine.color HighLine.color
101
+ # @see https://www.rubydoc.info/gems/highline/HighLine:indent HighLine#indent
92
102
  #
93
- def color(*args, &block)
94
- ::HighLine.color(*args, &block)
103
+ def indent(*args, &block)
104
+ highline.indent(*args, &block)
95
105
  end
96
106
 
97
107
  ##
98
- # @see https://www.rubydoc.info/gems/highline/HighLine.color_code HighLine.color_code
108
+ # @see https://www.rubydoc.info/gems/highline/HighLine:newline HighLine#newline
99
109
  #
100
- def color_code(*args, &block)
101
- ::HighLine.color_code(*args, &block)
110
+ def newline
111
+ highline.newline
102
112
  end
103
113
 
104
114
  ##
105
- # @see https://www.rubydoc.info/gems/highline/HighLine.uncolor HighLine.uncolor
115
+ # @see https://www.rubydoc.info/gems/highline/HighLine:puts HighLine#puts
106
116
  #
107
- def uncolor(*args, &block)
108
- ::HighLine.uncolor(*args, &block)
117
+ def puts(*args)
118
+ highline.puts(*args)
109
119
  end
110
120
 
111
121
  ##
112
- # @see https://www.rubydoc.info/gems/highline/HighLine:indent HighLine#indent
122
+ # @see https://www.rubydoc.info/gems/highline/HighLine:color HighLine#color
113
123
  #
114
- def indent(*args, &block)
115
- highline.indent(*args, &block)
124
+ def color(*args)
125
+ highline.color(*args)
116
126
  end
117
127
 
118
128
  ##
119
- # @see https://www.rubydoc.info/gems/highline/HighLine:newline HighLine#newline
129
+ # @see https://www.rubydoc.info/gems/highline/HighLine:color_code HighLine#color_code
130
+ #
131
+ def color_code(*args)
132
+ highline.color_code(*args)
133
+ end
134
+
135
+ ##
136
+ # @see https://www.rubydoc.info/gems/highline/HighLine:uncolor HighLine#uncolor
137
+ #
138
+ def uncolor(*args)
139
+ highline.uncolor(*args)
140
+ end
141
+
142
+ ##
143
+ # @see https://www.rubydoc.info/gems/highline/HighLine:new_scope HighLine#new_scope
120
144
  #
121
- def newline(*args, &block)
122
- highline.newline(*args, &block)
145
+ def new_scope
146
+ highline.new_scope
123
147
  end
124
148
  end
125
149
  end
@@ -32,7 +32,9 @@ module Toys
32
32
  ##
33
33
  # A mixin that provides a simple terminal. It includes a set of methods
34
34
  # that produce styled output, get user input, and otherwise interact with
35
- # the user's terminal.
35
+ # the user's terminal. This mixin is not as richly featured as other mixins
36
+ # such as Highline, but it has no gem dependencies so is ideal for basic
37
+ # cases.
36
38
  #
37
39
  # You may make these methods available to your tool by including the
38
40
  # following directive in your tool configuration:
@@ -40,12 +42,24 @@ module Toys
40
42
  # include :terminal
41
43
  #
42
44
  module Terminal
45
+ include Mixin
46
+
47
+ ##
48
+ # Context key for the terminal object.
49
+ # @return [Object]
50
+ #
51
+ KEY = ::Object.new.freeze
52
+
53
+ to_initialize do |opts = {}|
54
+ self[KEY] = Utils::Terminal.new(opts)
55
+ end
56
+
43
57
  ##
44
58
  # Returns a global terminal instance
45
59
  # @return [Toys::Utils::Terminal]
46
60
  #
47
61
  def terminal
48
- self[Terminal] ||= Utils::Terminal.new
62
+ self[KEY]
49
63
  end
50
64
 
51
65
  ##
data/lib/toys/template.rb CHANGED
@@ -77,7 +77,7 @@ module Toys
77
77
  # to_expand do |template|
78
78
  # desc "Prints a greeting to #{template.name}"
79
79
  # tool "templated-greeting" do
80
- # run do
80
+ # to_run do
81
81
  # puts "Hello, #{template.name}!"
82
82
  # end
83
83
  # end
@@ -112,7 +112,7 @@ module Toys
112
112
  # Provide the block that implements the template.
113
113
  #
114
114
  def to_expand(&block)
115
- @expander = block
115
+ self.expander = block
116
116
  end
117
117
 
118
118
  ##
data/lib/toys/tool.rb CHANGED
@@ -257,18 +257,6 @@ module Toys
257
257
  end
258
258
  end
259
259
 
260
- ##
261
- # Returns the value of the given option. Returns only options with string
262
- # or symbol keys; returns `nil` if passed other well-known context keys
263
- # such as verbosity.
264
- #
265
- # @param [String,Symbol] key
266
- # @return [Object]
267
- #
268
- def option(key)
269
- key.is_a?(::Symbol) || key.is_a?(::String) ? @__data[key] : nil
270
- end
271
-
272
260
  ##
273
261
  # Activate the given gem. If it is not present, attempt to install it (or
274
262
  # inform the user to update the bundle).
data/lib/toys-core.rb CHANGED
@@ -75,6 +75,7 @@ require "toys/errors"
75
75
  require "toys/input_file"
76
76
  require "toys/loader"
77
77
  require "toys/middleware"
78
+ require "toys/mixin"
78
79
  require "toys/runner"
79
80
  require "toys/template"
80
81
  require "toys/tool"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toys-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9.1
4
+ version: 0.3.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-25 00:00:00.000000000 Z
11
+ date: 2018-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -108,6 +108,7 @@ files:
108
108
  - lib/toys/input_file.rb
109
109
  - lib/toys/loader.rb
110
110
  - lib/toys/middleware.rb
111
+ - lib/toys/mixin.rb
111
112
  - lib/toys/runner.rb
112
113
  - lib/toys/standard_middleware/add_verbosity_flags.rb
113
114
  - lib/toys/standard_middleware/handle_usage_errors.rb