toys-core 0.11.5 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  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/exec.rb +12 -14
  32. data/lib/toys/standard_mixins/git_cache.rb +48 -0
  33. data/lib/toys/standard_mixins/xdg.rb +56 -0
  34. data/lib/toys/template.rb +2 -2
  35. data/lib/toys/{tool.rb → tool_definition.rb} +100 -41
  36. data/lib/toys/utils/exec.rb +4 -5
  37. data/lib/toys/utils/gems.rb +8 -7
  38. data/lib/toys/utils/git_cache.rb +184 -0
  39. data/lib/toys/utils/help_text.rb +90 -34
  40. data/lib/toys/utils/terminal.rb +1 -1
  41. data/lib/toys/utils/xdg.rb +293 -0
  42. metadata +14 -7
@@ -2,21 +2,27 @@
2
2
 
3
3
  module Toys
4
4
  ##
5
- # Information about source toys directories and files.
5
+ # Information about the source of a tool, such as the file, git repository,
6
+ # or block that defined it.
6
7
  #
7
8
  class SourceInfo
8
9
  ##
9
10
  # Create a SourceInfo.
10
11
  # @private
11
12
  #
12
- def initialize(parent, context_directory, source_type, source_path, source_proc,
13
- source_name, data_dir_name, lib_dir_name)
13
+ def initialize(parent, priority, context_directory, source_type, source_path, source_proc,
14
+ git_remote, git_path, git_commit, source_name, data_dir_name, lib_dir_name)
14
15
  @parent = parent
16
+ @root = parent&.root || self
17
+ @priority = priority
15
18
  @context_directory = context_directory
16
19
  @source_type = source_type
17
20
  @source = source_type == :proc ? source_proc : source_path
18
21
  @source_path = source_path
19
22
  @source_proc = source_proc
23
+ @git_remote = git_remote
24
+ @git_path = git_path
25
+ @git_commit = git_commit
20
26
  @source_name = source_name
21
27
  @data_dir_name = data_dir_name
22
28
  @lib_dir_name = lib_dir_name
@@ -32,6 +38,21 @@ module Toys
32
38
  #
33
39
  attr_reader :parent
34
40
 
41
+ ##
42
+ # The root ancestor of this SourceInfo.
43
+ #
44
+ # @return [Toys::SourceInfo] The root ancestor.
45
+ #
46
+ attr_reader :root
47
+
48
+ ##
49
+ # The priority of tools defined by this source. Higher values indicate a
50
+ # higher priority. Lower priority values could be negative.
51
+ #
52
+ # @return [Integer] The priority.
53
+ #
54
+ attr_reader :priority
55
+
35
56
  ##
36
57
  # The context directory path (normally the directory containing the
37
58
  # toplevel toys file or directory).
@@ -73,6 +94,30 @@ module Toys
73
94
  #
74
95
  attr_reader :source_proc
75
96
 
97
+ ##
98
+ # The git remote.
99
+ #
100
+ # @return [String] The git remote
101
+ # @return [nil] if this source is not fron git.
102
+ #
103
+ attr_reader :git_remote
104
+
105
+ ##
106
+ # The git path.
107
+ #
108
+ # @return [String] The git path. This could be the empty string.
109
+ # @return [nil] if this source is not fron git.
110
+ #
111
+ attr_reader :git_path
112
+
113
+ ##
114
+ # The git commit.
115
+ #
116
+ # @return [String] The git commit.
117
+ # @return [nil] if this source is not fron git.
118
+ #
119
+ attr_reader :git_commit
120
+
76
121
  ##
77
122
  # The user-visible name of this source.
78
123
  #
@@ -120,51 +165,109 @@ module Toys
120
165
  # Create a child SourceInfo relative to the parent path.
121
166
  # @private
122
167
  #
123
- def relative_child(filename)
124
- raise "relative_child is valid only on a directory source" unless source_type == :directory
168
+ def relative_child(filename, source_name: nil)
169
+ unless source_type == :directory
170
+ raise LoaderError, "relative_child is valid only on a directory source"
171
+ end
125
172
  child_path = ::File.join(source_path, filename)
