toys-core 0.3.5 → 0.3.6

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: 88644d1a61c31baed3ea200a6a936f79d5f81227b42c79ceeb949dd7be06d3ad
4
- data.tar.gz: 85a9544bd4950250ab0797d1fa0a110d949cf677b6739596a90c75b8d1cf8185
3
+ metadata.gz: 1552f14b276734b92f59f9c1d4464679ec1facdc6480e8ecb01b7818d7541712
4
+ data.tar.gz: d8da75bf066fa32de202edc57151a37c20b08a29537e7fbb25e9683d705fe625
5
5
  SHA512:
6
- metadata.gz: 3f09f94ffd7f77b58981bcd291a46bd354c02b11800d550ee9419b76ea74049efe9aa4833bf8ee4e4d41199f84e926b03577315d61d8512c8808878420453542
7
- data.tar.gz: 46e24892810dcb54266bad9647b9d2bbb0dde2c283b7e869183103dad84da238ada3dd37581f4a891c84c95af2fa45e33bb72c25e728281ede6027847bd9e984
6
+ metadata.gz: b3816d90527525a282e55b534a2c250fd7667b7c4a9c4922dbd9a67c9bea72223eb6e16f2d1a0d035213ce86be013bdce2a073c56b8f35c4e223262a494faaaa
7
+ data.tar.gz: d73196fce65e1c0cc5904dd93e529bd798cfd10a19a1ac4ac9c138b30c62d516f5e76380502e38306ad91105526fd699dbf41fa20643c2b8bd852dfa1914ce06
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Release History
2
2
 
3
+ ### 0.3.6 / 2018-05-21
4
+
5
+ * CHANGED: Renamed show_version middleware to show_root_version.
6
+ * CHANGED: Reworked set_default_descriptions interface for more flexibility.
7
+ * CHANGED: Renamed Utils::Exec#config_defaults to configure_defaults to match the helper.
8
+ * CHANGED: Removed Context#new_cli and exposed Context#cli instead.
9
+ * CHANGED: Renamed CLI#empty_clone to CLI#child.
10
+ * IMPROVED: show_help middleware lets you control display of the source path section.
11
+ * IMPROVED: Optional parameters are now supported for flags.
12
+ * IMPROVED: Support custom acceptors.
13
+ * IMPROVED: Highline helper automatically sets use_color based on the type of stdout.
14
+
3
15
  ### 0.3.5 / 2018-05-15
4
16
 
5
17
  * CHANGED: Exec logic now lives in a utils class.
data/lib/toys/cli.rb CHANGED
@@ -219,19 +219,24 @@ module Toys
219
219
 
220
220
  ##
221
221
  # Make a clone with the same settings but no paths in the loader.
222
+ # This is sometimes useful for running sub-tools.
222
223
  #
223
224
  # @return [Toys::CLI]
225
+ # @yieldparam cli [Toys::CLI] If you pass a block, the new CLI is yielded
226
+ # to it so you can add paths and make other modifications.
224
227
  #
225
- def empty_clone
226
- CLI.new(binary_name: @binary_name,
227
- config_dir_name: @config_dir_name,
228
- config_file_name: @config_file_name,
229
- index_file_name: @index_file_name,
230
- preload_file_name: @preload_file_name,
231
- middleware_stack: @middleware_stack,
232
- logger: @logger,
233
- base_level: @base_level,
234
- error_handler: @error_handler)
228
+ def child
229
+ cli = CLI.new(binary_name: @binary_name,
230
+ config_dir_name: @config_dir_name,
231
+ config_file_name: @config_file_name,
232
+ index_file_name: @index_file_name,
233
+ preload_file_name: @preload_file_name,
234
+ middleware_stack: @middleware_stack,
235
+ logger: @logger,
236
+ base_level: @base_level,
237
+ error_handler: @error_handler)
238
+ yield cli if block_given?
239
+ cli
235
240
  end
236
241
 
237
242
  ##
@@ -27,6 +27,8 @@
27
27
  # POSSIBILITY OF SUCH DAMAGE.
28
28
  ;
29
29
 
30
+ require "toys/context"
31
+
30
32
  module Toys
31
33
  ##
32
34
  # This class defines the DSL for a toys configuration file.
@@ -63,6 +65,12 @@ module Toys
63
65
  # toys greet rubyists
64
66
  #
65
67
  class ConfigDSL
