toys-core 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/LICENSE.md +1 -1
  4. data/README.md +149 -103
  5. data/docs/guide.md +366 -32
  6. data/lib/toys/acceptor.rb +34 -37
  7. data/lib/toys/arg_parser.rb +56 -37
  8. data/lib/toys/cli.rb +23 -16
  9. data/lib/toys/compat.rb +14 -0
  10. data/lib/toys/completion.rb +37 -43
  11. data/lib/toys/context.rb +5 -1
  12. data/lib/toys/core.rb +1 -1
  13. data/lib/toys/dsl/base.rb +2 -2
  14. data/lib/toys/dsl/flag.rb +6 -4
  15. data/lib/toys/dsl/flag_group.rb +1 -1
  16. data/lib/toys/dsl/internal.rb +5 -5
  17. data/lib/toys/dsl/positional_arg.rb +2 -2
  18. data/lib/toys/dsl/tool.rb +129 -72
  19. data/lib/toys/errors.rb +38 -83
  20. data/lib/toys/flag.rb +32 -27
  21. data/lib/toys/flag_group.rb +16 -9
  22. data/lib/toys/input_file.rb +11 -2
  23. data/lib/toys/loader.rb +60 -23
  24. data/lib/toys/middleware.rb +4 -4
  25. data/lib/toys/mixin.rb +15 -5
  26. data/lib/toys/module_lookup.rb +1 -1
  27. data/lib/toys/positional_arg.rb +12 -9
  28. data/lib/toys/source_info.rb +10 -9
  29. data/lib/toys/standard_middleware/add_verbosity_flags.rb +2 -2
  30. data/lib/toys/standard_middleware/handle_usage_errors.rb +1 -1
  31. data/lib/toys/standard_middleware/show_help.rb +63 -49
  32. data/lib/toys/standard_mixins/bundler.rb +3 -1
  33. data/lib/toys/standard_mixins/exec.rb +8 -8
  34. data/lib/toys/standard_mixins/fileutils.rb +6 -5
  35. data/lib/toys/standard_mixins/gems.rb +51 -24
  36. data/lib/toys/standard_mixins/git_cache.rb +2 -2
  37. data/lib/toys/standard_mixins/highline.rb +15 -15
  38. data/lib/toys/standard_mixins/terminal.rb +2 -2
  39. data/lib/toys/template.rb +18 -5
  40. data/lib/toys/tool_definition.rb +119 -37
  41. data/lib/toys/utils/completion_engine.rb +4 -4
  42. data/lib/toys/utils/exec.rb +1018 -604
  43. data/lib/toys/utils/gems.rb +45 -34
  44. data/lib/toys/utils/git_cache.rb +598 -583
  45. data/lib/toys/utils/help_text.rb +377 -20
  46. data/lib/toys/utils/standard_ui.rb +32 -31
  47. data/lib/toys/utils/terminal.rb +4 -4
  48. data/lib/toys/utils/xdg.rb +21 -12
  49. data/lib/toys/wrappable_string.rb +2 -2
  50. data/lib/toys-core.rb +0 -2
  51. metadata +4 -5
  52. data/lib/toys/settings.rb +0 -944
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f2805bf71091b4ea8bf6f6a670281171dc6a5df4edec5196d80d64124ce2a199
4
- data.tar.gz: b5c860449af3a0566e9b1fe8dc527cba4df6750ccc3b259365faf99fa79682fb
3
+ metadata.gz: 72758c7ebe4c70a841bd76672f81e206a6de66c2a1104c81a3eb5b6b8c0b3c1f
4
+ data.tar.gz: 8c5b44be27ba6721dbb1dda109b6f4c46c4b1fc45dcba5b2b295d9082d19582e
5
5
  SHA512:
