toys 0.24.0 → 0.25.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: 1a607f5cce147c21bdd90781026767b310054e69bbbff8c9a1103fdbd3d77b6b
4
- data.tar.gz: ab0b2ff711816c75e2a50206e93ae19673c21f88618a3332e0642387b7baa6f3
3
+ metadata.gz: e494ced1b44b862aee77dd732210549374c571b55b4da8d503034ef3f87bba6f
4
+ data.tar.gz: bceadfc53e8b691951eef4ea4ef6d8b2f666590f745185322577d4bb5ccff82e
5
5
  SHA512:
6
- metadata.gz: a99af47c6944f33da01db83f1aeb9d77021424cf2ef3b739c7f34caeaffac8dfbcfa25fff7e6ce73d742c4d4d44cabd1ab2b6521d3b64aeaf7d9adb5aeff0ffa
7
- data.tar.gz: 3d853bf3958d6894a5388830c5f4c2595f3631a13280741d93cc70410d43374c690273a23314bd1758b558a523b0d3d4372446f3054a2d616cf9b78db0d526bd
6
+ metadata.gz: 40b86310b2d3ad6ce6b16ba738f4d8f543943f008a41b77fdc91b8f858afe50fa2104b3adebb2719aba98e6e920ce7f86f5df00a3c9d8824b4ea85e395fa5710
7
+ data.tar.gz: e468cd88b4042956bf12cbead2316c592799e667d61299ae69ab66d7cf457f5cef727a3d3cbb1589c3bf3cc16d76a89f8e8c4fff036a343fc6ad5a488456c2c9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Release History
2
2
 
3
+ ### v0.25.0 / 2026-10-10
4
+
5
+ This is a release candidate release toward version 1.0. It includes a variety of fixes and small features, largely around adherence to clig.dev and other common CLI guidelines.
6
+
7
+ * Major updates
8
+ * ADDED: The `-h` flag is now a standard help flag, similar to `--help`.
9
+ * Updates to tool lookup
10
+ * ADDED: Toys now loads global tools from the XDG config directories
11
+ * ADDED: The `TOYS_GLOBAL_SOURCES` environment variable selects which global sources are searched
12
+ * BREAKING CHANGE: The `TOYS_PATH` environment variable is no longer supported. Use `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`, or `TOYS_GLOBAL_SOURCES` instead.
13
+ * BREAKING CHANGE: Toys no longer loads global tools from `/etc/.toys.rb` or `/etc/.toys/`. Move them into `/etc/xdg/toys` instead.
14
+ * BREAKING CHANGE: Removed the `Toys::StandardCLI::TOYS_PATH_ENV` constant.
15
+ * Updates to logging and warnings
16
+ * ADDED: Warnings are displayed when a tool invokes a deprecated interface. They can be turned off by setting `TOYS_SUPPRESS_WARNINGS` to a nonempty value.
17
+ * ADDED: Logs display with a simplified severity prefix unless verbosity is positive
18
+ * FIXED: The `DEBUG` log prefix is no longer colored white
19
+ * FIXED: Logs emitted from tool initializers honor the verbosity
20
+ * Updates to ANSI coloring control
21
+ * ADDED: The `FORCE_COLOR` environment variable forces styled output on, or off when set to 0 or false
22
+ * FIXED: An empty `NO_COLOR` environment variable no longer disables styled output, per the no-color.org spec
23
+ * FIXED: Styled output is disabled when the `TERM` environment variable is set to `dumb`
24
+ * FIXED: The highline mixin decides whether to use color from its own output stream, and honors `NO_COLOR`, `FORCE_COLOR`, and `TERM=dumb`
25
+ * FIXED: Help text displayed through a pager honors the styled output setting, including `NO_COLOR`, `FORCE_COLOR`, and `TERM=dumb`
26
+ * Other fixes
27
+ * FIXED: Bash tab completion discards stderr from the completion command, preventing unwanted output if warnings are emitted.
28
+ * FIXED: Tool-not-found suggestions include namespaces
29
+ * FIXED: The `:push` handler creates a new array rather than appending in place, so that a frozen or non-cloneable default doesn't cause problems
30
+ * FIXED: Re-vendor `simple_xdg` 0.1.2 to pick up home directory fix
31
+ * FIXED: Re-vendor `git_cache` 0.2.0 to report an unwritable cache directory clearly and fix repo lock races
32
+
3
33
  ### v0.24.0 / 2026-09-11
4
34
 
5
35
  * Feature: The `toys do` builtin provides an `--on-missing-gem` flag that governs how the `--gem` flag handles gems that are not installed.
data/README.md CHANGED
@@ -108,9 +108,10 @@ Toys searches up the directory hierarchy for Toys files. So it will find this
108
108
  also read multiple files if it finds them, so you can "scope" your tools more
109
109
  specifically or generally by locating them in your directory hierarchy.
110
110
 
111
- If you want to define "global" tools that apply anywhere, write a Toys file
112
- either in your home directory, or in the system configuration directory
113
- (usually `/etc`). Toys always searches these locations.
111
+ If you want to define "global" tools that apply anywhere, write a Toys file in
112
+ your home directory, or put tool files in the `toys` directory under your user
113
+ configuration directory (usually `~/.config/toys`) or the system configuration
114
+ directory (usually `/etc/xdg/toys`). Toys searches these locations by default.
114
115
 
115
116
  ### A more sophisticated example
116
117
 
data/bin/toys CHANGED
@@ -8,4 +8,11 @@ $LOAD_PATH.delete(::ENV["TOYS_LIB_PATH"])
8
8
  $LOAD_PATH.unshift(::ENV["TOYS_LIB_PATH"])
9
9
  require "toys"
10
10
 
11
- exit(::Toys::StandardCLI.new.run(::ARGV))
11
+ begin
12
+ cli = ::Toys::StandardCLI.new
13
+ rescue ::Toys::StandardCLI::InvalidGlobalSourcesError => e
14
+ # Not Kernel#warn, which -W0 would silence, hiding why toys exited.
15
+ $stderr.puts(e.message) # rubocop:disable Style/StderrPuts
16
+ exit(2)
17
+ end
18
+ exit(cli.run(::ARGV))
@@ -85,6 +85,8 @@ module Toys
85
85
  # as an argument, and returns a `Logger` to use when running that tool.
86
86
  # Optional. If not provided (and no global logger is set),
87
87
  # {Toys::CLI.default_logger_factory} is called to get a basic default.
