toys-core 0.11.2 → 0.12.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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -1
  3. data/README.md +1 -1
  4. data/lib/toys-core.rb +4 -1
  5. data/lib/toys/acceptor.rb +3 -3
  6. data/lib/toys/arg_parser.rb +6 -7
  7. data/lib/toys/cli.rb +44 -14
  8. data/lib/toys/compat.rb +19 -22
  9. data/lib/toys/completion.rb +3 -1
  10. data/lib/toys/context.rb +2 -2
  11. data/lib/toys/core.rb +1 -1
  12. data/lib/toys/dsl/base.rb +85 -0
  13. data/lib/toys/dsl/flag.rb +3 -3
  14. data/lib/toys/dsl/flag_group.rb +7 -7
  15. data/lib/toys/dsl/internal.rb +206 -0
  16. data/lib/toys/dsl/positional_arg.rb +3 -3
  17. data/lib/toys/dsl/tool.rb +174 -216
  18. data/lib/toys/errors.rb +1 -0
  19. data/lib/toys/flag.rb +15 -18
  20. data/lib/toys/flag_group.rb +5 -4
  21. data/lib/toys/input_file.rb +4 -4
  22. data/lib/toys/loader.rb +189 -50
  23. data/lib/toys/middleware.rb +1 -1
  24. data/lib/toys/mixin.rb +2 -2
  25. data/lib/toys/positional_arg.rb +3 -3
  26. data/lib/toys/settings.rb +900 -0
  27. data/lib/toys/source_info.rb +121 -18
  28. data/lib/toys/standard_middleware/apply_config.rb +5 -4
  29. data/lib/toys/standard_middleware/set_default_descriptions.rb +18 -18
  30. data/lib/toys/standard_middleware/show_help.rb +17 -5
  31. data/lib/toys/standard_mixins/bundler.rb +5 -1
  32. data/lib/toys/standard_mixins/exec.rb +22 -15
  33. data/lib/toys/standard_mixins/git_cache.rb +48 -0
  34. data/lib/toys/standard_mixins/xdg.rb +56 -0
  35. data/lib/toys/template.rb +2 -2
  36. data/lib/toys/{tool.rb → tool_definition.rb} +100 -41
  37. data/lib/toys/utils/exec.rb +37 -16
  38. data/lib/toys/utils/gems.rb +48 -14
  39. data/lib/toys/utils/git_cache.rb +184 -0
  40. data/lib/toys/utils/help_text.rb +90 -34
  41. data/lib/toys/utils/terminal.rb +1 -1
  42. data/lib/toys/utils/xdg.rb +293 -0
  43. metadata +15 -8
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Toys
6
+ module StandardMixins
7
+ ##
8
+ # A mixin that provides a git cache.
9
+ #
10
+ # This mixin provides an instance of {Toys::Utils::GitCache}, providing
11
+ # cached access to files from a remote git repo.
12
+ #
13
+ # Example usage:
14
+ #
15
+ # include :git_cache
16
+ #
17
+ # def run
18
+ # # Pull and cache the HEAD commit from the Toys repo.
19
+ # dir = git_cache.find("https://github.com/dazuma/toys.git")
20
+ # # Display the contents of the readme file.
21
+ # puts File.read(File.join(dir, "README.md"))
22
+ # end
23
+ #
24
+ module GitCache
25
+ include Mixin
26
+
27
+ ##
28
+ # Context key for the GitCache object.
29
+ # @return [Object]
30
+ #
31
+ KEY = ::Object.new.freeze
32
+
33
+ on_initialize do
34
+ require "toys/utils/git_cache"
35
+ self[KEY] = Utils::GitCache.new
36
+ end
37
+
38
+ ##
39
+ # Access the builtin GitCache.
40
+ #
41
+ # @return [Toys::Utils::GitCache]
42
+ #
43
+ def git_cache
44
+ self[KEY]
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Toys
6
+ module StandardMixins
7
+ ##
8
+ # A mixin that provides tools for working with the XDG Base Directory
9
+ # Specification.
10
+ #
11
+ # This mixin provides an instance of {Toys::Utils::XDG}, which includes
12
+ # utility methods that locate base directories and search paths for
13
+ # application state, configuration, caches, and other data, according to
14
+ # the [XDG Base Directory Spec version
15
+ # 0.8](https://specifications.freedesktop.org/basedir-spec/0.8/).
16
+ #
17
+ # Example usage:
18
+ #
19
+ # include :xdg
20
+ #
21
+ # def run
22
+ # # Get config file paths, in order from most to least inportant
23
+ # config_files = xdg.lookup_config("my-config.toml")
24
+ # config_files.each { |path| read_my_config(path) }
25
+ # end
26
+ #
27
+ module XDG
28
+ include Mixin
29
+
30
+ ##
31
+ # Context key for the XDG object.
32
+ # @return [Object]
33
+ #
34
+ KEY = ::Object.new.freeze
35
+
36
+ on_initialize do
37
+ require "toys/utils/xdg"
38
+ self[KEY] = Utils::XDG.new
39
+ end
40
+
41
+ ##
42
+ # Access XDG utility methods.
43
+ #
44
+ # @return [Toys::Utils::XDG]
45
+ #
46
+ def xdg
47
+ self[KEY]
48
+ end
49
+ end
50
+
51
+ ##
52
+ # An alternate name for the {XDG} module
53
+ #
54
+ Xdg = XDG
55
+ end
56
+ end
data/lib/toys/template.rb CHANGED
@@ -10,7 +10,7 @@ module Toys
10
10
  # Templates will often support configuration; for example the minitest