68
+ # Copy the well-known context key constants here, so that script blocks
69
+ # inside config DSL files can access them without qualification.
70
+ ::Toys::Context.constants.each do |const|
71
+ const_set(const, ::Toys::Context.const_get(const))
72
+ end
73
+
66
74
  ##
67
75
  # Create an instance of the DSL.
68
76
  # @private
@@ -84,6 +92,62 @@ module Toys
84
92
  @path = path
85
93
  end
86
94
 
95
+ ##
96
+ # Create an acceptor that can be passed into a flag or arg. An acceptor
97
+ # validates and/or converts a string parameter to a Ruby object. This
98
+ # acceptor may, for the current tool, be referenced by the name you provide
99
+ # when you create a flag or arg.
100
+ #
101
+ # An acceptor contains a validator, which parses and validates the string
102
+ # syntax of an argument, and a converter, which takes the validation
103
+ # results and returns a final value for the context data.
104
+ #
105
+ # The validator may be either a regular expression or a list of valid
106
+ # inputs.
107
+ #
108
+ # If the validator is a regular expression, it is matched against the
109
+ # argument string and succeeds only if the expression covers the *entire*
110
+ # string. The elements of the MatchData (i.e. the string matched, plus any
111
+ # captures) are then passed into the conversion function.
112
+ #
113
+ # If the validator is an array, the *string form* of the array elements
114
+ # (i.e. the results of calling to_s on each element) are considered the
115
+ # valid values for the argument. This is useful for enums, for example.
116
+ # In this case, the input is converted to the original array element, and
117
+ # any converter function you provide is ignored.
118
+ #
119
+ # If you provide no validator, then no validation takes place and all
120
+ # argument strings are considered valid. The string itself is passed on to
121
+ # the converter.
122
+ #
123
+ # The converter should be a proc that takes as its arguments the results
124
+ # of validation. For example, if you use a regular expression validator,
125
+ # the converter should take a series of strings arguments, the first of
126
+ # which is the full input string, and the rest of which are captures.
127
+ # If you provide no converter, no conversion is done and the input string
128
+ # is considered the final value. You may also provide the converter as a
129
+ # block.
130
+ #
131
+ # @param [String] name The acceptor name.
132
+ # @param [Regexp,Array,nil] validator The validator.
133
+ # @param [Proc,nil] converter The validator.
134
+ #
135
+ def acceptor(name, validator = nil, converter = nil, &block)
136
+ accept =
137
+ case validator
138
+ when ::Regexp
139
+ Tool::PatternAcceptor.new(name, validator, converter, &block)
140
+ when ::Array
141
+ Tool::EnumAcceptor.new(name, validator)
142
+ when nil
143
+ Tool::Acceptor.new(name, converter, &block)
144
+ else
145
+ raise ToolDefinitionError, "Illegal validator: #{validator.inspect}"
146
+ end
147
+ _cur_tool.add_acceptor(accept)
148
+ self
149
+ end
150
+
87
151
  ##
88
152
  # Create a subtool. You must provide a block defining the subtool.
89
153
  #
@@ -233,7 +297,10 @@ module Toys
233
297
  # @param [Symbol] key The key to use to retrieve the value from the
234
298
  # execution context.
235
299
  # @param [String...] flags The flags in OptionParser format.
236
- # @param [Object,nil] accept An OptionParser acceptor. Optional.
300
+ # @param [Object] accept An acceptor that validates and/or converts the
301
+ # value. You may provide either the name of an acceptor you have
302
+ # defined, or one of the default acceptors provided by OptionParser.
303
+ # Optional. If not specified, accepts any value as a string.
237
304
  # @param [Object] default The default value. This is the value that will
238
305
  # be set in the context if this flag is not provided on the command
239
306
  # line. Defaults to `nil`.
@@ -242,6 +309,9 @@ module Toys
242
309
  # and the previous value, and it should return the new value that
243
310
  # should be set. The default handler simply replaces the previous
244
311
  # value. i.e. the default is effectively `-> (val, _prev) { val }`.
312
+ # @param [Boolean] report_collisions Raise an exception if a flag is
313
+ # requested that is already in use or marked as unusable. Default is
314
+ # true.
245
315
  # @param [String,Array<String>,Toys::Utils::WrappableString] desc Short
246
316
  # description for the flag. See {Toys::ConfigDSL#desc} for a description
247
317
  # of the allowed formats. Defaults to the empty string.
@@ -250,22 +320,18 @@ module Toys
250
320
  # description of the allowed formats. (But note that this param takes
251
321
  # an Array of description lines, rather than a series of arguments.)
