toys-core 0.3.2 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|