11
11
  # template lets you configure the paths to the test files.
12
12
  #
13
- # ## Usage
13
+ # ### Usage
14
14
  #
15
15
  # To create a template, define a class and include this module.
16
16
  # The class defines the "configuration" of the template. If your template
@@ -25,7 +25,7 @@ module Toys
25
25
  # this block are "inserted" into the user's configuration. The template
26
26
  # object is passed to the block so you have access to the template options.
27
27
  #
28
- # ## Example
28
+ # ### Example
29
29
  #
30
30
  # This is a simple template that generates a "hello" tool. The tool simply
31
31
  # prints a `"Hello, #{name}!"` greeting. The name is set as a template
@@ -4,22 +4,25 @@ require "set"
4
4
 
5
5
  module Toys
6
6
  ##
7
- # A Tool describes a single command that can be invoked using Toys.
7
+ # A ToolDefinition describes a single command that can be invoked using Toys.
8
8
  # It has a name, a series of one or more words that you use to identify
9
9
  # the tool on the command line. It also has a set of formal flags and
10
10
  # command line arguments supported, and a block that gets run when the
11
11
  # tool is executed.
12
12
  #
13
- class Tool
13
+ class ToolDefinition
14
14
  ##
15
15
  # Create a new tool.
16
16
  # Should be created only from the DSL via the Loader.
17
17
  # @private
18
18
  #
19
- def initialize(loader, parent, full_name, priority, middleware_stack, middleware_lookup)
19
+ def initialize(parent, full_name, priority, source_root, middleware_stack, middleware_lookup,
20
+ tool_class = nil)
20
21
  @parent = parent
22
+ @settings = Settings.new(parent: parent&.settings)
21
23
  @full_name = full_name.dup.freeze
22
24
  @priority = priority
25
+ @source_root = source_root
23
26
  @built_middleware = middleware_stack.build(middleware_lookup)
24
27
  @subtool_middleware_stack = middleware_stack.dup
25
28
 
@@ -28,7 +31,9 @@ module Toys
28
31
  @templates = {}
29
32
  @completions = {}
30
33
 
31
- reset_definition(loader)
34
+ @precreated_class = tool_class
35
+
36
+ reset_definition
32
37
  end
33
38
 
34
39
  ##