126
173
  child_path, type = SourceInfo.check_path(child_path, true)
127
174
  return nil unless child_path
128
- SourceInfo.new(self, context_directory, type, child_path, nil, child_path,
129
- @data_dir_name, @lib_dir_name)
175
+ child_git_path = ::File.join(git_path, filename) if git_path
176
+ source_name ||=
177
+ if git_path
178
+ "git(remote=#{git_remote} path=#{child_git_path} commit=#{git_commit})"
179
+ else
180
+ child_path
181
+ end
182
+ SourceInfo.new(self, priority, context_directory, type, child_path, nil,
183
+ git_remote, child_git_path, git_commit,
184
+ source_name, @data_dir_name, @lib_dir_name)
130
185
  end
131
186
 
132
187
  ##
133
188
  # Create a child SourceInfo with an absolute path.
134
189
  # @private
135
190
  #
136
- def absolute_child(child_path)
191
+ def absolute_child(child_path, source_name: nil)
192
+ child_path, type = SourceInfo.check_path(child_path, false)
193
+ source_name ||= child_path
194
+ SourceInfo.new(self, priority, context_directory, type, child_path, nil, nil, nil, nil,
195
+ source_name, @data_dir_name, @lib_dir_name)
196
+ end
197
+
198
+ ##
199
+ # Create a child SourceInfo with a git source.
200
+ # @private
201
+ #
202
+ def git_child(child_git_remote, child_git_path, child_git_commit, child_path,
203
+ source_name: nil)
137
204
  child_path, type = SourceInfo.check_path(child_path, false)
138
- SourceInfo.new(self, context_directory, type, child_path, nil, child_path,
139
- @data_dir_name, @lib_dir_name)
205
+ source_name ||=
206
+ "git(remote=#{child_git_remote} path=#{child_git_path} commit=#{child_git_commit})"
207
+ SourceInfo.new(self, priority, context_directory, type, child_path, nil,
208
+ child_git_remote, child_git_path, child_git_commit,
209
+ source_name, @data_dir_name, @lib_dir_name)
140
210
  end
141
211
 
142
212
  ##
143
213
  # Create a proc child SourceInfo
144
214
  # @private
145
215
  #
146
- def proc_child(child_proc, source_name = nil)
216
+ def proc_child(child_proc, source_name: nil)
147
217
  source_name ||= self.source_name
148
- SourceInfo.new(self, context_directory, :proc, source_path, child_proc, source_name,
149
- @data_dir_name, @lib_dir_name)
218
+ SourceInfo.new(self, priority, context_directory, :proc, source_path, child_proc,
219
+ git_remote, git_path, git_commit,
220
+ source_name, @data_dir_name, @lib_dir_name)
150
221
  end
151
222
 
152
223
  ##
153
224
  # Create a root source info for a file path.
154
225
  # @private
155
226
  #
156
- def self.create_path_root(source_path, data_dir_name, lib_dir_name)
227
+ def self.create_path_root(source_path, priority,
228
+ context_directory: nil,
229
+ data_dir_name: nil,
230
+ lib_dir_name: nil,
231
+ source_name: nil)
232
+ source_path, type = check_path(source_path, false)
233
+ case context_directory
234
+ when :parent
235
+ context_directory = ::File.dirname(source_path)
236
+ when :path
237
+ context_directory = source_path
238
+ end
239
+ source_name ||= source_path
240
+ new(nil, priority, context_directory, type, source_path, nil, nil, nil, nil,
241
+ source_name, data_dir_name, lib_dir_name)
242
+ end
243
+
244
+ ##
245
+ # Create a root source info for a cached git repo.
246
+ # @private
247
+ #
248
+ def self.create_git_root(git_remote, git_path, git_commit, source_path, priority,
249
+ context_directory: nil,
250
+ data_dir_name: nil,
251
+ lib_dir_name: nil,
252
+ source_name: nil)
157
253
  source_path, type = check_path(source_path, false)
