toys 0.3.8 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c9e8109a98db77604b1b398e113a6c8dff058645fe36f63dd08c013e92c06330
4
- data.tar.gz: 9c706a637f851fa847fcc125b706499132d2fbdbbde12aaa6327f60bf95a1e3d
3
+ metadata.gz: c487937ebe79d0f42a022cc6bab700a49e684e5ec2c4dbfb6af52acb60b4876e
4
+ data.tar.gz: 65c95d766c8b2172099ed6be196a46740b4e05753bb3df455daf54c88ab4e6fc
5
5
  SHA512:
6
- metadata.gz: 6695774bf47169ccb18aa06fe45164229e75c8d20fcca24e79187d4f3e747b79adc80a24974dd8d7c0c2c3f4077225ce4362ee0d408bcb7e7213313ded926dfc
7
- data.tar.gz: e04182467471e21017b659b0b5366f9850a42b61b350edc8c46472d171dad4db244e03e4abac76fe1328beab9fcfbb72c97f7ba135939c6acc1524003ecce9c2
6
+ metadata.gz: 13c9507f71773f10696ba52f017975b87204329b1e8ec54fc2c6fdf4ec788469badde38b71573766e425bddd0cdd409ce80e76aa77ad0169e7d15a6e1fb38c4e
7
+ data.tar.gz: b7aaacef8a2017439390647ce2d519081ccda7ee27f34a3d06881040d2ebb6d906ea4e06d64dbc24179ed6642cb0cf2c1651facfb616a97fb8951db0e045a6fc
data/.yardopts CHANGED
@@ -8,4 +8,3 @@ README.md
8
8
  LICENSE.md
9
9
  CHANGELOG.md
10
10
  docs/guide.md
11
- docs/tutorial.md
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Release History
2
2
 
3
+ ### 0.3.9 / 2018-06-24
4
+
5
+ * CHANGED: Removed alias_as directive since it's incompatible with selective loading.
6
+ * ADDED: Ability to define named templates in Toys files
7
+ * ADDED: Ability to disable argument parsing
8
+ * ADDED: Rdoc template
9
+ * ADDED: Exec#exec_proc and Exec#exec_tool that supports all the stream redirects
10
+ * IMPROVED: Acceptors can be looked up recursively in the same way as mixins and templates
11
+ * FIXED: Templates were not activating needed gems
12
+
3
13
  ### 0.3.8 / 2018-06-10
4
14
 
5
15
  * CHANGED: Renamed helpers to mixins.
data/README.md CHANGED
@@ -16,7 +16,7 @@ them. Furthermore, when writing new scripts, I was repeating the same
16
16
  OptionParser boilerplate and common functionality.
17
17
 
18
18
  Toys was designed to address those problems by providing a framework for
19
- writing and organizing command line scripts. You provide the actual script
19
+ writing and organizing your own command line scripts. You provide the actual
20
20
  functionality, and Toys takes care of all the other details expected from a
21
21
  good command line tool. It provides a streamlined interface for defining and
22
22
  handling command line flags and positional arguments, and sensible ways to
@@ -25,14 +25,14 @@ usage information at a glance, and it also provides a search feature to help
25
25
  you find the script you need.
26
26
 
27
27
  Toys can also be used to share scripts. For example, it can be used instead of
28
- Rake to provide build and test scripts for a project--- tools that, unlike Rake
28
+ Rake to provide build and test scripts for a projecttools that, unlike Rake
29
29
  tasks, can be invoked and passed arguments using familiar unix command line
30
30
  arguments and flags. The Toys github repo itself comes with Toys configs
31
31
  instead of Rakefiles.
32
32
 
33
33
  Unlike most command line frameworks, Toys is *not primarily* designed to help
34
34
  you build and ship a custom command line binary written in Ruby. However, you
35
- *can* use it in that way by building witn the "toys-core" API, available as a
35
+ *can* use it in that way by building with the "toys-core" API, available as a
36
36
  separate gem. For more info on using toys-core, see
37
37
  https://ruby-doc.info/gems/toys-core
38
38
 
@@ -63,9 +63,9 @@ The "system version" tool displays the current version of the toys gem.
63
63
 
64
64
  ### Write your first tool
65
65
 
66
- You can define tools by creating toys *config files*. Using your favorite
67
- editor, create a new file called `.toys.rb` (note the leading period) in your
68
- current directory. Copy the following into the file, and save it:
66
+ You can define tools by creating a *Toys file*. Go into any directory, and,
67
+ using your favorite editor, create a new file called `.toys.rb` (note the
68
+ leading period). Copy the following into the file, and save it:
69
69
 
70
70
  tool "greet" do
71
71
  desc "My first tool!"
@@ -110,9 +110,7 @@ and basic console-based interfaces, and another library that makes it easy to
110
110
  spawn and control subprocesses. You can also take advantage of a variety of
111
111
  third-party libraries such as Highline and TTY.
112
112
 
113
- For a more detailed look at Toys, see the
114
- {file:docs/tutorial.md Extended Tutorial} and the
115
- {file:docs/guide.md User Guide}.
113
+ For a more detailed look at Toys, see the {file:docs/guide.md User Guide}.
116
114
 
117
115
  ## Contributing
118
116
 
data/docs/guide.md CHANGED
@@ -10,14 +10,13 @@ write and organize scripts to automate their workflows.
10
10
 
