toys-core 0.3.6 → 0.3.7

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/lib/toys-core.rb +20 -5
  4. data/lib/toys/cli.rb +39 -32
  5. data/lib/toys/core_version.rb +1 -1
  6. data/lib/toys/{tool → definition}/acceptor.rb +21 -15
  7. data/lib/toys/{utils/line_output.rb → definition/alias.rb} +47 -59
  8. data/lib/toys/{tool/arg_definition.rb → definition/arg.rb} +17 -7
  9. data/lib/toys/{tool/flag_definition.rb → definition/flag.rb} +19 -9
  10. data/lib/toys/definition/tool.rb +574 -0
  11. data/lib/toys/dsl/arg.rb +118 -0
  12. data/lib/toys/dsl/flag.rb +132 -0
  13. data/lib/toys/dsl/tool.rb +521 -0
  14. data/lib/toys/errors.rb +2 -2
  15. data/lib/toys/helpers.rb +3 -3
  16. data/lib/toys/helpers/exec.rb +31 -25
  17. data/lib/toys/helpers/fileutils.rb +8 -2
  18. data/lib/toys/helpers/highline.rb +8 -1
  19. data/lib/toys/{alias.rb → helpers/terminal.rb} +44 -53
  20. data/lib/toys/input_file.rb +61 -0
  21. data/lib/toys/loader.rb +87 -77
  22. data/lib/toys/middleware.rb +3 -3
  23. data/lib/toys/middleware/add_verbosity_flags.rb +22 -20
  24. data/lib/toys/middleware/base.rb +53 -5
  25. data/lib/toys/middleware/handle_usage_errors.rb +9 -12
  26. data/lib/toys/middleware/set_default_descriptions.rb +6 -7
  27. data/lib/toys/middleware/show_help.rb +71 -67
  28. data/lib/toys/middleware/show_root_version.rb +9 -9
  29. data/lib/toys/runner.rb +157 -0
  30. data/lib/toys/template.rb +4 -3
  31. data/lib/toys/templates.rb +2 -2
  32. data/lib/toys/templates/clean.rb +2 -2
  33. data/lib/toys/templates/gem_build.rb +5 -5
  34. data/lib/toys/templates/minitest.rb +2 -2
  35. data/lib/toys/templates/rubocop.rb +2 -2
  36. data/lib/toys/templates/yardoc.rb +2 -2
  37. data/lib/toys/tool.rb +168 -625
  38. data/lib/toys/utils/exec.rb +19 -18
  39. data/lib/toys/utils/gems.rb +140 -0
  40. data/lib/toys/utils/help_text.rb +25 -20
  41. data/lib/toys/utils/terminal.rb +412 -0
  42. data/lib/toys/utils/wrappable_string.rb +3 -1
  43. metadata +15 -24
  44. data/lib/toys/config_dsl.rb +0 -699
  45. data/lib/toys/context.rb +0 -290
  46. data/lib/toys/helpers/spinner.rb +0 -142
@@ -27,6 +27,8 @@
27
27
  # POSSIBILITY OF SUCH DAMAGE.
28
28
  ;
29
29
 
30
+ require "toys/utils/terminal"
31
+
30
32
  module Toys
31
33
  module Utils
32
34
  ##
@@ -99,7 +101,7 @@ module Toys
99
101
  line = ""
100
102
  line_len = 0
101
103
  fragments.each do |frag|
102
- frag_len = ::HighLine.uncolor(frag).size
104
+ frag_len = Utils::Terminal.remove_style_escapes(frag).size
103
105
  if line_len.zero?
104
106
  line = frag
105
107
  line_len = frag_len
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toys-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.6
4
+ version: 0.3.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-21 00:00:00.000000000 Z
11
+ date: 2018-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: highline
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.7'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.7'
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: minitest
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -108,17 +94,23 @@ files:
108
94
  - README.md
109
95
  - docs/getting-started.md
110
96
  - lib/toys-core.rb
111
- - lib/toys/alias.rb
112
97
  - lib/toys/cli.rb
