toys-core 0.14.7 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|