88
+ # See {Toys::Runner} for how a logger can receive the verbosity of
89
+ # the run.
88
90
  # @param base_level [Integer] The logger level that should correspond
89
91
  # to zero verbosity.
90
92
  # Optional. If not provided, defaults to the level the logger has
@@ -314,8 +316,8 @@ module Toys
314
316
  # source list. If the given search directory path does not exist or does
315
317
  # not contain either the file or directory, nothing is added.
316
318
  #
317
- # The main Toys executable uses this method to load tools from directories
318
- # in the `TOYS_PATH`.
319
+ # The main Toys executable uses this method to load tools from the
320
+ # directories in its upward walk and from the home directory.
319
321
  #
320
322
  # @param search_path [String,Pathname] A directory path to search for the
321
323
  # well-known source file and directory. Must be a String or a Pathname.
@@ -349,9 +351,6 @@ module Toys
349
351
  # given directory and works up through parent directories until it reaches
350
352
  # the file system root or it encounters one of the "terminate" directories.
351
353
  #
352
- # The main Toys executable uses this method to load tools from the current
353
- # directory and its ancestors.
354
- #
355
354
  # @param start [String,Pathname,nil] The first directory path to search.
356
355
  # If not given, defaults to the current working directory. If provided,
357
356
  # must be a String or a Pathname. Paths should generally be absolute.
@@ -9,6 +9,6 @@ module Toys
9
9
  # Current version of Toys core.
10
10
  # @return [String]
11
11
  #
12
- VERSION = "0.24.0"
12
+ VERSION = "0.25.0"
13
13
  end
14
14
  end
@@ -264,10 +264,12 @@ module Toys
264
264
  SET_HANDLER = proc { |val| val }
265
265
 
266
266
  ##
267
- # The push handler pushes the given value using the `<<` operator.
267
+ # The push handler appends the given value, returning a new array. The
268
+ # previous array is not modified, so a shared or frozen default array
269
+ # can be used safely.
268
270
  # @return [Proc]
269
271
  #
270
- PUSH_HANDLER = proc { |val, prev| prev.nil? ? [val] : prev << val }
272
+ PUSH_HANDLER = proc { |val, prev| prev.nil? ? [val] : prev + [val] }
271
273
 
272
274
  ##
273
275
  # The default handler is the set handler, which replaces the previous value.
@@ -34,6 +34,15 @@ module Toys
34
34
  # end
35
35
  # end
36
36
  #
37
+ # While a tool runs, the Runner sets the level of the tool's logger to reflect
38
+ # the verbosity, as described under the `base_level` parameter of
39
+ # {#initialize}. A logger can also receive the verbosity itself, by
40
+ # implementing a `verbosity` attribute: if the logger responds to both
41
+ # `verbosity` and `verbosity=`, the Runner sets it to the verbosity (an
42
+ # Integer) for the duration of the run, and restores the previous value
43
+ # afterward. This lets a logger vary its behavior, such as its formatting, by
44
+ # verbosity independently of its level.
45
+ #
37
46
  # **_Defined in the toys-core gem_**
38
47
  #
39
48
  class Runner
@@ -72,7 +81,8 @@ module Toys
72
81
  # @param logger_factory [Proc,nil] A proc that takes a
73
82
  # {Toys::ToolDefinition} as an argument, and returns a logger to use
74
83
  # when running that tool. If not given,
75
- # {Toys::Runner::DEFAULT_LOGGER_FACTORY} is used.
84
+ # {Toys::Runner::DEFAULT_LOGGER_FACTORY} is used. See {Toys::Runner}
85
+ # for how a logger can receive the verbosity of the run.
76
86
  # @param base_level [Integer,nil] The logger level that corresponds to zero
77
87
  # verbosity. If not provided, the level the logger has before a run
78
88
  # adjusts it is used (typically Logger::WARN). A run nested inside
@@ -22,8 +22,9 @@ module Toys
22
22
  # occurs. Default is {USAGE_ERROR_EXIT_CODE}.
23
23
  # @param stream [IO] Output stream to write to. Default is stderr.
24
24
  # @param styled_output [boolean,nil] Cause the tool to display help text
25
- # with ansi styles. If `nil`, display styles if the output stream is
26
- # a tty. Default is `nil`.
25
+ # with ansi styles. If `nil`, whether to display styles is inferred
26
+ # from the output stream and the environment. See
27
+ # {Toys::Utils::Terminal.infer_styled}. Default is `nil`.
27
28
  #
28
29
  def initialize(exit_code: nil, stream: $stderr, styled_output: nil)
29
30
  # Source available in the toys-core gem
@@ -17,7 +17,7 @@ module Toys
17
17
  # Default help flags
18
18
  # @return [Array<String>]
19
19
  #
20
- DEFAULT_HELP_FLAGS = ["-?", "--help"].freeze
20
+ DEFAULT_HELP_FLAGS = ["-h", "-?", "--help"].freeze
21
21
 
22
22
  ##
23
23
  # Default usage flags
@@ -165,8 +165,9 @@ module Toys
165
165
  # false) if the output stream is not a tty.
166
166
  # @param stream [IO] Output stream to write to. Default is stdout.
167
167
  # @param styled_output [boolean,nil] Cause the tool to display help text
168
- # with ansi styles. If `nil`, display styles if the output stream is
169
- # a tty. Default is `nil`.
168
+ # with ansi styles. If `nil`, whether to display styles is inferred
169
+ # from the output stream and the environment. See
170
+ # {Toys::Utils::Terminal.infer_styled}. Default is `nil`.
170
171
  #
