toys-core 0.18.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +3 -3
- data/docs/guide.md +85 -16
- data/lib/toys/cli.rb +3 -2
- data/lib/toys/core.rb +1 -1
- data/lib/toys/standard_mixins/exec.rb +1 -1
- data/lib/toys/utils/exec.rb +2 -1
- data/lib/toys/utils/gems.rb +12 -9
- data/lib/toys/utils/standard_ui.rb +2 -1
- metadata +18 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d4b8d67e21cd27582f76c3799f9d61127001c9b8a9f195615220873c8908ba45
|
|
4
|
+
data.tar.gz: d2987e582ec982852d1b3196c7634c60b4b113f63841c6a67e7d88b446fe4955
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4a27f6c2a6d66cb4281a4bc1bfd9a40870843f1aae249c6b11f140211263f34b99f3434013eae5ab9d13707153ca37c49d5301268c4b066da0bc573caacc601a
|
|
7
|
+
data.tar.gz: 0fb0966f58aa5c8b979d72f3f22770f1403a94992b9226e5b839f8b161d1a4481c7f504b6d432c2f2905d213c087c93ec459e3f97a3d4e81ac56b806cfa8f524
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Release History
|
|
2
2
|
|
|
3
|
+
### v0.19.0 / 2025-12-22
|
|
4
|
+
|
|
5
|
+
Compatibility update for Ruby 4.0, including:
|
|
6
|
+
|
|
7
|
+
* The logger gem is now an explicit dependency
|
|
8
|
+
* Calling a tool via exec no longer disables rubygems
|
|
9
|
+
* Bundler integration does a better job of cleaning up temporary lockfiles under bundler 4
|
|
10
|
+
|
|
11
|
+
Additionally, this release includes updates to readmes and users guides
|
|
12
|
+
|
|
3
13
|
### v0.18.0 / 2025-12-05
|
|
4
14
|
|
|
5
15
|
* ADDED: The load_gem directive can now take version requirements as positional arguments
|
data/README.md
CHANGED
|
@@ -99,9 +99,9 @@ look familiar. Let's run it now, and experiment with passing flags to it.
|
|
|
99
99
|
Notice that we did not create a `tool` block, but instead set up description,
|
|
100
100
|
flags, and functionality directly in the configuration block. This configures
|
|
101
101
|
the "root tool", i.e. what happens when you run the executable without passing
|
|
102
|
-
a tool name to it. (In fact, it's legal to do this in Toys as well,
|
|
103
|
-
functionality at the "top level" of a `.toys.rb` file without
|
|
104
|
-
`tool` block.)
|
|
102
|
+
a tool name to it. (In fact, it's technically legal to do this in Toys as well,
|
|
103
|
+
by setting functionality at the "top level" of a `.toys.rb` file without any
|
|
104
|
+
`tool` block, although you probably won't actually want to do so.)
|
|
105
105
|
|
|
106
106
|
### Tool-based executables
|
|
107
107
|
|
data/docs/guide.md
CHANGED
|
@@ -59,8 +59,8 @@ An executable can customize many aspects of its behavior, such as the
|
|
|
59
59
|
**logging output**, **error handling**, and even shell **tab completion**.
|
|
60
60
|
|
|
61
61
|
Finally, Toys-Core can also be used to publish **Toys extensions**, collections
|
|
62
|
-
of mixins, templates, and predefined tools that can be distributed as gems
|
|
63
|
-
enhance Toys for other users.
|
|
62
|
+
of mixins, templates, and/or predefined tools that can be distributed as gems
|
|
63
|
+
to enhance Toys for other users.
|
|
64
64
|
|
|
65
65
|
## Using the CLI object
|
|
66
66
|
|
|
@@ -123,10 +123,10 @@ When you call {Toys::CLI#run}, the CLI runs through three phases:
|
|
|
123
123
|
When the CLI needs the definition of a tool, it queries the {Toys::Loader}. The
|
|
124
124
|
loader object is configured with a set of tool _sources_ representing ways to
|
|
125
125
|
define a tool. These sources may be blocks passed directly to the CLI, or
|
|
126
|
-
directories and files loaded from the file system or even
|
|
127
|
-
repositories. When a tool is requested by name, the loader is
|
|
128
|
-
locating the tool definition in those sources, and constructing
|
|
129
|
-
definition object, represented by {Toys::ToolDefinition}.
|
|
126
|
+
directories and files loaded from the file system, from gems, or even from
|
|
127
|
+
remote git repositories. When a tool is requested by name, the loader is
|
|
128
|
+
responsible for locating the tool definition in those sources, and constructing
|
|
129
|
+
the tool definition object, represented by {Toys::ToolDefinition}.
|
|
130
130
|
|
|
131
131
|
One important property of the loader is that it is _lazy_. It queries tool
|
|
132
132
|
sources only when it has reason to believe that a tool it is looking for may be
|
|
@@ -184,7 +184,7 @@ class, but it implements a few extra features and cleans up a few ambiguities.
|
|
|
184
184
|
|
|
185
185
|
The execution phase involves:
|
|
186
186
|
|
|
187
|
-
* Running the tool's initializers
|
|
187
|
+
* Running the tool's initializers (if any) in order.
|
|
188
188
|
* Running the tool's middleware. Each middleware "wraps" the execution of
|
|
189
189
|
subsequent middleware and the final tool execution, and has the opportunity
|
|
190
190
|
to inject functionality before and after the main execution, or even to
|
|
@@ -266,7 +266,7 @@ at the start of this guide uses this technique:
|
|
|
266
266
|
The block simply contains Toys DSL syntax. The above example configures the
|
|
267
267
|
"root tool", that is, the functionality of the program if you do not pass a
|
|
268
268
|
tool name on the command line. You can also include "tool" blocks to define
|
|
269
|
-
named tools, just as you would in a normal Toys file.
|
|
269
|
+
named tools and subtools, just as you would in a normal Toys file.
|
|
270
270
|
|
|
271
271
|
The reference documentation for {Toys::CLI#add_config_block} lists several
|
|
272
272
|
options that can be passed in. `:context_directory` lets you select a context
|
|
@@ -289,7 +289,7 @@ paths to the CLI using {Toys::CLI#add_config_path}.
|
|
|
289
289
|
cli = Toys::CLI.new
|
|
290
290
|
|
|
291
291
|
# Load a file defining the functionality
|
|
292
|
-
cli.add_config_path("/usr/local/share/my_tool.rb)
|
|
292
|
+
cli.add_config_path("/usr/local/share/my_tool.rb")
|
|
293
293
|
|
|
294
294
|
result = cli.run(*ARGV)
|
|
295
295
|
exit(result)
|
|
@@ -375,9 +375,82 @@ the front of the list, with the highest priority. Parent directories are added
|
|
|
375
375
|
at subsequently lower priorities, and common directories such as the home
|
|
376
376
|
directory are loaded at the lowest priority.
|
|
377
377
|
|
|
378
|
-
###
|
|
378
|
+
### Customizing built-in mixins and templates
|
|
379
379
|
|
|
380
|
-
|
|
380
|
+
Mixins and templates are two of the most useful mechanisms for sharing code and
|
|
381
|
+
generating code for tools. In the main Toys gem, a certain set of mixins are
|
|
382
|
+
built-in and can be referenced via symbols. For example, the *exec* mixin that
|
|
383
|
+
provides facilities for running and controlling external processes, can be
|
|
384
|
+
included using `include :exec`. In this section, we see how to define your own
|
|
385
|
+
"built-in" mixins and templates that can be referenced via symbol.
|
|
386
|
+
|
|
387
|
+
"Built-in" mixins and templates (and middleware, which we shall cover later)
|
|
388
|
+
are provided via the {Toys::ModuleLookup} mechanism. ModuleLookup lets you
|
|
389
|
+
select a directory for "standard" instances. By default, Toys-Core establishes
|
|
390
|
+
the `toys/standard_mixins` directory in the gem as the standard directory for
|
|
391
|
+
mixins, and whenever you reference a mixin by symbol, it is used to determine
|
|
392
|
+
the name of a file to open and the name of a module to load. You can, however,
|
|
393
|
+
change this directory and provide a different ModuleLookup when constructing a
|
|
394
|
+
CLI object.
|
|
395
|
+
|
|
396
|
+
Suppose, for example, you are writing a gem `my_tools` that uses Toys-Core, and
|
|
397
|
+
you have a directory in your gem's `lib` called `my_tools/mixins` where you
|
|
398
|
+
want your standard mixins to live. You could define mixins there:
|
|
399
|
+
|
|
400
|
+
# This file is my_tools/mixins/foo_mixin.rb
|
|
401
|
+
|
|
402
|
+
require "toys-core"
|
|
403
|
+
|
|
404
|
+
module MyTools
|
|
405
|
+
module Mixins
|
|
406
|
+
module FooMixin
|
|
407
|
+
include Toys::Mixin
|
|
408
|
+
|
|
409
|
+
def foo
|
|
410
|
+
puts "Foo was called"
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
Here is how you could configure a CLI to load standard mixins from that
|
|
417
|
+
directory, and then use the above mixin.
|
|
418
|
+
|
|
419
|
+
# This file is my_tools.rb
|
|
420
|
+
|
|
421
|
+
require "toys-core"
|
|
422
|
+
|
|
423
|
+
my_mixin_lookup = Toys::ModuleLookup.new.add_path("my_tools/mixins")
|
|
424
|
+
cli = Toys::CLI.new(mixin_lookup: my_mixin_lookup)
|
|
425
|
+
|
|
426
|
+
cli.add_config_block do
|
|
427
|
+
def run
|
|
428
|
+
include :foo_mixin
|
|
429
|
+
foo
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
When you configure a ModuleLookup, you provide one or more paths, which are
|
|
434
|
+
path prefixes that are used in a `require` statement. In the above example,
|
|
435
|
+
we used the path `my_tools/mixins` for the ModuleLookup. Now when the CLI uses
|
|
436
|
+
this ModuleLookup to find a mixin called `:foo_mixin`, it will attempt to
|
|
437
|
+
`require "my_tools/mixins/foo_mixin"`, which matches the file where we defined
|
|
438
|
+
our mixin.
|
|
439
|
+
|
|
440
|
+
Notice also that `foo_mixin.rb` above defines FooMixin within a specific module
|
|
441
|
+
hierarchy, corresponding to the file name `my_tools/mixins/foo_mixin.rb`
|
|
442
|
+
according to standard Ruby naming conventions. The fully-qualified module name
|
|
443
|
+
for the mixin must match this expected name, constructed from the path provided
|
|
444
|
+
to the ModuleLookup and the name of the mixin. You can change the way this name
|
|
445
|
+
mapping occurs, by providing the `:module_base` argument to the ModuleLookup
|
|
446
|
+
constructor.
|
|
447
|
+
|
|
448
|
+
Template lookup happens similarly. Toys-Core does not provide a set of default
|
|
449
|
+
templates, but the Toys gem does; the `StandardCLI` class used by Toys sets the
|
|
450
|
+
`:template_lookup` to point to the `toys/templates` directory in that gem's
|
|
451
|
+
library. If you want to customize the default template lookup for your
|
|
452
|
+
Toys-based library, you can similarly provide your own ModuleLookup. This will
|
|
453
|
+
let you control how templates are resolved when specified by symbol.
|
|
381
454
|
|
|
382
455
|
## Customizing diagnostic output
|
|
383
456
|
|
|
@@ -588,7 +661,7 @@ replace normal tool execution.
|
|
|
588
661
|
|
|
589
662
|
Middleware is normally configured as part of the CLI object. Each CLI includes
|
|
590
663
|
an ordered list, a _stack_, of middleware specifications, each represented by
|
|
591
|
-
{Toys::Middleware::Spec}. A middleware spec can
|
|
664
|
+
{Toys::Middleware::Spec}. A middleware spec can reference a specific middleware
|
|
592
665
|
object, a class to instantiate, or a name that can be looked up from a
|
|
593
666
|
directory of middleware class files. You can pass an array of these specs to a
|
|
594
667
|
CLI object when you instantiate it.
|
|
@@ -724,10 +797,6 @@ by other middleware (including middleware that replaces execution such as
|
|
|
724
797
|
Now, every tool run by this CLI wil have the `--show-timing` flag and
|
|
725
798
|
associated functionality.
|
|
726
799
|
|
|
727
|
-
#### Changing built-in middleware
|
|
728
|
-
|
|
729
|
-
(TODO)
|
|
730
|
-
|
|
731
800
|
## Shell and command line integration
|
|
732
801
|
|
|
733
802
|
(TODO)
|
data/lib/toys/cli.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
3
5
|
module Toys
|
|
4
6
|
##
|
|
5
7
|
# A Toys-based CLI.
|
|
@@ -125,7 +127,7 @@ module Toys
|
|
|
125
127
|
# Optional. If not provided, defaults to the set of standard template
|
|
126
128
|
# classes provided by toys core, as defined by
|
|
127
129
|
# {Toys::CLI.default_template_lookup}. If you explicitly want no
|
|
128
|
-
# standard
|
|
130
|
+
# standard templates, pass an empty instance of {Toys::ModuleLookup}.
|
|
129
131
|
#
|
|
130
132
|
# @param config_dir_name [String] A directory with this name that appears
|
|
131
133
|
# in the loader path, is treated as a configuration directory whose
|
|
@@ -562,7 +564,6 @@ module Toys
|
|
|
562
564
|
# @return [Proc]
|
|
563
565
|
#
|
|
564
566
|
def default_logger_factory
|
|
565
|
-
require "logger"
|
|
566
567
|
proc do
|
|
567
568
|
logger = ::Logger.new($stderr)
|
|
568
569
|
logger.level = ::Logger::WARN
|
data/lib/toys/core.rb
CHANGED
|
@@ -817,7 +817,7 @@ module Toys
|
|
|
817
817
|
def self._setup_clean_process(cmd)
|
|
818
818
|
raise ::ArgumentError, "Toys process is unknown" unless ::Toys.executable_path
|
|
819
819
|
cmd = ::Shellwords.split(cmd) if cmd.is_a?(::String)
|
|
820
|
-
cmd = [::RbConfig.ruby,
|
|
820
|
+
cmd = [::RbConfig.ruby, ::Toys.executable_path] + cmd
|
|
821
821
|
if defined?(::Bundler)
|
|
822
822
|
if ::Bundler.respond_to?(:with_unbundled_env)
|
|
823
823
|
::Bundler.with_unbundled_env { yield(cmd) }
|
data/lib/toys/utils/exec.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
3
5
|
module Toys
|
|
4
6
|
module Utils
|
|
5
7
|
##
|
|
@@ -263,7 +265,6 @@ module Toys
|
|
|
263
265
|
#
|
|
264
266
|
def initialize(**opts, &block)
|
|
265
267
|
require "rbconfig"
|
|
266
|
-
require "logger"
|
|
267
268
|
require "stringio"
|
|
268
269
|
@default_opts = Opts.new(&block).add(opts)
|
|
269
270
|
end
|
data/lib/toys/utils/gems.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "fileutils"
|
|
3
4
|
require "monitor"
|
|
4
5
|
|
|
5
6
|
module Toys
|
|
@@ -193,9 +194,7 @@ module Toys
|
|
|
193
194
|
end
|
|
194
195
|
end
|
|
195
196
|
|
|
196
|
-
##
|
|
197
197
|
# @private
|
|
198
|
-
#
|
|
199
198
|
def self.find_gemfile(search_dir, gemfile_names: nil)
|
|
200
199
|
gemfile_names ||= DEFAULT_GEMFILE_NAMES
|
|
201
200
|
Array(gemfile_names).each do |file|
|
|
@@ -207,13 +206,18 @@ module Toys
|
|
|
207
206
|
|
|
208
207
|
@global_mutex = ::Monitor.new
|
|
209
208
|
|
|
210
|
-
##
|
|
211
209
|
# @private
|
|
212
|
-
#
|
|
213
210
|
def self.synchronize(&block)
|
|
214
211
|
@global_mutex.synchronize(&block)
|
|
215
212
|
end
|
|
216
213
|
|
|
214
|
+
# @private
|
|
215
|
+
def self.delete_at_exit(path)
|
|
216
|
+
# Call this from a class method so it doesn't hold onto the instance
|
|
217
|
+
# for the duration of the Ruby process
|
|
218
|
+
at_exit { ::FileUtils.rm_f(path) }
|
|
219
|
+
end
|
|
220
|
+
|
|
217
221
|
private
|
|
218
222
|
|
|
219
223
|
def terminal
|
|
@@ -344,7 +348,7 @@ module Toys
|
|
|
344
348
|
elsif ::RUBY_VERSION < "3"
|
|
345
349
|
[">= 2.2", "< 2.5"]
|
|
346
350
|
else
|
|
347
|
-
["
|
|
351
|
+
[">= 2.2", "< 5"]
|
|
348
352
|
end
|
|
349
353
|
end
|
|
350
354
|
|
|
@@ -421,11 +425,10 @@ module Toys
|
|
|
421
425
|
end
|
|
422
426
|
|
|
423
427
|
def delete_modified_gemfile(modified_gemfile_path)
|
|
424
|
-
|
|
425
|
-
::File.delete(modified_gemfile_path) if ::File.exist?(modified_gemfile_path)
|
|
428
|
+
::FileUtils.rm_f(modified_gemfile_path)
|
|
426
429
|
modified_lockfile_path = find_lockfile_path(modified_gemfile_path)
|
|
427
|
-
::
|
|
428
|
-
|
|
430
|
+
::FileUtils.rm_f(modified_lockfile_path)
|
|
431
|
+
Gems.delete_at_exit(modified_lockfile_path)
|
|
429
432
|
end
|
|
430
433
|
|
|
431
434
|
def restore_toys_libs
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "logger"
|
|
4
|
+
|
|
3
5
|
module Toys
|
|
4
6
|
module Utils
|
|
5
7
|
##
|
|
@@ -28,7 +30,6 @@ module Toys
|
|
|
28
30
|
# terminal output. Default is `$stderr`.
|
|
29
31
|
#
|
|
30
32
|
def initialize(output: nil)
|
|
31
|
-
require "logger"
|
|
32
33
|
require "toys/utils/terminal"
|
|
33
34
|
@terminal = output || $stderr
|
|
34
35
|
@terminal = Terminal.new(output: @terminal) unless @terminal.is_a?(Terminal)
|
metadata
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: toys-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.19.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Azuma
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: logger
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
12
26
|
description: Toys-Core is the command line tool framework underlying Toys. It can
|
|
13
27
|
be used to create command line executables using the Toys DSL and classes.
|
|
14
28
|
email:
|
|
@@ -78,10 +92,10 @@ homepage: https://github.com/dazuma/toys
|
|
|
78
92
|
licenses:
|
|
79
93
|
- MIT
|
|
80
94
|
metadata:
|
|
81
|
-
changelog_uri: https://dazuma.github.io/toys/gems/toys-core/v0.
|
|
95
|
+
changelog_uri: https://dazuma.github.io/toys/gems/toys-core/v0.19.0/file.CHANGELOG.html
|
|
82
96
|
source_code_uri: https://github.com/dazuma/toys/tree/main/toys-core
|
|
83
97
|
bug_tracker_uri: https://github.com/dazuma/toys/issues
|
|
84
|
-
documentation_uri: https://dazuma.github.io/toys/gems/toys-core/v0.
|
|
98
|
+
documentation_uri: https://dazuma.github.io/toys/gems/toys-core/v0.19.0
|
|
85
99
|
rdoc_options: []
|
|
86
100
|
require_paths:
|
|
87
101
|
- lib
|