11
11
  Unlike most command line frameworks, Toys is *not primarily* designed to help
12
12
  you build and ship a custom command line binary written in Ruby. Rather, it
13
- provides a single multi-command binary called `toys`. You configure this binary
14
- by writing configuration files that define the commands that Toys recongizes.
15
- (You can, however, build your own custom command line binary using the separate
16
- **toys-core** library.)
13
+ provides a single binary called `toys`. You define the commands recognized by
14
+ the Toys binary by writing configuration files. (You can, however, build your
15
+ own custom command line binary using the related **toys-core** library.)
17
16
 
18
17
  This user's guide covers everything you need to know to use Toys effectively.
19
18
 
20
- ## Conceptual overview
19
+ ## Conceptual Overview
21
20
 
22
21
  Toys is a command line *framework*. It provides a binary called `toys` along
23
22
  with basic functions such as argument parsing and online help. You provide the
@@ -42,9 +41,9 @@ directories**. It searches for these in the current directory, its ancestors,
42
41
  and in the Toys **search path**.
43
42
 
44
43
  Toys provides various features to help you write tools. This includes providing
45
- a **logger** for each tool, **helper modules** that provide common functions a
46
- tool can call, and **templates** which are prefabricated tools that you can
47
- configure for your needs.
44
+ a **logger** for each tool, **mixins** that provide common functions a tool can
45
+ call (such as controlling subprocesses and styling output), and **templates**
46
+ which are prefabricated tools that you can configure for your needs.
48
47
 
49
48
  Finally, Toys provides useful **built-in behavior**, including automatically
50
49
  providing flags to display help screens and set verbosity. It also includes a
@@ -89,7 +88,7 @@ argument.
89
88
 
90
89
  Namespaces such as `system` are themselves tools and can be executed like any
91
90
  other tool. In the above case, it takes the argument `frodo`, determines it has
92
- no subtool of that name, and prints an error message. Most commonly, though,
91
+ no subtool of that name, and prints an error message. More commonly, though,
93
92
  you might execute a namespace without arguments:
94
93
 
95
94
  toys system
@@ -128,17 +127,18 @@ optional **values** for flags. Following are a few examples.
128
127
 
129
128
  Pass a single short flag (for verbose output).
130
129
 
131
- toys -v
130
+ toys system version -v
132
131
 
133
132
  Pass multiple long flags (for verbose output and recursive subtool search).
134
133
 
135
- toys --verbose --recursive
134
+ toys system version --verbose --recursive
136
135
 
137
136
  You can combine short flags. This does the same as the previous example.
138
137
 
139
- toys -rv
138
+ toys system version -rv
140
139
 
141
- Pass a value using a long flag. This searches subtools for the keyword `build`.
140
+ Pass a value using a long flag. The root tool supports the `--search` flag to
141
+ search for tools that have the given keyword.
142
142
 
143
143
  toys --search=build
144
144
  toys --search build
@@ -1095,46 +1095,756 @@ Additional mixins are forthcoming...
1095
1095
 
1096
1096
  ## Sharing Code
1097
1097
 
1098
-
1098
+ As you accumulate additional and more complex tools, you may find that some of
1099
+ your tools need to share some common configuration, data, or logic. You might,
1100
+ for example, have a set of admin scripts that need to do some common
1101
+ authentication. This section describes several techniques for sharing code
1102
+ between tools, and describes the scope of Ruby structures, such as methods,
1103
+ classes, and constants, that you might define in your tools.
1099
1104
 
1100
1105
  ### Defining Mixins
1101
1106
 
1107
+ We saw earlier that you can mix a module (with all its methods) into your tool
1108
+ using the `include` directive. You can specify a module itself, or the name of
1109
+ a built-in mixin such as `:exec` or `:terminal`. But you can also define your
1110
+ own mixin using the `mixin` directive. A mixin defined in a tool can be
1111
+ `include`d in that tool or any of its subtools or their subtools, recursively,
1112
+ so it's a useful way to share code. Here's how that works.
1113
+
1114
+ Define a mixin using the `mixin` directive, and give it a name and a block. In
1115
+ the block, you can define methods that will be made available to any tool that
1116
+ includes the mixin, in the same way that you can include a Ruby module.
1117
+
1118
+ (Unlike full modules, however, mixins allow only methods to be shared. Mixins
1119
+ do not support constants. See the next section on using constants to learn how
1120
+ constants are treated by Toys.)
1102
1121
 
1122
+ Here's an example. Suppose you had common setup code that you wanted to share
1123
+ among your testing tools.
1124
+
1125
+ tool "test" do
1126
+ # Define a mixin, which is just a collection of methods.
1127
+ mixin "common_test_code" do
1128
+ def setup
1129
+ # Do setup here
1130
+ end
1131
+ end
1132
+
1133
+ tool "unit" do
1134
+ # Include the mixin by name
1135
+ include "common_test_code"
1136
+ def run
1137
+ setup # Mixin methods are made available
1138
+ puts "run only unit tests here..."
1139
+ end
1140
+ end
1141
+
1142
+ tool "integration" do
1143
+ include "common_test_code"
1144
+ def run
1145
+ setup
1146
+ puts "run only integration tests here..."
1147
+ end
1148
+ end
1149
+ end
1150
+
1151
+ A mixin is available to the tool in which it is defined, and any subtools and
1152
+ descendants defined at the same point in the Toys search path, but not from
1153
+ tools defined in a different point in the search path. For example, if you
1154
+ define a mixin in a file located in a `.toys` directory, it will be visible to
1155
+ descendant tools defined in that same directory, but not in a different `.toys`
1156
+ directory.
1157
+
1158
+ A common technique, for example, would be to define a mixin in the index file
1159
+ in a Toys directory. You can then include it from any subtools defined in other
1160
+ files in that same directory.
1103
1161
 