@@ -37,8 +42,8 @@ module Toys
37
42
  # Should be called only from the DSL.
38
43
  # @private
39
44
  #
40
- def reset_definition(loader)
41
- @tool_class = DSL::Tool.new_class(@full_name, @priority, loader)
45
+ def reset_definition
46
+ @tool_class = @precreated_class || create_class
42
47
 
43
48
  @source_info = nil
44
49
  @definition_finished = false
@@ -72,6 +77,13 @@ module Toys
72
77
  @completion = DefaultCompletion.new
73
78
  end
74
79
 
80
+ ##
81
+ # Settings for this tool
82
+ #
83
+ # @return [Toys::Tool::Settings]
84
+ #
85
+ attr_reader :settings
86
+
75
87
  ##
76
88
  # The name of the tool as an array of strings.
77
89
  # This array may not be modified.
@@ -87,6 +99,13 @@ module Toys
87
99
  #
88
100
  attr_reader :priority
89
101
 
102
+ ##
103
+ # The root source info defining this tool, or nil if there is no source.
104
+ #
105
+ # @return [Toys::SourceInfo,nil]
106
+ #
107
+ attr_reader :source_root
108
+
90
109
  ##
91
110
  # The tool class.
92
111
  #
@@ -217,14 +236,14 @@ module Toys
217
236
  #
218
237
  # When reading, this may return an instance of one of the subclasses of
219
238
  # {Toys::Completion::Base}, or a Proc that duck-types it. Generally, this
220
- # defaults to a {Toys::Tool::DefaultCompletion}, providing a standard
221
- # algorithm that finds appropriate completions from flags, positional
222
- # arguments, and subtools.
239
+ # defaults to a {Toys::ToolDefinition::DefaultCompletion}, providing a
240
+ # standard algorithm that finds appropriate completions from flags,
241
+ # positional arguments, and subtools.
223
242
  #
224
243
  # When setting, you may pass any of the following:
225
244
  # * `nil` or `:default` which sets the value to a default instance.
226
- # * A Hash of options to pass to the {Toys::Tool::DefaultCompletion}
227
- # constructor.
245
+ # * A Hash of options to pass to the
246
+ # {Toys::ToolDefinition::DefaultCompletion} constructor.
228
247
  # * Any other form recognized by {Toys::Completion.create}.
229
248
  #
230
249
  # @return [Toys::Completion::Base,Proc]
@@ -408,7 +427,7 @@ module Toys
408
427
  # Get the named acceptor from this tool or its ancestors.
409
428
  #
410
429
  # @param name [String] The acceptor name.
411
- # @return [Tool::Acceptor::Base] The acceptor.
430
+ # @return [Toys::Acceptor::Base] The acceptor.
412
431
  # @return [nil] if no acceptor of the given name is found.
413
432
  #
414
433
  def lookup_acceptor(name)
@@ -441,7 +460,7 @@ module Toys
441
460
  # Get the named completion from this tool or its ancestors.
442
461
  #
443
462
  # @param name [String] The completion name
444
- # @return [Tool::Completion::Base,Proc] The completion proc.
463
+ # @return [Toys::Completion::Base,Proc] The completion proc.
445
464
  # @return [nil] if no completion of the given name is found.
446
465
  #
447
466
  def lookup_completion(name)
@@ -451,11 +470,31 @@ module Toys
451
470
  ##
452
471
  # Include the given mixin in the tool class.
453
472
  #
454
- # @param name [String,Symbol,Module] The mixin name or module
473
+ # The mixin must be given as a module. You can use {#lookup_mixin} or
474
+ # {Loader#resolve_standard_mixin} to resolve named mixins.
475
+ #
476
+ # @param mod [Module] The mixin module
455
477
  # @return [self]
456
478
  #