171
172
  def initialize(help_flags: false,
172
173
  usage_flags: false,
@@ -25,6 +25,11 @@ module Toys
25
25
  # The arguments will be passed on to the
26
26
  # [HighLine constructor](https://www.rubydoc.info/gems/highline/HighLine:initialize).
27
27
  #
28
+ # Whether the HighLine object uses color is inferred from its output
29
+ # stream and the environment, using the same rule as a terminal. See
30
+ # {Toys::Utils::Terminal.infer_styled}. You can override it by setting
31
+ # `use_color` on the HighLine object.
32
+ #
28
33
  # **_Defined in the toys-core gem_**
29
34
  #
30
35
  module Highline
@@ -16,7 +16,9 @@ module Toys
16
16
  # Access a git cache.
17
17
  #
18
18
  # @param cache_dir [String] The path to the cache directory. Defaults to
19
- # a specific directory in the user's XDG cache.
19
+ # a specific directory in the user's XDG cache. Cache data is stored
20
+ # in a subdirectory named for the cache format version, so that clients
21
+ # using incompatible formats can share a cache directory safely.
20
22
  #
21
23
  def initialize(cache_dir: nil)
22
24
  # Source available in the toys-core gem
@@ -98,8 +100,9 @@ module Toys
98
100
  # repositories are requested, they will be reloaded from the remote
99
101
  # repository from scratch.
100
102
  #
101
- # Be careful not to remove repos that are currently in use by other
102
- # Toys::Utils::GitCache clients.
103
+ # This waits for any in-progress {#get} calls for these repos to finish.
104
+ # However, be careful not to remove repos whose shared sources are
105
+ # currently in use by other Toys::Utils::GitCache clients.
103
106
  #
104
107
  # @param remotes [Array<String>,:all,nil] The remotes to remove. If set
105
108
  # to :all or nil, removes all repos.
@@ -30,14 +30,18 @@ module Toys
30
30
  # stream. Default is `true`.
31
31
  # @param exec_service [Toys::Utils::Exec] The service to use for
32
32
  # executing commands, or `nil` (the default) to use a default.
33
+ # @param output [IO,StringIO,nil] The stream to which the pager process
34
+ # writes its output, and the default fallback stream. If `nil` (the
35
+ # default), the pager process inherits the parent's standard output.
33
36
  # @param fallback_io [IO] An IO-like object to write to if the pager is
34
- # disabled. Defaults to `$stdout`.
37
+ # disabled or could not be executed. Defaults to the `output` stream
38
+ # if one is given, otherwise `$stdout`.
35
39
  # @param rescue_broken_pipes [boolean] If `true` (the default), broken
36
40
  # pipes are silently rescued. This prevents the exception from
37
41
  # propagating out if the pager is interrupted. Set this parameter to
38
42
  # `false` to disable this behavior.
39
43
  #
40
- def initialize(command: true, exec_service: nil, fallback_io: nil,
44
+ def initialize(command: true, exec_service: nil, output: nil, fallback_io: nil,
41
45
  rescue_broken_pipes: true)
42
46
  # Source available in the toys-core gem
43
47
  end
@@ -71,12 +75,32 @@ module Toys
71
75
  #
72
76
  attr_accessor :command
73
77
 
78
+ ##
79
+ # The stream to which the pager process writes its output, or `nil` if
80
+ # the pager process inherits the parent's standard output.
81
+ #
82
+ # @return [IO,StringIO,nil]
83
+ #
84
+ attr_accessor :output
85
+
74
86
  ##
75
87
  # The IO stream used if the pager is disabled or could not be executed.
88
+ # If not set explicitly, this is the {#output} stream if one is set,
89
+ # otherwise `$stdout`.
76
90
  #
77
91
  # @return [IO]
78
92
  #
79
- attr_accessor :fallback_io
93
+ def fallback_io
94
+ # Source available in the toys-core gem
95
+ end
96
+
97
+ ##
98
+ # Set the IO stream used if the pager is disabled or could not be
99
+ # executed. Set to `nil` to use the default.
100
+ #
101
+ # @param value [IO,nil]
102
+ #
103
+ attr_writer :fallback_io
80
104
 
81
105
  class << self
82
106
  ##
@@ -91,8 +115,12 @@ module Toys
91
115
  # stream. Default is `true`.
92
116
  # @param exec_service [Toys::Utils::Exec] The service to use for
93
117
  # executing commands, or `nil` (the default) to use a default.
118
+ # @param output [IO,StringIO,nil] The stream to which the pager process
119
+ # writes its output, and the default fallback stream. If `nil` (the
120
+ # default), the pager process inherits the parent's standard output.
94
121
  # @param fallback_io [IO] An IO-like object to write to if the pager is
95
- # disabled. Defaults to `$stdout`.
122
+ # disabled or could not be executed. Defaults to the `output` stream
123
+ # if one is given, otherwise `$stdout`.
96
124
  # @param rescue_broken_pipes [boolean] If `true` (the default), broken
97
125
  # pipes are silently rescued. This prevents the exception from
98
126
  # propagating out if the pager is interrupted. Set this parameter to
@@ -107,6 +135,7 @@ module Toys
107
135
  #
108
136
  def start(command: true,
109
137
  exec_service: nil,
138
+ output: nil,
110
139
  fallback_io: nil,
111
140
  rescue_broken_pipes: true,
112
141
  &block)
@@ -16,6 +16,32 @@ module Toys
16
16
  # **_Defined in the toys-core gem_**
17
17
  #
18
18
  class StandardUI
19
+ ##
20
+ # The logger class created by {StandardUI#create_logger}. It is a
21
+ # standard `Logger` that also has a `verbosity` attribute, which the
22
+ # {Toys::Runner} sets to the verbosity of the run, as described in
23
+ # {Toys::Runner}. The formatter installed by {StandardUI#create_logger}
24
+ # uses it to choose a format.
25
+ #
26
+ # **_Defined in the toys-core gem_**
27
+ #
28
+ class VerbosityLogger < ::Logger
29
+ ##
30
+ # Create a logger. Takes the same arguments as the standard `Logger`.
31
+ # The verbosity is initially zero.
32
+ #
33
+ def initialize(*args, **kwargs)
34
+ # Source available in the toys-core gem
35
+ end
36
+
37
+ ##
38
+ # The verbosity of the current run, or zero if not running.
39
+ #
40
+ # @return [Integer]
41
+ #
42
+ attr_accessor :verbosity
43
+ end
44
+
19
45
  ##
20
46
  # Create a Standard UI.
21
47
  #
@@ -114,10 +140,17 @@ module Toys
114
140
  # specification in {Toys::Runner}, this must take a {Toys::ToolDefinition}
115
141
  # as an argument, and return a `Logger`.
116
142
  #
117
- # The base implementation returns a logger that writes to the UI's
118
- # terminal, using {#format_log_entry} as the formatter. It sets the level
119
- # to `Logger::WARN` by default. Either this method or the helper methods
120
- # can be overridden to change this behavior.
143
+ # The base implementation returns a
144
+ # {Toys::Utils::StandardUI::VerbosityLogger}, which receives the
145
+ # verbosity of the run from the {Toys::Runner}. The logger writes to the
146
+ # UI's terminal. It formats each entry using {#format_verbose_log_entry}
147
+ # if {#verbose_log_format?} returns true for the verbosity, or
148
+ # {#format_simple_log_entry} otherwise. It sets the level to
149
+ # `Logger::WARN` by default. Either this method or the helper methods can
150
+ # be overridden to change this behavior.
151
+ #
152
+ # If {#format_log_entry} is overridden, however, the override formats
153
+ # every entry regardless of verbosity. That behavior is deprecated.
121
154
  #
122
155
  # @param _tool {Toys::ToolDefinition} The tool definition of the tool to
123
156
  # be executed
@@ -175,10 +208,54 @@ module Toys
175
208
  # Source available in the toys-core gem
176
209
  end
177
210
 
211
+ ##
212
+ # Determines whether loggers created by this UI's logger factory use
213
+ # the verbose format, {#format_verbose_log_entry}, rather than the simple
214
+ # format, {#format_simple_log_entry}, for the given verbosity.
215
+ #
216
+ # The base implementation returns true if the verbosity is positive. This
217
+ # method can be overridden to change the behavior of loggers created by
218
+ # this UI.
219
+ #
220
+ # @param verbosity [Integer] The verbosity of the run.
221
+ # @return [boolean]
222
+ #
223
+ def verbose_log_format?(verbosity)
224
+ # Source available in the toys-core gem
225
+ end
226
+
227
+ ##
228
+ # Implementation of the formatter used by loggers created by this UI's
229
+ # logger factory when the simple format is in effect. This interface is
230
+ # defined by the standard `Logger` class.
231
+ #
232
+ # The base implementation prefixes the first line of the message with the
233
+ # severity, styled using {#log_header_severity_styles}. If the message is
234
+ # an exception, it includes the exception message and class, but omits
235
+ # the backtrace.
236
+ #
237
+ # This method can be overridden to change the behavior of loggers created
238
+ # by this UI.
239
+ #
240
+ # @param severity [String]
241
+ # @param _time [Time]
242
+ # @param _progname [String]
243
+ # @param msg [Object]
244
+ # @return [String]
245
+ #
246
+ def format_simple_log_entry(severity, _time, _progname, msg)
247
+ # Source available in the toys-core gem
248
+ end
249
+
178
250
  ##
179
251
  # Implementation of the formatter used by loggers created by this UI's
180
- # logger factory. This interface is defined by the standard `Logger`
181
- # class.
252
+ # logger factory when the verbose format is in effect. This interface is
253
+ # defined by the standard `Logger` class.
254
+ #
255
+ # The base implementation prefixes the message with a header containing
256
+ # the timestamp and severity, styled using {#log_header_severity_styles}.
257
+ # If the message is an exception, it includes the exception message and
258
+ # class, followed by the backtrace.
182
259
  #
183
260
  # This method can be overridden to change the behavior of loggers created
184
261
  # by this UI.
@@ -189,7 +266,32 @@ module Toys
189
266
  # @param msg [Object]
190
267
  # @return [String]
191
268
  #
192
- def format_log_entry(severity, time, _progname, msg)
269
+ def format_verbose_log_entry(severity, time, _progname, msg)
270
+ # Source available in the toys-core gem
271
+ end
272
+
273
+ ##
274
+ # A legacy formatter for loggers created by this UI's logger factory.
275
+ # This interface is defined by the standard `Logger` class.
276
+ #
277
+ # The base implementation calls {#format_verbose_log_entry}, and is not
278
+ # used by loggers created by this UI's logger factory unless it is
279
+ # overridden. If a subclass overrides this method, the override is used
280
+ # to format every entry regardless of verbosity, and
281
+ # {#verbose_log_format?}, {#format_verbose_log_entry}, and
282
+ # {#format_simple_log_entry} are not called by the logger. The override
283
+ # may call `super` to get the verbose format.
284
+ #
285
+ # @deprecated Override {#format_simple_log_entry} and
286
+ # {#format_verbose_log_entry} instead.
287
+ #
288
+ # @param severity [String]
289
+ # @param time [Time]
290
+ # @param progname [String]
291
+ # @param msg [Object]
292
+ # @return [String]
293
+ #
294
+ def format_log_entry(severity, time, progname, msg)
193
295
  # Source available in the toys-core gem
194
296
  end
195
297
  end
@@ -106,13 +106,55 @@ module Toys
106
106
  # Source available in the toys-core gem
107
107
  end
108
108
 
109
+ ##
110
+ # Infers whether styled output should be written to the given output,
111
+ # from the output itself and the environment. This is the rule a
112
+ # terminal uses when it is not told explicitly whether to style output,
113
+ # and it is available to tools that write styled output by other means.
114
+ #
115
+ # The following checks are applied in order, and the first that applies
116
+ # decides the result:
117
+ #
118
+ # 1. If the `FORCE_COLOR` environment variable is set to `0` or `false`
119
+ # (in any case), output is not styled. This follows Node.js and the
120
+ # chalk library, which are the most common consumers of
121
+ # `FORCE_COLOR`, rather than the
122
+ # [force-color.org](https://force-color.org) standard, which would
123
+ # force styling on for these values.
124
+ # 2. If the `FORCE_COLOR` environment variable is set to any other
125
+ # nonempty value, output is styled. Following the force-color.org
126
+ # standard, this overrides `NO_COLOR`, so that color can be forced
127
+ # for one run even when `NO_COLOR` is set as a general preference.
128
+ # An empty `FORCE_COLOR` is treated as if it were unset, also
129
+ # following the force-color.org standard.
130
+ # 3. If the `NO_COLOR` environment variable is set to a nonempty value,
131
+ # output is not styled, following the
132
+ # [no-color.org](https://no-color.org) standard.
133
+ # 4. If the `TERM` environment variable is set to `dumb`, output is not
134
+ # styled.
135
+ # 5. Otherwise, output is styled if the output is a tty.
136
+ #
137
+ # Note that all styling is affected, not only color. Also note that an
138
+ # explicit choice, such as passing `styled: true` or `styled: false` to
139
+ # {Terminal#initialize}, takes precedence over all of these checks,
140
+ # because this method is then not called at all.
141
+ #
142
+ # @param output [IO,Logger,nil] The output stream.
143
+ # @param env [Hash{String=>String}] The environment. Defaults to `ENV`.
144
+ # @return [boolean] Whether output should be styled.
145
+ #
146
+ def self.infer_styled(output, env: ::ENV)
147
+ # Source available in the toys-core gem
148
+ end
149
+
109
150
  ##
110
151
  # Create a terminal.
111
152
  #
112
153
  # @param input [IO,nil] Input stream.
113
154
  # @param output [IO,Logger,nil] Output stream or logger.
114
155
  # @param styled [boolean,nil] Whether to output ansi styles. If `nil`, the
115
- # setting is inferred from whether the output has a tty.
156
+ # setting is inferred from the output and the environment. See
157
+ # {Terminal.infer_styled}.
116
158
  #
117
159
  def initialize(input: $stdin, output: $stdout, styled: nil)
118
160
  # Source available in the toys-core gem
@@ -63,6 +63,12 @@ module Toys
63
63
  ##
64
64
  # Returns the absolute path to the current user's home directory.
65
65
  #
66
+ # Uses the value of the `$HOME` environment variable if it is an absolute
67
+ # path, otherwise falls back to the system's notion of the home directory.
68
+ # If no home directory can be determined (for example, when `$HOME` is
69
+ # unset and the current user has no passwd entry, as can happen in a
70
+ # container run under an arbitrary UID), returns the filesystem root `"/"`.
71
+ #
66
72
  # @return [String]
67
73
  #
68
74
  def home_dir
@@ -359,7 +365,7 @@ module Toys
359
365
  # Version of the simple_xdg gem
360
366
  # @return [String]
361
367
  #
362
- VERSION = "0.1.1"
368
+ VERSION = "0.1.2"
363
369
  end
364
370
  end
365
371
  end
@@ -0,0 +1,96 @@
1
+ module Toys
2
+ ##
3
+ # A warning reporter that supports throttling of repeated messages and
4
+ # environment variable based silencing. Used in particular to display
5
+ # deprecation warnings.
6
+ #
7
+ # **_Defined in the toys-core gem_**
8
+ #
9
+ module Warnings
10
+ ##
11
+ # @return [Integer] The default value for {Warnings.max_count}.
12
+ #
13
+ DEFAULT_MAX_COUNT = 5
14
+
15
+ ##
16
+ # @return [String] The name of an environment variable that, when set to a
17
+ # non-empty value, suppresses warnings emitted by this module.
18
+ #
19
+ SUPPRESS_WARNINGS_ENV = "TOYS_SUPPRESS_WARNINGS"
20
+
21
+ FURTHER_SUPPRESSED_MSG = "further warnings suppressed"
22
+ private_constant :FURTHER_SUPPRESSED_MSG
23
+
24
+ ENV_SUPPRESSION_MSG = "to suppress these warnings altogether, set #{SUPPRESS_WARNINGS_ENV} to a nonempty value"
25
+ private_constant :ENV_SUPPRESSION_MSG
26
+
27
+ @mutex = ::Mutex.new
28
+ @max_count = DEFAULT_MAX_COUNT
29
+
30
+ class << self
31
+ ##
32
+ # The maximum number of times a warning with the same identity will be
33
+ # displayed before further instances are suppressed, or nil to keep
34
+ # displaying each warning regardless of how many times it has repeated.
35
+ # Defaults to {DEFAULT_MAX_COUNT}. Can be set using
36
+ # {Toys::Warnings.max_count=}.
37
+ #
38
+ # @return [Integer,nil]
39
+ #
40
+ attr_reader :max_count
41
+
42
+ ##
43
+ # Set the maximum number of times a warning with the same identity will
44
+ # be displayed before further instances are suppressed. Must be a
45
+ # nonnegative integer, or nil to keep displaying each warning regardless
46
+ # of how many times it has repeated. The value 0 suppresses warnings
47
+ # unconditionally.
48
+ #
49
+ # @param value [Integer,nil] The new max_count value
50
+ #
51
+ def max_count=(value)
52
+ # Source available in the toys-core gem
53
+ end
54
+
55
+ ##
56
+ # Displays a warning message.
57
+ #
58
+ # You must pass an identifier object and a message string. The identifier
59
+ # should identify "which" warning is being displayed, and is used to
60
+ # count repeated warnings so they can be throttled after a certain number
61
+ # of instances.
62
+ #
63
+ # Uses the Ruby `Kernel#warn` method, so it is affected by `$VERBOSE` and
64
+ # the `-W0` flag. Does not currently support the `category:` argument to
65
+ # `Kernel#warn` because it is not supported in Ruby 2.7, and in newer
66
+ # Rubies, common values such as `category: :deprecated` default to silent,
67
+ # whereas this method should not be silent unless explicitly requested.
68
+ #
69
+ # @param identifier [Object] An object that identifies the warning for
70
+ # counting purposes. Generally this should be a fixed small set of
71
+ # objects, preferably symbols, as each identifier seen is used as a
72
+ # hash key and never deleted.
73
+ # @param message [String] The warning message
74
+ # @param uplevel [Integer,nil] If given and set to a nonnegative Integer,
75
+ # the warning will be prepended with the caller frame, that many
76
+ # stack levels above the call site. If not given or set to nil, the
77
+ # caller is not included in the report.
78
+ # @param max_count [Integer,nil,:default] The maximum number of times a
79
+ # warning with the same identity will be displayed before further
80
+ # instances are suppressed. Must be a nonnegative integer, or nil to
81
+ # keep displaying each warning regardless of how many times it has
82
+ # repeated. The value 0 suppresses warnings of this identifier
83
+ # unconditionally. The special value `:default` (which is used if the
84
+ # argument is not provided) falls back to {Toys::Warnings.max_count}.
85
+ #
86
+ # @return [Integer] The number of times this warning's identifier has
87
+ # happened, regardless of whether it was actually displayed.
88
+ #
89
+ def warn(identifier, message, uplevel: nil, max_count: :default)
90
+ # Source available in the toys-core gem
91
+ end
92
+ end
93
+
94
+ reset_counts
95
+ end
96
+ end
@@ -53,7 +53,8 @@
53
53
  # {Toys::Middleware}, which are resolved by name through
54
54
  # {Toys::ModuleLookup}, as well as {Toys::WrappableString},
55
55
  # {Toys::ToolNameSplitter} which interprets delimiters in tool names, the
56
- # named sentinel {Toys::UniqueKey}, and the error classes.
56
+ # named sentinel {Toys::UniqueKey}, the warning reporter {Toys::Warnings},
57
+ # and the error classes.
57
58
  #
58
59
  # The deliberate upward dependencies are:
59
60
  #
data/docs/guide.md CHANGED
@@ -233,7 +233,7 @@ However, Toys adds a few standard flags globally to every tool. (It is possible
233
233
  for individual tools to override these flags, but most tools should support
234
234
  them.) These standard flags include:
235
235
 
236
- * `--help` (also `-?`) which displays the full help screen for the tool.
236
+ * `--help` (also `-h` or `-?`) which displays the full help screen for the tool.
237
237
  * `--usage` which displays a shorter usage screen for the tool.
238
238
  * `--verbose` (also `-v`) which increases the verbosity. This affects the
239
239
  tool's logging display, increasing the number of log levels shown. This
@@ -1461,6 +1461,19 @@ tool file the error occurred, but doesn't give you the entire stack trace
1461
1461
  (which could include a number of frames internal to the Toys framework). If you
1462
1462
  want to see the full stack trace, set the `TOYS_TRACE` environment variable.
1463
1463
 
1464
+ ### Warnings
1465
+
1466
+ Toys may display warnings on the standard error stream, for example when a
1467
+ tool uses a feature of Toys that has been deprecated. These warnings are
1468
+ separate from the logger described above, and are not affected by verbosity
1469
+ or by the `--quiet` flag. If the same warning is triggered repeatedly during a
1470
+ single run, Toys displays only the first few instances.
1471
+
1472
+ To suppress these warnings entirely, set the `TOYS_SUPPRESS_WARNINGS`
1473
+ environment variable to a nonempty value. Because Toys uses Ruby's standard
1474
+ `Kernel#warn` mechanism to display them, they are also silenced if Ruby
1475
+ warnings are disabled, for example by running Ruby with the `-W0` flag.
1476
+
1464
1477
  ### Running tools from tools
1465
1478
 
1466
1479
  A common operation a tool might want to do is "call" another tool. This can be
@@ -1723,12 +1736,26 @@ When Toys runs, it looks for tools in a **search path**. Specifically:
1723
1736
  working directory*.
1724
1737
  2. It does the same in the *parent directory* of the current directory, and
1725
1738
  then its parent, and so on until it hits either the root of the file system
1726
- or one of the global directories described in (3).
1727
- 3. It looks in a list of *global directories*, specified in the environment
1728
- variable `TOYS_PATH`. This variable can contain a colon-delimited list of
1729
- directory paths. If the variable is not set, the current user's *home
1730
- directory*, and the system configuration directory (`/etc` on Unix systems)
1731
- are used by default. Toys does *not* search parents of global directories.
1739
+ or the current user's *home directory*. The home directory itself is not
1740
+ part of this step.
1741
+ 3. It looks in a list of *global sources*:
1742
+ * A `.toys.rb` file and/or a `.toys` directory in the current user's
1743
+ home directory.
1744
+ * The `toys` directory under the user configuration directory given by
1745
+ the `XDG_CONFIG_HOME` environment variable (`~/.config/toys` by
1746
+ default).
1747
+ * The `toys` directory under each system configuration directory given by
1748
+ the colon-delimited `XDG_CONFIG_DIRS` environment variable
1749
+ (`/etc/xdg/toys` by default), in order.
1750
+
1751
+ Unlike `.toys` directories, the `toys` directories under the configuration
1752
+ directories are not tied to any project directory, so tools loaded from
1753
+ them have no
1754
+ [context directory](#working-directory-and-context-directory) by default.
1755
+
1756
+ Toys does *not* search parents of global sources. If the current working
1757
+ directory is inside one of the `toys` configuration directories, Toys
1758
+ skips steps (1) and (2) and loads only the global sources.
1732
1759
 
1733
1760
  It uses the *first* implementation that it finds for the requested tool. For
1734
1761
  example, if the tool `greet` is defined in the `.toys.rb` file in the current
@@ -1756,6 +1783,15 @@ That is, they may be different depending on what directory you are in. However,
1756
1783
  step (3) is *not* context-dependent, and is searched regardless of where you
1757
1784
  are located. Tools defined here are *global*, available everywhere.
1758
1785
 
1786
+ You can choose which global sources are searched by setting the
1787
+ `TOYS_GLOBAL_SOURCES` environment variable. The global sources form three
1788
+ groups: `home` (the home directory), `user` (the user configuration directory),
1789
+ and `site` (the system configuration directories). Set the variable to a
1790
+ comma-delimited list of the groups to search, in that order. For example,
1791
+ `TOYS_GLOBAL_SOURCES=user,site` omits the home directory. Set it to `none` to
1792
+ search no global sources, which can be useful for reproducible runs in CI. If
1793
+ the variable is unset or empty, all three groups are searched.
1794
+
1759
1795
  #### Stopping search
1760
1796
 
1761
1797
  Though it is uncommon practice, it is possible to stop the search process and
@@ -66,10 +66,27 @@ module Toys
66
66
  DEFAULT_VERSION_FLAG_DESC = "Show the version of Toys."
67
67
 
68
68
  ##
69
- # Name of the toys path environment variable.
69
+ # Name of the environment variable that selects which groups of global
70
+ # sources are searched.
70
71
  # @return [String]
71
72
  #
72
- TOYS_PATH_ENV = "TOYS_PATH"
73
+ GLOBAL_SOURCES_ENV = "TOYS_GLOBAL_SOURCES"
74
+
75
+ ##
76
+ # The groups of global sources, in search order. The `home` group is
77
+ # `$HOME/.toys.rb` and `$HOME/.toys/`, the `user` group is the `toys`
78
+ # tool directory under `$XDG_CONFIG_HOME`, and the `site` group is the
79
+ # `toys` tool directories under each of `$XDG_CONFIG_DIRS`.
80
+ # @return [Array<String>]
81
+ #
82
+ GLOBAL_SOURCE_GROUPS = ["home", "user", "site"].freeze
83
+
84
+ ##
85
+ # Raised by the constructor if the `TOYS_GLOBAL_SOURCES` environment
86
+ # variable has an invalid value.
87
+ #
88
+ class InvalidGlobalSourcesError < ::StandardError
89
+ end
73
90
 
74
91
  ##
75
92
  # Create a standard CLI, configured with the appropriate paths and
@@ -77,7 +94,8 @@ module Toys
77
94
  #
78
95
  # @param custom_paths [String,Array<String>] Custom paths to use. If set,
79
96
  # the CLI uses only the given paths. If not, the CLI will search for
80
- # paths from the current directory and global paths.
97
+ # paths from the current directory and global paths, as selected by
98
+ # the `TOYS_GLOBAL_SOURCES` environment variable.
81
99
  # @param include_builtins [boolean] Add the builtin tools. Default is true.
82
100
  # @param cur_dir [String,nil] Starting search directory for sources.
83
101
  # Defaults to the current working directory.
@@ -87,6 +105,8 @@ module Toys
87
105
  # @param gems_util [Toys::Utils::Gems,nil] A custom Gems utility instance
88
106
  # to use when resolving gem sources. Optional. If nil or not
89
107
  # specified, uses a process-wide default Gems utility.
108
+ # @raise [InvalidGlobalSourcesError] if no custom paths are given and the
109
+ # `TOYS_GLOBAL_SOURCES` environment variable has an invalid value.
90
110
  #
91
111
  def initialize(custom_paths: nil,
92
112
  include_builtins: true,
@@ -112,7 +132,7 @@ module Toys
112
132
  if custom_paths
113
133
  Array(custom_paths).each { |path| add_source(path) }
114
134
  else
115
- add_current_directory_paths(cur_dir)
135
+ add_default_sources(cur_dir)
116
136
  end
117
137
  add_builtins if include_builtins
118
138
  end
@@ -130,21 +150,171 @@ module Toys
130
150
  end
131
151
 
132
152
  ##
133
- # Add paths for the given current directory and its ancestors, plus the
134
- # global paths.
153
+ # Add the sources found by the default search: the current directory and
154
+ # its ancestors, followed by the selected global sources.
135
155
  #
136
- # @param cur_dir [String] The starting directory path, or nil to use the
137
- # current directory
156
+ # @param cur_dir [String,nil] The starting directory path, or nil to use
157
+ # the current directory
138
158
  # @return [self]
139
159
  #
140
- def add_current_directory_paths(cur_dir)
141
- cur_dir = skip_toys_dir(cur_dir || ::Dir.pwd, TOPLEVEL_TOOL_DIR_NAME)
142
- global_dirs = default_global_dirs
143
- add_search_path_hierarchy(start: cur_dir, terminate: global_dirs)
144
- global_dirs.each { |path| add_search_path(path) }
160
+ def add_default_sources(cur_dir)
161
+ groups = selected_global_groups
162
+ warn_removed_global_paths
163
+ require "toys/utils/xdg"
164
+ xdg = Utils::XDG.new
165
+ home_dir = real_directory(xdg.home_dir)
166
+ user_dirs = [real_directory(::File.join(xdg.config_home, "toys"))].compact
167
+ site_dirs = xdg.config_dirs.map { |dir| real_directory(::File.join(dir, "toys")) }.compact
168
+ walk_dirs = upward_walk_dirs(cur_dir || ::Dir.pwd, home_dir, user_dirs + site_dirs)
169
+ walk_dirs.each { |dir| add_search_path(dir) }
170
+ warn_etc_toys_files(walk_dirs)
171
+ add_global_sources(groups, home_dir, user_dirs, site_dirs)
145
172
  self
146
173
  end
147
174
 
175
+ ##
176
+ # Parse and validate the global sources environment variable.
177
+ #
178
+ # @return [Array<String>] The selected groups
179
+ # @raise [InvalidGlobalSourcesError] if the value is invalid
180
+ #
181
+ def selected_global_groups
182
+ value = ::ENV[GLOBAL_SOURCES_ENV].to_s
183
+ return GLOBAL_SOURCE_GROUPS if value.empty?
184
+ return [] if value == "none"
185
+ groups = value.split(",", -1)
186
+ return groups if GLOBAL_SOURCE_GROUPS.select { |group| groups.include?(group) } == groups
187
+ raise InvalidGlobalSourcesError,
188
+ "Invalid value for #{GLOBAL_SOURCES_ENV}: #{value.inspect}. Expected \"none\", or a" \
189
+ " comma-delimited list of groups from #{GLOBAL_SOURCE_GROUPS.join(',')} in that order."
190
+ end
191
+
192
+ ##
193
+ # Add the global sources in the selected groups, skipping any directory
194
+ # that resolves to one already added.
195
+ #
196
+ # @param groups [Array<String>] The selected groups
197
+ # @param home_dir [String,nil] The real path of the home directory
198
+ # @param user_dirs [Array<String>] Real paths of the user tool directories
199
+ # @param site_dirs [Array<String>] Real paths of the site tool directories
200
+ #
201
+ def add_global_sources(groups, home_dir, user_dirs, site_dirs)
202
+ added_dirs = []
203
+ if groups.include?("home") && home_dir
204
+ add_search_path(home_dir)
205
+ home_toys_dir = real_directory(::File.join(home_dir, TOPLEVEL_TOOL_DIR_NAME))
206
+ added_dirs << home_toys_dir if home_toys_dir
207
+ end
208
+ tool_dirs = []
209
+ tool_dirs.concat(user_dirs) if groups.include?("user")
210
+ tool_dirs.concat(site_dirs) if groups.include?("site")
211
+ tool_dirs.each do |dir|
212
+ next if added_dirs.include?(dir) || !::File.readable?(dir)
213
+ added_dirs << dir
214
+ add_source(SourceSpec.path(dir))
215
+ end
216
+ end
217
+
218
+ ##
219
+ # Returns the directories searched by the upward walk from the given
220
+ # directory, or none if the directory is inside a global tool directory.
221
+ #
222
+ # @param cur_dir [String] The starting directory
223
+ # @param home_dir [String,nil] The real path of the home directory
224
+ # @param global_tool_dirs [Array<String>] Real paths of the global tool
225
+ # directories
226
+ # @return [Array<String>]
227
+ #
228
+ def upward_walk_dirs(cur_dir, home_dir, global_tool_dirs)
229
+ cur_dir = real_directory(cur_dir) || ::File.expand_path(cur_dir)
230
+ cur_dir = skip_toys_dir(cur_dir, TOPLEVEL_TOOL_DIR_NAME)
231
+ return [] if global_tool_dirs.any? { |dir| path_within?(cur_dir, dir) }
232
+ walk_up(cur_dir, home_dir)
233
+ end
234
+
235
+ ##
236
+ # Returns the directories visited by the upward walk, starting at the
237
+ # given directory and stopping before the given terminating directory or
238
+ # after the root.
239
+ #
240
+ # @param start [String] The starting directory
241
+ # @param terminate [String,nil] The directory to stop before
242
+ # @return [Array<String>]
243
+ #
244
+ def walk_up(start, terminate)
245
+ dirs = []
246
+ dir = start
247
+ loop do
248
+ break if dir == terminate
249
+ dirs << dir
250
+ parent = ::File.dirname(dir)
251
+ break if parent == dir
252
+ dir = parent
253
+ end
254
+ dirs
255
+ end
256
+
257
+ ##
258
+ # Determines whether the given path is the given directory or is inside
259
+ # it, comparing whole path components.
260
+ #
261
+ # @param path [String] The path to check
262
+ # @param dir [String] The directory
263
+ # @return [boolean]
264
+ #
265
+ def path_within?(path, dir)
266
+ loop do
267
+ return true if path == dir
268
+ parent = ::File.dirname(path)
269
+ return false if parent == path
270
+ path = parent
271
+ end
272
+ end
273
+
274
+ ##
275
+ # Returns the real path of the given directory, or nil if it does not
276
+ # exist or is not a directory.
277
+ #
278
+ # @param path [String] The directory path
279
+ # @return [String,nil]
280
+ #
281
+ def real_directory(path)
282
+ return nil unless ::File.directory?(path)
283
+ ::File.realpath(path)
284
+ rescue ::SystemCallError
285
+ nil
286
+ end
287
+
288
+ ##
289
+ # Warns if the removed `TOYS_PATH` environment variable is set.
290
+ #
291
+ def warn_removed_global_paths
292
+ return if ::ENV["TOYS_PATH"].to_s.empty?
293
+ Warnings.warn(:toys_path_removed,
294
+ "TOYS_PATH is no longer supported and is ignored. To relocate global tool" \
295
+ " directories, set XDG_CONFIG_HOME or XDG_CONFIG_DIRS. To suppress them, set" \
296
+ " #{GLOBAL_SOURCES_ENV}. To load tools from a path once, use `toys do --path`.",
297
+ max_count: 1)
298
+ end
299
+
300
+ ##
301
+ # Warns if the removed `/etc` toys file or directory exists and was not
302
+ # loaded by the upward walk.
303
+ #
304
+ # @param walk_dirs [Array<String>] The directories visited by the walk
305
+ #
306
+ def warn_etc_toys_files(walk_dirs)
307
+ etc_dir = real_directory("/etc")
308
+ return if etc_dir.nil? || walk_dirs.include?(etc_dir)
309
+ file_path = ::File.join(etc_dir, TOPLEVEL_TOOL_FILE_NAME)
310
+ dir_path = ::File.join(etc_dir, TOPLEVEL_TOOL_DIR_NAME)
311
+ return unless ::File.exist?(file_path) || ::File.exist?(dir_path)
312
+ Warnings.warn(:etc_toys_removed,
313
+ "/etc/#{TOPLEVEL_TOOL_FILE_NAME} and /etc/#{TOPLEVEL_TOOL_DIR_NAME} are no longer" \
314
+ " loaded. Move global tools into the /etc/xdg/toys directory instead.",
315
+ max_count: 1)
316
+ end
317
+
148
318
  ##
149
319
  # Step out of any toys dir.
150
320
  #
@@ -165,21 +335,6 @@ module Toys
165
335
  end
166
336
  end
167
337
 
168
- ##
169
- # Returns the default set of global source directories.
170
- #
171
- # @return [Array<String>]
172
- #
173
- def default_global_dirs
174
- paths = ::ENV[TOYS_PATH_ENV].to_s.split(::File::PATH_SEPARATOR)
175
- paths = [::Dir.home, "/etc"] if paths.empty?
176
- paths
177
- .compact
178
- .uniq
179
- .select { |path| ::File.directory?(path) && ::File.readable?(path) }
180
- .map { |path| ::File.realpath(::File.expand_path(path)) }
181
- end
182
-
183
338
  ##
184
339
  # Returns the middleware for the standard Toys CLI.
185
340
  #
data/lib/toys/version.rb CHANGED
@@ -5,5 +5,5 @@ module Toys
5
5
  # Current version of the Toys command line executable.
6
6
  # @return [String]
7
7
  #
8
- VERSION = "0.24.0"
8
+ VERSION = "0.25.0"
9
9
  end
@@ -2,5 +2,5 @@ if [[ $# -eq 0 ]]; then
2
2
  set -- "toys"
3
3
  fi
4
4
  for arg in "$@"; do
5
- complete -C "toys system bash-completion eval" -o nospace "$arg"
5
+ complete -C "toys system bash-completion eval 2>/dev/null" -o nospace "$arg"
6
6
  done
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toys
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.0
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.24.0
18
+ version: 0.25.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.24.0
25
+ version: 0.25.0
26
26
  description: Toys is a configurable command line tool. Write commands in Ruby using
27
27
  a simple DSL, and Toys will provide the command line executable and take care of
28
28
  all the details such as argument parsing, online help, and error reporting. Toys
@@ -108,6 +108,7 @@ files:
108
108
  - core-docs/toys/utils/standard_ui.rb
109
109
  - core-docs/toys/utils/terminal.rb
110
110
  - core-docs/toys/utils/xdg.rb
111
+ - core-docs/toys/warnings.rb
111
112
  - core-docs/toys/wrappable_string.rb
112
113
  - docs/guide.md
113
114
  - lib/toys.rb
@@ -130,10 +131,10 @@ homepage: https://github.com/dazuma/toys
130
131
  licenses:
131
132
  - MIT
132
133
  metadata:
133
- changelog_uri: https://dazuma.github.io/toys/gems/toys/v0.24.0/file.CHANGELOG.html
134
- source_code_uri: https://github.com/dazuma/toys/tree/toys/v0.24.0/toys
134
+ changelog_uri: https://dazuma.github.io/toys/gems/toys/v0.25.0/file.CHANGELOG.html
135
+ source_code_uri: https://github.com/dazuma/toys/tree/toys/v0.25.0/toys
135
136
  bug_tracker_uri: https://github.com/dazuma/toys/issues
136
- documentation_uri: https://dazuma.github.io/toys/gems/toys/v0.24.0
137
+ documentation_uri: https://dazuma.github.io/toys/gems/toys/v0.25.0
137
138
  rdoc_options: []
138
139
  require_paths:
139
140
  - lib
@@ -148,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
148
149
  - !ruby/object:Gem::Version
149
150
  version: '0'
150
151
  requirements: []
151
- rubygems_version: 4.0.16
152
+ rubygems_version: 4.0.20
152
153
  specification_version: 4
153
154
  summary: A configurable command line tool
154
155
  test_files: []