158
- context_directory = ::File.dirname(source_path)
159
- new(nil, context_directory, type, source_path, nil, source_path, data_dir_name, lib_dir_name)
254
+ source_name ||= "git(remote=#{git_remote} path=#{git_path} commit=#{git_commit})"
255
+ new(nil, priority, context_directory, type, source_path, nil, git_remote,
256
+ git_path, git_commit, source_name, data_dir_name, lib_dir_name)
160
257
  end
161
258
 
162
259
  ##
163
260
  # Create a root source info for a proc.
164
261
  # @private
165
262
  #
166
- def self.create_proc_root(source_proc, source_name, data_dir_name, lib_dir_name)
167
- new(nil, nil, :proc, nil, source_proc, source_name, data_dir_name, lib_dir_name)
263
+ def self.create_proc_root(source_proc, priority,
264
+ context_directory: nil,
265
+ data_dir_name: nil,
266
+ lib_dir_name: nil,
267
+ source_name: nil)
268
+ source_name ||= "(code block #{source_proc.object_id})"
269
+ new(nil, priority, context_directory, :proc, nil, source_proc, nil, nil,
270
+ nil, source_name, data_dir_name, lib_dir_name)
168
271
  end
169
272
 
170
273
  ##
@@ -19,9 +19,9 @@ module Toys
19
19
  def initialize(parent_source: nil, source_name: nil, &block)
20
20
  @source_info =
21
21
  if parent_source
22
- parent_source.proc_child(block, source_name)
22
+ parent_source.proc_child(block, source_name: source_name)
23
23
  else
24
- SourceInfo.create_proc_root(block, source_name)
24
+ SourceInfo.create_proc_root(block, source_name: source_name)
25
25
  end
26
26
  @block = block
27
27
  end
@@ -30,9 +30,10 @@ module Toys
30
30
  # Appends the configuration block.
31
31
  # @private
32
32
  #
33
- def config(tool, _loader)
33
+ def config(tool, loader)
34
34
  tool_class = tool.tool_class
35
- DSL::Tool.prepare(tool_class, nil, @source_info) do
35
+ DSL::Internal.prepare(tool_class, tool.full_name, tool.priority, nil, @source_info,
36
+ loader) do
36
37
  tool_class.class_eval(&@block)
37
38
  end
38
39
  yield
@@ -115,12 +115,12 @@ module Toys
115
115
  # By default, it uses the parameters given to the middleware object.
116
116
  # Override this method to provide different logic.
117
117
  #
118
- # @param tool [Toys::Tool] The tool to document.
118
+ # @param tool [Toys::ToolDefinition] The tool to document.
119
119
  # @param data [Hash] Additional data that might be useful. Currently,
120
120
  # the {Toys::Loader} is passed with key `:loader`. Future versions
121
121
  # of Toys may provide additional information.
122
122
  # @return [String,Array<String>,Toys::WrappableString] The default
123
- # description. See {Toys::Tool#desc=} for info on the format.
123
+ # description. See {Toys::DSL::Tool#desc} for info on the format.
124
124
  # @return [nil] if this middleware should not set the description.
125
125
  #
126
126
  def generate_tool_desc(tool, data)
@@ -141,12 +141,12 @@ module Toys
141
141
  # By default, it uses the parameters given to the middleware object.
142
142
  # Override this method to provide different logic.
143
143
  #
144
- # @param tool [Toys::Tool] The tool to document
144
+ # @param tool [Toys::ToolDefinition] The tool to document
145
145
  # @param data [Hash] Additional data that might be useful. Currently,
146
146
  # the {Toys::Loader} is passed with key `:loader`. Future versions of
147
147
  # Toys may provide additional information.
148
148
  # @return [Array<Toys::WrappableString,String,Array<String>>] The default
149
- # long description. See {Toys::Tool#long_desc=} for info on the
149
+ # long description. See {Toys::DSL::Tool#long_desc} for info on the
150
150
  # format.
151
151
  # @return [nil] if this middleware should not set the long description.
152
152
  #
@@ -166,10 +166,10 @@ module Toys
166
166
  #
167
167
  # @param flag [Toys::Flag] The flag to document