1104
1162
  ### Using Constants
1105
1163
 
1164
+ You can define and use Ruby cconstants, i.e. names beginning with a capital
1165
+ letter, in a Toys file. However, they are subject to Ruby's rules regarding
1166
+ constant scope and lookup, which can be confusing, especially in a DSL. Toys
1167
+ tries to simplify those rules and make constant behavior somewhat tractable,
1168
+ but if you do use constants (which includes modules and classes defined in a
1169
+ Toys file), it is important to understand how they work.
1170
+
1171
+ Constants in Toys are visible only within the Toys file in which they are
1172
+ defined. They always behave as though they are defined at the "top level" of
1173
+ the file. Even if you define a constant lexically "inside" a tool or a mixin,
1174
+ the constant does _not_ end up connected to that tool or mixin; it is always
1175
+ defined at the file level.
1106
1176
 
1177
+ tool "test" do
1178
+ tool "unit" do
1179
+ # This constant is now usable for the rest of the file
1180
+ API_KEY_FOR_TESTING = "12345"
1181
+ def run
1182
+ # It is visible here
1183
+ puts API_KEY_FOR_TESTING
1184
+ end
1185
+ end
1107
1186
 
1108
- ### Expanding Templates
1187
+ tool "integration" do
1188
+ def run
1189
+ # And it is still visible here
1190
+ puts API_KEY_FOR_TESTING
1191
+ end
1192
+ end
1193
+ end
1109
1194
 
1195
+ Because of this, it is highly recommended that you define constants only at the
1196
+ top level of a Toys file, so it doesn't "look" like it is scoped to something
1197
+ smaller. In particular, do not attempt to define constants in a mixin. The
1198
+ constants will not actually be connected to the mixin, and will not be
1199
+ available to tools that include the mixin.
1110
1200
 
1201
+ Modules and classes defined using the `module` or `class` keyword, are also
1202
+ constants, and thus follow the same rules. So you could, for example, define a
1203
+ "mixin" module like this:
1204
+
1205
+ module CommonTestCode
1206
+ def setup
1207
+ # Do setup here
1208
+ end
1209
+ end
1210
+
1211
+ tool "test" do
1212
+ tool "unit" do
1213
+ # Include the modules as a mixin
1214
+ include CommonTestCode
1215
+ def run
1216
+ setup # Module methods are made available
1217
+ puts "run only unit tests here..."
1218
+ end
1219
+ end
1220
+
1221
+ tool "integration" do
1222
+ include CommonTestCode
1223
+ def run
1224
+ setup
1225
+ puts "run only integration tests here..."
1226
+ end
1227
+ end
1228
+ end
1229
+
1230
+ The difference between this technique and using the `mixin` directive we saw
1231
+ earlier, is the scope. The module here is accessed via a constant, and so, like
1232
+ any constant, it is visible only in the same file it is defined in. The `mixin`
1233
+ directive creates mixins that are visible from _all_ files at the same point in
1234
+ the search path.
1235
+
1236
+ ### Templates
1237
+
1238
+ One final way to share code is to expand a **template**.
1239
+
1240
+ A template is a class that inserts a bunch of lines into a Toys file. It is
1241
+ often used to "instantiate" prefabricated tools. For instance, Toys comes with
1242
+ a template called "minitest" that can generate a test tool for you. You
1243
+ instantiate it using the `expand` directive in your Toys file, like this:
1244
+
1245
+ expand :minitest
1246
+
1247
+ And it will generate a tool called "test" that runs your test suite.
1248
+
1249
+ Most templates generate one or more complete tools. However, it is possible for
1250
+ a template to generate just part of a tool, such as one or more description
1251
+ directives. In general, expanding a template simply adds directives to your
1252
+ Toys file.
1253
+
1254
+ Many templates can be configured with options such as the name of the tool to
1255
+ generate, or details of the tool's behavior. This is done by passing additional
1256
+ arguments to the `expand` directive, such as:
1257
+
1258
+ expand :minitest, name: "unit-test", warnings: true
1259
+
1260
+ Alternatively, you may provide a block to `expand`. It will yield the template
1261
+ to your block, letting you modify its properties:
1262
+
1263
+ expand :minitest do |tmpl|
1264
+ tmpl.name "unit-test"
1265
+ tmpl.warnings = true
1266
+ end
1267
+
1268
+ Toys provides several built-in templates that are useful for project and gem
1269
+ development, including templates that generate build, test, and documentation
1270
+ tools. You can read more about these templates in the next section on using
1271
+ Toys as a Rake replacement.
1272
+
1273
+ You may also write your own templates. Here's how...
1111
1274
 
1112
1275
  #### Defining Templates
1113
1276
 
1277
+ One way to define a template is to use the `template` directive. Like the
1278
+ `mixin` directive, this creates a named template that you can access inside the
1279
+ current tool and any of its subtools.
1114
1280
 
1281
+ Following is a simple template example:
1115
1282
 