6
- metadata.gz: 95490a978d1a3ae04be668a2fd318de2499e9610bb6072a053776fb47214d2444c0d93a73fa690b46a6d4706e2fec1f20b76f8d111100ec65216f0c274efe77a
7
- data.tar.gz: b9421ebfa989c45444024222cc3576a166d5797d7c982033265a11aa149c71ef0ab069441c70da490819e5bbafe95eb017c92289d6b46d7917c19634ee3eaf64
6
+ metadata.gz: f9cb82ec77824ca0d5ca3e220559498c717aeef15e0a66b60b96f51e087a5313e6c8b2a9c547fd3cb84d41e1fd0f70dab2d416ddcce3e28559f7438437e532d8
7
+ data.tar.gz: f3216d320f1feb0edd4b5e65cf3adc453adc97e8865b332182350bb27c65bc9580469cd55f06b3fda42c0e6b75d98180eb48e17ec10baa4eaa15e8524787b10d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,60 @@
1
1
  # Release History
2
2
 
3
+ ### v0.22.0 / 2026-05-05
4
+
5
+ Toys-core 0.22 is a major release focused on polish and cleanup in preparation for version 1.0. It includes a number of small breaking changes where needed to clean up the interfaces.
6
+
7
+ Breaking interface changes:
8
+
9
+ * The `static` directive no longer "forces" creating of helper methods, instead using the same logic as the flag and argument directives. In particular, by default it will not create a method starting with underscore.
10
+ * Removed `Toys::Settings` and moved inheritable_helper_methods to a dedicated tool attribute. Use the `basic_settings` gem if you need the old settings class.
11
+ * `Toys::Acceptor#create` no longer takes a hash as the spec. (This was undocumented but worked previously.) To construct an object, pass the class as the main spec object, and the keyword arguments in the options.
12
+ * `Toys::Acceptor::Enum#values` now returns the values themselves instead of a zipped array that includes strings.
13
+ * `Toys::FlagGroup::Base` is no longer instantiable; use `Toys::FlagGroup::Optional` instead.
14
+ * The `acceptor` and `display_name` attributes of `Toys::PositionalArg` are no longer writable and must be set in the constructor.
15
+ * `Toys::Completion#create` no longer takes a hash as the spec. (This was undocumented but worked previously.) To construct an object, pass the class as the main spec object, and the keyword arguments in the options.
16
+ * The `delegation_target` attribute of `Toys::ToolDefinition::DefaultCompletion` is no longer writable and must be set in the constructor.
17
+ * You can no longer override a completion class using the `:""` key. (This was undocumented but worked previously.) Just pass a fully constructed completion object if you need a custom object.
18
+ * The original `Module#include` method is now available in the DSL as `include_module` instead of `super_include`.
19
+ * Template classes no longer automatically include `Toys::Context::Key`. This behavior was undocumented and inconsistent between different ways of defining templates.
20
+ * Made `Toys::CLI#load_tool` return the block value rather than the exit_code.
21
+ * Dropped undocumented `Loader#add_path_set` option to include individual source names in the relative_paths argument.
22
+ * Renamed `use_less` in the `Toys::StandardMiddleware::ShowHelp` constructor to `use_pager`, and added support for custom pagers.
23
+ * Renamed many of the methods in `StandardUI` to reduce confusion.
24
+ * Removed `LoaderError` and used `ToolDefinitionError` for those cases, as it was decided that the distinction was ambiguous and dependent on internal details.
25
+ * Removed `ContextualError#underlying_error` as it was synonymous with `cause`.
26
+ * Consolidated `ContextualError` public interface into a single `capture` method.
27
+ * `ArgParser::ExtraArgumentsError` now takes `:arguments` instead of `:values`, and provides an accessor for the same.
28
+ * `ArgParser::ToolUnrecognizedError` now takes `:full_name` instead of `:values`, and provides an accessor for the same.
29
+ * Renamed `ArgParser::UsageError#full_message` to `message_with_suggestions` to avoid overriding `Exception#full_message`.
30
+
31
+ New features:
32
+
33
+ * The range acceptor supports beginless and endless ranges.
34
+ * A custom source_name can be provided to `Loader#add_path_set`, `Loader#add_git`, and `Loader#add_gem`.
35
+ * The `:gems` mixin provides a context key for retrieving the underlying `Toys::Utils::Gems` service object.
36
+ * The `:gems` mixin provides an explicit `Toys::Utils::Gems::ClassMethods` module defining the directives added to the tool class.
37
+ * The `activate` and `bundle` methods in the Gems utility now return useful results.
38
+
39
+ Other fixes:
40
+
41
+ * The `:update` argument to the `load_git` directive had no effect if the `:as` argument was provided.
42
+ * `FlagValueUnacceptableError` and `ArgValueUnacceptableError` have their value set correctly.
43
+ * If a CLI has a static (shared) logger, creating a child with `logger: nil` actually clears it.
44
+ * Removed unused `Toys::StandardMiddleware::ShowHelp::TOOL_NAME_KEY`.
45
+ * ShowHelp middleware displays an error message instead of raising an exception when help cannot be generated due to a bad search regex.
46
+ * `ArgParser::UsageError` is now a proper exception.
47
+ * `ContextualError` does a better job of capturing relevant syntax errors.
48
+ * Various minor completion system fixes.
49
+
50
+ Several libraries under `toys/utils` were extracted into their own gems. The current code remains under `Toys::Utils` as a vendored copy of the external gem, so the extracted gems are not actually dependencies of Toys. The affected libraries are:
51
+
52
+ * `Toys::Utils::Exec` which was extracted to the gem `exec_service`.
53
+ * `Toys::Utils::XDG` which was extracted to the gem `simple_xdg`.
54
+ * `Toys::Utils::GitCache` which was extracted to the gem `git_cache`.
55
+
56
+ Finally, a variety of clarifications and fixes were made to the reference documentation, readme, and user's guide.
57
+
3
58
  ### v0.21.0 / 2026-03-23