168
168
  # @param data [Hash] Additional data that might be useful. Currently,
169
- # the {Toys::Tool} is passed with key `:tool`. Future
169
+ # the {Toys::ToolDefinition} is passed with key `:tool`. Future
170
170
  # versions of Toys may provide additional information.
171
171
  # @return [String,Array<String>,Toys::WrappableString] The default
172
- # description. See {Toys::Tool#desc=} for info on the format.
172
+ # description. See {Toys::DSL::Tool#desc} for info on the format.
173
173
  # @return [nil] if this middleware should not set the description.
174
174
  #
175
175
  def generate_flag_desc(flag, data) # rubocop:disable Lint/UnusedMethodArgument
@@ -185,10 +185,10 @@ module Toys
185
185
  #
186
186
  # @param flag [Toys::Flag] The flag to document
187
187
  # @param data [Hash] Additional data that might be useful. Currently,
188
- # the {Toys::Tool} is passed with key `:tool`. Future versions of
188
+ # the {Toys::ToolDefinition} is passed with key `:tool`. Future
189
189
  # versions of Toys may provide additional information.
190
190
  # @return [Array<Toys::WrappableString,String,Array<String>>] The default
191
- # long description. See {Toys::Tool#long_desc=} for info on the
191
+ # long description. See {Toys::DSL::Tool#long_desc} for info on the
192
192
  # format.
193
193
  # @return [nil] if this middleware should not set the long description.
194
194
  #
@@ -202,10 +202,10 @@ module Toys
202
202
  #
203
203
  # @param arg [Toys::PositionalArg] The arg to document
204
204
  # @param data [Hash] Additional data that might be useful. Currently,
205
- # the {Toys::Tool} is passed with key `:tool`. Future versions of
206
- # Toys may provide additional information.
205
+ # the {Toys::ToolDefinition} is passed with key `:tool`. Future
206
+ # versions of Toys may provide additional information.
207
207
  # @return [String,Array<String>,Toys::WrappableString] The default
208
- # description. See {Toys::Tool#desc=} for info on the format.
208
+ # description. See {Toys::DSL::Tool#desc} for info on the format.
209
209
  # @return [nil] if this middleware should not set the description.
210
210
  #
211
211
  def generate_arg_desc(arg, data) # rubocop:disable Lint/UnusedMethodArgument
@@ -227,10 +227,10 @@ module Toys
227
227
  #
228
228
  # @param arg [Toys::PositionalArg] The arg to document
229
229
  # @param data [Hash] Additional data that might be useful. Currently,
230
- # the {Toys::Tool} is passed with key `:tool`. Future versions of
231
- # Toys may provide additional information.
230
+ # the {Toys::ToolDefinition} is passed with key `:tool`. Future
231
+ # versions of Toys may provide additional information.
232
232
  # @return [Array<Toys::WrappableString,String,Array<String>>] The default
233
- # long description. See {Toys::Tool#long_desc=} for info on the
233
+ # long description. See {Toys::DSL::Tool#long_desc} for info on the
234
234
  # format.
235
235
  # @return [nil] if this middleware should not set the long description.
236
236
  #
@@ -244,10 +244,10 @@ module Toys
244
244
  #
245
245
  # @param group [Toys::FlagGroup] The flag group to document
246
246
  # @param data [Hash] Additional data that might be useful. Currently,
247
- # the {Toys::Tool} is passed with key `:tool`. Future
247
+ # the {Toys::ToolDefinition} is passed with key `:tool`. Future
248
248
  # versions of Toys may provide additional information.
249
249
  # @return [String,Array<String>,Toys::WrappableString] The default
250
- # description. See {Toys::Tool#desc=} for info on the format.
250
+ # description. See {Toys::DSL::Tool#desc} for info on the format.
251
251
  # @return [nil] if this middleware should not set the description.
252
252
  #
253
253
  def generate_flag_group_desc(group, data) # rubocop:disable Lint/UnusedMethodArgument
@@ -264,10 +264,10 @@ module Toys
264
264
  #