1116
- ## Advanced Tool Definition Techniques
1283
+ template "greet" do
1284
+ def initialize(name: "greet", whom: "world")
1285
+ @name = name
1286
+ @whom = whom
1287
+ end
1288
+ attr_accessor :name
1289
+ attr_accessor :whom
1290
+
1291
+ to_expand do |template|
1292
+ tool template.name do
1293
+ desc "A greeting tool generated from a template"
1294
+ run do
1295
+ puts "Hello, #{template.whom}!"
1296
+ end
1297
+ end
1298
+ end
1299
+ end
1300
+
1301
+ expand "greet"
1302
+
1303
+ expand "greet", name: "greet-ruby", whom: "ruby"
1304
+
1305
+ Above we created a template called "greet". A template is simply a class. It
1306
+ will typically have a constructor, and methods to access configuration
1307
+ properties. When the template is expanded, the class gets instantiated, and you
1308
+ can set those properties.
1309
+
1310
+ Next, a template has a `to_expand` block. This block contains the Toys file
1311
+ directives that should be generated by the template. The template object is
1312
+ passed to the block, so it can access the template configuration when
1313
+ generating directives. The "greet" template in the above example generates a
1314
+ tool whose name is set by the template's `name` property.
1315
+
1316
+ Notice that in the above example, we used `run do`, providing a _block_ for the
1317
+ tool's execution, rather than `def run`, providing a method. Both forms are
1318
+ valid and will work in a template (as well in a normal Toys file), but the
1319
+ block form is often useful in a template because you can access the `template`
1320
+ variable inside the block, whereas it would not be accessible if you defined a
1321
+ method. Similarly, if your template generates helper methods, and the body of
1322
+ those methods need access to the `template` variable, you can use
1323
+ [Module#define_method](http://ruby-doc.org/core/Module.html#method-i-define_method)
1324
+ instead of `def`.
1325
+
1326
+ By convention, it is a good idea for configuration options for your template to
1327
+ be settable either as arguments to the constructor, or as `attr_accessor`
1328
+ properties. In this way, when you expand the template, options can be provided
1329
+ either as arguments to the `expand` directive, or in a block passed to the
1330
+ directive by setting properties on the template object.
1331
+
1332
+ #### Template Classes
1333
+
1334
+ Finally, templates are classes, and you can create a template directly as a
1335
+ class by including the
1336
+ [Toys::Template](https://www.rubydoc.info/gems/toys-core/Toys/Template) module
1337
+ in your class definition.
1338
+
1339
+ class GreetTemplate
1340
+ include Toys::Template
1341
+
1342
+ def initialize(name: "greet", whom: "world")
1343
+ @name = name
1344
+ @whom = whom
1345
+ end
1346
+ attr_accessor :name
1347
+ attr_accessor :whom
1348
+
1349
+ to_expand do |template|
1350
+ tool template.name do
1351
+ desc "A greeting tool generated from a template"
1352
+ run do
1353
+ puts "Hello, #{template.whom}!"
1354
+ end
1355
+ end
1356
+ end
1357
+ end
1358
+
1359
+ expand GreetTemplate, name: "greet-ruby", whom: "ruby"
1360
+
1361
+ Remember that classes created this way are constants, and so the name
1362
+ `GreetTemplate` is available only inside the Toys file where it was defined.
1363
+
1364
+ You must `include Toys::Template` if you define a template directly as a class,
1365
+ but you can omit it if you use the `template` directive to define the template.
1366
+
1367
+ Defining templates as classes is also a useful way for third-party gems to
1368
+ provide Toys integration. For example, suppose you are writing a code analysis
1369
+ gem, and you want to make it easy for your users to create a Toys tool that
1370
+ invokes your analysis. Just write a template class in your gem, maybe named
1371
+ `MyAnalysis::ToysTemplate`. Now, just instruct your users to include the
1372
+ following in their Toys file:
1373
+
1374
+ require "my_analysis"
1375
+ expand MyAnalysis::ToysTemplate
1376
+
1377
+ ## Toys as a Rake Replacement
1378
+
1379
+ Toys was designed to organize scripts that may be "scoped" to a project or
1380
+ directory. Rake is also commonly used for this purpose: you can write a
1381
+ "Rakefile" that defines rake tasks scoped to a directory. In many cases, Toys
1382
+ can be used as a replacement for Rake. Indeed, the Toys repository itself,
1383
+ rather than a Rakefile, contains a `.toys.rb` file that defines tools for
1384
+ running tests, builds, and so forth.
1385
+
1386
+ This section will explore the differences between Toys and Rake, and describe
1387
+ how to use Toys for some of the things traditionally done with Rake.
1388
+
1389
+ ### Comparing Toys and Rake
1390
+
1391
+ Although Toys and Rake serve many of the same use cases, they have very
1392
+ different design goals, and it is useful to understand them.
1393
+
1394
+ Rake's design is based on the classic "make" tool often provided in unix
1395
+ development environments. This design focuses on _targets_ and _dependencies_,
1396
+ and is meant for a world where you invoke an external compiler tool whenever
1397
+ changes are made to an individual source file or any of its dependencies. This
1398
+ "declarative" approach expresses very well the build process for programs
1399
+ written in C and similar compiled languages.
1400
+
1401
+ Ruby, however, does not have an external compiler, and certainly not one that
1402
+ requires separate invocation for each source file as does the C compiler. So
1403
+ although Rake does support file dependencies, they are much less commonly used
1404
+ than in their Makefile cousins. Instead, in practice, most Rake tasks are not
1405
+ connected to a dependency at all; they are simply standalone tasks, what would
1406
+ be called "phony" targets in Makefile parlance. Such tasks are more imperative
1407
+ than declarative.
1408
+
1409
+ The Toys approach to build tools simply embraces the fact that our build
1410
+ processes already tend to be imperative. So unlike Rake, Toys does not provide
1411
+ syntax for describing targets and dependencies, since we generally don't have
1412
+ them in Ruby programs. Instead, it is optimized for writing tools.
1413
+
1414
+ For example, Rake provides a primitive mechanism for passing arguments to a
1415
+ task, but it is clumsy and quite different from most unix programs. However, to
1416
+ do otherwise would clash with Rake's design goal of treating tasks as targets
1417
+ and dependencies. Toys does not have those design goals, so it is able to
1418
+ embrace the familiar ways to pass command line arguments.
1419
+
1420
+ Toys actually borrows some of its design from the "mix" build tool used for
1421
+ Elixir and Erlang programs. Unlike C, the Erlang and Elixir compilers do their
1422
+ own dependency management, so mix does not require those capabilities. Instead,
1423
+ it focuses on making it easy to define imperative tasks.
1424
+
1425
+ All told, this boils down to the principle of using the best tool for the job.
1426
+ There will be times when you need to express file-based dependencies in some of
1427
+ your build tasks. Rake will continue to be your friend in those cases. However,
1428
+ for high level tasks such as "run my tests", "build my YARD documentation", or
1429
+ "release my gem", you may find Toys easier to use.
1430
+
1431
+ ### From Rakefiles to Toys Files
1432
+
1433
+ If you want to migrate some of your project's build tasks from Rake to Toys,
1434
+ there are some common patterns.
1435
+
1436
+ When you use Rake for these tasks, you will typically require a particular file
1437
+ from your Rakefile, and/or write some code. Different tools will have different
1438
+ mechanisms for generating tasks. For example, a test task might be defined like
1439
+ this:
1440
+
1441
+ require "rake/testtask"
1442
+ Rake::TestTask.new do |t|
1443
+ t.test_files = FileList["test/test*.rb"]
1444
+ end
1445
+
1446
+ In Toys, templates are the standard mechanism for generating tools.
1447
+
1448
+ expand :minitest do |t|
1449
+ t.files = ["test/test*.rb"]
1450
+ end
1451
+
1452
+ The following sections will describe some of the built-in templates provided by
1453
+ Toys to generate common build tools.
1454
+
1455
+ Note that Rakefiles and Toys files can coexist in the same directory, so you
1456
+ can use either or both tools, depending on your needs.
1457
+
1458
+ ### Running Tests
1459
+
1460
+ Toys provides a built-in template for minitest, called `:minitest`. It is
1461
+ implemented by the template class {Toys::Templates::Minitest}, and it uses the
1462
+ minitest gem, which is provided with most recent versions of Ruby.
1463
+
1464
+ expand :minitest, files: ["test/test*.rb"], libs: ["lib", "ext"]
1465
+
1466
+ See the {Toys::Templates::Minitest} documentation for details on the various
1467
+ options.
1468
+
1469
+ If you want to enforce code style using the "rubocop" gem, you can use the
1470
+ built-in `:rubocop` template:
1471
+
1472
+ expand :rubocop
1473
+
1474
+ See the {Toys::Templates::Rubocop} documentation for details on the available
1475
+ options.
1476
+
1477
+ ### Building and Releasing Gems
1478
+
1479
+ The `:gem_build` built-in template can generate a variety of build and release
1480
+ tools for gems, and is a useful alternative to the Rake tasks provided by
1481
+ bundler. It is implemented by {Toys::Templates::GemBuild}.
1482
+
1483
+ Expanding `:gem_build` by default looks for a gemspec file in the current
1484
+ directory, and builds that gem into a `pkg` directory. You can also build a
1485
+ specific gem if you have multiple gemspec files.
1117
1486
 
1487
+ You may also configure the template so it also releases the gem to Rubygems
1488
+ (using your stored Rubygems credentials), by setting the `push_gem` option.
1489
+ For example, here is how to generate a "release" tool that builds and releases
1490
+ your gem:
1118
1491
 
1492
+ expand :gem_build, name: "release", push_gem: true
1493
+
1494
+ See the {Toys::Templates::GemBuild} documentation for details on the various
1495
+ options for build tools.
1496
+
1497
+ To generate a "clean" tool, you can use the `:clean` built-in template. For
1498
+ example:
1499
+
1500
+ expand :clean, paths: ["pkg", "doc", "tmp"]
1501
+
1502
+ See the {Toys::Templates::Clean} documentation for details on the various
1503
+ options for clean tools.
1504
+
1505
+ ### Building Documentation
1506
+
1507
+ Toys provides an `:rdoc` template for creating tools that generate RDoc
1508
+ documentation, and a `:yardoc` template for creating tools that generate YARD.
1509
+ Both templates provide a variety of options for controlling documentation
1510
+ generation. See {Toys::Templates::Rdoc} and {Toys::Templates::Yardoc} for
1511
+ detailed information.
1512
+
1513
+ Here's an example for YARD:
1514
+
1515
+ expand :yardoc, protected: true, markup: "markdown"
1516
+
1517
+ ### Gem Example
1518
+
1519
+ Let's look at a complete example that combines the techniques above to provide
1520
+ all the basic tools for a Ruby gem. It includes:
1521
+
1522
+ * A testing tool that can be run with `toys test`
1523
+ * Code style checking using Rubocop, run with `toys rubocop`
1524
+ * Documentation building using Yardoc, run with `toys yardoc`
1525
+ * Gem building, run with `toys build`
1526
+ * Gem build and release to Rubygems.org, run with `toys release`
1527
+ * A full CI tool, run with `toys ci`, that can be run from your favorite CI
1528
+ system. It runs the tests and style checks, and checks (but does not
1529
+ actually build) the documentation for warnings and completeness.
1530
+
1531
+ Below is the full annotated `.toys.rb` file. For many gems, you could drop this
1532
+ into the gem source repo with minimal or no modifications. Indeed, this is
1533
+ essentially identical to the Toys files provided for the **toys** and
1534
+ **toys-core** gems themselves.
1535
+
1536
+ # A "clean" tool that cleans out gem builds (from the pkg directory), and
1537
+ # documentation builds (from doc and .yardoc)
1538
+ expand :clean, paths: ["pkg", "doc", ".yardoc"]
1539
+
1540
+ # This is the "test" tool.
1541
+ expand :minitest, libs: ["lib", "test"]
1542
+
1543
+ # This is the "rubocop" tool.
1544
+ expand :rubocop
1545
+
1546
+ # This is the "yardoc" tool. We cause it to fail on warnings and if there
1547
+ # are any undocumented objects, which is useful for CI. We also configure
1548
+ # the tool so it recognizes the "--no-output" flag. The CI tool will use
1549
+ # this flag to invoke yardoc but suppress output, because it just wants to
1550
+ # check for warnings.
1551
+ expand :yardoc do |t|
1552
+ t.generate_output_flag = true
1553
+ t.fail_on_warning = true
1554
+ t.fail_on_undocumented_objects = true
1555
+ end
1556
+
1557
+ # The normal "build" tool that just builds a gem into the pkg directory.
1558
+ expand :gem_build
1559
+
1560
+ # A full gem "release" tool that builds the gem, and pushes it to rubygems.
1561
+ # This assumes your local rubygems configuration is set up with the proper
1562
+ # credentials.
1563
+ expand :gem_build, name: "release", push_gem: true
1564
+
1565
+ # Now we have a full CI tool. It runs the test, rubocop, and yardoc tools
1566
+ # and checks for errors. This tool could be invoked from Travis-CI or
1567
+ # similar CI system.
1568
+ tool "ci" do
1569
+ # The :exec mixin provides the exec_tool() method that we will use to run
1570
+ # other tools and check their exit status.
1571
+ include :exec
1572
+ # The :terminal mixin provides an enhanced "puts" method that lets you
1573
+ # write styled text to the terminal.
1574
+ include :terminal
1575
+
1576
+ # A helper method, that runs a tool and outputs the result. It also
1577
+ # terminates if the tool reported an error.
1578
+ def run_stage(name, tool)
1579
+ if exec_tool(tool).success?
1580
+ puts("** #{name} passed", :green, :bold)
1581
+ puts
1582
+ else
1583
+ puts("** CI terminated: #{name} failed!", :red, :bold)
1584
+ exit(1)
1585
+ end
1586
+ end
1587
+
1588
+ # The main run method. It just calls the above helper method for the
1589
+ # three tools we want to run for CI
1590
+ def run
1591
+ run_stage("Tests", ["test"])
1592
+ run_stage("Style checker", ["rubocop"])
1593
+ run_stage("Docs generation", ["yardoc", "--no-output"])
1594
+ end
1595
+ end
1596
+
1597
+ ## Advanced Tool Definition Techniques
1598
+
1599
+ This section covers some additional features that are often useful for writing
1600
+ tools. I've labeled them "advanced", but all that really means is that this
1601
+ user's guide didn't happen to have covered them until this section. Each of
1602
+ these features is very useful for certain types of tools, and it is good at
1603
+ least to know that you *can* do these things, even if you don't use them
1604
+ regularly.
1119
1605
 
1120
1606
  ### Aliases
1121
1607
 
1608
+ An **alias** is simply an alternate name for a tool. For example, suppose you
1609
+ have a tool called `test` that you run with `toys test`. You could define an
1610
+ alias `t` that points to `test`; then you can run the same tool with `toys t`.
1611
+
1612
+ To define an alias, use the `alias_tool` directive:
1613
+
1614
+ tool "test" do
1615
+ # Define test tool here...
1616
+ end
1617
+
1618
+ alias_tool "t", "test"
1619
+
1620
+ You may create an alias of a subtool, but the alias must have the same parent
1621
+ (namespace) tool as the target tool. For example:
1622
+
1623
+ tool "gem" do
1624
+ tool "test" do
1625
+ # Define test tool here...
1626
+ end
1122
1627
 
1628
+ # Allows you to invoke `toys gem t`
1629
+ alias_tool "t", "test"
1630
+ end
1123
1631
 
1124
1632
  ### Custom Acceptors
1125
1633
 
1634
+ We saw earlier that flags and positional arguments can have acceptors, which
1635
+ control the allowed format, and may also convert the string argument to a Ruby
1636
+ object. By default, Toys supports the same acceptors recognized by Ruby's
1637
+ OptionParser library. And like OptionParser, Toys also lets you define your own
1638
+ acceptors.
1639
+
1640
+ Define an acceptor using the `acceptor` directive. You provide a name for the
1641
+ acceptor, and specify how to validate input strings and how to convert input
1642
+ strings to Ruby objects. You may then reference the acceptor in that tool or
1643
+ any of its subtools or their subtools, recursively.
1644
+
1645
+ There are several ways to define an acceptor.
1646
+
1647
+ You may validate input strings against a regular expression, by passing the
1648
+ regex to the `acceptor` directive. You may also optionally provide a block to
1649
+ convert input strings to objects (or omit the block to use the original string
1650
+ as the option value.) For example, a simple hexadecimal input acceptor might
1651
+ look like this:
1652
+
1653
+ acceptor("hex", /^[0-9a-fA-F]+$/) { |input| input.to_i(16) }
1654
+
1655
+ You may also accept enum values by passing an array of valid values to the
1656
+ `acceptor` directive. Inputs will be matched against the `to_s` form of the
1657
+ given values, and will be converted to the value itself. For example, one way
1658
+ to accept integers from 1 to 5 is:
1659
+
1660
+ acceptor("1to5", [1, 2, 3, 4, 5])
1126
1661
 
1662
+ There are various other options. See the reference documentation for
1663
+ [Toys::DSL::Tool#acceptor](https://www.rubydoc.info/gems/toys-core/Toys%2FDSL%2FTool:acceptor).
1664
+
1665
+ An acceptor is available to the tool in which it is defined, and any subtools
1666
+ and descendants defined at the same point in the Toys search path, but not from
1667
+ tools defined in a different point in the search path. For example, if you
1668
+ define an acceptor in a file located in a `.toys` directory, it will be visible
1669
+ to descendant tools defined in that same directory, but not in a different
1670
+ `.toys` directory.
1671
+
1672
+ A common technique, for example, would be to define an acceptor in the index
1673
+ file in a Toys directory. You can then include it from any subtools defined in
1674
+ other files in that same directory.
1127
1675
 
1128
1676
  ### Controlling Built-in Flags
1129
1677
 
1678
+ Earlier we saw that certain flags are added automatically to every tool:
1679
+ `--verbose`, `--quiet`, `--help`, and so forth. You may occasionally want to
1680
+ disable some of these "built-in" flags. There are two ways to do so:
1681
+
1682
+ If you want to use one of the built-in flags for another purpose, simply define
1683
+ the flag as you choose. Flags explicitly defined by your tool take precedence
1684
+ over the built-ins.
1685
+
1686
+ For example, normally two built-in flags are provided to decrease the verbosity
1687
+ level: `-q` and `--quiet`. If you define `-q` yourself—for example to activate
1688
+ a "quick" mode—then `-q` will be repurposed for your flag, but `--quiet` will
1689
+ still be present to decrease verbosity.
1690
+
1691
+ # Repurposes -q to set the "quick" option instead of "quiet"
1692
+ flag :quick, "-q"
1693
+
1694
+ You may also completely disable a flag, and _not_ repurpose it, using the
1695
+ `disable_flag` directive. It lets you mark one or more flags as "never use".
1130
1696
 
1697
+ For example, if you disable the `-q` flag, then `-q` will no longer be a
1698
+ built-in flag that decreases the verbosity, but `--quiet` will remain. To
1699
+ completely disable decreasing the verbosity, disable both `-q` and `--quiet`.
1131
1700
 
1132
- ### Middleware
1701
+ # Disables -q but leaves --quiet
1702
+ disable_flag "-q"
1133
1703
 
1704
+ # Completely disables decreasing verbosity
1705
+ disable_flag "-q", "--quiet"
1134
1706
 
1707
+ ### Disabling Argument Parsing
1135
1708
 
1136
- ## Toys Administration using the System Tools
1709
+ Normally Toys handles parsing command line arguments for you. This makes
1710
+ writing tools easier, but also allows Toys to generate documentation
1711
+ automatically for flags and arguments. However, occasionally you'll not want
1712
+ Toys to perform any parsing, but just to give you the command line arguments
1713
+ raw. One common case is if your tool turns around and passes its arguments to
1714
+ another subprocess.
1715
+
1716
+ To disable argument parsing, use the `disable_argument_parsing` directive. This
1717
+ directive disables parsing and validation of flags and positional arguments.
1718
+ (Thus, it is incompatible with specifying any flags or arguments for the tool.)
1719
+ Instead, you can retrieve the raw arguments using the
1720
+ [Toys::Tool#args method](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:args).
1721
+
1722
+ Here is an example that wraps calls to git:
1723
+
1724
+ tool "my-git" do
1725
+ desc "Prints a message, and then calls git normally"
1726
+ disable_argument_parsing
1727
+ def run
1728
+ puts "Calling my-git!"
1729
+ Kernel.exec(["git"] + args)
1730
+ end
1731
+ end
1137
1732
 
1733
+ ### Activating Gems
1734
+
1735
+ Sometimes implementing a tool will require a third-party gem. Some mixins also
1736
+ utilize a gem. Toys provides a way to help the user install such gems if
1737
+ needed.
1738
+
1739
+ If the gem is needed to *define* the tool, use the `gem` directive to ensure
1740
+ the gem is installed and activated. This takes the name of the gem, and an
1741
+ optional set of version requirements. If a gem matching the given version
1742
+ requirements is installed, it is activated. If not, the gem is installed (which
1743
+ the user can confirm or abort). Or, if Toys is being run in a bundle, a message
1744
+ is printed informing the user that they need to add the gem to their Gemfile.
1745
+
1746
+ For example, here's a way to configure a tool with flags for each of the
1747
+ HighLine styles:
1748
+
1749
+ tool "highline-styles-demo" do
1750
+ gem "highline", "~> 2.0"
1751
+ require "highline"
1752
+ HighLine::BuiltinStyles::STYLES.each do |style|
1753
+ style = style.downcase
1754
+ flag style.to_sym, "--#{style}", "Apply #{style} to the text"
1755
+ end
1756
+ def run
1757
+ # ...
1758
+
1759
+ If the gem is *not* needed to define the tool, but is needed to *run* the tool,
1760
+ then you can call
1761
+ [Toys::Tool#gem](https://www.rubydoc.info/gems/toys-core/Toys%2FTool:gem) from
1762
+ your `run` method. Here's an example:
1763
+
1764
+ tool "rake" do
1765
+ disable_argument_passing
1766
+ def run
1767
+ gem "rake", "~> 12.0"
1768
+ Kernel.exec(["rake"] + args)
1769
+ end
1770
+ end
1138
1771
 
1772
+ If a gem satisfying the given version constraints is already activated, it
1773
+ remains active. If a gem with a conflicting version is already activated, an
1774
+ exception is raised.
1139
1775
 
1140
- ## Embedding Toys
1776
+ If you are not in the Toys DSL context—e.g. you are writing a class-based
1777
+ mixin—you should use
1778
+ [Toys::Utils::Gems.activate](https://www.rubydoc.info/gems/toys-core/Toys%2FUtils%2FGems:activate)
1779
+ instead. For example:
1780
+
1781
+ Toys::Utils::Gems.activate("highline", "~> 2.0")
1782
+
1783
+ Note these methods are a bit different from the
1784
+ [gem method](http://ruby-doc.org/stdlib-2.5.1/libdoc/rubygems/rdoc/Kernel.html)
1785
+ provided by Rubygems. The Toys version attempts to install a missing gem for
1786
+ you, whereas Rubygems will just throw an exception.
1787
+
1788
+ ## Toys Administration Using the System Tools
1789
+
1790
+ Toys comes with a few built-in tools, including some that let you administer
1791
+ Toys itself. These tools live in the `system` namespace.
1792
+
1793
+ ### Getting the Toys Version
1794
+
1795
+ You can get the current version of Toys by running:
1796
+
1797
+ toys system version
1798
+
1799
+ Note that the same output can be obtained by passing the `--version` flag to
1800
+ the root tool:
1801
+
1802
+ toys --version
1803
+
1804
+ ### Upgrading Toys
1805
+
1806
+ To update Toys to the latest released version, run:
1807
+
1808
+ toys system update
1809
+
1810
+ This will determine the latest version from Rubygems, and update your Toys
1811
+ installation if it is not already current.
1812
+
1813
+ Normall it asks you for confirmation before downloading. To disable interactive
1814
+ confirmation, pass the `--yes` flag.
1815
+
1816
+ A similar effect can of course be obtained simply by `gem install toys`.
1817
+
1818
+ ## Writing Your Own CLI Using Toys
1819
+
1820
+ Toys is not primarily designed to help you write a custom command-line binary,
1821
+ but you can use it in that fashion. Toys is factored into two gems:
1822
+ **toys-core**, which includes all the underlying machinery for creating
1823
+ command-line binaries, and **toys**, which is really just a wrapper that
1824
+ provides the `toys` binary itself and its built-in commands and behavior. To
1825
+ write your own command line binary based on the Toys system, just require the
1826
+ **toys-core** gem and configure your binary the way you want.
1827
+
1828
+ Toys-Core is modular and lets you customize much of the behavior of a command
1829
+ line binary. For example:
1830
+
1831
+ * Toys itself automatically adds a number of flags, such as `--verbose` and
1832
+ `--help`, to each tool. Toys-Core lets you customize what flags are
1833
+ automatically added for your own command line binary.
1834
+ * Toys itself provides a default way to run tools that have no `run` method:
1835
+ it assumes such tools are namespaces, and displays the online help screen.
1836
+ Toys-Core lets you provide an alternate default run method for your own
1837
+ command line binary.
1838
+ * Toys itself provides several built-in tools, such as `do`, and `system`.
1839
+ Toys-Core lets your own command line binary define its own built-in tools.
1840
+ * Toys itself implements a particular search path for user-provided Toys
1841
+ files, and looks for specific file and directory names such as `.toys.rb`.
1842
+ Toys-Core lets you change the search path, the file/directory names, or
1843
+ disable user-provided Toys files altogether for your own command line
1844
+ binary. Indeed, most command line binaries do not need user-customizable
1845
+ tools, and can ship with only built-in tools.
1846
+ * Toys itself has a particular way of displaying online help and displaying
1847
+ errors. Toys-Core lets your own command line binary customize these.
1848
+
1849
+ For more information, see the
1850
+ [Toys-Core documentation](https://www.rubydoc.info/gems/toys-core/).