4
59
 
5
60
  This release includes a variety of small fixes and updates toward improving product polish in preparation for a 1.0 release. It focuses on the following areas:
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # License
2
2
 
3
- Copyright 2019-2023 Daniel Azuma and the Toys contributors
3
+ Copyright 2019-2026 Daniel Azuma and the Toys contributors
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -29,7 +29,9 @@ need to be modified if you're running on Windows.
29
29
 
30
30
  Install the **toys-core** gem using:
31
31
 
32
- $ gem install toys-core
32
+ ```
33
+ $ gem install toys-core
34
+ ```
33
35
 
34
36
  You can also install the **toys** gem, which brings in **toys-core** as a
35
37
  dependency.
@@ -39,22 +41,28 @@ dependency.
39
41
  We'll start by creating an executable Ruby script. Using your favorite text
40
42
  editor, create a new file called `mycmd` with the following contents:
41
43
 
42
- #!/usr/bin/env ruby
44
+ ```ruby
45
+ #!/usr/bin/env ruby
43
46
 
44
- require "toys-core"
47
+ require "toys-core"
45
48
 
46
- cli = Toys::CLI.new
49
+ cli = Toys::CLI.new
47
50
 
48
- exit(cli.run(*ARGV))
51
+ exit(cli.run(*ARGV))
52
+ ```
49
53
 
50
54
  Make sure the file's executable bit is set:
51
55
 
52
- $ chmod a+x mycmd
56
+ ```
57
+ $ chmod a+x mycmd
58
+ ```
53
59
 
54
60
  That's it! This is a fully-functional Toys-based executable! Let's see what
55
61
  happens when you run it:
56
62
 
57
- $ ./mycmd
63
+ ```
64
+ $ ./mycmd
65
+ ```
58
66
 
59
67
  Just as with Toys itself, you get a help screen by default (since we haven't
60
68
  yet actually implemented any behavior.) As you can see, some of the same
@@ -71,30 +79,34 @@ information to the Toys CLI object in a block.
71
79
 