252
322
  # Defaults to the empty array.
253
- # @param [Boolean] only_unique If true, any flags that are already
254
- # defined in this tool are removed from this flag. For example, if
255
- # an earlier flag uses `-a`, and this flag wants to use both
256
- # `-a` and `-b`, then only `-b` will be assigned to this flag.
257
- # Defaults to false.
258
323
  # @yieldparam flag_dsl [Toys::ConfigDSL::FlagDSL] An object that lets you
259
324
  # configure this flag in a block.
260
325
  #
261
326
  def flag(key, *flags,
262
- accept: nil, default: nil, handler: nil, desc: nil, long_desc: nil,
263
- only_unique: false)
327
+ accept: nil, default: nil, handler: nil,
328
+ report_collisions: true,
329
+ desc: nil, long_desc: nil)
264
330
  return self if _cur_tool.nil?
265
- flag_dsl = FlagDSL.new(flags, accept, default, handler, desc, long_desc)
331
+ flag_dsl = FlagDSL.new(flags, accept, default, handler, report_collisions, desc, long_desc)
266
332
  yield flag_dsl if block_given?
267
333
  _cur_tool.lock_definition_path(@path)
268
- flag_dsl._add_to(_cur_tool, key, only_unique)
334
+ flag_dsl._add_to(_cur_tool, key)
269
335
  self
270
336
  end
271
337
 
@@ -276,7 +342,10 @@ module Toys
276
342
  #
277
343
  # @param [Symbol] key The key to use to retrieve the value from the
278
344
  # execution context.
279
- # @param [Object,nil] accept An OptionParser acceptor. Optional.
345
+ # @param [Object] accept An acceptor that validates and/or converts the
346
+ # value. You may provide either the name of an acceptor you have
347
+ # defined, or one of the default acceptors provided by OptionParser.
348
+ # Optional. If not specified, accepts any value as a string.
280
349
  # @param [String] display_name A name to use for display (in help text and
281
350
  # error reports). Defaults to the key in upper case.
282
351
  # @param [String,Array<String>,Toys::Utils::WrappableString] desc Short
@@ -311,7 +380,10 @@ module Toys
311
380
  # @param [Object] default The default value. This is the value that will
312
381
  # be set in the context if this argument is not provided on the command
313
382
  # line. Defaults to `nil`.
314
- # @param [Object,nil] accept An OptionParser acceptor. Optional.
383
+ # @param [Object] accept An acceptor that validates and/or converts the
384
+ # value. You may provide either the name of an acceptor you have
385
+ # defined, or one of the default acceptors provided by OptionParser.
386
+ # Optional. If not specified, accepts any value as a string.
315
387
  # @param [String] display_name A name to use for display (in help text and
316
388
  # error reports). Defaults to the key in upper case.
317
389
  # @param [String,Array<String>,Toys::Utils::WrappableString] desc Short
@@ -346,7 +418,10 @@ module Toys
346
418
  # @param [Object] default The default value. This is the value that will
347
419
  # be set in the context if no unmatched arguments are provided on the
348
420
  # command line. Defaults to the empty array `[]`.
349
- # @param [Object,nil] accept An OptionParser acceptor. Optional.
421
+ # @param [Object] accept An acceptor that validates and/or converts the
422
+ # value. You may provide either the name of an acceptor you have
423
+ # defined, or one of the default acceptors provided by OptionParser.
424
+ # Optional. If not specified, accepts any value as a string.
350
425
  # @param [String] display_name A name to use for display (in help text and
351
426
  # error reports). Defaults to the key in upper case.
352
427
  # @param [String,Array<String>,Toys::Utils::WrappableString] desc Short
@@ -418,11 +493,12 @@ module Toys
418
493
  #
419
494
  class FlagDSL
420
495
  ## @private
421
- def initialize(flags, accept, default, handler, desc, long_desc)
496
+ def initialize(flags, accept, default, handler, report_collisions, desc, long_desc)
422
497
  @flags = flags
423
498
  @accept = accept
424
499
  @default = default
425
500
  @handler = handler
501
+ @report_collisions = report_collisions
426
502
  @desc = desc
427
503
  @long_desc = long_desc
428
504
  end
@@ -467,6 +543,16 @@ module Toys
467
543
  self
468
544
  end
469
545
 
546
+ ##
547
+ # Set whether to raise an exception if a flag is requested that is
548
+ # already in use or marked as disabled.
549
+ # @param [Boolean] setting
550
+ #
551
+ def report_collisions(setting)
552
+ @report_collisions = setting
553
+ self
554
+ end
555
+
470
556
  ##