457
- def include_mixin(name)
458
- tool_class.include(name)
479
+ def include_mixin(mod, *args, **kwargs)
480
+ check_definition_state
481
+ if tool_class.included_modules.include?(mod)
482
+ raise ToolDefinitionError, "Mixin already included: #{mod.name}"
483
+ end
484
+ @includes_modules = true
485
+ if tool_class.respond_to?(:super_include)
486
+ tool_class.super_include(mod)
487
+ else
488
+ tool_class.include(mod)
489
+ end
490
+ if mod.respond_to?(:initializer)
491
+ callback = mod.initializer
492
+ add_initializer(callback, *args, **kwargs) if callback
493
+ end
494
+ if mod.respond_to?(:inclusion)
495
+ callback = mod.inclusion
496
+ tool_class.class_exec(*args, **kwargs, &callback) if callback
497
+ end
459
498
  self
460
499
  end
461
500
 
@@ -565,7 +604,7 @@ module Toys
565
604
  # completion.
566
605
  #
567
606
  # @param name [String] The name of the completion.
568
- # @param completion [Proc,Tool::Completion::Base,Object] The completion to
607
+ # @param completion [Proc,Toys::Completion::Base,Object] The completion to
569
608
  # add. You can provide either a completion object, or a spec understood
570
609
  # by {Toys::Completion.create}.
571
610
  # @param options [Hash] Additional options to pass to the completion.
@@ -669,11 +708,12 @@ module Toys
669
708
  #
670
709
  # @param type [Symbol] The type of group. Default is `:optional`.
671
710
  # @param desc [String,Array<String>,Toys::WrappableString] Short
672
- # description for the group. See {Toys::Tool#desc=} for a description
673
- # of allowed formats. Defaults to `"Flags"`.
711
+ # description for the group. See {Toys::ToolDefinition#desc} for a
712
+ # description of allowed formats. Defaults to `"Flags"`.
674
713
  # @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
675
- # Long description for the flag group. See {Toys::Tool#long_desc=} for
676
- # a description of allowed formats. Defaults to the empty array.
714
+ # Long description for the flag group. See
715
+ # {Toys::ToolDefinition#long_desc} for a description of allowed
716
+ # formats. Defaults to the empty array.
677
717
  # @param name [String,Symbol,nil] The name of the group, or nil for no
678
718
  # name.
679
719
  # @param report_collisions [Boolean] If `true`, raise an exception if a
@@ -741,11 +781,11 @@ module Toys
741
781
  # this flag. You may provide a group name, a FlagGroup object, or
742
782
  # `nil` which denotes the default group.
743
783
  # @param desc [String,Array<String>,Toys::WrappableString] Short
744
- # description for the flag. See {Toys::Tool#desc=} for a description of
745
- # allowed formats. Defaults to the empty string.
784
+ # description for the flag. See {Toys::ToolDefinition#desc} for a
785
+ # description of allowed formats. Defaults to the empty string.
746
786
  # @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
747
- # Long description for the flag. See {Toys::Tool#long_desc=} for a
748
- # description of allowed formats. Defaults to the empty array.
787
+ # Long description for the flag. See {Toys::ToolDefinition#long_desc}
788
+ # for a description of allowed formats. Defaults to the empty array.
749
789
  # @param display_name [String] A display name for this flag, used in help
750
790
  # text and error messages.
751
791
  # @return [self]
@@ -808,11 +848,11 @@ module Toys
808
848
  # @param display_name [String] A name to use for display (in help text and
809
849
  # error reports). Defaults to the key in upper case.
810
850
  # @param desc [String,Array<String>,Toys::WrappableString] Short
811
- # description for the arg. See {Toys::Tool#desc=} for a description of
812
- # allowed formats. Defaults to the empty string.
851
+ # description for the arg. See {Toys::ToolDefinition#desc} for a
852
+ # description of allowed formats. Defaults to the empty string.
813
853
  # @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
814
- # Long description for the arg. See {Toys::Tool#long_desc=} for a
815
- # description of allowed formats. Defaults to the empty array.
854
+ # Long description for the arg. See {Toys::ToolDefinition#long_desc}
855
+ # for a description of allowed formats. Defaults to the empty array.
816
856
  # @return [self]