265
265
  # @param group [Toys::FlagGroup] The flag group to document
266
266
  # @param data [Hash] Additional data that might be useful. Currently,
267
- # the {Toys::Tool} is passed with key `:tool`. Future
267
+ # the {Toys::ToolDefinition} is passed with key `:tool`. Future
268
268
  # versions of Toys may provide additional information.
269
269
  # @return [Array<Toys::WrappableString,String,Array<String>>] The default
270
- # long description. See {Toys::Tool#long_desc=} for info on the
270
+ # long description. See {Toys::DSL::Tool#long_desc} for info on the
271
271
  # format.
272
272
  # @return [nil] if this middleware should not set the long description.
273
273
  #
@@ -159,6 +159,8 @@ module Toys
159
159
  # that tool.
160
160
  # @param show_source_path [Boolean] Show the source path section. Default
161
161
  # is `false`.
162
+ # @param separate_sources [Boolean] Split up tool list by source root.
163
+ # Defaults to false.
162
164
  # @param use_less [Boolean] If the `less` tool is available, and the
163
165
  # output stream is a tty, then use `less` to display help text.
164
166
  # @param stream [IO] Output stream to write to. Default is stdout.
@@ -177,6 +179,7 @@ module Toys
177
179
  fallback_execution: false,
178
180
  allow_root_args: false,
179
181
  show_source_path: false,
182
+ separate_sources: false,
180
183
  use_less: false,
181
184
  stream: $stdout,
182
185
  styled_output: nil)
@@ -191,6 +194,7 @@ module Toys
191
194
  @fallback_execution = fallback_execution
192
195
  @allow_root_args = allow_root_args
193
196
  @show_source_path = show_source_path
197
+ @separate_sources = separate_sources
194
198
  @stream = stream
195
199
  @styled_output = styled_output
196
200
  @use_less = use_less && !Compat.jruby?
@@ -250,7 +254,9 @@ module Toys
250
254
  help_text = get_help_text(context, true)
251
255
  str = help_text.usage_string(
252
256
  recursive: context[RECURSIVE_SUBTOOLS_KEY],
253
- include_hidden: context[SHOW_ALL_SUBTOOLS_KEY], wrap_width: terminal.width
257
+ include_hidden: context[SHOW_ALL_SUBTOOLS_KEY],
258
+ separate_sources: @separate_sources,
259
+ wrap_width: terminal.width
254
260
  )
255
261
  terminal.puts(str)
256
262
  end
@@ -258,8 +264,11 @@ module Toys
258
264
  def show_list(context)
259
265
  help_text = get_help_text(context, true)
260
266
  str = help_text.list_string(
261
- recursive: context[RECURSIVE_SUBTOOLS_KEY], search: context[SEARCH_STRING_KEY],
262
- include_hidden: context[SHOW_ALL_SUBTOOLS_KEY], wrap_width: terminal.width
267
+ recursive: context[RECURSIVE_SUBTOOLS_KEY],
268
+ search: context[SEARCH_STRING_KEY],
269
+ include_hidden: context[SHOW_ALL_SUBTOOLS_KEY],
270
+ separate_sources: @separate_sources,
271
+ wrap_width: terminal.width
263
272
  )
264
273
  terminal.puts(str)
265
274
  end
@@ -267,8 +276,11 @@ module Toys
267
276
  def show_help(context, use_extra_args)
268
277
  help_text = get_help_text(context, use_extra_args)
269
278
  str = help_text.help_string(
270
- recursive: context[RECURSIVE_SUBTOOLS_KEY], search: context[SEARCH_STRING_KEY],
271
- include_hidden: context[SHOW_ALL_SUBTOOLS_KEY], show_source_path: @show_source_path,
279
+ recursive: context[RECURSIVE_SUBTOOLS_KEY],
280
+ search: context[SEARCH_STRING_KEY],
281
+ include_hidden: context[SHOW_ALL_SUBTOOLS_KEY],
282
+ show_source_path: @show_source_path,
283
+ separate_sources: @separate_sources,
272
284
  wrap_width: terminal.width
273
285
  )