471
557
  # Set the short description. See {Toys::ConfigDSL#desc} for the allowed
472
558
  # formats.
@@ -489,11 +575,11 @@ module Toys
489
575
  end
490
576
 
491
577
  ## @private
492
- def _add_to(tool, key, only_unique)
578
+ def _add_to(tool, key)
493
579
  tool.add_flag(key, @flags,
494
580
  accept: @accept, default: @default, handler: @handler,
495
- desc: @desc, long_desc: @long_desc,
496
- only_unique: only_unique)
581
+ report_collisions: @report_collisions,
582
+ desc: @desc, long_desc: @long_desc)
497
583
  end
498
584
  end
499
585
 
data/lib/toys/context.rb CHANGED
@@ -31,75 +31,91 @@ require "logger"
31
31
 
32
32
  module Toys
33
33
  ##
34
- # The object context in effect during the execution of a tool.
34
+ # This class manages the object context in effect during the execution of a
35
+ # tool. The context is a hash of key-value pairs.
35
36
  #
36
- # The context is generally a hash of key-value pairs.
37
- # Keys that begin with two underscores are reserved common elements of the
38
- # context such as the tool being executed, or the verbosity level.
39
- # Other keys are available for use by your tool. Generally, they are set
40
- # by flags and arguments in your tool. Context values may also be set
41
- # by middleware. By convention, middleware-set keys begin with a single
42
- # underscore.
37
+ # Flags and arguments defined by your tool normally report their values in
38
+ # the context, using keys that are strings or symbols.
39
+ #
40
+ # Keys that are neither strings nor symbols are by convention used for other
41
+ # context information, including:
42
+ # * Common information such as the {Toys::Tool} object being executed, the
43
+ # arguments originally passed to it, or the usage error string. These
44
+ # well-known keys can be accessed via constants in the {Toys::Context}
45
+ # module.
46
+ # * Common settings such as the verbosity level, and whether to exit
47
+ # immediately if a subprocess exits with a nonzero result. These keys are
48
+ # also present as {Toys::Context} constants.
49
+ # * Private information used internally by middleware and helpers.
50
+ #
51
+ # This class provides convenience accessors for common keys and settings, and
52
+ # you can retrieve argument-set keys using the {#options} hash.
43
53
  #
44
54
  class Context
55
+ ##
56
+ # Context key for the currently running CLI.
57
+ # @return [Object]
58
+ #
59
+ CLI = ::Object.new.freeze
60
+
45
61
  ##
46
62
  # Context key for the verbosity value. Verbosity is an integer defaulting
47
63
  # to 0, with higher values meaning more verbose and lower meaning quieter.
48
- # @return [Symbol]
64
+ # @return [Object]
49
65
  #
50
- VERBOSITY = :__verbosity
66
+ VERBOSITY = ::Object.new.freeze
51
67
 
52
68
  ##
53
69
  # Context key for the `Toys::Tool` object being executed.
54
- # @return [Symbol]
70
+ # @return [Object]
55
71
  #
56
- TOOL = :__tool
72
+ TOOL = ::Object.new.freeze
57
73
 
58
74
  ##
59
75
  # Context key for the full name of the tool being executed. Value is an
60
76
  # array of strings.
61
- # @return [Symbol]
77
+ # @return [Object]
62
78
  #
63
- TOOL_NAME = :__tool_name
79
+ TOOL_NAME = ::Object.new.freeze
64
80
 
65
81
  ##
66
82
  # Context key for the active `Toys::Loader` object.
67
- # @return [Symbol]
83
+ # @return [Object]
68
84
  #
69
- LOADER = :__loader
85
+ LOADER = ::Object.new.freeze
70
86
 
71
87
  ##
72
88
  # Context key for the active `Logger` object.
73
- # @return [Symbol]
89
+ # @return [Object]
74
90
  #
75
- LOGGER = :__logger
91
+ LOGGER = ::Object.new.freeze
76
92
 
77
93
  ##
78
94
  # Context key for the name of the toys binary. Value is a string.
79
- # @return [Symbol]
95
+ # @return [Object]
80
96
  #
81
- BINARY_NAME = :__binary_name
97
+ BINARY_NAME = ::Object.new.freeze
82
98
 
83
99
  ##
84
100
  # Context key for the argument list passed to the current tool. Value is
85
101
  # an array of strings.