72
80
  Let's add some functionality to `mycmd`.
73
81
 
74
- #!/usr/bin/env ruby
82
+ ```ruby
83
+ #!/usr/bin/env ruby
75
84
 
76
- require "toys-core"
85
+ require "toys-core"
77
86
 
78
- cli = Toys::CLI.new
87
+ cli = Toys::CLI.new
79
88
 
80
- #### Insert the following block ...
81
- cli.add_config_block do
82
- desc "My first executable!"
83
- flag :whom, default: "world"
84
- def run
85
- puts "Hello, #{whom}!"
86
- end
87
- end
89
+ #### Insert the following block ...
90
+ cli.add_config_block do
91
+ desc "My first executable!"
92
+ flag :whom, default: "world"
93
+ def run
94
+ puts "Hello, #{whom}!"
95
+ end
96
+ end
88
97
 
89
- exit(cli.run(*ARGV))
98
+ exit(cli.run(*ARGV))
99
+ ```
90
100
 
91
101
  If you went through the tutorial in the README for the Toys gem, this should
92
102
  look familiar. Let's run it now, and experiment with passing flags to it.
93
103
 
94
- $ ./mycmd
95
- $ ./mycmd --whom=ruby
96
- $ ./mycmd --bye
97
- $ ./mycmd --help
104
+ ```
105
+ $ ./mycmd
106
+ $ ./mycmd --whom=ruby
107
+ $ ./mycmd --bye
108
+ $ ./mycmd --help
109
+ ```
98
110
 
99
111
  Notice that we did not create a `tool` block, but instead set up description,
100
112
  flags, and functionality directly in the configuration block. This configures
@@ -109,40 +121,46 @@ But perhaps you want your executable to have multiple "tools", similar to other
109
121
  familiar executables like git or kubectl. You can define tools, including
110
122
  nested tools, by writing `tool` blocks in your config. Here's an example:
111
123
 
112
- #!/usr/bin/env ruby
124
+ ```ruby
125
+ #!/usr/bin/env ruby
113
126
 
114
- require "toys-core"
127
+ require "toys-core"
115
128
 
116
- cli = Toys::CLI.new
129
+ cli = Toys::CLI.new
117
130
 
118
- #### Change the config block as follows ...
119
- cli.add_config_block do
120
- # Things outside any tool block still apply to the root
121
- desc "My first executable with several tools"
131
+ #### Change the config block as follows ...
132
+ cli.add_config_block do
133
+ # Things outside any tool block still apply to the root
134
+ desc "My first executable with several tools"
122
135
 
123
- # We'll put the greet function here
124
- tool "greet" do
125
- desc "My first tool!"
126
- flag :whom, default: "world"
127
- def run
128
- puts "Hello, #{whom}!"
129
- end
130
- end
131
-
132
- # Try writing a second tool here. You could use the "new-repo"
133
- # example from the Toys tutorial.
136
+ # We'll put the greet function here
137
+ tool "greet" do
138
+ desc "My first tool!"
139
+ flag :whom, default: "world"
140
+ def run
141
+ puts "Hello, #{whom}!"
134
142
  end
143
+ end
144
+
145
+ # Try writing a second tool here. You could use the "new-repo"
146
+ # example from the Toys tutorial.
147
+ end
135
148
 
136
- exit(cli.run(*ARGV))
149
+ exit(cli.run(*ARGV))
150
+ ```
137
151
 
138
152
  Now you can run `greet` as a tool:
139
153
 
140
- $ ./mycmd greet
154
+ ```
155
+ $ ./mycmd greet
156
+ ```
141
157
 
142
158
  The "root" functionality once again shows global help, including a list of the
143
159
  available tools.
144
160
 
145
- $ ./mycmd
161
+ ```
162
+ $ ./mycmd
163
+ ```
146
164
 
147
165
  Notice that the description set at the "root" of the config block (outside the
148
166
  tool blocks) shows up here.