274
286
  if less_path
@@ -16,8 +16,6 @@ module Toys
16
16
  # This is a frontend for {Toys::Utils::Exec}. More information is
17
17
  # available in that class's documentation.
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
@@ -149,7 +147,7 @@ module Toys
149
147
  #
150
148
  # include :exec, exit_on_nonzero_status: true
151
149
  #
152
- # ## Configuration Options
150
+ # ### Configuration Options
153
151
  #
154
152
  # A variety of options can be used to control subprocesses. These can be
155
153
  # provided to any method that starts a subprocess. You can also set
@@ -267,7 +265,7 @@ module Toys
267
265
  # If the process is not set to run in the background, and a block is
268
266
  # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
269
267
  #
270
- # ## Examples
268
+ # ### Examples
271
269
  #
272
270
  # Run a command without a shell, and print the exit code (0 for success):
273
271
  #
@@ -303,7 +301,7 @@ module Toys
303
301
  # If the process is not set to run in the background, and a block is
304
302
  # provided, a {Toys::Utils::Exec::Controller} will be yielded to it.
305
303
  #
306
- # ## Example
304
+ # ### Example
307
305
  #
308
306
  # Execute a small script with warnings
309
307
  #
@@ -337,7 +335,7 @@ module Toys
337
335
  # Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
338
336
  # do not support this method because they do not support fork.
339
337
  #
340
- # ## Example
338
+ # ### Example
341
339
  #
342
340
  # Run a proc in a forked process.
343
341
  #
@@ -377,7 +375,7 @@ module Toys
377
375
  # Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
378
376
  # do not support this method because they do not support fork.
379
377
  #
380
- # ## Example
378
+ # ### Example
381
379
  #
382
380
  # Run the "system update" tool and pass it an argument.
383
381
  #
@@ -424,7 +422,7 @@ module Toys
424
422
  # run a tool that uses a different bundle. It may also be necessary on
425
423
  # environments without "fork" (such as JRuby or Ruby on Windows).
426
424
  #
427
- # ## Example
425
+ # ### Example
428
426
  #
429
427
  # Run the "system update" tool and pass it an argument.
430
428
  #
@@ -459,7 +457,7 @@ module Toys
459
457
  # If a block is provided, a {Toys::Utils::Exec::Controller} will be
460
458
  # yielded to it.
461
459
  #
462
- # ## Example
460
+ # ### Example
463
461
  #
464
462
  # Capture the output of an echo command
465
463
  #
@@ -490,7 +488,7 @@ module Toys
490
488
  # If a block is provided, a {Toys::Utils::Exec::Controller} will be
491
489
  # yielded to it.
492
490
  #
493
- # ## Example
491
+ # ### Example
494
492
  #
495
493
  # Capture the output of a ruby script.
496
494
  #
@@ -524,7 +522,7 @@ module Toys
524
522
  # Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
525
523
  # do not support this method because they do not support fork.
526
524
  #
527
- # ## Example
525
+ # ### Example
528
526
  #
529
527
  # Run a proc in a forked process and capture its output:
530
528
  #
@@ -564,7 +562,7 @@ module Toys
564
562
  # Beware that some Ruby environments (e.g. JRuby, and Ruby on Windows)
565
563
  # do not support this method because they do not support fork.
566
564
  #
567
- # ## Example
565
+ # ### Example
568
566
  #
569
567
  # Run the "system version" tool and capture its output.
570
568
  #
@@ -612,7 +610,7 @@ module Toys
612
610
  # run a tool that uses a different bundle. It may also be necessary on
613
611
  # environments without "fork" (such as JRuby or Ruby on Windows).
614
612
  #
615
- # ## Example
613
+ # ### Example
616
614
  #
617
615
  # Run the "system version" tool and capture its output.
618
616
  #
@@ -642,7 +640,7 @@ module Toys
642
640
  # If a block is provided, a {Toys::Utils::Exec::Controller} will be
643
641
  # yielded to it.
644
642
  #
645
- # ## Example
643
+ # ### Example
646
644
  #
647
645
  # Run a shell script
648
646
  #