817
857
  #
818
858
  def add_required_arg(key, accept: nil, complete: nil, display_name: nil,
@@ -846,11 +886,11 @@ module Toys
846
886
  # @param display_name [String] A name to use for display (in help text and
847
887
  # error reports). Defaults to the key in upper case.
848
888
  # @param desc [String,Array<String>,Toys::WrappableString] Short
849
- # description for the arg. See {Toys::Tool#desc=} for a description of
850
- # allowed formats. Defaults to the empty string.
889
+ # description for the arg. See {Toys::ToolDefinition#desc} for a
890
+ # description of allowed formats. Defaults to the empty string.
851
891
  # @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
852
- # Long description for the arg. See {Toys::Tool#long_desc=} for a
853
- # description of allowed formats. Defaults to the empty array.
892
+ # Long description for the arg. See {Toys::ToolDefinition#long_desc}
893
+ # for a description of allowed formats. Defaults to the empty array.
854
894
  # @return [self]
855
895
  #
856
896
  def add_optional_arg(key, default: nil, accept: nil, complete: nil,
@@ -884,11 +924,11 @@ module Toys
884
924
  # @param display_name [String] A name to use for display (in help text and
885
925
  # error reports). Defaults to the key in upper case.
886
926
  # @param desc [String,Array<String>,Toys::WrappableString] Short
887
- # description for the arg. See {Toys::Tool#desc=} for a description of
888
- # allowed formats. Defaults to the empty string.
927
+ # description for the arg. See {Toys::ToolDefinition#desc} for a
928
+ # description of allowed formats. Defaults to the empty string.
889
929
  # @param long_desc [Array<String,Array<String>,Toys::WrappableString>]
890
- # Long description for the arg. See {Toys::Tool#long_desc=} for a
891
- # description of allowed formats. Defaults to the empty array.
930
+ # Long description for the arg. See {Toys::ToolDefinition#long_desc}
931
+ # for a description of allowed formats. Defaults to the empty array.
892
932
  # @return [self]
893
933
  #
894
934
  def set_remaining_args(key, default: [], accept: nil, complete: nil,
@@ -910,7 +950,9 @@ module Toys
910
950
  #
911
951
  def run_handler=(proc)
912
952
  check_definition_state(is_method: true)
913
- @tool_class.to_run(&proc)
953
+ tool_class.class_eval do
954
+ define_method(:run, &proc)
955
+ end
914
956
  end
915
957
 
916
958
  ##
@@ -966,7 +1008,7 @@ module Toys
966
1008
  end
967
1009
 
968
1010
  ##
969
- # Set the completion strategy for this Tool.
1011
+ # Set the completion strategy for this ToolDefinition.
970
1012
  #
971
1013
  # See {#completion} for details.
972
1014
  #
@@ -1056,7 +1098,7 @@ module Toys
1056
1098
  def finish_definition(loader)
1057
1099
  unless @definition_finished
1058
1100
  ContextualError.capture("Error installing tool middleware!", tool_name: full_name) do
1059
- config_proc = proc {}
1101
+ config_proc = proc { nil }
1060
1102
  @built_middleware.reverse_each do |middleware|
1061
1103
  config_proc = make_config_proc(middleware, loader, config_proc)
1062
1104
  end
@@ -1120,6 +1162,7 @@ module Toys
1120
1162
  def initialize(complete_subtools: true, include_hidden_subtools: false,
1121
1163
  complete_args: true, complete_flags: true, complete_flag_values: true,
1122
1164
  delegation_target: nil)
1165
+ super()
1123
1166
  @complete_subtools = complete_subtools
1124
1167
  @include_hidden_subtools = include_hidden_subtools
1125
1168
  @complete_flags = complete_flags
@@ -1206,7 +1249,7 @@ module Toys
1206
1249
  return unless arg_parser.flags_allowed?
1207
1250
  active_flag_def = arg_parser.active_flag_def
1208
1251
  return if active_flag_def && active_flag_def.value_type == :required
1209
- match = /\A(--\w[\?\w-]*)=(.*)\z/.match(context.fragment_prefix)
1252
+ match = /\A(--\w[?\w-]*)=(.*)\z/.match(context.fragment_prefix)
1210
1253
  return unless match
1211
1254
  flag_value_context = context.with(fragment_prefix: match[2])
1212
1255
  flag_def = flag_value_context.tool.resolve_flag(match[1]).unique_flag
@@ -1287,8 +1330,24 @@ module Toys
1287
1330
  end
1288
1331
  end
1289
1332
 
1333
+ ##
1334
+ # Tool-based settings class.
1335
+ #
1336
+ # The following settings are supported:
1337
+ #
1338
+ # * `propagate_helper_methods` (_Boolean_) - Whether subtools should
1339
+ # inherit methods defined by parent tools. Defaults to `false`.
1340
+ #
1341
+ class Settings < ::Toys::Settings
1342
+ settings_attr :propagate_helper_methods, default: false
1343
+ end
1344
+
1290
1345
  private
1291
1346
 
1347
+ def create_class
1348
+ ::Class.new(@parent&.settings&.propagate_helper_methods ? @parent.tool_class : ::Toys::Context)
1349
+ end
1350
+
1292
1351
  def make_config_proc(middleware, loader, next_config)
1293
1352
  if middleware.respond_to?(:config)
1294
1353
  proc { middleware.config(self, loader, &next_config) }
@@ -16,8 +16,6 @@ module Toys
16
16
  # This class is not loaded by default. Before using it directly, you should
17
17
  # `require "toys/utils/exec"`
18
18
  #
19
- # ## Features
20
- #
21
19
  # ### Controlling processes
22
20
  #
23
21
  # A process can be started in the *foreground* or the *background*. If you
@@ -138,7 +136,7 @@ module Toys
138
136
  # end
139
137
  # exec_service.exec(["git", "init"], result_callback: my_callback)
140
138
  #
141
- # ## Configuration options
139
+ # ### Configuration options
142
140
  #
143
141
  # A variety of options can be used to control subprocesses. These can be
144
142
  # provided to any method that starts a subprocess. Youc an also set
@@ -250,13 +248,14 @@ module Toys
250
248
  exec_opts = Opts.new(@default_opts).add(opts)
251
249
  spawn_cmd =
252
250
  if cmd.is_a?(::Array)
253
- if cmd.size == 1 && cmd.first.is_a?(::String)
254
- [[cmd.first, exec_opts.config_opts[:argv0] || cmd.first]]
251
+ if cmd.size > 1
252
+ binary = canonical_binary_spec(cmd.first, exec_opts)
253
+ [binary] + cmd[1..-1].map(&:to_s)
255
254
  else
256
- cmd
255
+ [canonical_binary_spec(Array(cmd.first), exec_opts)]
257
256
  end
258
257
  else
259
- [cmd]
258
+ [cmd.to_s]
260
259
  end
261
260
  executor = Executor.new(exec_opts, spawn_cmd, block)
262
261
  executor.execute
@@ -796,7 +795,7 @@ module Toys
796
795
  # {Result#success?} or {Result#error?} will return true, and
797
796
  # {Result.exit_code} will return the numeric exit code.
798
797
  # * The process executed but was terminated by an uncaught signal.
799
- # {Result#signaled?} will return true, and {Result#term_signal} will
798
+ # {Result#signaled?} will return true, and {Result#signal_code} will
800
799
  # return the numeric signal code.
801
800
  #
802
801
  class Result
@@ -848,6 +847,8 @@ module Toys
848
847
  # The exception raised if a process couldn't be started.
849
848
  #
850
849
  # Exactly one of {#exception} and {#status} will be non-nil.
850
+ # Exactly one of {#exception}, {#exit_code}, or {#signal_code} will be
851
+ # non-nil.
851
852
  #
852
853
  # @return [Exception] The exception raised from process start.
853
854
  # @return [nil] if the process started successfully.
@@ -857,7 +858,7 @@ module Toys
857
858
  ##
858
859
  # The numeric status code for a process that exited normally,
859
860
  #
860
- # Exactly one of {#exception}, {#exit_code}, and {#term_signal} will be
861
+ # Exactly one of {#exception}, {#exit_code}, or {#signal_code} will be
861
862
  # non-nil.
862
863
  #
863
864
  # @return [Integer] the numeric status code, if the process started
@@ -872,16 +873,17 @@ module Toys
872
873
  ##
873
874
  # The numeric signal code that caused process termination.
874
875
  #
875
- # Exactly one of {#exception}, {#exit_code}, and {#term_signal} will be
876
+ # Exactly one of {#exception}, {#exit_code}, or {#signal_code} will be
876
877
  # non-nil.
877
878
  #
878
879
  # @return [Integer] The signal that caused the process to terminate.
879
880
  # @return [nil] if the process did not start successfully, or executed
880
881
  # and exited with a normal exit code.
881
882
  #
882
- def term_signal
883
+ def signal_code
883
884
  status&.termsig
884
885
  end
886
+ alias term_signal signal_code
885
887
 
886
888
  ##
887
889
  # Returns true if the subprocess failed to start, or false if the
@@ -900,7 +902,7 @@ module Toys
900
902
  # @return [Boolean]
901
903
  #
902
904
  def signaled?
903
- !term_signal.nil?
905
+ !signal_code.nil?
904
906
  end
905
907
 
906
908
  ##
@@ -968,12 +970,19 @@ module Toys
968
970
  def log_command
969
971
  logger = @config_opts[:logger]
970
972
  if logger && @config_opts[:log_level] != false
971
- cmd_str = @config_opts[:log_cmd]
972
- cmd_str ||= @spawn_cmd.size == 1 ? @spawn_cmd.first : @spawn_cmd.inspect if @spawn_cmd
973
+ cmd_str = @config_opts[:log_cmd] || default_log_str(@spawn_cmd)
973
974
  logger.add(@config_opts[:log_level] || ::Logger::INFO, cmd_str) if cmd_str
974
975
  end
975
976
  end
976
977
 
978
+ def default_log_str(spawn_cmd)
979
+ return nil unless spawn_cmd
980
+ return spawn_cmd.first if spawn_cmd.size == 1 && spawn_cmd.first.is_a?(::String)
981
+ cmd_binary = spawn_cmd.first
982
+ cmd_binary = cmd_binary.first if cmd_binary.is_a?(::Array)
983
+ ([cmd_binary] + spawn_cmd[1..-1]).inspect
984
+ end
985
+
977
986
  def start_with_controller
978
987
  pid =
979
988
  begin
@@ -1082,9 +1091,10 @@ module Toys
1082
1091
 
1083
1092
  def interpret_out_array_within_fork(stream)
1084
1093
  if stream.first == :child
1085
- if stream[1] == :err
1094
+ case stream[1]
1095
+ when :err
1086
1096
  $stderr
1087
- elsif stream[1] == :out
1097
+ when :out
1088
1098
  $stdout
1089
1099
  end
1090
1100
  else
@@ -1300,6 +1310,17 @@ module Toys
1300
1310
  end
1301
1311
  end
1302
1312
  end
1313
+
1314
+ private
1315
+
1316
+ def canonical_binary_spec(cmd, exec_opts)
1317
+ config_argv0 = exec_opts.config_opts[:argv0]
1318
+ return cmd.to_s if !config_argv0 && !cmd.is_a?(::Array)
1319
+ cmd = Array(cmd)
1320
+ actual_cmd = cmd.first
1321
+ argv0 = cmd[1] || config_argv0 || actual_cmd
1322
+ [actual_cmd.to_s, argv0.to_s]
1323
+ end
1303
1324
  end
1304
1325
  end
1305
1326
  end