@@ -157,43 +175,47 @@ These and many more aspects of the behavior of our executable can be customized
157
175
  by passing options to the `Toys::CLI` constructor. Here's an example that
158
176
  modifies error handling and delimiter parsing.
159
177
 
160
- #!/usr/bin/env ruby
161
-
162
- require "toys-core"
163
-
164
- #### Pass some additional options to the CLI constructor ...
165
- cli = Toys::CLI.new(
166
- extra_delimiters: ":",
167
- error_handler: ->(err) {
168
- puts "Aww shucks, an error happened: #{err.message}"
169
- return 1
170
- }
171
- )
172
-
173
- #### Change the config block as follows ...
174
- cli.add_config_block do
175
- tool "example" do
176
- tool "greet" do
177
- def run
178
- puts "Hello, world!"
179
- end
180
- end
181
- tool "error" do
182
- def run
183
- raise "Whoops!"
184
- end
185
- end
178
+ ```ruby
179
+ #!/usr/bin/env ruby
180
+
181
+ require "toys-core"
182
+
183
+ #### Pass some additional options to the CLI constructor ...
184
+ cli = Toys::CLI.new(
185
+ extra_delimiters: ":",
186
+ error_handler: ->(err) {
187
+ puts "Aww shucks, an error happened: #{err.message}"
188
+ return 1
189
+ }
190
+ )
191
+
192
+ #### Change the config block as follows ...
193
+ cli.add_config_block do
194
+ tool "example" do
195
+ tool "greet" do
196
+ def run
197
+ puts "Hello, world!"
186
198
  end
187
199
  end
200
+ tool "error" do
201
+ def run
202
+ raise "Whoops!"
203
+ end
204
+ end
205
+ end
206
+ end
188
207
 
189
- exit(cli.run(*ARGV))
208
+ exit(cli.run(*ARGV))
209
+ ```
190
210
 
191
211
  Try these runs. Do they behave as you expected?
192
212
 
193
- $ ./mycmd example greet
194
- $ ./mycmd example:greet
195
- $ ./mycmd example.greet
196
- $ ./mycmd example error
213
+ ```
214
+ $ ./mycmd example greet
215
+ $ ./mycmd example:greet
216
+ $ ./mycmd example.greet
217
+ $ ./mycmd example error
218
+ ```
197
219
 
198
220
  ### Configuring middleware
199
221
 
@@ -204,32 +226,36 @@ your tools by default.
204
226
  The next example provides a custom middleware stack, resulting in a different
205
227
  set of common tool functionality.
206
228
 
207
- #!/usr/bin/env ruby
229
+ ```ruby
230
+ #!/usr/bin/env ruby
208
231
 
209
- require "toys-core"
232
+ require "toys-core"
210
233
 
211
- #### Change the CLI construction again ...
212
- middlewares = [
213
- [:set_default_descriptions, default_tool_desc: "Hey look, a tool!"],
214
- [:show_help, help_flags: true]
215
- ]
216
- cli = Toys::CLI.new middleware_stack: middlewares
234
+ #### Change the CLI construction again ...
235
+ middlewares = [
236
+ [:set_default_descriptions, default_tool_desc: "Hey look, a tool!"],
237
+ [:show_help, help_flags: true]
238
+ ]
239
+ cli = Toys::CLI.new middleware_stack: middlewares
217
240
 
218
- #### Use this config block ...
219
- cli.add_config_block do
220
- tool "greet" do
221
- def run
222
- puts "Hello, world!"
223
- end
224
- end
241
+ #### Use this config block ...
242
+ cli.add_config_block do
243
+ tool "greet" do
244
+ def run
245
+ puts "Hello, world!"
225
246
  end
247
+ end
248
+ end
226
249
 
227
- exit(cli.run(*ARGV))
250
+ exit(cli.run(*ARGV))
251
+ ```
228
252
 
229
253
  We've now modified the default description applied to tools that don't provide