113
- - lib/toys/config_dsl.rb
114
- - lib/toys/context.rb
115
98
  - lib/toys/core_version.rb
99
+ - lib/toys/definition/acceptor.rb
100
+ - lib/toys/definition/alias.rb
101
+ - lib/toys/definition/arg.rb
102
+ - lib/toys/definition/flag.rb
103
+ - lib/toys/definition/tool.rb
104
+ - lib/toys/dsl/arg.rb
105
+ - lib/toys/dsl/flag.rb
106
+ - lib/toys/dsl/tool.rb
116
107
  - lib/toys/errors.rb
117
108
  - lib/toys/helpers.rb
118
109
  - lib/toys/helpers/exec.rb
119
110
  - lib/toys/helpers/fileutils.rb
120
111
  - lib/toys/helpers/highline.rb
121
- - lib/toys/helpers/spinner.rb
112
+ - lib/toys/helpers/terminal.rb
113
+ - lib/toys/input_file.rb
122
114
  - lib/toys/loader.rb
123
115
  - lib/toys/middleware.rb
124
116
  - lib/toys/middleware/add_verbosity_flags.rb
@@ -127,6 +119,7 @@ files:
127
119
  - lib/toys/middleware/set_default_descriptions.rb
128
120
  - lib/toys/middleware/show_help.rb
129
121
  - lib/toys/middleware/show_root_version.rb
122
+ - lib/toys/runner.rb
130
123
  - lib/toys/template.rb
131
124
  - lib/toys/templates.rb
132
125
  - lib/toys/templates/clean.rb
@@ -135,13 +128,11 @@ files:
135
128
  - lib/toys/templates/rubocop.rb
136
129
  - lib/toys/templates/yardoc.rb
137
130
  - lib/toys/tool.rb
138
- - lib/toys/tool/acceptor.rb
139
- - lib/toys/tool/arg_definition.rb
140
- - lib/toys/tool/flag_definition.rb
141
131
  - lib/toys/utils/exec.rb
132
+ - lib/toys/utils/gems.rb
142
133
  - lib/toys/utils/help_text.rb
143
- - lib/toys/utils/line_output.rb
144
134
  - lib/toys/utils/module_lookup.rb
135
+ - lib/toys/utils/terminal.rb
145
136
  - lib/toys/utils/wrappable_string.rb
146
137
  homepage: https://github.com/dazuma/toys
147
138
  licenses:
@@ -1,699 +0,0 @@
1
- # Copyright 2018 Daniel Azuma
2
- #
3
- # All rights reserved.
4
- #
5
- # Redistribution and use in source and binary forms, with or without
6
- # modification, are permitted provided that the following conditions are met:
7
- #
8
- # * Redistributions of source code must retain the above copyright notice,
9
- # this list of conditions and the following disclaimer.
10
- # * Redistributions in binary form must reproduce the above copyright notice,
11
- # this list of conditions and the following disclaimer in the documentation
12
- # and/or other materials provided with the distribution.
13
- # * Neither the name of the copyright holder, nor the names of any other
14
- # contributors to this software, may be used to endorse or promote products
15
- # derived from this software without specific prior written permission.
16
- #
17
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
- # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21
- # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
- # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
- # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
- # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
- # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
- # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
- # POSSIBILITY OF SUCH DAMAGE.
28
- ;
29
-
30
- require "toys/context"
31
-
32
- module Toys
33
- ##
34
- # This class defines the DSL for a toys configuration file.
35
- #
36
- # A toys configuration defines one or more named tools. It provides syntax
37
- # for setting the description, defining flags and arguments, specifying
38
- # how to execute the tool, and requesting helper modules and other services.
39
- # It also lets you define subtools, nested arbitrarily deep, using blocks.
40
- #
41
- # Generally ConfigDSL is invoked from the {Loader}. Applications should not
42
- # need to create instances of ConfigDSL directly.
43
- #
44
- # ## Simple example
45
- #
46
- # Create a file called `.toys.rb` in the current directory, with the
47
- # following contents:
48
- #
49
- # tool "greet" do
50
- # desc "Prints a simple greeting"
51
- #
52
- # optional_arg :recipient, default: "world"
53
- #
54
- # script do
55
- # puts "Hello, #{self[:recipient]}!"
56
- # end
57
- # end
58
- #
59
- # Now you can execute it using:
60
- #
61
- # toys greet
62
- #
63
- # or try:
64
- #
65
- # toys greet rubyists
66
- #
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
-
74
- ##
75
- # Create an instance of the DSL.
76
- # @private
77
- #
78
- # @param [Array<String>] words Full name of the current tool.
79
- # @param [Array<String>,nil] remaining_words Arguments remaining in the
80
- # current lookup.
81
- # @param [Integer] priority Priority of this configuration
82
- # @param [Toys::Loader] loader Current active loader
83
- # @param [String] path The path to the config file being evaluated
84
- #
85
- # @return [Toys::ConfigDSL]
86
- #
87
- def initialize(words, remaining_words, priority, loader, path)
88
- @words = words
89
- @remaining_words = remaining_words
90
- @priority = priority
91
- @loader = loader
92
- @path = path
93
- end
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
-
151
- ##
152
- # Create a subtool. You must provide a block defining the subtool.
153
- #
154
- # If the subtool is already defined (either as a tool or a namespace), the
155
- # old definition is discarded and replaced with the new definition.
156
- #
157
- # @param [String] word The name of the subtool
158
- #
159
- def tool(word, &block)
160
- word = word.to_s
161
- subtool_words = @words + [word]
162
- next_remaining = Loader.next_remaining_words(@remaining_words, word)
163
- ConfigDSL.evaluate(subtool_words, next_remaining, @priority, @loader, @path, block)
164
- self
165
- end
166
- alias name tool
167
-
168
- ##
169
- # Create an alias in the current namespace.
170
- #
171
- # @param [String] word The name of the alias
172
- # @param [String] target The target of the alias
173
- #
174
- def alias_tool(word, target)
175
- @loader.make_alias(@words + [word.to_s], @words + [target.to_s], @priority)
176
- self
177
- end
178
-
179
- ##
180
- # Create an alias of the current tool.
181
- #
182
- # @param [String] word The name of the alias
183
- #
184
- def alias_as(word)
185
- if @words.empty?
186
- raise ToolDefinitionError, "Cannot make an alias of the root."
187
- end
188
- @loader.make_alias(@words[0..-2] + [word.to_s], @words, @priority)
189
- self
190
- end
191
-
192
- ##
193
- # Include another config file or directory at the current location.
194
- #
195
- # @param [String] path The file or directory to include.
196
- #
197
- def include(path)
198
- @loader.include_path(path, @words, @remaining_words, @priority)
199
- self
200
- end
201
-
202
- ##
203
- # Expand the given template in the current location.
204
- #
205
- # The template may be specified as a class or a well-known template name.
206
- # You may also provide arguments to pass to the template.
207
- #
208
- # @param [Class,String,Symbol] template_class The template, either as a
209
- # class or a well-known name.
210
- # @param [Object...] args Template arguments
211
- #
212
- def expand(template_class, *args)
213
- unless template_class.is_a?(::Class)
214
- name = template_class.to_s
215
- template_class = Templates.lookup(name)
216
- if template_class.nil?
217
- raise ToolDefinitionError, "Template not found: #{name.inspect}"
218
- end
219
- end
220
- template = template_class.new(*args)
221
- yield template if block_given?
222
- instance_exec(template, &template_class.expander)
223
- self
224
- end
225
-
226
- ##
227
- # Set the short description for the current tool. The short description is
228
- # displayed with the tool in a subtool list. You may also use the
229
- # equivalent method `short_desc`.
230
- #
231
- # The description is a {Toys::Utils::WrappableString}, which may be word-
232
- # wrapped when displayed in a help screen. You may pass a
233
- # {Toys::Utils::WrappableString} directly to this method, or you may pass
234
- # any input that can be used to construct a wrappable string:
235
- #
236
- # * If you pass a String, its whitespace will be compacted (i.e. tabs,
237
- # newlines, and multiple consecutive whitespace will be turned into a
238
- # single space), and it will be word-wrapped on whitespace.
239
- # * If you pass an Array of Strings, each string will be considered a
240
- # literal word that cannot be broken, and wrapping will be done across
241
- # the strings in the array. In this case, whitespace is not compacted.
242
- #
243
- # For example, if you pass in a sentence as a simple string, it may be
244
- # word wrapped when displayed:
245
- #
246
- # desc "This sentence may be wrapped."
247
- #
248
- # To specify a sentence that should never be word-wrapped, pass it as the
249
- # sole element of a string array:
250
- #
251
- # desc ["This sentence will not be wrapped."]
252
- #
253
- # @param [Toys::Utils::WrappableString,String,Array<String>] str
254
- #
255
- def desc(str)
256
- return self if _cur_tool.nil?
257
- _cur_tool.lock_definition_path(@path)
258
- _cur_tool.desc = str
259
- self
260
- end
261
- alias short_desc desc
262
-
263
- ##
264
- # Set the long description for the current tool. The long description is
265
- # displayed in the usage documentation for the tool itself.
266
- #
267
- # A long description is a series of descriptions, which are generally
268
- # displayed in a series of lines/paragraphs. Each individual description
269
- # uses the form described in the {Toys::ConfigDSL#desc} documentation, and
270
- # may be word-wrapped when displayed. To insert a blank line, include an
271
- # empty string as one of the descriptions.
272
- #
273
- # Example:
274
- #
275
- # long_desc "This is an initial paragraph that might be word wrapped.",
276
- # "This next paragraph is followed by a blank line.",
277
- # "",
278
- # ["This line will not be wrapped."]
279
- #
280
- # @param [Toys::Utils::WrappableString,String,Array<String>...] strs
281
- #
282
- def long_desc(*strs)
283
- return self if _cur_tool.nil?
284
- _cur_tool.lock_definition_path(@path)
285
- _cur_tool.long_desc = strs
286
- self
287
- end
288
-
289
- ##
290
- # Add a flag to the current tool. Each flag must specify a key which
291
- # the script may use to obtain the flag value from the context.
292
- # You may then provide the flags themselves in `OptionParser` form.
293
- #
294
- # Attributes of the flag may be passed in as arguments to this method, or
295
- # set in a block passed to this method.
296
- #
297
- # @param [Symbol] key The key to use to retrieve the value from the
298
- # execution context.
299
- # @param [String...] flags The flags in OptionParser format.
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.
304
- # @param [Object] default The default value. This is the value that will
305
- # be set in the context if this flag is not provided on the command
306
- # line. Defaults to `nil`.
307
- # @param [Proc,nil] handler An optional handler for setting/updating the
308
- # value. If given, it should take two arguments, the new given value
309
- # and the previous value, and it should return the new value that
310
- # should be set. The default handler simply replaces the previous
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.
315
- # @param [String,Array<String>,Toys::Utils::WrappableString] desc Short
316
- # description for the flag. See {Toys::ConfigDSL#desc} for a description
317
- # of the allowed formats. Defaults to the empty string.
318
- # @param [Array<String,Array<String>,Toys::Utils::WrappableString>] long_desc
319
- # Long description for the flag. See {Toys::ConfigDSL#long_desc} for a
320
- # description of the allowed formats. (But note that this param takes
321
- # an Array of description lines, rather than a series of arguments.)
322
- # Defaults to the empty array.
323
- # @yieldparam flag_dsl [Toys::ConfigDSL::FlagDSL] An object that lets you
324
- # configure this flag in a block.
325
- #
326
- def flag(key, *flags,
327
- accept: nil, default: nil, handler: nil,
328
- report_collisions: true,
329
- desc: nil, long_desc: nil)
330
- return self if _cur_tool.nil?
331
- flag_dsl = FlagDSL.new(flags, accept, default, handler, report_collisions, desc, long_desc)
332
- yield flag_dsl if block_given?
333
- _cur_tool.lock_definition_path(@path)
334
- flag_dsl._add_to(_cur_tool, key)
335
- self
336
- end
337
-
338
- ##
339
- # Add a required positional argument to the current tool. You must specify
340
- # a key which the script may use to obtain the argument value from the
341
- # context.
342
- #
343
- # @param [Symbol] key The key to use to retrieve the value from the
344
- # execution context.
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.
349
- # @param [String] display_name A name to use for display (in help text and
350
- # error reports). Defaults to the key in upper case.
351
- # @param [String,Array<String>,Toys::Utils::WrappableString] desc Short
352
- # description for the flag. See {Toys::ConfigDSL#desc} for a description
353
- # of the allowed formats. Defaults to the empty string.
354
- # @param [Array<String,Array<String>,Toys::Utils::WrappableString>] long_desc
355
- # Long description for the flag. See {Toys::ConfigDSL#long_desc} for a
356
- # description of the allowed formats. (But note that this param takes
357
- # an Array of description lines, rather than a series of arguments.)
358
- # Defaults to the empty array.
359
- # @yieldparam arg_dsl [Toys::ConfigDSL::ArgDSL] An object that lets you
360
- # configure this argument in a block.
361
- #
362
- def required_arg(key, accept: nil, display_name: nil, desc: nil, long_desc: nil)
363
- return self if _cur_tool.nil?
364
- arg_dsl = ArgDSL.new(accept, nil, display_name, desc, long_desc)
365
- yield arg_dsl if block_given?
366
- _cur_tool.lock_definition_path(@path)
367
- arg_dsl._add_required_to(_cur_tool, key)
368
- self
369
- end
370
- alias required required_arg
371
-
372
- ##
373
- # Add an optional positional argument to the current tool. You must specify
374
- # a key which the script may use to obtain the argument value from the
375
- # context. If an optional argument is not given on the command line, the
376
- # value is set to the given default.
377
- #
378
- # @param [Symbol] key The key to use to retrieve the value from the
379
- # execution context.
380
- # @param [Object] default The default value. This is the value that will
381
- # be set in the context if this argument is not provided on the command
382
- # line. Defaults to `nil`.
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.
387
- # @param [String] display_name A name to use for display (in help text and
388
- # error reports). Defaults to the key in upper case.
389
- # @param [String,Array<String>,Toys::Utils::WrappableString] desc Short
390
- # description for the flag. See {Toys::ConfigDSL#desc} for a description
391
- # of the allowed formats. Defaults to the empty string.
392
- # @param [Array<String,Array<String>,Toys::Utils::WrappableString>] long_desc
393
- # Long description for the flag. See {Toys::ConfigDSL#long_desc} for a
394
- # description of the allowed formats. (But note that this param takes
395
- # an Array of description lines, rather than a series of arguments.)
396
- # Defaults to the empty array.
397
- # @yieldparam arg_dsl [Toys::ConfigDSL::ArgDSL] An object that lets you
398
- # configure this argument in a block.
399
- #
400
- def optional_arg(key, default: nil, accept: nil, display_name: nil,
401
- desc: nil, long_desc: nil)
402
- return self if _cur_tool.nil?
403
- arg_dsl = ArgDSL.new(accept, default, display_name, desc, long_desc)
404
- yield arg_dsl if block_given?
405
- _cur_tool.lock_definition_path(@path)
406
- arg_dsl._add_optional_to(_cur_tool, key)
407
- self
408
- end
409
- alias optional optional_arg
410
-
411
- ##
412
- # Specify what should be done with unmatched positional arguments. You must
413
- # specify a key which the script may use to obtain the remaining args from
414
- # the context.
415
- #
416
- # @param [Symbol] key The key to use to retrieve the value from the
417
- # execution context.
418
- # @param [Object] default The default value. This is the value that will
419
- # be set in the context if no unmatched arguments are provided on the
420
- # command line. Defaults to the empty array `[]`.
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.
425
- # @param [String] display_name A name to use for display (in help text and
426
- # error reports). Defaults to the key in upper case.
427
- # @param [String,Array<String>,Toys::Utils::WrappableString] desc Short
428
- # description for the flag. See {Toys::ConfigDSL#desc} for a description
429
- # of the allowed formats. Defaults to the empty string.
430
- # @param [Array<String,Array<String>,Toys::Utils::WrappableString>] long_desc
431
- # Long description for the flag. See {Toys::ConfigDSL#long_desc} for a
432
- # description of the allowed formats. (But note that this param takes
433
- # an Array of description lines, rather than a series of arguments.)
434
- # Defaults to the empty array.
435
- # @yieldparam arg_dsl [Toys::ConfigDSL::ArgDSL] An object that lets you
436
- # configure this argument in a block.
437
- #
438
- def remaining_args(key, default: [], accept: nil, display_name: nil,
439
- desc: nil, long_desc: nil)
440
- return self if _cur_tool.nil?
441
- arg_dsl = ArgDSL.new(accept, default, display_name, desc, long_desc)
442
- yield arg_dsl if block_given?
443
- _cur_tool.lock_definition_path(@path)
444
- arg_dsl._set_remaining_on(_cur_tool, key)
445
- self
446
- end
447
- alias remaining remaining_args
448
-
449
- ##
450
- # Specify the script for this tool. This is a block that will be called,
451
- # with `self` set to a {Toys::Context}.
452
- #
453
- def script(&block)
454
- return self if _cur_tool.nil?
455
- _cur_tool.lock_definition_path(@path)
456
- _cur_tool.script = block
457
- self
458
- end
459
-
460
- ##
461
- # Define a helper method that may be called from this tool's script.
462
- # You must provide a name for the method, and a block for the method
463
- # definition.
464
- #
465
- # @param [String,Symbol] name Name of the method. May not begin with an
466
- # underscore.
467
- #
468
- def helper(name, &block)
469
- return self if _cur_tool.nil?
470
- _cur_tool.lock_definition_path(@path)
471
- _cur_tool.add_helper(name, &block)
472
- self
473
- end
474
-
475
- ##
476
- # Specify that the given module should be mixed in to this tool's script.
477
- # Effectively, the module is added to the {Toys::Context} object.
478
- # You may either provide a module directly, or specify the name of a
479
- # well-known module.
480
- #
481
- # @param [Module,Symbol] mod Module or name of well-known module.
482
- #
483
- def use(mod)
484
- return self if _cur_tool.nil?
485
- _cur_tool.lock_definition_path(@path)
486
- _cur_tool.use_module(mod)
487
- self
488
- end
489
-
490
- ##
491
- # DSL for a flag definition block. Lets you set flag attributes in a block
492
- # instead of a long series of keyword arguments.
493
- #
494
- class FlagDSL
495
- ## @private
496
- def initialize(flags, accept, default, handler, report_collisions, desc, long_desc)
497
- @flags = flags
498
- @accept = accept
499
- @default = default
500
- @handler = handler
501
- @report_collisions = report_collisions
502
- @desc = desc
503
- @long_desc = long_desc
504
- end
505
-
506
- ##
507
- # Add flags in OptionParser format. This may be called multiple times,
508
- # and the results are cumulative.
509
- # @param [String...] flags
510
- #
511
- def flags(*flags)
512
- @flags += flags
513
- self
514
- end
515
-
516
- ##
517
- # Set the OptionParser acceptor.
518
- # @param [Object] accept
519
- #
520
- def accept(accept)
521
- @accept = accept
522
- self
523
- end
524
-
525
- ##
526
- # Set the default value.
527
- # @param [Object] default
528
- #
529
- def default(default)
530
- @default = default
531
- self
532
- end
533
-
534
- ##
535
- # Set the optional handler for setting/updating the value when a flag is
536
- # parsed. It should be a Proc taking two arguments, the new given value
537
- # and the previous value, and it should return the new value that should
538
- # be set.
539
- # @param [Proc] handler
540
- #
541
- def handler(handler)
542
- @handler = handler
543
- self
544
- end
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
-
556
- ##
557
- # Set the short description. See {Toys::ConfigDSL#desc} for the allowed
558
- # formats.
559
- # @param [String,Array<String>,Toys::Utils::WrappableString] desc
560
- #
561
- def desc(desc)
562
- @desc = desc
563
- self
564
- end
565
-
566
- ##
567
- # Adds to the long description. This may be called multiple times, and
568
- # the results are cumulative. See {Toys::ConfigDSL#long_desc} for the
569
- # allowed formats.
570
- # @param [String,Array<String>,Toys::Utils::WrappableString...] long_desc
571
- #
572
- def long_desc(*long_desc)
573
- @long_desc += long_desc
574
- self
575
- end
576
-
577
- ## @private
578
- def _add_to(tool, key)
579
- tool.add_flag(key, @flags,
580
- accept: @accept, default: @default, handler: @handler,
581
- report_collisions: @report_collisions,
582
- desc: @desc, long_desc: @long_desc)
583
- end
584
- end
585
-
586
- ##
587
- # DSL for an arg definition block. Lets you set arg attributes in a block
588
- # instead of a long series of keyword arguments.
589
- #
590
- class ArgDSL
591
- ## @private
592
- def initialize(accept, default, display_name, desc, long_desc)
593
- @accept = accept
594
- @default = default
595
- @display_name = display_name
596
- @desc = desc
597
- @long_desc = long_desc
598
- end
599
-
600
- ##
601
- # Set the OptionParser acceptor.
602
- # @param [Object] accept
603
- #
604
- def accept(accept)
605
- @accept = accept
606
- self
607
- end
608
-
609
- ##
610
- # Set the default value.
611
- # @param [Object] default
612
- #
613
- def default(default)
614
- @default = default
615
- self
616
- end
617
-
618
- ##
619
- # Set the name of this arg as it appears in help screens.
620
- # @param [String] display_name
621
- #
622
- def display_name(display_name)
623
- @handler = display_name
624
- self
625
- end
626
-
627
- ##
628
- # Set the short description. See {Toys::ConfigDSL#desc} for the allowed
629
- # formats.
630
- # @param [String,Array<String>,Toys::Utils::WrappableString] desc
631
- #
632
- def desc(desc)
633
- @desc = desc
634
- self
635
- end
636
-
637
- ##
638
- # Adds to the long description. This may be called multiple times, and
639
- # the results are cumulative. See {Toys::ConfigDSL#long_desc} for the
640
- # allowed formats.
641
- # @param [String,Array<String>,Toys::Utils::WrappableString...] long_desc
642
- #
643
- def long_desc(*long_desc)
644
- @long_desc += long_desc
645
- self
646
- end
647
-
648
- ## @private
649
- def _add_required_to(tool, key)
650
- tool.add_required_arg(key,
651
- accept: @accept, display_name: @display_name,
652
- desc: @desc, long_desc: @long_desc)
653
- end
654
-
655
- ## @private
656
- def _add_optional_to(tool, key)
657
- tool.add_optional_arg(key,
658
- accept: @accept, default: @default, display_name: @display_name,
659
- desc: @desc, long_desc: @long_desc)
660
- end
661
-
662
- ## @private
663
- def _set_remaining_on(tool, key)
664
- tool.set_remaining_args(key,
665
- accept: @accept, default: @default, display_name: @display_name,
666
- desc: @desc, long_desc: @long_desc)
667
- end
668
- end
669
-
670
- ## @private
671
- def _binding
672
- binding
673
- end
674
-
675
- ## @private
676
- def _cur_tool
677
- unless defined? @_cur_tool
678
- @_cur_tool = @loader.get_or_create_tool(@words, priority: @priority)
679
- end
680
- @_cur_tool
681
- end
682
-
683
- ## @private
684
- def self.evaluate(words, remaining_words, priority, loader, path, source)
685
- dsl = new(words, remaining_words, priority, loader, path)
686
- case source
687
- when String
688
- ContextualError.capture_path("Error while loading Toys config!", path) do
689
- # rubocop:disable Security/Eval
690
- eval(source, dsl._binding, path, 1)
691
- # rubocop:enable Security/Eval
692
- end
693
- when ::Proc
694
- dsl.instance_eval(&source)
695
- end
696
- nil
697
- end
698
- end
699
- end