toys-core 0.3.2 → 0.3.3
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 +4 -4
- data/CHANGELOG.md +13 -0
- data/lib/toys/config_dsl.rb +26 -23
- data/lib/toys/core_version.rb +1 -1
- data/lib/toys/helpers.rb +3 -1
- data/lib/toys/helpers/{file_utils.rb → fileutils.rb} +7 -2
- data/lib/toys/helpers/highline.rb +127 -0
- data/lib/toys/helpers/spinner.rb +136 -0
- data/lib/toys/middleware/add_verbosity_switches.rb +2 -2
- data/lib/toys/middleware/handle_usage_errors.rb +5 -1
- data/lib/toys/middleware/show_usage.rb +11 -7
- data/lib/toys/middleware/show_version.rb +1 -1
- data/lib/toys/templates/clean.rb +1 -1
- data/lib/toys/templates/gem_build.rb +3 -1
- data/lib/toys/templates/minitest.rb +2 -2
- data/lib/toys/tool.rb +258 -99
- data/lib/toys/utils/module_lookup.rb +17 -5
- data/lib/toys/utils/usage.rb +101 -47
- data/lib/toys/utils/wrappable_string.rb +92 -0
- metadata +20 -3
@@ -80,7 +80,7 @@ module Toys
|
|
80
80
|
DEFAULT_VERBOSE_SWITCHES)
|
81
81
|
unless verbose_switches.empty?
|
82
82
|
tool.add_switch(Context::VERBOSITY, *verbose_switches,
|
83
|
-
|
83
|
+
docs: "Increase verbosity",
|
84
84
|
handler: ->(_val, cur) { cur + 1 },
|
85
85
|
only_unique: true)
|
86
86
|
end
|
@@ -88,7 +88,7 @@ module Toys
|
|
88
88
|
DEFAULT_QUIET_SWITCHES)
|
89
89
|
unless quiet_switches.empty?
|
90
90
|
tool.add_switch(Context::VERBOSITY, *quiet_switches,
|
91
|
-
|
91
|
+
docs: "Decrease verbosity",
|
92
92
|
handler: ->(_val, cur) { cur - 1 },
|
93
93
|
only_unique: true)
|
94
94
|
end
|
@@ -27,6 +27,8 @@
|
|
27
27
|
# POSSIBILITY OF SUCH DAMAGE.
|
28
28
|
;
|
29
29
|
|
30
|
+
require "highline"
|
31
|
+
|
30
32
|
require "toys/middleware/base"
|
31
33
|
require "toys/utils/usage"
|
32
34
|
|
@@ -54,9 +56,11 @@ module Toys
|
|
54
56
|
#
|
55
57
|
def execute(context)
|
56
58
|
if context[Context::USAGE_ERROR]
|
59
|
+
width = ::HighLine.new.output_cols
|
60
|
+
usage = Utils::Usage.from_context(context)
|
57
61
|
puts(context[Context::USAGE_ERROR])
|
58
62
|
puts("")
|
59
|
-
puts(
|
63
|
+
puts(usage.string(show_path: true, wrap_width: width))
|
60
64
|
context.exit(@exit_code)
|
61
65
|
else
|
62
66
|
yield
|
@@ -27,6 +27,8 @@
|
|
27
27
|
# POSSIBILITY OF SUCH DAMAGE.
|
28
28
|
;
|
29
29
|
|
30
|
+
require "highline"
|
31
|
+
|
30
32
|
require "toys/middleware/base"
|
31
33
|
require "toys/utils/usage"
|
32
34
|
|
@@ -112,10 +114,10 @@ module Toys
|
|
112
114
|
DEFAULT_HELP_SWITCHES)
|
113
115
|
is_default = !tool.includes_executor? && @fallback_execution
|
114
116
|
if !help_switches.empty?
|
115
|
-
|
116
|
-
|
117
|
+
docs = "Show help message"
|
118
|
+
docs << " (default for groups)" if is_default
|
117
119
|
tool.add_switch(:_help, *help_switches,
|
118
|
-
|
120
|
+
docs: docs,
|
119
121
|
default: is_default,
|
120
122
|
only_unique: true)
|
121
123
|
elsif is_default
|
@@ -134,9 +136,11 @@ module Toys
|
|
134
136
|
def execute(context)
|
135
137
|
if context[:_help]
|
136
138
|
usage = Utils::Usage.from_context(context)
|
139
|
+
width = ::HighLine.new.output_cols
|
137
140
|
puts(usage.string(recursive: context[:_recursive_subcommands],
|
138
141
|
search: context[:_search_subcommands],
|
139
|
-
show_path: context.verbosity > 0
|
142
|
+
show_path: context.verbosity > 0,
|
143
|
+
wrap_width: width))
|
140
144
|
else
|
141
145
|
yield
|
142
146
|
end
|
@@ -150,8 +154,8 @@ module Toys
|
|
150
154
|
unless recursive_switches.empty?
|
151
155
|
tool.add_switch(:_recursive_subcommands, *recursive_switches,
|
152
156
|
default: @default_recursive,
|
153
|
-
|
154
|
-
|
157
|
+
docs: "Show all subcommands recursively" \
|
158
|
+
" (default is #{@default_recursive})",
|
155
159
|
only_unique: true)
|
156
160
|
end
|
157
161
|
end
|
@@ -161,7 +165,7 @@ module Toys
|
|
161
165
|
DEFAULT_SEARCH_SWITCHES)
|
162
166
|
unless search_switches.empty?
|
163
167
|
tool.add_switch(:_search_subcommands, *search_switches,
|
164
|
-
|
168
|
+
docs: "Search subcommands for the given term",
|
165
169
|
only_unique: true)
|
166
170
|
end
|
167
171
|
end
|
data/lib/toys/templates/clean.rb
CHANGED
@@ -88,8 +88,9 @@ module Toys
|
|
88
88
|
tool(template.name) do
|
89
89
|
desc "#{task_type} the gem: #{template.gem_name}"
|
90
90
|
|
91
|
-
use :file_utils
|
92
91
|
use :exec
|
92
|
+
use :fileutils
|
93
|
+
use :highline
|
93
94
|
|
94
95
|
execute do
|
95
96
|
configure_exec(exit_on_nonzero_status: true)
|
@@ -104,6 +105,7 @@ module Toys
|
|
104
105
|
logger.error "Cannot push the gem when there are uncommited changes"
|
105
106
|
exit(1)
|
106
107
|
end
|
108
|
+
exit(1) unless agree("Release #{gemfile}? (y/n) ")
|
107
109
|
sh "gem push pkg/#{gemfile}"
|
108
110
|
if template.tag
|
109
111
|
sh "git tag v#{version}"
|
@@ -89,9 +89,9 @@ module Toys
|
|
89
89
|
switch(
|
90
90
|
:warnings, "-w", "--[no-]warnings",
|
91
91
|
default: template.warnings,
|
92
|
-
|
92
|
+
docs: "Turn on Ruby warnings (defaults to #{template.warnings})"
|
93
93
|
)
|
94
|
-
remaining_args(:tests,
|
94
|
+
remaining_args(:tests, docs: "Paths to the tests to run (defaults to all tests)")
|
95
95
|
|
96
96
|
execute do
|
97
97
|
ruby_args = []
|
data/lib/toys/tool.rb
CHANGED
@@ -29,6 +29,8 @@
|
|
29
29
|
|
30
30
|
require "optparse"
|
31
31
|
|
32
|
+
require "toys/utils/wrappable_string"
|
33
|
+
|
32
34
|
module Toys
|
33
35
|
##
|
34
36
|
# A Tool is a single command that can be invoked using Toys.
|
@@ -50,8 +52,8 @@ module Toys
|
|
50
52
|
@definition_path = nil
|
51
53
|
@definition_finished = false
|
52
54
|
|
53
|
-
@desc =
|
54
|
-
@long_desc =
|
55
|
+
@desc = []
|
56
|
+
@long_desc = []
|
55
57
|
|
56
58
|
@default_data = {}
|
57
59
|
@switch_definitions = []
|
@@ -168,19 +170,25 @@ module Toys
|
|
168
170
|
##
|
169
171
|
# Returns the effective short description for this tool. This will be
|
170
172
|
# displayed when this tool is listed in a command list.
|
171
|
-
# @return [String]
|
172
173
|
#
|
173
|
-
|
174
|
-
|
174
|
+
# @param [Integer,nil] wrap_width Wrap wrappable strings to the given
|
175
|
+
# width, or `nil` for no wrapping.
|
176
|
+
# @return [Array<String>]
|
177
|
+
#
|
178
|
+
def effective_desc(wrap_width: nil)
|
179
|
+
Tool.resolve_wrapping(@desc, wrap_width)
|
175
180
|
end
|
176
181
|
|
177
182
|
##
|
178
183
|
# Returns the effective long description for this tool. This will be
|
179
184
|
# displayed as part of the usage for this particular tool.
|
180
|
-
# @return [String]
|
181
185
|
#
|
182
|
-
|
183
|
-
|
186
|
+
# @param [Integer,nil] wrap_width Wrap wrappable strings to the given
|
187
|
+
# width, or `nil` for no wrapping.
|
188
|
+
# @return [Array<String>]
|
189
|
+
#
|
190
|
+
def effective_long_desc(wrap_width: nil)
|
191
|
+
Tool.resolve_wrapping(@long_desc.empty? ? @desc : @long_desc, wrap_width)
|
184
192
|
end
|
185
193
|
|
186
194
|
##
|
@@ -188,7 +196,7 @@ module Toys
|
|
188
196
|
# @return [Boolean]
|
189
197
|
#
|
190
198
|
def includes_description?
|
191
|
-
!@long_desc.
|
199
|
+
!@long_desc.empty? || !@desc.empty?
|
192
200
|
end
|
193
201
|
|
194
202
|
##
|
@@ -224,7 +232,7 @@ module Toys
|
|
224
232
|
# @return [Array<String>]
|
225
233
|
#
|
226
234
|
def used_switches
|
227
|
-
@switch_definitions.reduce([]) { |used, sdef| used + sdef.
|
235
|
+
@switch_definitions.reduce([]) { |used, sdef| used + sdef.effective_switches }.uniq
|
228
236
|
end
|
229
237
|
|
230
238
|
##
|
@@ -246,21 +254,21 @@ module Toys
|
|
246
254
|
##
|
247
255
|
# Set the short description.
|
248
256
|
#
|
249
|
-
# @param [String]
|
257
|
+
# @param [String,Array<String>] strs The short description
|
250
258
|
#
|
251
|
-
def desc=(
|
259
|
+
def desc=(strs)
|
252
260
|
check_definition_state
|
253
|
-
@desc =
|
261
|
+
@desc = Tool.canonicalize_desc(strs)
|
254
262
|
end
|
255
263
|
|
256
264
|
##
|
257
265
|
# Set the long description.
|
258
266
|
#
|
259
|
-
# @param [String]
|
267
|
+
# @param [String,Array<String>] strs The long description
|
260
268
|
#
|
261
|
-
def long_desc=(
|
269
|
+
def long_desc=(strs)
|
262
270
|
check_definition_state
|
263
|
-
@long_desc =
|
271
|
+
@long_desc = Tool.canonicalize_desc(strs)
|
264
272
|
end
|
265
273
|
|
266
274
|
##
|
@@ -315,8 +323,9 @@ module Toys
|
|
315
323
|
# @param [Object] default The default value. This is the value that will
|
316
324
|
# be set in the context if this switch is not provided on the command
|
317
325
|
# line. Defaults to `nil`.
|
318
|
-
# @param [String,
|
319
|
-
#
|
326
|
+
# @param [String,Toys::Utils::WrappableString,
|
327
|
+
# Array<String,Toys::Utils::WrappableString>] docs Documentation for
|
328
|
+
# the switch. Defaults to empty array.
|
320
329
|
# @param [Boolean] only_unique If true, any switches that are already
|
321
330
|
# defined in this tool are removed from this switch. For example, if
|
322
331
|
# an earlier switch uses `-a`, and this switch wants to use both
|
@@ -329,14 +338,9 @@ module Toys
|
|
329
338
|
# value. i.e. the default is effectively `-> (val, _prev) { val }`.
|
330
339
|
#
|
331
340
|
def add_switch(key, *switches,
|
332
|
-
accept: nil, default: nil,
|
341
|
+
accept: nil, default: nil, docs: nil, only_unique: false, handler: nil)
|
333
342
|
check_definition_state
|
334
|
-
|
335
|
-
bad_switch = switches.find { |s| Tool.extract_switch(s).empty? }
|
336
|
-
if bad_switch
|
337
|
-
raise ToolDefinitionError, "Illegal switch: #{bad_switch.inspect}"
|
338
|
-
end
|
339
|
-
switch_info = SwitchDefinition.new(key, switches + Array(accept) + Array(doc), handler)
|
343
|
+
switch_info = SwitchDefinition.new(key, switches, accept, docs, handler)
|
340
344
|
if only_unique
|
341
345
|
switch_info.remove_switches(used_switches)
|
342
346
|
end
|
@@ -355,13 +359,14 @@ module Toys
|
|
355
359
|
# @param [Symbol] key The key to use to retrieve the value from the
|
356
360
|
# execution context.
|
357
361
|
# @param [Object,nil] accept An OptionParser acceptor. Optional.
|
358
|
-
# @param [String,
|
359
|
-
#
|
362
|
+
# @param [String,Toys::Utils::WrappableString,
|
363
|
+
# Array<String,Toys::Utils::WrappableString>] docs Documentation for
|
364
|
+
# the arg. Defaults to empty array.
|
360
365
|
#
|
361
|
-
def add_required_arg(key, accept: nil,
|
366
|
+
def add_required_arg(key, accept: nil, docs: nil)
|
362
367
|
check_definition_state
|
363
368
|
@default_data[key] = nil
|
364
|
-
@required_arg_definitions << ArgDefinition.new(key, accept,
|
369
|
+
@required_arg_definitions << ArgDefinition.new(key, accept, docs)
|
365
370
|
self
|
366
371
|
end
|
367
372
|
|
@@ -377,13 +382,14 @@ module Toys
|
|
377
382
|
# @param [Object] default The default value. This is the value that will
|
378
383
|
# be set in the context if this argument is not provided on the command
|
379
384
|
# line. Defaults to `nil`.
|
380
|
-
# @param [String,
|
381
|
-
#
|
385
|
+
# @param [String,Toys::Utils::WrappableString,
|
386
|
+
# Array<String,Toys::Utils::WrappableString>] docs Documentation for
|
387
|
+
# the arg. Defaults to empty array.
|
382
388
|
#
|
383
|
-
def add_optional_arg(key, accept: nil, default: nil,
|
389
|
+
def add_optional_arg(key, accept: nil, default: nil, docs: nil)
|
384
390
|
check_definition_state
|
385
391
|
@default_data[key] = default
|
386
|
-
@optional_arg_definitions << ArgDefinition.new(key, accept,
|
392
|
+
@optional_arg_definitions << ArgDefinition.new(key, accept, docs)
|
387
393
|
self
|
388
394
|
end
|
389
395
|
|
@@ -398,14 +404,14 @@ module Toys
|
|
398
404
|
# @param [Object] default The default value. This is the value that will
|
399
405
|
# be set in the context if no unmatched arguments are provided on the
|
400
406
|
# command line. Defaults to the empty array `[]`.
|
401
|
-
# @param [String,
|
402
|
-
#
|
403
|
-
#
|
407
|
+
# @param [String,Toys::Utils::WrappableString,
|
408
|
+
# Array<String,Toys::Utils::WrappableString>] docs Documentation for
|
409
|
+
# the args. Defaults to empty array.
|
404
410
|
#
|
405
|
-
def set_remaining_args(key, accept: nil, default: [],
|
411
|
+
def set_remaining_args(key, accept: nil, default: [], docs: nil)
|
406
412
|
check_definition_state
|
407
413
|
@default_data[key] = default
|
408
|
-
@remaining_args_definition = ArgDefinition.new(key, accept,
|
414
|
+
@remaining_args_definition = ArgDefinition.new(key, accept, docs)
|
409
415
|
self
|
410
416
|
end
|
411
417
|
|
@@ -452,51 +458,58 @@ module Toys
|
|
452
458
|
self
|
453
459
|
end
|
454
460
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
end
|
467
|
-
|
468
|
-
class << self
|
469
|
-
## @private
|
470
|
-
def canonical_switch(name)
|
471
|
-
name.to_s.downcase.tr("_", "-").gsub(/[^a-z0-9-]/, "")
|
472
|
-
end
|
473
|
-
|
474
|
-
## @private
|
475
|
-
def extract_switch(str)
|
476
|
-
if !str.is_a?(String)
|
477
|
-
[]
|
478
|
-
elsif str =~ /^(-[\?\w])(\s?\w+)?$/
|
479
|
-
[$1]
|
461
|
+
##
|
462
|
+
# Representation of a single switch
|
463
|
+
#
|
464
|
+
class SwitchSyntax
|
465
|
+
##
|
466
|
+
# Parse switch syntax
|
467
|
+
# @param [String] str syntax.
|
468
|
+
#
|
469
|
+
def initialize(str)
|
470
|
+
if str =~ /^(-[\?\w])(\s?(\w+))?$/
|
471
|
+
setup(str, [$1], $1, "-", " ", $3)
|
480
472
|
elsif str =~ /^--\[no-\](\w[\?\w-]*)$/
|
481
|
-
["--#{$1}", "--no-#{$1}"]
|
482
|
-
elsif str =~ /^(--\w[\?\w-]*)([=\s]\w+)?$/
|
483
|
-
[$1]
|
473
|
+
setup(str, ["--#{$1}", "--no-#{$1}"], "--[no-]#{$1}", "--", nil, nil)
|
474
|
+
elsif str =~ /^(--\w[\?\w-]*)(([=\s])(\w+))?$/
|
475
|
+
setup(str, [$1], $1, "--", $3, $4)
|
484
476
|
else
|
485
|
-
|
477
|
+
raise ToolDefinitionError, "Illegal switch: #{str.inspect}"
|
486
478
|
end
|
487
479
|
end
|
480
|
+
|
481
|
+
attr_reader :str
|
482
|
+
attr_reader :str_without_value
|
483
|
+
attr_reader :switches
|
484
|
+
attr_reader :switch_style
|
485
|
+
attr_reader :value_delim
|
486
|
+
attr_reader :value_label
|
487
|
+
|
488
|
+
private
|
489
|
+
|
490
|
+
def setup(str, switches, str_without_value, switch_style, value_delim, value_label)
|
491
|
+
@str = str
|
492
|
+
@switches = switches
|
493
|
+
@str_without_value = str_without_value
|
494
|
+
@switch_style = switch_style
|
495
|
+
@value_delim = value_delim
|
496
|
+
@value_label = value_label
|
497
|
+
end
|
488
498
|
end
|
489
499
|
|
490
500
|
##
|
491
|
-
# Representation of a formal
|
501
|
+
# Representation of a formal set of switches.
|
492
502
|
#
|
493
503
|
class SwitchDefinition
|
494
504
|
##
|
495
505
|
# Create a SwitchDefinition
|
506
|
+
# @private
|
496
507
|
#
|
497
508
|
# @param [Symbol] key This switch will set the given context key.
|
498
|
-
# @param [Array<String>]
|
499
|
-
#
|
509
|
+
# @param [Array<String>] switches Switches in OptionParser format
|
510
|
+
# @param [Object] accept An OptionParser acceptor, or `nil` for none.
|
511
|
+
# @param [String,Toys::Utils::WrappableString,
|
512
|
+
# Array<String,Toys::Utils::WrappableString>] docs Documentation
|
500
513
|
# @param [Proc,nil] handler An optional handler for setting/updating the
|
501
514
|
# value. If given, it should take two arguments, the new given value
|
502
515
|
# and the previous value, and it should return the new value that
|
@@ -504,11 +517,15 @@ module Toys
|
|
504
517
|
# the previous value. i.e. the default is effectively
|
505
518
|
# `-> (val, _prev) { val }`.
|
506
519
|
#
|
507
|
-
def initialize(key,
|
520
|
+
def initialize(key, switches, accept, docs, handler = nil)
|
508
521
|
@key = key
|
509
|
-
|
522
|
+
switches = ["--#{Tool.canonical_switch(key)}=VALUE"] if switches.empty?
|
523
|
+
@switch_syntax = switches.map { |s| SwitchSyntax.new(s) }
|
524
|
+
@accept = accept
|
525
|
+
@docs = Tool.canonicalize_desc(docs)
|
510
526
|
@handler = handler || ->(val, _prev) { val }
|
511
|
-
|
527
|
+
reset_data
|
528
|
+
@effective_switches = nil
|
512
529
|
end
|
513
530
|
|
514
531
|
##
|
@@ -518,10 +535,22 @@ module Toys
|
|
518
535
|
attr_reader :key
|
519
536
|
|
520
537
|
##
|
521
|
-
# Returns the
|
538
|
+
# Returns an array of SwitchSyntax for the switches.
|
539
|
+
# @return [Array<SwitchSyntax>]
|
540
|
+
#
|
541
|
+
attr_reader :switch_syntax
|
542
|
+
|
543
|
+
##
|
544
|
+
# Returns the acceptor, which may be `nil`.
|
545
|
+
# @return [Object]
|
546
|
+
#
|
547
|
+
attr_reader :accept
|
548
|
+
|
549
|
+
##
|
550
|
+
# Returns the documentation strings, which may be the empty array.
|
522
551
|
# @return [Array<String>]
|
523
552
|
#
|
524
|
-
attr_reader :
|
553
|
+
attr_reader :docs
|
525
554
|
|
526
555
|
##
|
527
556
|
# Returns the handler.
|
@@ -530,11 +559,45 @@ module Toys
|
|
530
559
|
attr_reader :handler
|
531
560
|
|
532
561
|
##
|
533
|
-
# Returns
|
562
|
+
# Returns an array of SwitchSyntax including only single-dash switches
|
563
|
+
# @return [Array<SwitchSyntax>]
|
564
|
+
#
|
565
|
+
def single_switch_syntax
|
566
|
+
@single_switch_syntax ||= switch_syntax.find_all { |ss| ss.switch_style == "-" }
|
567
|
+
end
|
568
|
+
|
569
|
+
##
|
570
|
+
# Returns an array of SwitchSyntax including only double-dash switches
|
571
|
+
# @return [Array<SwitchSyntax>]
|
572
|
+
#
|
573
|
+
def double_switch_syntax
|
574
|
+
@double_switch_syntax ||= switch_syntax.find_all { |ss| ss.switch_style == "--" }
|
575
|
+
end
|
576
|
+
|
577
|
+
##
|
578
|
+
# Returns the list of effective switches used.
|
534
579
|
# @return [Array<String>]
|
535
580
|
#
|
536
|
-
def
|
537
|
-
@
|
581
|
+
def effective_switches
|
582
|
+
@effective_switches ||= switch_syntax.map(&:switches).flatten
|
583
|
+
end
|
584
|
+
|
585
|
+
##
|
586
|
+
# Returns the documentation strings with wrapping resolved.
|
587
|
+
#
|
588
|
+
# @param [Integer,nil] width Wrapping width, or `nil` to use default.
|
589
|
+
# @return [Array<String>]
|
590
|
+
#
|
591
|
+
def wrapped_docs(width)
|
592
|
+
Tool.resolve_wrapping(docs, width)
|
593
|
+
end
|
594
|
+
|
595
|
+
##
|
596
|
+
# All optparser switches and acceptor if present
|
597
|
+
# @return [Array]
|
598
|
+
#
|
599
|
+
def optparser_info
|
600
|
+
@optparser_info ||= switch_syntax.map(&:str) + Array(accept)
|
538
601
|
end
|
539
602
|
|
540
603
|
##
|
@@ -543,7 +606,25 @@ module Toys
|
|
543
606
|
# @return [Boolean]
|
544
607
|
#
|
545
608
|
def active?
|
546
|
-
!
|
609
|
+
!effective_switches.empty?
|
610
|
+
end
|
611
|
+
|
612
|
+
##
|
613
|
+
# Return the value label if one exists
|
614
|
+
# @return [String,nil]
|
615
|
+
#
|
616
|
+
def value_label
|
617
|
+
find_canonical_value_label
|
618
|
+
@value_label
|
619
|
+
end
|
620
|
+
|
621
|
+
##
|
622
|
+
# Return the value delimiter if one exists
|
623
|
+
# @return [String,nil]
|
624
|
+
#
|
625
|
+
def value_delim
|
626
|
+
find_canonical_value_label
|
627
|
+
@value_delim
|
547
628
|
end
|
548
629
|
|
549
630
|
##
|
@@ -551,12 +632,43 @@ module Toys
|
|
551
632
|
# @param [Array<String>] switches
|
552
633
|
#
|
553
634
|
def remove_switches(switches)
|
554
|
-
@
|
555
|
-
|
635
|
+
@switch_syntax.select! do |ss|
|
636
|
+
ss.switches.all? { |s| !switches.include?(s) }
|
556
637
|
end
|
557
|
-
|
638
|
+
reset_data
|
558
639
|
self
|
559
640
|
end
|
641
|
+
|
642
|
+
private
|
643
|
+
|
644
|
+
def reset_data
|
645
|
+
@effective_switches = nil
|
646
|
+
@optparser_info = nil
|
647
|
+
@single_switch_syntax = nil
|
648
|
+
@double_switch_syntax = nil
|
649
|
+
@value_label = nil
|
650
|
+
@value_delim = nil
|
651
|
+
end
|
652
|
+
|
653
|
+
def find_canonical_value_label
|
654
|
+
return if @value_delim
|
655
|
+
double_switch_syntax.reverse_each do |ss|
|
656
|
+
next unless ss.value_label
|
657
|
+
@value_label = ss.value_label
|
658
|
+
@value_delim = ss.value_delim
|
659
|
+
break
|
660
|
+
end
|
661
|
+
return if @value_delim
|
662
|
+
single_switch_syntax.reverse_each do |ss|
|
663
|
+
next unless ss.value_label
|
664
|
+
@value_label = ss.value_label
|
665
|
+
@value_delim = ss.value_delim
|
666
|
+
break
|
667
|
+
end
|
668
|
+
return if @value_delim
|
669
|
+
@value_label = nil
|
670
|
+
@value_delim = ""
|
671
|
+
end
|
560
672
|
end
|
561
673
|
|
562
674
|
##
|
@@ -565,15 +677,17 @@ module Toys
|
|
565
677
|
class ArgDefinition
|
566
678
|
##
|
567
679
|
# Create an ArgDefinition
|
680
|
+
# @private
|
568
681
|
#
|
569
682
|
# @param [Symbol] key This argument will set the given context key.
|
570
|
-
# @param [Object] accept An OptionParser acceptor
|
571
|
-
# @param [
|
683
|
+
# @param [Object] accept An OptionParser acceptor, or `nil` for none.
|
684
|
+
# @param [String,Toys::Utils::WrappableString,
|
685
|
+
# Array<String,Toys::Utils::WrappableString>] docs Documentation
|
572
686
|
#
|
573
|
-
def initialize(key, accept,
|
687
|
+
def initialize(key, accept, docs)
|
574
688
|
@key = key
|
575
689
|
@accept = accept
|
576
|
-
@
|
690
|
+
@docs = Tool.canonicalize_desc(docs)
|
577
691
|
end
|
578
692
|
|
579
693
|
##
|
@@ -583,16 +697,16 @@ module Toys
|
|
583
697
|
attr_reader :key
|
584
698
|
|
585
699
|
##
|
586
|
-
# Returns the acceptor
|
700
|
+
# Returns the acceptor, which may be `nil`.
|
587
701
|
# @return [Object]
|
588
702
|
#
|
589
703
|
attr_reader :accept
|
590
704
|
|
591
705
|
##
|
592
|
-
# Returns the documentation strings.
|
593
|
-
# @return [Array<String>]
|
706
|
+
# Returns the documentation strings, which may be the empty array.
|
707
|
+
# @return [Array<String,Toys::Utils::WrappableString>]
|
594
708
|
#
|
595
|
-
attr_reader :
|
709
|
+
attr_reader :docs
|
596
710
|
|
597
711
|
##
|
598
712
|
# Return a canonical name for this arg. Used in usage documentation.
|
@@ -603,22 +717,68 @@ module Toys
|
|
603
717
|
Tool.canonical_switch(key)
|
604
718
|
end
|
605
719
|
|
720
|
+
##
|
721
|
+
# Returns the documentation strings with wrapping resolved.
|
722
|
+
#
|
723
|
+
# @param [Integer,nil] width Wrapping width, or `nil` to use default.
|
724
|
+
# @return [Array<String>]
|
725
|
+
#
|
726
|
+
def wrapped_docs(width)
|
727
|
+
Tool.resolve_wrapping(docs, width)
|
728
|
+
end
|
729
|
+
|
606
730
|
##
|
607
731
|
# Process the given value through the acceptor.
|
732
|
+
# May raise an exception if the acceptor rejected the input.
|
608
733
|
#
|
609
|
-
# @
|
734
|
+
# @param [String] input Input value
|
735
|
+
# @return [Object] Accepted value
|
610
736
|
#
|
611
|
-
def process_value(
|
612
|
-
return
|
737
|
+
def process_value(input)
|
738
|
+
return input unless accept
|
613
739
|
n = canonical_name
|
614
|
-
result =
|
740
|
+
result = input
|
615
741
|
optparse = ::OptionParser.new
|
616
742
|
optparse.on("--#{n}=VALUE", accept) { |v| result = v }
|
617
|
-
optparse.parse(["--#{n}",
|
743
|
+
optparse.parse(["--#{n}", input])
|
618
744
|
result
|
619
745
|
end
|
620
746
|
end
|
621
747
|
|
748
|
+
private
|
749
|
+
|
750
|
+
def make_config_proc(middleware, next_config)
|
751
|
+
proc { middleware.config(self, &next_config) }
|
752
|
+
end
|
753
|
+
|
754
|
+
def check_definition_state
|
755
|
+
if @definition_finished
|
756
|
+
raise ToolDefinitionError,
|
757
|
+
"Defintion of tool #{display_name.inspect} is already finished"
|
758
|
+
end
|
759
|
+
end
|
760
|
+
|
761
|
+
class << self
|
762
|
+
## @private
|
763
|
+
def canonical_switch(name)
|
764
|
+
name.to_s.downcase.tr("_", "-").gsub(/[^a-z0-9-]/, "")
|
765
|
+
end
|
766
|
+
|
767
|
+
## @private
|
768
|
+
def canonicalize_desc(desc)
|
769
|
+
Array(desc).map do |d|
|
770
|
+
d.is_a?(Utils::WrappableString) ? d : d.split("\n")
|
771
|
+
end.flatten.freeze
|
772
|
+
end
|
773
|
+
|
774
|
+
## @private
|
775
|
+
def resolve_wrapping(strs, wrap_width)
|
776
|
+
strs.map do |s|
|
777
|
+
s.is_a?(Utils::WrappableString) && !wrap_width.nil? ? s.wrap(wrap_width) : s.to_s
|
778
|
+
end.flatten
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
622
782
|
##
|
623
783
|
# An internal class that manages execution of a tool
|
624
784
|
# @private
|
@@ -667,7 +827,7 @@ module Toys
|
|
667
827
|
optparse.new
|
668
828
|
optparse.new
|
669
829
|
@tool.switch_definitions.each do |switch|
|
670
|
-
optparse.on(*switch.
|
830
|
+
optparse.on(*switch.optparser_info) do |val|
|
671
831
|
@data[switch.key] = switch.handler.call(val, @data[switch.key])
|
672
832
|
end
|
673
833
|
end
|
@@ -714,9 +874,8 @@ module Toys
|
|
714
874
|
|
715
875
|
def create_child_context(cli)
|
716
876
|
context = Context.new(cli, @data)
|
717
|
-
@tool.modules
|
718
|
-
|
719
|
-
end
|
877
|
+
modules = @tool.modules
|
878
|
+
context.extend(*modules) unless modules.empty?
|
720
879
|
@tool.helpers.each do |name, block|
|
721
880
|
context.define_singleton_method(name, &block)
|
722
881
|
end
|