230
254
  their own description. See the effect with:
231
255
 
232
- $ ./mycmd greet --help
256
+ ```
257
+ $ ./mycmd greet --help
258
+ ```
233
259
 
234
260
  We've also omitted some of the default middleware, including the one that adds
235
261
  the `--verbose` and `--quiet` flags to all your tools. Notice those flags are
@@ -240,7 +266,9 @@ We've also omitted the middleware that provides default execution behavior
240
266
  haven't defined a top-level `run` method in this last example, invoking the
241
267
  root tool will cause an error:
242
268
 
243
- $ ./mycmd
269
+ ```
270
+ $ ./mycmd
271
+ ```
244
272
 
245
273
  It is even possible to write your own middleware. In general, while the
246
274
  `Toys::CLI` constructor provides defaults that should work for many use cases,
@@ -258,12 +286,16 @@ includes a few simple examples that you can use as a starting point.
258
286
 
259
287
  To experiment with the examples, clone the Toys repo from GitHub:
260
288
 
261
- $ git clone https://github.com/dazuma/toys.git
262
- $ cd toys
289
+ ```
290
+ $ git clone https://github.com/dazuma/toys.git
291
+ $ cd toys
292
+ ```
263
293
 
264
294
  Navigate to the simple-gem example:
265
295
 
266
- $ cd toys-core/examples/simple-gem
296
+ ```
297
+ $ cd toys-core/examples/simple-gem
298
+ ```
267
299
 
268
300
  This example wraps the simple "greet" executable that we covered earlier, in a
269
301
  gem. You can see the
@@ -273,23 +305,31 @@ in the bin directory.
273
305
  Try it out by building and installing the gem. From the `examples/simple-gem`
274
306
  directory, run:
275
307
 
276
- $ toys install
308
+ ```
309
+ $ toys install
310
+ ```
277
311
 
278
312
  Once the gem has successfully installed, you can run the executable, which
279
313
  RubyGems should have added to your path. (Note: if you are using a ruby
280
314
  installation manager, you may need to "rehash" or "reshim" to gain access to
281
315
  the executable.)
282
316
 
283
- $ toys-core-simple-example --whom=Toys
317
+ ```
318
+ $ toys-core-simple-example --whom=Toys
319
+ ```
284
320
 
285
321
  Clean up by uninstalling the gem:
286
322
 
287
- $ gem uninstall toys-core-simple-example
323
+ ```
324
+ $ gem uninstall toys-core-simple-example
325
+ ```
288
326
 
289
327
  If the implementation of your executable is more complex, you might want to
290
328
  break it up into multiple files. The multi-file gem example demonstrates this.
291
329
 
292
- $ cd ../multi-file-gem
330
+ ```
331
+ $ cd ../multi-file-gem
332
+ ```
293
333
 
294
334
  This executable's implementation resides in its
295
335
  [lib directory](https://github.com/dazuma/toys/tree/main/toys-core/examples/multi-file-gem/lib),
@@ -305,18 +345,24 @@ as you can see in
305
345
 
306
346
  Try it out now. From the `examples/multi-file-gem` directory, run:
307
347
 
308
- $ toys install
348
+ ```
349
+ $ toys install
350
+ ```
309
351
 
310
352
  Once the gem has successfully installed, you can run the executable, which
311
353
  RubyGems should have added to your path. (Note: if you are using a ruby
312
354
  installation manager, you may need to "rehash" or "reshim" to gain access to
313
355
  the executable.)
314
356
 
315
- $ toys-core-multi-file-example greet
357
+ ```
358
+ $ toys-core-multi-file-example greet
359
+ ```
316
360
 
317
361
  Clean up by uninstalling the gem:
318
362
 
319
- $ gem uninstall toys-core-multi-file-example
363
+ ```
364
+ $ gem uninstall toys-core-multi-file-example
365
+ ```
320
366
 
321
367
  ### Learning more
322
368