toys-core 0.3.5 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
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
  #