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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4bd5a5658f6cecd3721768123c8125b9f8d0459f9f6812aede164c3207c30da3
4
- data.tar.gz: 2576dc86d5ea42e516bc2b812809ad653b3c7302a3d30a9bc28be3490de749e8
3
+ metadata.gz: d4b8d67e21cd27582f76c3799f9d61127001c9b8a9f195615220873c8908ba45
4
+ data.tar.gz: d2987e582ec982852d1b3196c7634c60b4b113f63841c6a67e7d88b446fe4955
5
5
  SHA512:
6
- metadata.gz: 6795ecfbda46c2259164fcef70089882c07c087e40cb378ee2726691fde2c3e89888bb13323dc974260ce79211f0ad603a67bb73de09319eca8c57a9fb3006cd
7
- data.tar.gz: 9d2f4b8da60d7470d4bc3a0759841ed705d194025556bde61efa084ec7d5a8f400acece16ef289c41c3cc0c8e98229a34035cc075d59798626347c53621d90a4
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, by setting
103
- functionality at the "top level" of a `.toys.rb` file without including any
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 to
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 remote git
127
- repositories. When a tool is requested by name, the loader is responsible for
128
- locating the tool definition in those sources, and constructing the tool
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, if any, in order.
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
- ### Changing built-in mixins and templates
378
+ ### Customizing built-in mixins and templates
379
379
 
380
- (TODO)
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 be a specific middleware
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 tenokates, pass an empty instance of {Toys::ModuleLookup}.
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
@@ -9,7 +9,7 @@ module Toys
9
9
  # Current version of Toys core.
10
10
  # @return [String]
11
11
  #
12
- VERSION = "0.18.0"
12
+ VERSION = "0.19.0"
13
13
  end
14
14
 
15
15
  ##
@@ -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, "--disable=gems", ::Toys.executable_path] + cmd
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) }
@@ -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
@@ -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
- ["~> 2.2"]
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
- # rubocop:disable Lint/NonAtomicFileOperation
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
- ::File.delete(modified_lockfile_path) if ::File.exist?(modified_lockfile_path)
428
- # rubocop:enable Lint/NonAtomicFileOperation
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.18.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.18.0/file.CHANGELOG.html
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.18.0
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