86
- # @return [Symbol]
102
+ # @return [Object]
87
103
  #
88
- ARGS = :__args
104
+ ARGS = ::Object.new.freeze
89
105
 
90
106
  ##
91
107
  # Context key for the usage error raised. Value is a string if there was
92
108
  # an error, or nil if there was no error.
93
- # @return [Symbol]
109
+ # @return [Object]
94
110
  #
95
- USAGE_ERROR = :__usage_error
111
+ USAGE_ERROR = ::Object.new.freeze
96
112
 
97
113
  ##
98
114
  # Context key for whether nonzero exit codes from subprocesses should cause
99
115
  # an immediate exit. Value is a truthy or falsy value.
100
- # @return [Symbol]
116
+ # @return [Object]
101
117
  #
102
- EXIT_ON_NONZERO_STATUS = :__exit_on_nonzero_status
118
+ EXIT_ON_NONZERO_STATUS = ::Object.new.freeze
103
119
 
104
120
  ##
105
121
  # Create a Context object. Applications generally will not need to create
@@ -111,15 +127,23 @@ module Toys
111
127
  # @param [Hash] data
112
128
  #
113
129
  def initialize(cli, data)
114
- @_cli = cli
115
130
  @_data = data
131
+ @_data[CLI] = cli
116
132
  @_data[LOADER] = cli.loader
117
133
  @_data[BINARY_NAME] = cli.binary_name
118
134
  @_data[LOGGER] = cli.logger
119
135
  end
120
136
 
121
137
  ##
122
- # Return the verbosity as an integer.
138
+ # Return the currently running CLI.
139
+ # @return [Toys::CLI]
140
+ #
141
+ def cli
142
+ @_data[CLI]
143
+ end
144
+
145
+ ##
146
+ # Return the current verbosity setting as an integer.
123
147
  # @return [Integer]
124
148
  #
125
149
  def verbosity
@@ -196,7 +220,7 @@ module Toys
196
220
  alias get []
197
221
 
198
222
  ##
199
- # Set an option or other piece of data by key.
223
+ # Set an option or other piece of context data by key.
200
224
  #
201
225
  # @param [Symbol] key
202
226
  # @param [Object] value
@@ -206,7 +230,7 @@ module Toys
206
230
  end
207
231
 
208
232
  ##
209
- # Set an option or other piece of data by key.
233
+ # Set an option or other piece of context data by key.
210
234
  #
211
235
  # @param [Symbol] key
212
236
  # @param [Object] value
@@ -221,15 +245,16 @@ module Toys
221
245
  end
222
246
 
223
247
  ##
224
- # Returns the subset of the context that does not include well-known keys
225
- # such as tool and verbosity. Technically, this includes all keys that do
226
- # not begin with two underscores.
248
+ # Returns the subset of the context that uses string or symbol keys. By
249
+ # convention, this includes keys that are set by tool flags and arguments,
250
+ # but does not include well-known context values such as verbosity or
251
+ # private context values used by middleware or helpers.
227
252
  #
228
253
  # @return [Hash]
229
254
  #
230
255
  def options
231
256
  @_data.select do |k, _v|
232
- !k.is_a?(::Symbol) || !k.to_s.start_with?("__")
257
+ k.is_a?(::Symbol) || k.is_a?(::String)
233
258
  end
234
259
  end
235
260
 
@@ -245,26 +270,13 @@ module Toys
245
270
  # @return [Integer] The resulting status code
246
271
  #
247
272
  def run(*args, cli: nil, exit_on_nonzero_status: nil)
248
- cli ||= @_cli
273
+ cli ||= @_data[CLI]
249
274
  exit_on_nonzero_status = @_data[EXIT_ON_NONZERO_STATUS] if exit_on_nonzero_status.nil?
250
275
  code = cli.run(args.flatten, verbosity: @_data[VERBOSITY])
251
276
  exit(code) if exit_on_nonzero_status && !code.zero?
252
277
  code
253
278
  end
254
279
 
255
- ##
256
- # Return a new CLI with the same settings as the currnet CLI but no paths.
257
- # This can be used to run a toys "sub-instance". Add any new paths to the
258
- # returned CLI, then call {#run}, passing in the CLI, to execute a tool.
259
- #
260
- # @return [Toys::CLI]
261
- #
262
- def new_cli
263
- cli = @_cli.empty_clone
264
- yield cli if block_given?
265
- cli
266
- end
267
-
268
280
  ##
269
281
  # Exit immediately with the given status code
270
282
  #