toys-core 0.14.7 → 0.15.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/LICENSE.md +1 -1
- data/README.md +10 -5
- data/docs/guide.md +534 -39
- data/lib/toys/cli.rb +76 -172
- data/lib/toys/compat.rb +15 -30
- data/lib/toys/context.rb +51 -0
- data/lib/toys/core.rb +1 -1
- data/lib/toys/dsl/flag.rb +40 -2
- data/lib/toys/dsl/flag_group.rb +15 -5
- data/lib/toys/dsl/internal.rb +23 -8
- data/lib/toys/dsl/positional_arg.rb +32 -1
- data/lib/toys/dsl/tool.rb +174 -68
- data/lib/toys/errors.rb +2 -2
- data/lib/toys/middleware.rb +3 -2
- data/lib/toys/settings.rb +1 -1
- data/lib/toys/standard_mixins/bundler.rb +16 -1
- data/lib/toys/standard_mixins/exec.rb +29 -8
- data/lib/toys/standard_mixins/gems.rb +17 -3
- data/lib/toys/standard_mixins/highline.rb +12 -12
- data/lib/toys/standard_mixins/terminal.rb +7 -7
- data/lib/toys/tool_definition.rb +153 -50
- data/lib/toys/utils/exec.rb +22 -1
- data/lib/toys/utils/gems.rb +3 -0
- data/lib/toys/utils/standard_ui.rb +261 -0
- data/lib/toys-core.rb +51 -3
- metadata +6 -5
data/lib/toys/dsl/tool.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Toys
|
4
4
|
module DSL
|
5
5
|
##
|
6
|
-
# This
|
6
|
+
# This module defines the DSL for a Toys configuration file.
|
7
7
|
#
|
8
8
|
# A Toys configuration defines one or more named tools. It provides syntax
|
9
9
|
# for setting the description, defining flags and arguments, specifying
|
@@ -25,6 +25,9 @@ module Toys
|
|
25
25
|
# end
|
26
26
|
# end
|
27
27
|
#
|
28
|
+
# The DSL directives `tool`, `desc`, `optional_arg`, and others are defined
|
29
|
+
# in this module.
|
30
|
+
#
|
28
31
|
# Now you can execute it using:
|
29
32
|
#
|
30
33
|
# toys greet
|
@@ -81,8 +84,8 @@ module Toys
|
|
81
84
|
# ### Example
|
82
85
|
#
|
83
86
|
# The following example creates an acceptor named "hex" that is defined
|
84
|
-
# via a regular expression. It
|
85
|
-
# a flag.
|
87
|
+
# via a regular expression. It uses the acceptor to validate values
|
88
|
+
# passed to a flag.
|
86
89
|
#
|
87
90
|
# tool "example" do
|
88
91
|
# acceptor "hex", /[0-9a-fA-F]+/, type_desc: "hex numbers"
|
@@ -155,16 +158,21 @@ module Toys
|
|
155
158
|
#
|
156
159
|
# A template is an object that generates DSL directives. You can use it
|
157
160
|
# to build "prefabricated" tools, and then instantiate them in your Toys
|
158
|
-
# files.
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
#
|
161
|
+
# files.
|
162
|
+
#
|
163
|
+
# A template is an object that defines an `expansion` procedure. This
|
164
|
+
# procedure generates the DSL directives implemented by the template. The
|
165
|
+
# template object typically also includes attributes that are used to
|
166
|
+
# configure the expansion.
|
167
|
+
#
|
168
|
+
# The simplest way to define a template is to pass a block to the
|
169
|
+
# {#template} directive. In the block, define an `initialize` method that
|
170
|
+
# accepts any arguments that may be passed to the template when it is
|
171
|
+
# instantiated and are used to configure the template. Define
|
172
|
+
# `attr_reader`s or other methods to make this configuration accessible
|
173
|
+
# from the object. Then define an `on_expand` block that implements the
|
174
|
+
# template's expansion. The template object is passed as an object to the
|
175
|
+
# `on_expand` block.
|
168
176
|
#
|
169
177
|
# Alternately, you can create a template class separately and pass it
|
170
178
|
# directly. See {Toys::Template} for details on creating a template
|
@@ -172,7 +180,9 @@ module Toys
|
|
172
180
|
#
|
173
181
|
# ### Example
|
174
182
|
#
|
175
|
-
# The following example creates and uses a simple template.
|
183
|
+
# The following example creates and uses a simple template. The template
|
184
|
+
# defines a tool, with a configurable name, that simply prints out a
|
185
|
+
# configurable message.
|
176
186
|
#
|
177
187
|
# template "hello-generator" do
|
178
188
|
# def initialize(name, message)
|
@@ -180,7 +190,7 @@ module Toys
|
|
180
190
|
# @message = message
|
181
191
|
# end
|
182
192
|
# attr_reader :name, :message
|
183
|
-
#
|
193
|
+
# on_expand do |template|
|
184
194
|
# tool template.name do
|
185
195
|
# to_run do
|
186
196
|
# puts template.message
|
@@ -973,6 +983,12 @@ module Toys
|
|
973
983
|
# arguments.) Defaults to the empty array.
|
974
984
|
# @param display_name [String] A display name for this flag, used in help
|
975
985
|
# text and error messages.
|
986
|
+
# @param add_method [true,false,nil] Whether to add a method for this
|
987
|
+
# flag. If omitted or set to nil, uses the default behavior, which
|
988
|
+
# adds the method if the key is a symbol representing a legal method
|
989
|
+
# name that starts with a letter and does not override any public
|
990
|
+
# method in the Ruby Object class or collide with any method directly
|
991
|
+
# defined in the tool class.
|
976
992
|
# @param block [Proc] Configures the flag. See {Toys::DSL::Flag} for the
|
977
993
|
# directives that can be called in this block.
|
978
994
|
# @return [self]
|
@@ -981,17 +997,17 @@ module Toys
|
|
981
997
|
accept: nil, default: nil, handler: nil,
|
982
998
|
complete_flags: nil, complete_values: nil,
|
983
999
|
report_collisions: true, group: nil,
|
984
|
-
desc: nil, long_desc: nil, display_name: nil,
|
1000
|
+
desc: nil, long_desc: nil, display_name: nil, add_method: nil,
|
985
1001
|
&block)
|
986
1002
|
cur_tool = DSL::Internal.current_tool(self, true)
|
987
1003
|
return self if cur_tool.nil?
|
988
1004
|
flag_dsl = DSL::Flag.new(
|
989
1005
|
flags.flatten, accept, default, handler, complete_flags, complete_values,
|
990
|
-
report_collisions, group, desc, long_desc, display_name
|
1006
|
+
report_collisions, group, desc, long_desc, display_name, add_method
|
991
1007
|
)
|
992
1008
|
flag_dsl.instance_exec(flag_dsl, &block) if block
|
993
1009
|
flag_dsl._add_to(cur_tool, key)
|
994
|
-
DSL::Internal.maybe_add_getter(self, key)
|
1010
|
+
DSL::Internal.maybe_add_getter(self, key, flag_dsl._get_add_method)
|
995
1011
|
self
|
996
1012
|
end
|
997
1013
|
|
@@ -1043,6 +1059,12 @@ module Toys
|
|
1043
1059
|
# a description of the allowed formats. (But note that this param
|
1044
1060
|
# takes an Array of description lines, rather than a series of
|
1045
1061
|
# arguments.) Defaults to the empty array.
|
1062
|
+
# @param add_method [true,false,nil] Whether to add a method for this
|
1063
|
+
# argument. If omitted or set to nil, uses the default behavior,
|
1064
|
+
# which adds the method if the key is a symbol representing a legal
|
1065
|
+
# method name that starts with a letter and does not override any
|
1066
|
+
# public method in the Ruby Object class or collide with any method
|
1067
|
+
# directly defined in the tool class.
|
1046
1068
|
# @param block [Proc] Configures the positional argument. See
|
1047
1069
|
# {Toys::DSL::PositionalArg} for the directives that can be called in
|
1048
1070
|
# this block.
|
@@ -1050,14 +1072,15 @@ module Toys
|
|
1050
1072
|
#
|
1051
1073
|
def required_arg(key,
|
1052
1074
|
accept: nil, complete: nil, display_name: nil,
|
1053
|
-
desc: nil, long_desc: nil,
|
1075
|
+
desc: nil, long_desc: nil, add_method: nil,
|
1054
1076
|
&block)
|
1055
1077
|
cur_tool = DSL::Internal.current_tool(self, true)
|
1056
1078
|
return self if cur_tool.nil?
|
1057
|
-
arg_dsl = DSL::PositionalArg.new(accept, nil, complete, display_name,
|
1079
|
+
arg_dsl = DSL::PositionalArg.new(accept, nil, complete, display_name,
|
1080
|
+
desc, long_desc, add_method)
|
1058
1081
|
arg_dsl.instance_exec(arg_dsl, &block) if block
|
1059
1082
|
arg_dsl._add_required_to(cur_tool, key)
|
1060
|
-
DSL::Internal.maybe_add_getter(self, key)
|
1083
|
+
DSL::Internal.maybe_add_getter(self, key, arg_dsl._get_add_method)
|
1061
1084
|
self
|
1062
1085
|
end
|
1063
1086
|
alias required required_arg
|
@@ -1115,6 +1138,12 @@ module Toys
|
|
1115
1138
|
# a description of the allowed formats. (But note that this param
|
1116
1139
|
# takes an Array of description lines, rather than a series of
|
1117
1140
|
# arguments.) Defaults to the empty array.
|
1141
|
+
# @param add_method [true,false,nil] Whether to add a method for this
|
1142
|
+
# argument. If omitted or set to nil, uses the default behavior,
|
1143
|
+
# which adds the method if the key is a symbol representing a legal
|
1144
|
+
# method name that starts with a letter and does not override any
|
1145
|
+
# public method in the Ruby Object class or collide with any method
|
1146
|
+
# directly defined in the tool class.
|
1118
1147
|
# @param block [Proc] Configures the positional argument. See
|
1119
1148
|
# {Toys::DSL::PositionalArg} for the directives that can be called in
|
1120
1149
|
# this block.
|
@@ -1122,14 +1151,15 @@ module Toys
|
|
1122
1151
|
#
|
1123
1152
|
def optional_arg(key,
|
1124
1153
|
default: nil, accept: nil, complete: nil, display_name: nil,
|
1125
|
-
desc: nil, long_desc: nil,
|
1154
|
+
desc: nil, long_desc: nil, add_method: nil,
|
1126
1155
|
&block)
|
1127
1156
|
cur_tool = DSL::Internal.current_tool(self, true)
|
1128
1157
|
return self if cur_tool.nil?
|
1129
|
-
arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name,
|
1158
|
+
arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name,
|
1159
|
+
desc, long_desc, add_method)
|
1130
1160
|
arg_dsl.instance_exec(arg_dsl, &block) if block
|
1131
1161
|
arg_dsl._add_optional_to(cur_tool, key)
|
1132
|
-
DSL::Internal.maybe_add_getter(self, key)
|
1162
|
+
DSL::Internal.maybe_add_getter(self, key, arg_dsl._get_add_method)
|
1133
1163
|
self
|
1134
1164
|
end
|
1135
1165
|
alias optional optional_arg
|
@@ -1187,6 +1217,12 @@ module Toys
|
|
1187
1217
|
# a description of the allowed formats. (But note that this param
|
1188
1218
|
# takes an Array of description lines, rather than a series of
|
1189
1219
|
# arguments.) Defaults to the empty array.
|
1220
|
+
# @param add_method [true,false,nil] Whether to add a method for these
|
1221
|
+
# arguments. If omitted or set to nil, uses the default behavior,
|
1222
|
+
# which adds the method if the key is a symbol representing a legal
|
1223
|
+
# method name that starts with a letter and does not override any
|
1224
|
+
# public method in the Ruby Object class or collide with any method
|
1225
|
+
# directly defined in the tool class.
|
1190
1226
|
# @param block [Proc] Configures the positional argument. See
|
1191
1227
|
# {Toys::DSL::PositionalArg} for the directives that can be called in
|
1192
1228
|
# this block.
|
@@ -1194,20 +1230,21 @@ module Toys
|
|
1194
1230
|
#
|
1195
1231
|
def remaining_args(key,
|
1196
1232
|
default: [], accept: nil, complete: nil, display_name: nil,
|
1197
|
-
desc: nil, long_desc: nil,
|
1233
|
+
desc: nil, long_desc: nil, add_method: nil,
|
1198
1234
|
&block)
|
1199
1235
|
cur_tool = DSL::Internal.current_tool(self, true)
|
1200
1236
|
return self if cur_tool.nil?
|
1201
|
-
arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name,
|
1237
|
+
arg_dsl = DSL::PositionalArg.new(accept, default, complete, display_name,
|
1238
|
+
desc, long_desc, add_method)
|
1202
1239
|
arg_dsl.instance_exec(arg_dsl, &block) if block
|
1203
1240
|
arg_dsl._set_remaining_on(cur_tool, key)
|
1204
|
-
DSL::Internal.maybe_add_getter(self, key)
|
1241
|
+
DSL::Internal.maybe_add_getter(self, key, arg_dsl._get_add_method)
|
1205
1242
|
self
|
1206
1243
|
end
|
1207
1244
|
alias remaining remaining_args
|
1208
1245
|
|
1209
1246
|
##
|
1210
|
-
# Set
|
1247
|
+
# Set option values statically and create helper methods.
|
1211
1248
|
#
|
1212
1249
|
# If any given key is a symbol representing a valid method name, then a
|
1213
1250
|
# helper method is automatically added to retrieve the value. Otherwise,
|
@@ -1241,17 +1278,17 @@ module Toys
|
|
1241
1278
|
if key.is_a?(::Hash)
|
1242
1279
|
cur_tool.default_data.merge!(key)
|
1243
1280
|
key.each_key do |k|
|
1244
|
-
DSL::Internal.maybe_add_getter(self, k)
|
1281
|
+
DSL::Internal.maybe_add_getter(self, k, true)
|
1245
1282
|
end
|
1246
1283
|
else
|
1247
1284
|
cur_tool.default_data[key] = value
|
1248
|
-
DSL::Internal.maybe_add_getter(self, key)
|
1285
|
+
DSL::Internal.maybe_add_getter(self, key, true)
|
1249
1286
|
end
|
1250
1287
|
self
|
1251
1288
|
end
|
1252
1289
|
|
1253
1290
|
##
|
1254
|
-
# Set
|
1291
|
+
# Set option values statically without creating helper methods.
|
1255
1292
|
#
|
1256
1293
|
# ### Example
|
1257
1294
|
#
|
@@ -1297,7 +1334,8 @@ module Toys
|
|
1297
1334
|
# @return [self]
|
1298
1335
|
#
|
1299
1336
|
def enforce_flags_before_args(state = true)
|
1300
|
-
DSL::Internal.current_tool(self, true)
|
1337
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1338
|
+
cur_tool&.enforce_flags_before_args(state)
|
1301
1339
|
self
|
1302
1340
|
end
|
1303
1341
|
|
@@ -1313,7 +1351,8 @@ module Toys
|
|
1313
1351
|
# @return [self]
|
1314
1352
|
#
|
1315
1353
|
def require_exact_flag_match(state = true)
|
1316
|
-
DSL::Internal.current_tool(self, true)
|
1354
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1355
|
+
cur_tool&.require_exact_flag_match(state)
|
1317
1356
|
self
|
1318
1357
|
end
|
1319
1358
|
|
@@ -1325,10 +1364,20 @@ module Toys
|
|
1325
1364
|
# This directive is mutually exclusive with any of the directives that
|
1326
1365
|
# declare arguments or flags.
|
1327
1366
|
#
|
1367
|
+
# ### Example
|
1368
|
+
#
|
1369
|
+
# tool "mytool" do
|
1370
|
+
# disable_argument_parsing
|
1371
|
+
# def run
|
1372
|
+
# puts "Arguments passed: #{args}"
|
1373
|
+
# end
|
1374
|
+
# end
|
1375
|
+
#
|
1328
1376
|
# @return [self]
|
1329
1377
|
#
|
1330
1378
|
def disable_argument_parsing
|
1331
|
-
DSL::Internal.current_tool(self, true)
|
1379
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1380
|
+
cur_tool&.disable_argument_parsing
|
1332
1381
|
self
|
1333
1382
|
end
|
1334
1383
|
|
@@ -1354,7 +1403,8 @@ module Toys
|
|
1354
1403
|
# @return [self]
|
1355
1404
|
#
|
1356
1405
|
def disable_flag(*flags)
|
1357
|
-
DSL::Internal.current_tool(self, true)
|
1406
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1407
|
+
cur_tool&.disable_flag(*flags)
|
1358
1408
|
self
|
1359
1409
|
end
|
1360
1410
|
|
@@ -1399,30 +1449,55 @@ module Toys
|
|
1399
1449
|
end
|
1400
1450
|
|
1401
1451
|
##
|
1402
|
-
# Specify how to run this tool.
|
1403
|
-
# method namd `run`. Alternatively, however, you can pass a block to the
|
1404
|
-
# `to_run` method.
|
1452
|
+
# Specify how to run this tool.
|
1405
1453
|
#
|
1406
|
-
#
|
1407
|
-
#
|
1408
|
-
# {#
|
1454
|
+
# Typically the entrypoint for a tool is a method named `run`. However,
|
1455
|
+
# you can change this by passing a different method name, as a symbol, to
|
1456
|
+
# {#to_run}.
|
1409
1457
|
#
|
1410
|
-
#
|
1458
|
+
# You can also alternatively pass a block to {#to_run}. You might do this
|
1459
|
+
# if your method needs access to local variables in the lexical scope.
|
1460
|
+
# However, it is often more convenient to use {#static} to set those
|
1461
|
+
# values in the context.
|
1462
|
+
#
|
1463
|
+
# ### Examples
|
1464
|
+
#
|
1465
|
+
# # Set a different method name as the entrypoint:
|
1466
|
+
#
|
1467
|
+
# tool "foo" do
|
1468
|
+
# to_run :foo
|
1469
|
+
# def foo
|
1470
|
+
# puts "The fool tool ran!"
|
1471
|
+
# end
|
1472
|
+
# end
|
1473
|
+
#
|
1474
|
+
# # Use a block to retain access to the enclosing lexical scope from
|
1475
|
+
# # the run method:
|
1411
1476
|
#
|
1412
1477
|
# tool "foo" do
|
1413
|
-
# cur_time = Time.
|
1478
|
+
# cur_time = Time.now
|
1414
1479
|
# to_run do
|
1415
1480
|
# puts "The time at tool definition was #{cur_time}"
|
1416
1481
|
# end
|
1417
1482
|
# end
|
1418
1483
|
#
|
1419
|
-
#
|
1484
|
+
# # But the following is approximately equivalent:
|
1485
|
+
#
|
1486
|
+
# tool "foo" do
|
1487
|
+
# static :cur_time, Time.now
|
1488
|
+
# def run
|
1489
|
+
# puts "The time at tool definition was #{cur_time}"
|
1490
|
+
# end
|
1491
|
+
# end
|
1492
|
+
#
|
1493
|
+
# @param handler [Proc,Symbol,nil] The run handler as a method name
|
1494
|
+
# symbol or a proc, or nil to explicitly set as non-runnable.
|
1495
|
+
# @param block [Proc] The run handler as a block.
|
1420
1496
|
# @return [self]
|
1421
1497
|
#
|
1422
|
-
def to_run(&block)
|
1498
|
+
def to_run(handler = nil, &block)
|
1423
1499
|
cur_tool = DSL::Internal.current_tool(self, true)
|
1424
|
-
|
1425
|
-
cur_tool.run_handler = block
|
1500
|
+
cur_tool&.run_handler = handler || block
|
1426
1501
|
self
|
1427
1502
|
end
|
1428
1503
|
alias on_run to_run
|
@@ -1430,9 +1505,12 @@ module Toys
|
|
1430
1505
|
##
|
1431
1506
|
# Specify how to handle interrupts.
|
1432
1507
|
#
|
1433
|
-
# You
|
1434
|
-
#
|
1435
|
-
# Interrupt exception that
|
1508
|
+
# You can provide either a block to be called, a Proc to be called, or
|
1509
|
+
# the name of a method to be called. In each case, the block, Proc, or
|
1510
|
+
# method can optionally take one argument, the Interrupt exception that
|
1511
|
+
# was raised.
|
1512
|
+
#
|
1513
|
+
# Note: this is equivalent to `on_signal("SIGINT")`.
|
1436
1514
|
#
|
1437
1515
|
# ### Example
|
1438
1516
|
#
|
@@ -1440,7 +1518,7 @@ module Toys
|
|
1440
1518
|
# def run
|
1441
1519
|
# sleep 10
|
1442
1520
|
# end
|
1443
|
-
# on_interrupt do
|
1521
|
+
# on_interrupt do
|
1444
1522
|
# puts "I was interrupted."
|
1445
1523
|
# end
|
1446
1524
|
# end
|
@@ -1452,23 +1530,53 @@ module Toys
|
|
1452
1530
|
#
|
1453
1531
|
def on_interrupt(handler = nil, &block)
|
1454
1532
|
cur_tool = DSL::Internal.current_tool(self, true)
|
1455
|
-
|
1456
|
-
|
1533
|
+
cur_tool&.interrupt_handler = handler || block
|
1534
|
+
self
|
1535
|
+
end
|
1536
|
+
|
1537
|
+
##
|
1538
|
+
# Specify how to handle the given signal.
|
1539
|
+
#
|
1540
|
+
# You can provide either a block to be called, a Proc to be called, or
|
1541
|
+
# the name of a method to be called. In each case, the block, Proc, or
|
1542
|
+
# method can optionally take one argument, the SignalException that was
|
1543
|
+
# raised.
|
1544
|
+
#
|
1545
|
+
# ### Example
|
1546
|
+
#
|
1547
|
+
# tool "foo" do
|
1548
|
+
# def run
|
1549
|
+
# sleep 10
|
1550
|
+
# end
|
1551
|
+
# on_signal("QUIT") do |e|
|
1552
|
+
# puts "Signal caught: #{e.signm}."
|
1553
|
+
# end
|
1554
|
+
# end
|
1555
|
+
#
|
1556
|
+
# @param signal [Integer,String,Symbol] The signal name or number
|
1557
|
+
# @param handler [Proc,Symbol,nil] The signal callback proc or method
|
1558
|
+
# name. Pass nil to disable signal handling.
|
1559
|
+
# @param block [Proc] The signal callback as a block.
|
1560
|
+
# @return [self]
|
1561
|
+
#
|
1562
|
+
def on_signal(signal, handler = nil, &block)
|
1563
|
+
cur_tool = DSL::Internal.current_tool(self, true)
|
1564
|
+
cur_tool&.set_signal_handler(signal, handler || block)
|
1457
1565
|
self
|
1458
1566
|
end
|
1459
1567
|
|
1460
1568
|
##
|
1461
1569
|
# Specify how to handle usage errors.
|
1462
1570
|
#
|
1463
|
-
# You
|
1464
|
-
#
|
1465
|
-
# usage errors
|
1571
|
+
# You can provide either a block to be called, a Proc to be called, or
|
1572
|
+
# the name of a method to be called. In each case, the block, Proc, or
|
1573
|
+
# method can optionally take one argument, the array of usage errors
|
1574
|
+
# reported.
|
1466
1575
|
#
|
1467
1576
|
# ### Example
|
1468
1577
|
#
|
1469
|
-
# This tool runs even if a usage error is encountered
|
1470
|
-
#
|
1471
|
-
# {Toys::Context::Key::UNMATCHED_ARGS}, and similar keys.
|
1578
|
+
# This tool runs even if a usage error is encountered, by setting the
|
1579
|
+
# `run` method as the usage error handler.
|
1472
1580
|
#
|
1473
1581
|
# tool "foo" do
|
1474
1582
|
# def run
|
@@ -1484,8 +1592,7 @@ module Toys
|
|
1484
1592
|
#
|
1485
1593
|
def on_usage_error(handler = nil, &block)
|
1486
1594
|
cur_tool = DSL::Internal.current_tool(self, true)
|
1487
|
-
|
1488
|
-
cur_tool.usage_error_handler = handler || block
|
1595
|
+
cur_tool&.usage_error_handler = handler || block
|
1489
1596
|
self
|
1490
1597
|
end
|
1491
1598
|
|
@@ -1493,7 +1600,7 @@ module Toys
|
|
1493
1600
|
# Specify that the given module should be mixed into this tool, and its
|
1494
1601
|
# methods made available when running the tool.
|
1495
1602
|
#
|
1496
|
-
# You
|
1603
|
+
# You can provide either a module, the string name of a mixin that you
|
1497
1604
|
# have defined in this tool or one of its ancestors, or the symbol name
|
1498
1605
|
# of a well-known mixin.
|
1499
1606
|
#
|
@@ -1528,7 +1635,7 @@ module Toys
|
|
1528
1635
|
##
|
1529
1636
|
# Determine if the given module/mixin has already been included.
|
1530
1637
|
#
|
1531
|
-
# You
|
1638
|
+
# You can provide either a module, the string name of a mixin that you
|
1532
1639
|
# have defined in this tool or one of its ancestors, or the symbol name
|
1533
1640
|
# of a well-known mixin.
|
1534
1641
|
#
|
@@ -1594,7 +1701,8 @@ module Toys
|
|
1594
1701
|
# @return [nil] if there is no context.
|
1595
1702
|
#
|
1596
1703
|
def context_directory
|
1597
|
-
DSL::Internal.current_tool(self, false)
|
1704
|
+
cur_tool = DSL::Internal.current_tool(self, false)
|
1705
|
+
cur_tool&.context_directory || source_info.context_directory
|
1598
1706
|
end
|
1599
1707
|
|
1600
1708
|
##
|
@@ -1615,8 +1723,7 @@ module Toys
|
|
1615
1723
|
#
|
1616
1724
|
def set_context_directory(dir) # rubocop:disable Naming/AccessorMethodName
|
1617
1725
|
cur_tool = DSL::Internal.current_tool(self, false)
|
1618
|
-
|
1619
|
-
cur_tool.custom_context_directory = dir
|
1726
|
+
cur_tool&.custom_context_directory = dir
|
1620
1727
|
self
|
1621
1728
|
end
|
1622
1729
|
|
@@ -1655,8 +1762,7 @@ module Toys
|
|
1655
1762
|
def subtool_apply(&block)
|
1656
1763
|
cur_tool = DSL::Internal.current_tool(self, false)
|
1657
1764
|
return self if cur_tool.nil?
|
1658
|
-
cur_tool.subtool_middleware_stack.add(:apply_config,
|
1659
|
-
parent_source: source_info, &block)
|
1765
|
+
cur_tool.subtool_middleware_stack.add(:apply_config, parent_source: source_info, &block)
|
1660
1766
|
self
|
1661
1767
|
end
|
1662
1768
|
|
data/lib/toys/errors.rb
CHANGED
@@ -140,7 +140,7 @@ module Toys
|
|
140
140
|
e = ContextualError.new(e, banner, **opts)
|
141
141
|
end
|
142
142
|
raise e
|
143
|
-
rescue ::ScriptError, ::StandardError => e
|
143
|
+
rescue ::ScriptError, ::StandardError, ::SignalException => e
|
144
144
|
e = ContextualError.new(e, banner)
|
145
145
|
add_fields_if_missing(e, opts)
|
146
146
|
add_config_path_if_missing(e, path)
|
@@ -158,7 +158,7 @@ module Toys
|
|
158
158
|
rescue ContextualError => e
|
159
159
|
add_fields_if_missing(e, opts)
|
160
160
|
raise e
|
161
|
-
rescue ::ScriptError, ::StandardError => e
|
161
|
+
rescue ::ScriptError, ::StandardError, ::SignalException => e
|
162
162
|
raise ContextualError.new(e, banner, **opts)
|
163
163
|
end
|
164
164
|
|
data/lib/toys/middleware.rb
CHANGED
@@ -21,8 +21,9 @@ module Toys
|
|
21
21
|
# Generally, a middleware is a class that implements one or more of the
|
22
22
|
# methods defined in this module: {Toys::Middleware#config}, and
|
23
23
|
# {Toys::Middleware#run}. This module provides default implementations that
|
24
|
-
# do nothing, but
|
25
|
-
# only to methods they
|
24
|
+
# do nothing, but it is not required to include this module, or even to
|
25
|
+
# define both methods. Middleware objects need respond only to methods they
|
26
|
+
# care about.
|
26
27
|
#
|
27
28
|
module Middleware
|
28
29
|
##
|
data/lib/toys/settings.rb
CHANGED
@@ -223,7 +223,7 @@ module Toys
|
|
223
223
|
# has a parent, the parent is queried. If that parent also does not have
|
224
224
|
# a value for the field, it may query its parent in turn, and so forth.
|
225
225
|
# * If we encounter a root settings with no parent, and still no value is
|
226
|
-
# set for the field, the default is returned.
|
226
|
+
# set for the field, the default for the *original* setting is returned.
|
227
227
|
#
|
228
228
|
# Example:
|
229
229
|
#
|
@@ -5,6 +5,21 @@ module Toys
|
|
5
5
|
##
|
6
6
|
# Ensures that a bundle is installed and set up when this tool is run.
|
7
7
|
#
|
8
|
+
# This is the normal recommended way to use [bundler](https://bundler.io)
|
9
|
+
# with Toys. Including this mixin in a tool will cause Toys to ensure that
|
10
|
+
# the bundle is installed and available during tool execution. For example:
|
11
|
+
#
|
12
|
+
# tool "run-rails" do
|
13
|
+
# include :bundler
|
14
|
+
# def run
|
15
|
+
# # Note: no "bundle exec" required because Toys has already
|
16
|
+
# # installed and loaded the bundle.
|
17
|
+
# exec "rails s"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# ### Customization
|
22
|
+
#
|
8
23
|
# The following parameters can be passed when including this mixin:
|
9
24
|
#
|
10
25
|
# * `:static` (Boolean) If `true`, installs the bundle immediately, when
|
@@ -39,7 +54,7 @@ module Toys
|
|
39
54
|
# Defaults to {Toys::Utils::Gems::DEFAULT_GEMFILE_NAMES}.
|
40
55
|
#
|
41
56
|
# * `:toys_gemfile_names` (Array\<String\>) File names that are
|
42
|
-
# recognized as Gemfiles when
|
57
|
+
# recognized as Gemfiles when searching in Toys directories.
|
43
58
|
# Defaults to {DEFAULT_TOYS_GEMFILE_NAMES}.
|
44
59
|
#
|
45
60
|
# * `:on_missing` (Symbol) What to do if a needed gem is not installed.
|
@@ -3,10 +3,10 @@
|
|
3
3
|
module Toys
|
4
4
|
module StandardMixins
|
5
5
|
##
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# in a
|
9
|
-
# process's streams.
|
6
|
+
# The `:exec` mixin provides set of helper methods for executing processes
|
7
|
+
# and subcommands. It provides shortcuts for common cases such as invoking
|
8
|
+
# a Ruby script in a subprocess or capturing output in a string. It also
|
9
|
+
# provides an interface for controlling a spawned process's streams.
|
10
10
|
#
|
11
11
|
# You can make these methods available to your tool by including the
|
12
12
|
# following directive in your tool configuration:
|
@@ -16,6 +16,25 @@ 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
|
+
# ### Mixin overview
|
20
|
+
#
|
21
|
+
# The mixin provides a number of methods for spawning processes. The most
|
22
|
+
# basic are {#exec} and {#exec_proc}. The {#exec} method spawns an
|
23
|
+
# operating system process specified by an executable and a set of
|
24
|
+
# arguments. The {#exec_proc} method takes a `Proc` and forks a Ruby
|
25
|
+
# process. Both of these can be heavily configured with stream handling,
|
26
|
+
# result handling, and numerous other options described below. The mixin
|
27
|
+
# also provides convenience methods for common cases such as spawning a
|
28
|
+
# Ruby process, spawning a shell script, or capturing output.
|
29
|
+
#
|
30
|
+
# The mixin also stores default configuration that it applies to processes
|
31
|
+
# it spawns. You can change these defaults by calling {#configure_exec}.
|
32
|
+
#
|
33
|
+
# Underlying the mixin is a service object of type {Toys::Utils::Exec}.
|
34
|
+
# Normally you would use the mixin methods to access this functionality,
|
35
|
+
# but you can also retrieve the service object itself by calling
|
36
|
+
# {Toys::Context#get} with the key {Toys::StandardMixins::Exec::KEY}.
|
37
|
+
#
|
19
38
|
# ### Controlling processes
|
20
39
|
#
|
21
40
|
# A process can be started in the *foreground* or the *background*. If you
|
@@ -24,7 +43,7 @@ module Toys
|
|
24
43
|
# If you start a background process, its streams will be redirected to null
|
25
44
|
# by default, and control will be returned to you immediately.
|
26
45
|
#
|
27
|
-
#
|
46
|
+
# While a process is running, you can control it using a
|
28
47
|
# {Toys::Utils::Exec::Controller} object. Use a controller to interact with
|
29
48
|
# the process's input and output streams, send it signals, or wait for it
|
30
49
|
# to complete.
|
@@ -44,7 +63,7 @@ module Toys
|
|
44
63
|
# When running a process in the background, the controller is returned from
|
45
64
|
# the method that starts the process:
|
46
65
|
#
|
47
|
-
# controller =
|
66
|
+
# controller = exec(["git", "init"], background: true)
|
48
67
|
#
|
49
68
|
# ### Stream handling
|
50
69
|
#
|
@@ -464,7 +483,8 @@ module Toys
|
|
464
483
|
#
|
465
484
|
def exec_separate_tool(cmd, **opts, &block)
|
466
485
|
Exec._setup_clean_process(cmd) do |clean_cmd|
|
467
|
-
|
486
|
+
opts = Exec._setup_exec_opts(opts, self)
|
487
|
+
self[KEY].exec(clean_cmd, **opts, &block)
|
468
488
|
end
|
469
489
|
end
|
470
490
|
|
@@ -650,7 +670,8 @@ module Toys
|
|
650
670
|
#
|
651
671
|
def capture_separate_tool(cmd, **opts, &block)
|
652
672
|
Exec._setup_clean_process(cmd) do |clean_cmd|
|
653
|
-
|
673
|
+
opts = Exec._setup_exec_opts(opts, self)
|
674
|
+
self[KEY].capture(clean_cmd, **opts, &block)
|
654
675
|
end
|
655
676
|
end
|
656
677
|
|