toys-core 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +98 -0
- data/LICENSE.md +16 -24
- data/README.md +307 -59
- data/docs/guide.md +44 -4
- data/lib/toys-core.rb +58 -49
- data/lib/toys/acceptor.rb +672 -0
- data/lib/toys/alias.rb +106 -0
- data/lib/toys/arg_parser.rb +624 -0
- data/lib/toys/cli.rb +422 -181
- data/lib/toys/compat.rb +83 -0
- data/lib/toys/completion.rb +442 -0
- data/lib/toys/context.rb +354 -0
- data/lib/toys/core_version.rb +18 -26
- data/lib/toys/dsl/flag.rb +213 -56
- data/lib/toys/dsl/flag_group.rb +237 -51
- data/lib/toys/dsl/positional_arg.rb +210 -0
- data/lib/toys/dsl/tool.rb +968 -317
- data/lib/toys/errors.rb +46 -28
- data/lib/toys/flag.rb +821 -0
- data/lib/toys/flag_group.rb +282 -0
- data/lib/toys/input_file.rb +18 -26
- data/lib/toys/loader.rb +110 -100
- data/lib/toys/middleware.rb +24 -31
- data/lib/toys/mixin.rb +90 -59
- data/lib/toys/module_lookup.rb +125 -0
- data/lib/toys/positional_arg.rb +184 -0
- data/lib/toys/source_info.rb +192 -0
- data/lib/toys/standard_middleware/add_verbosity_flags.rb +38 -43
- data/lib/toys/standard_middleware/handle_usage_errors.rb +39 -40
- data/lib/toys/standard_middleware/set_default_descriptions.rb +111 -89
- data/lib/toys/standard_middleware/show_help.rb +130 -113
- data/lib/toys/standard_middleware/show_root_version.rb +29 -35
- data/lib/toys/standard_mixins/exec.rb +116 -78
- data/lib/toys/standard_mixins/fileutils.rb +16 -24
- data/lib/toys/standard_mixins/gems.rb +29 -30
- data/lib/toys/standard_mixins/highline.rb +34 -41
- data/lib/toys/standard_mixins/terminal.rb +72 -26
- data/lib/toys/template.rb +51 -35
- data/lib/toys/tool.rb +1161 -206
- data/lib/toys/utils/completion_engine.rb +171 -0
- data/lib/toys/utils/exec.rb +279 -182
- data/lib/toys/utils/gems.rb +58 -49
- data/lib/toys/utils/help_text.rb +117 -111
- data/lib/toys/utils/terminal.rb +69 -62
- data/lib/toys/wrappable_string.rb +162 -0
- metadata +24 -22
- data/lib/toys/definition/acceptor.rb +0 -191
- data/lib/toys/definition/alias.rb +0 -112
- data/lib/toys/definition/arg.rb +0 -140
- data/lib/toys/definition/flag.rb +0 -370
- data/lib/toys/definition/flag_group.rb +0 -205
- data/lib/toys/definition/source_info.rb +0 -190
- data/lib/toys/definition/tool.rb +0 -842
- data/lib/toys/dsl/arg.rb +0 -132
- data/lib/toys/runner.rb +0 -188
- data/lib/toys/standard_middleware.rb +0 -47
- data/lib/toys/utils/module_lookup.rb +0 -135
- data/lib/toys/utils/wrappable_string.rb +0 -165
@@ -1,191 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2018 Daniel Azuma
|
4
|
-
#
|
5
|
-
# All rights reserved.
|
6
|
-
#
|
7
|
-
# Redistribution and use in source and binary forms, with or without
|
8
|
-
# modification, are permitted provided that the following conditions are met:
|
9
|
-
#
|
10
|
-
# * Redistributions of source code must retain the above copyright notice,
|
11
|
-
# this list of conditions and the following disclaimer.
|
12
|
-
# * Redistributions in binary form must reproduce the above copyright notice,
|
13
|
-
# this list of conditions and the following disclaimer in the documentation
|
14
|
-
# and/or other materials provided with the distribution.
|
15
|
-
# * Neither the name of the copyright holder, nor the names of any other
|
16
|
-
# contributors to this software, may be used to endorse or promote products
|
17
|
-
# derived from this software without specific prior written permission.
|
18
|
-
#
|
19
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
23
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
29
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
30
|
-
;
|
31
|
-
|
32
|
-
module Toys
|
33
|
-
module Definition
|
34
|
-
##
|
35
|
-
# An Acceptor validates and converts arguments. It is designed to be
|
36
|
-
# compatible with the OptionParser accept mechanism.
|
37
|
-
#
|
38
|
-
# First, an acceptor validates an argument via the {#match} method. This
|
39
|
-
# method should determine whether the argument is valid, and return
|
40
|
-
# information that will help with conversion of the argument.
|
41
|
-
#
|
42
|
-
# Second, an acceptor converts the argument from the input string to its
|
43
|
-
# final form via the {#convert} method.
|
44
|
-
#
|
45
|
-
# Finally, an acceptor has a name that may appear in help text for flags
|
46
|
-
# and arguments that use it.
|
47
|
-
#
|
48
|
-
class Acceptor
|
49
|
-
##
|
50
|
-
# Create a base acceptor.
|
51
|
-
#
|
52
|
-
# The base acceptor does not do any validation (i.e. it accepts all
|
53
|
-
# arguments). You may subclass this object and override the {#match}
|
54
|
-
# method to change this behavior.
|
55
|
-
#
|
56
|
-
# The base acceptor lets you provide a converter as a proc. The proc
|
57
|
-
# should take one or more arguments, the first of which is the entire
|
58
|
-
# argument string, and the others of which are any additional values
|
59
|
-
# returned from validation. The converter should return the final
|
60
|
-
# converted value of the argument.
|
61
|
-
#
|
62
|
-
# The converter may be provided either as a proc in the `converter`
|
63
|
-
# parameter, or as a block. If neither is provided, the base acceptor
|
64
|
-
# performs no conversion and uses the argument string.
|
65
|
-
#
|
66
|
-
# @param [String] name A visible name for the acceptor, shown in help.
|
67
|
-
# @param [Proc] converter A converter function. May also be given as a
|
68
|
-
# block.
|
69
|
-
#
|
70
|
-
def initialize(name, converter = nil, &block)
|
71
|
-
@name = name.to_s
|
72
|
-
@converter = converter || block
|
73
|
-
end
|
74
|
-
|
75
|
-
##
|
76
|
-
# Name of the acceptor
|
77
|
-
# @return [String]
|
78
|
-
#
|
79
|
-
attr_reader :name
|
80
|
-
alias to_s name
|
81
|
-
|
82
|
-
##
|
83
|
-
# Validate the given input.
|
84
|
-
#
|
85
|
-
# You may override this method to specify a validation function. For a
|
86
|
-
# valid input, the function must return either the original argument
|
87
|
-
# string, or an array of which the first element is the original argument
|
88
|
-
# string, and the remaining elements may comprise additional information.
|
89
|
-
# All returned information is then passed to the conversion function.
|
90
|
-
# Note that a MatchInfo object is a legitimate return value since it
|
91
|
-
# duck-types the appropriate array.
|
92
|
-
#
|
93
|
-
# For an invalid input, you should return a falsy value.
|
94
|
-
#
|
95
|
-
# The default implementation simply returns the original argument string,
|
96
|
-
# indicating all inputs are valid.
|
97
|
-
#
|
98
|
-
# @param [String] str Input argument string
|
99
|
-
# @return [String,Array]
|
100
|
-
#
|
101
|
-
def match(str)
|
102
|
-
str
|
103
|
-
end
|
104
|
-
|
105
|
-
##
|
106
|
-
# Convert the given input. Uses the converter provided to this object's
|
107
|
-
# constructor. Subclasses may also override this method.
|
108
|
-
#
|
109
|
-
# @param [String] str Original argument string
|
110
|
-
# @param [Object...] extra Zero or more additional arguments comprising
|
111
|
-
# additional elements returned from the match function.
|
112
|
-
# @return [Object] The converted argument as it should be stored in the
|
113
|
-
# context data.
|
114
|
-
#
|
115
|
-
def convert(str, *extra)
|
116
|
-
@converter ? @converter.call(str, *extra) : str
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
##
|
121
|
-
# An acceptor that uses a regex to validate input.
|
122
|
-
#
|
123
|
-
class PatternAcceptor < Acceptor
|
124
|
-
##
|
125
|
-
# Create a pattern acceptor.
|
126
|
-
#
|
127
|
-
# You must provide a regular expression as a validator. You may also
|
128
|
-
# provide a converter proc. See {Toys::Definition::Acceptor} for details
|
129
|
-
# on the converter.
|
130
|
-
#
|
131
|
-
# @param [String] name A visible name for the acceptor, shown in help.
|
132
|
-
# @param [Regexp] regex Regular expression defining value values.
|
133
|
-
# @param [Proc] converter A converter function. May also be given as a
|
134
|
-
# block. Note that the converter will be passed all elements of
|
135
|
-
# the MatchInfo.
|
136
|
-
#
|
137
|
-
def initialize(name, regex, converter = nil, &block)
|
138
|
-
super(name, converter, &block)
|
139
|
-
@regex = regex
|
140
|
-
end
|
141
|
-
|
142
|
-
##
|
143
|
-
# Overrides {Toys::Definition::Acceptor#match} to use the given regex.
|
144
|
-
#
|
145
|
-
def match(str)
|
146
|
-
@regex.match(str)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
##
|
151
|
-
# An acceptor that recognizes a fixed set of values.
|
152
|
-
#
|
153
|
-
# You provide a list of valid values. The input argument string will be
|
154
|
-
# matched against the string forms of these valid values. If it matches,
|
155
|
-
# the converter will return the actual value.
|
156
|
-
#
|
157
|
-
# For example, you could pass `[:one, :two, 3]` as the set of values. If
|
158
|
-
# an argument of `"two"` is passed in, the converter will yield a final
|
159
|
-
# value of the symbol `:two`. If an argument of "3" is passed in, the
|
160
|
-
# converter will yield the integer `3`. If an argument of "three" is
|
161
|
-
# passed in, the match will fail.
|
162
|
-
#
|
163
|
-
class EnumAcceptor < Acceptor
|
164
|
-
##
|
165
|
-
# Create an acceptor.
|
166
|
-
#
|
167
|
-
# @param [String] name A visible name for the acceptor, shown in help.
|
168
|
-
# @param [Array] values Valid values.
|
169
|
-
#
|
170
|
-
def initialize(name, values)
|
171
|
-
super(name)
|
172
|
-
@values = Array(values).map { |v| [v.to_s, v] }
|
173
|
-
end
|
174
|
-
|
175
|
-
##
|
176
|
-
# Overrides {Toys::Definition::Acceptor#match} to find the value.
|
177
|
-
#
|
178
|
-
def match(str)
|
179
|
-
@values.find { |s, _e| s == str }
|
180
|
-
end
|
181
|
-
|
182
|
-
##
|
183
|
-
# Overrides {Toys::Definition::Acceptor#convert} to return the original
|
184
|
-
# element.
|
185
|
-
#
|
186
|
-
def convert(_str, elem)
|
187
|
-
elem
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
end
|
@@ -1,112 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2018 Daniel Azuma
|
4
|
-
#
|
5
|
-
# All rights reserved.
|
6
|
-
#
|
7
|
-
# Redistribution and use in source and binary forms, with or without
|
8
|
-
# modification, are permitted provided that the following conditions are met:
|
9
|
-
#
|
10
|
-
# * Redistributions of source code must retain the above copyright notice,
|
11
|
-
# this list of conditions and the following disclaimer.
|
12
|
-
# * Redistributions in binary form must reproduce the above copyright notice,
|
13
|
-
# this list of conditions and the following disclaimer in the documentation
|
14
|
-
# and/or other materials provided with the distribution.
|
15
|
-
# * Neither the name of the copyright holder, nor the names of any other
|
16
|
-
# contributors to this software, may be used to endorse or promote products
|
17
|
-
# derived from this software without specific prior written permission.
|
18
|
-
#
|
19
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
23
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
29
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
30
|
-
;
|
31
|
-
|
32
|
-
module Toys
|
33
|
-
module Definition
|
34
|
-
##
|
35
|
-
# An alias is a name that refers to another name.
|
36
|
-
#
|
37
|
-
class Alias
|
38
|
-
##
|
39
|
-
# Create a new alias.
|
40
|
-
#
|
41
|
-
# @param [Array<String>] full_name The name of the alias.
|
42
|
-
# @param [String,Array<String>] target The name of the target. May either
|
43
|
-
# be a local reference (a single string) or a global reference (an
|
44
|
-
# array of strings)
|
45
|
-
#
|
46
|
-
def initialize(loader, full_name, target, priority)
|
47
|
-
@target_name =
|
48
|
-
if target.is_a?(::Array)
|
49
|
-
target.map(&:to_s)
|
50
|
-
else
|
51
|
-
full_name[0..-2] + [target.to_s]
|
52
|
-
end
|
53
|
-
@target_name.freeze
|
54
|
-
@full_name = full_name.map(&:to_s).freeze
|
55
|
-
@priority = priority
|
56
|
-
@tool_class = DSL::Tool.new_class(@full_name, priority, loader)
|
57
|
-
end
|
58
|
-
|
59
|
-
##
|
60
|
-
# Return the tool class.
|
61
|
-
# @return [Class]
|
62
|
-
#
|
63
|
-
attr_reader :tool_class
|
64
|
-
|
65
|
-
##
|
66
|
-
# Return the name of the tool as an array of strings.
|
67
|
-
# This array may not be modified.
|
68
|
-
# @return [Array<String>]
|
69
|
-
#
|
70
|
-
attr_reader :full_name
|
71
|
-
|
72
|
-
##
|
73
|
-
# Return the priority of this alias.
|
74
|
-
# @return [Integer]
|
75
|
-
#
|
76
|
-
attr_reader :priority
|
77
|
-
|
78
|
-
##
|
79
|
-
# Return the name of the target as an array of strings.
|
80
|
-
# This array may not be modified.
|
81
|
-
# @return [Array<String>]
|
82
|
-
#
|
83
|
-
attr_reader :target_name
|
84
|
-
|
85
|
-
##
|
86
|
-
# Returns the local name of this tool.
|
87
|
-
# @return [String]
|
88
|
-
#
|
89
|
-
def simple_name
|
90
|
-
full_name.last
|
91
|
-
end
|
92
|
-
|
93
|
-
##
|
94
|
-
# Returns a displayable name of this tool, generally the full name
|
95
|
-
# delimited by spaces.
|
96
|
-
# @return [String]
|
97
|
-
#
|
98
|
-
def display_name
|
99
|
-
full_name.join(" ")
|
100
|
-
end
|
101
|
-
|
102
|
-
##
|
103
|
-
# Returns a displayable name of the target, generally the full name
|
104
|
-
# delimited by spaces.
|
105
|
-
# @return [String]
|
106
|
-
#
|
107
|
-
def display_target
|
108
|
-
target_name.join(" ")
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
data/lib/toys/definition/arg.rb
DELETED
@@ -1,140 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2018 Daniel Azuma
|
4
|
-
#
|
5
|
-
# All rights reserved.
|
6
|
-
#
|
7
|
-
# Redistribution and use in source and binary forms, with or without
|
8
|
-
# modification, are permitted provided that the following conditions are met:
|
9
|
-
#
|
10
|
-
# * Redistributions of source code must retain the above copyright notice,
|
11
|
-
# this list of conditions and the following disclaimer.
|
12
|
-
# * Redistributions in binary form must reproduce the above copyright notice,
|
13
|
-
# this list of conditions and the following disclaimer in the documentation
|
14
|
-
# and/or other materials provided with the distribution.
|
15
|
-
# * Neither the name of the copyright holder, nor the names of any other
|
16
|
-
# contributors to this software, may be used to endorse or promote products
|
17
|
-
# derived from this software without specific prior written permission.
|
18
|
-
#
|
19
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
23
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
29
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
30
|
-
;
|
31
|
-
|
32
|
-
require "optparse"
|
33
|
-
|
34
|
-
module Toys
|
35
|
-
module Definition
|
36
|
-
##
|
37
|
-
# Representation of a formal positional argument
|
38
|
-
#
|
39
|
-
class Arg
|
40
|
-
##
|
41
|
-
# Create an Arg definition
|
42
|
-
# @private
|
43
|
-
#
|
44
|
-
def initialize(key, type, accept, default, desc, long_desc, display_name = nil)
|
45
|
-
@key = key
|
46
|
-
@type = type
|
47
|
-
@accept = accept
|
48
|
-
@default = default
|
49
|
-
@desc = Utils::WrappableString.make(desc)
|
50
|
-
@long_desc = Utils::WrappableString.make_array(long_desc)
|
51
|
-
@display_name = display_name || key.to_s.tr("-", "_").gsub(/\W/, "").upcase
|
52
|
-
end
|
53
|
-
|
54
|
-
##
|
55
|
-
# Returns the key.
|
56
|
-
# @return [Symbol]
|
57
|
-
#
|
58
|
-
attr_reader :key
|
59
|
-
|
60
|
-
##
|
61
|
-
# Type of this argument.
|
62
|
-
# @return [:required,:optional,:remaining]
|
63
|
-
#
|
64
|
-
attr_reader :type
|
65
|
-
|
66
|
-
##
|
67
|
-
# Returns the acceptor, which may be `nil`.
|
68
|
-
# @return [Object]
|
69
|
-
#
|
70
|
-
attr_accessor :accept
|
71
|
-
|
72
|
-
##
|
73
|
-
# Returns the default value, which may be `nil`.
|
74
|
-
# @return [Object]
|
75
|
-
#
|
76
|
-
attr_reader :default
|
77
|
-
|
78
|
-
##
|
79
|
-
# Returns the short description string.
|
80
|
-
# @return [Toys::Utils::WrappableString]
|
81
|
-
#
|
82
|
-
attr_reader :desc
|
83
|
-
|
84
|
-
##
|
85
|
-
# Returns the long description strings as an array.
|
86
|
-
# @return [Array<Toys::Utils::WrappableString>]
|
87
|
-
#
|
88
|
-
attr_reader :long_desc
|
89
|
-
|
90
|
-
##
|
91
|
-
# Returns the displayable name.
|
92
|
-
# @return [String]
|
93
|
-
#
|
94
|
-
attr_accessor :display_name
|
95
|
-
|
96
|
-
##
|
97
|
-
# Process the given value through the acceptor.
|
98
|
-
# May raise an exception if the acceptor rejected the input.
|
99
|
-
#
|
100
|
-
# @param [String] input Input value
|
101
|
-
# @return [Object] Accepted value
|
102
|
-
#
|
103
|
-
def process_value(input)
|
104
|
-
return input unless accept
|
105
|
-
result = input
|
106
|
-
optparse = ::OptionParser.new
|
107
|
-
optparse.accept(accept) if accept.is_a?(Acceptor)
|
108
|
-
optparse.on("--abc VALUE", accept) { |v| result = v }
|
109
|
-
optparse.parse(["--abc", input])
|
110
|
-
result
|
111
|
-
end
|
112
|
-
|
113
|
-
##
|
114
|
-
# Set the short description string.
|
115
|
-
#
|
116
|
-
# The description may be provided as a {Toys::Utils::WrappableString}, a
|
117
|
-
# single string (which will be wrapped), or an array of strings, which will
|
118
|
-
# be interpreted as string fragments that will be concatenated and wrapped.
|
119
|
-
#
|
120
|
-
# @param [Toys::Utils::WrappableString,String,Array<String>] desc
|
121
|
-
#
|
122
|
-
def desc=(desc)
|
123
|
-
@desc = Utils::WrappableString.make(desc)
|
124
|
-
end
|
125
|
-
|
126
|
-
##
|
127
|
-
# Set the long description strings.
|
128
|
-
#
|
129
|
-
# Each string may be provided as a {Toys::Utils::WrappableString}, a single
|
130
|
-
# string (which will be wrapped), or an array of strings, which will be
|
131
|
-
# interpreted as string fragments that will be concatenated and wrapped.
|
132
|
-
#
|
133
|
-
# @param [Array<Toys::Utils::WrappableString,String,Array<String>>] long_desc
|
134
|
-
#
|
135
|
-
def long_desc=(long_desc)
|
136
|
-
@long_desc = Utils::WrappableString.make_array(long_desc)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
data/lib/toys/definition/flag.rb
DELETED
@@ -1,370 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Copyright 2018 Daniel Azuma
|
4
|
-
#
|
5
|
-
# All rights reserved.
|
6
|
-
#
|
7
|
-
# Redistribution and use in source and binary forms, with or without
|
8
|
-
# modification, are permitted provided that the following conditions are met:
|
9
|
-
#
|
10
|
-
# * Redistributions of source code must retain the above copyright notice,
|
11
|
-
# this list of conditions and the following disclaimer.
|
12
|
-
# * Redistributions in binary form must reproduce the above copyright notice,
|
13
|
-
# this list of conditions and the following disclaimer in the documentation
|
14
|
-
# and/or other materials provided with the distribution.
|
15
|
-
# * Neither the name of the copyright holder, nor the names of any other
|
16
|
-
# contributors to this software, may be used to endorse or promote products
|
17
|
-
# derived from this software without specific prior written permission.
|
18
|
-
#
|
19
|
-
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
20
|
-
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
21
|
-
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
22
|
-
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
23
|
-
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
24
|
-
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
25
|
-
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
26
|
-
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
27
|
-
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
28
|
-
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
29
|
-
# POSSIBILITY OF SUCH DAMAGE.
|
30
|
-
;
|
31
|
-
|
32
|
-
module Toys
|
33
|
-
module Definition
|
34
|
-
##
|
35
|
-
# Representation of a single flag.
|
36
|
-
#
|
37
|
-
class FlagSyntax
|
38
|
-
##
|
39
|
-
# Parse flag syntax
|
40
|
-
# @param [String] str syntax.
|
41
|
-
#
|
42
|
-
def initialize(str)
|
43
|
-
case str
|
44
|
-
when /^(-([\?\w]))$/
|
45
|
-
setup(str, [$1], $1, $2, "-", nil, nil, nil, nil)
|
46
|
-
when /^(-([\?\w]))( ?)\[(\w+)\]$/
|
47
|
-
setup(str, [$1], $1, $2, "-", :value, :optional, $3, $4)
|
48
|
-
when /^(-([\?\w]))\[( )(\w+)\]$/
|
49
|
-
setup(str, [$1], $1, $2, "-", :value, :optional, $3, $4)
|
50
|
-
when /^(-([\?\w]))( ?)(\w+)$/
|
51
|
-
setup(str, [$1], $1, $2, "-", :value, :required, $3, $4)
|
52
|
-
when /^--\[no-\](\w[\?\w-]*)$/
|
53
|
-
setup(str, ["--#{$1}", "--no-#{$1}"], str, $1, "--", :boolean, nil, nil, nil)
|
54
|
-
when /^(--(\w[\?\w-]*))$/
|
55
|
-
setup(str, [$1], $1, $2, "--", nil, nil, nil, nil)
|
56
|
-
when /^(--(\w[\?\w-]*))([= ])\[(\w+)\]$/
|
57
|
-
setup(str, [$1], $1, $2, "--", :value, :optional, $3, $4)
|
58
|
-
when /^(--(\w[\?\w-]*))\[([= ])(\w+)\]$/
|
59
|
-
setup(str, [$1], $1, $2, "--", :value, :optional, $3, $4)
|
60
|
-
when /^(--(\w[\?\w-]*))([= ])(\w+)$/
|
61
|
-
setup(str, [$1], $1, $2, "--", :value, :required, $3, $4)
|
62
|
-
else
|
63
|
-
raise ToolDefinitionError, "Illegal flag: #{str.inspect}"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
attr_reader :original_str
|
68
|
-
attr_reader :flags
|
69
|
-
attr_reader :str_without_value
|
70
|
-
attr_reader :sort_str
|
71
|
-
attr_reader :flag_style
|
72
|
-
attr_reader :flag_type
|
73
|
-
attr_reader :value_type
|
74
|
-
attr_reader :value_delim
|
75
|
-
attr_reader :value_label
|
76
|
-
attr_reader :canonical_str
|
77
|
-
|
78
|
-
## @private
|
79
|
-
def configure_canonical(canonical_flag_type, canonical_value_type,
|
80
|
-
canonical_value_label, canonical_value_delim)
|
81
|
-
return unless flag_type.nil?
|
82
|
-
@flag_type = canonical_flag_type
|
83
|
-
return unless canonical_flag_type == :value
|
84
|
-
@value_type = canonical_value_type
|
85
|
-
canonical_value_delim = "" if canonical_value_delim == "=" && flag_style == "-"
|
86
|
-
canonical_value_delim = "=" if canonical_value_delim == "" && flag_style == "--"
|
87
|
-
@value_delim = canonical_value_delim
|
88
|
-
@value_label = canonical_value_label
|
89
|
-
label = @value_type == :optional ? "[#{@value_label}]" : @value_label
|
90
|
-
@canonical_str = "#{str_without_value}#{@value_delim}#{label}"
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
def setup(original_str, flags, str_without_value, sort_str, flag_style, flag_type,
|
96
|
-
value_type, value_delim, value_label)
|
97
|
-
@original_str = original_str
|
98
|
-
@flags = flags
|
99
|
-
@str_without_value = str_without_value
|
100
|
-
@sort_str = sort_str
|
101
|
-
@flag_style = flag_style
|
102
|
-
@flag_type = flag_type
|
103
|
-
@value_type = value_type
|
104
|
-
@value_delim = value_delim
|
105
|
-
@value_label = value_label ? value_label.upcase : value_label
|
106
|
-
@canonical_str = original_str
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
##
|
111
|
-
# Representation of a formal set of flags that set a particular context
|
112
|
-
# key. The flags within a single Flag definition are synonyms.
|
113
|
-
#
|
114
|
-
class Flag
|
115
|
-
##
|
116
|
-
# The default handler replaces the previous value.
|
117
|
-
# @return [Proc]
|
118
|
-
#
|
119
|
-
DEFAULT_HANDLER = ->(val, _prev) { val }
|
120
|
-
|
121
|
-
##
|
122
|
-
# Create a Flag definition
|
123
|
-
# @private
|
124
|
-
#
|
125
|
-
def initialize(key, flags, used_flags, report_collisions, accept, handler,
|
126
|
-
default, display_name, group)
|
127
|
-
@group = group
|
128
|
-
@key = key
|
129
|
-
@flag_syntax = flags.map { |s| FlagSyntax.new(s) }
|
130
|
-
@accept = accept
|
131
|
-
@handler = handler || DEFAULT_HANDLER
|
132
|
-
@desc = Utils::WrappableString.make(desc)
|
133
|
-
@long_desc = Utils::WrappableString.make_array(long_desc)
|
134
|
-
@default = default
|
135
|
-
needs_val = (!accept.nil? && accept != ::TrueClass && accept != ::FalseClass) ||
|
136
|
-
(!default.nil? && default != true && default != false)
|
137
|
-
create_default_flag_if_needed(needs_val)
|
138
|
-
remove_used_flags(used_flags, report_collisions)
|
139
|
-
canonicalize(needs_val)
|
140
|
-
summarize(display_name)
|
141
|
-
end
|
142
|
-
|
143
|
-
##
|
144
|
-
# Returns the flag group containing this flag
|
145
|
-
# @return [Toys::Definition::FlagGroup]
|
146
|
-
#
|
147
|
-
attr_reader :group
|
148
|
-
|
149
|
-
##
|
150
|
-
# Returns the key.
|
151
|
-
# @return [Symbol]
|
152
|
-
#
|
153
|
-
attr_reader :key
|
154
|
-
|
155
|
-
##
|
156
|
-
# Returns an array of FlagSyntax for the flags.
|
157
|
-
# @return [Array<FlagSyntax>]
|
158
|
-
#
|
159
|
-
attr_reader :flag_syntax
|
160
|
-
|
161
|
-
##
|
162
|
-
# Returns the acceptor, which may be `nil`.
|
163
|
-
# @return [Object]
|
164
|
-
#
|
165
|
-
attr_reader :accept
|
166
|
-
|
167
|
-
##
|
168
|
-
# Returns the default value, which may be `nil`.
|
169
|
-
# @return [Object]
|
170
|
-
#
|
171
|
-
attr_reader :default
|
172
|
-
|
173
|
-
##
|
174
|
-
# Returns the short description string.
|
175
|
-
# @return [Toys::Utils::WrappableString]
|
176
|
-
#
|
177
|
-
attr_reader :desc
|
178
|
-
|
179
|
-
##
|
180
|
-
# Returns the long description strings as an array.
|
181
|
-
# @return [Array<Toys::Utils::WrappableString>]
|
182
|
-
#
|
183
|
-
attr_reader :long_desc
|
184
|
-
|
185
|
-
##
|
186
|
-
# Returns the handler for setting/updating the value.
|
187
|
-
# @return [Proc]
|
188
|
-
#
|
189
|
-
attr_reader :handler
|
190
|
-
|
191
|
-
##
|
192
|
-
# The type of flag. Possible values are `:boolean` for a simple boolean
|
193
|
-
# switch, or `:value` for a flag that sets a value.
|
194
|
-
# @return [:boolean,:value]
|
195
|
-
#
|
196
|
-
attr_reader :flag_type
|
197
|
-
|
198
|
-
##
|
199
|
-
# The type of value. Set to `:required` or `:optional` if the flag type
|
200
|
-
# is `:value`. Otherwise set to `nil`.
|
201
|
-
# @return [:required,:optional,nil]
|
202
|
-
#
|
203
|
-
attr_reader :value_type
|
204
|
-
|
205
|
-
##
|
206
|
-
# The string label for the value as it should display in help, or `nil`
|
207
|
-
# if the flag type is not `:value`.
|
208
|
-
# @return [String,nil]
|
209
|
-
#
|
210
|
-
attr_reader :value_label
|
211
|
-
|
212
|
-
##
|
213
|
-
# The value delimiter, which may be `""`, `" "`, or `"="`. Set to `nil`
|
214
|
-
# if the flag type is not `:value`.
|
215
|
-
# @return [String,nil]
|
216
|
-
#
|
217
|
-
attr_reader :value_delim
|
218
|
-
|
219
|
-
##
|
220
|
-
# Returns the display name of this flag.
|
221
|
-
# @return [String]
|
222
|
-
#
|
223
|
-
attr_reader :display_name
|
224
|
-
|
225
|
-
##
|
226
|
-
# Returns a string that can be used to sort this flag
|
227
|
-
# @return [String]
|
228
|
-
#
|
229
|
-
attr_reader :sort_str
|
230
|
-
|
231
|
-
##
|
232
|
-
# Returns an array of FlagSyntax including only single-dash flags
|
233
|
-
# @return [Array<FlagSyntax>]
|
234
|
-
#
|
235
|
-
def single_flag_syntax
|
236
|
-
@single_flag_syntax ||= flag_syntax.find_all { |ss| ss.flag_style == "-" }
|
237
|
-
end
|
238
|
-
|
239
|
-
##
|
240
|
-
# Returns an array of FlagSyntax including only double-dash flags
|
241
|
-
# @return [Array<FlagSyntax>]
|
242
|
-
#
|
243
|
-
def double_flag_syntax
|
244
|
-
@double_flag_syntax ||= flag_syntax.find_all { |ss| ss.flag_style == "--" }
|
245
|
-
end
|
246
|
-
|
247
|
-
##
|
248
|
-
# Returns the list of effective flags used.
|
249
|
-
# @return [Array<String>]
|
250
|
-
#
|
251
|
-
def effective_flags
|
252
|
-
@effective_flags ||= flag_syntax.map(&:flags).flatten
|
253
|
-
end
|
254
|
-
|
255
|
-
##
|
256
|
-
# Returns a list suitable for passing to OptionParser.
|
257
|
-
# @return [Array]
|
258
|
-
#
|
259
|
-
def optparser_info
|
260
|
-
@optparser_info ||= flag_syntax.map(&:canonical_str) + Array(accept)
|
261
|
-
end
|
262
|
-
|
263
|
-
##
|
264
|
-
# Returns true if this flag is active. That is, it has a nonempty
|
265
|
-
# flags list.
|
266
|
-
# @return [Boolean]
|
267
|
-
#
|
268
|
-
def active?
|
269
|
-
!effective_flags.empty?
|
270
|
-
end
|
271
|
-
|
272
|
-
##
|
273
|
-
# Set the short description string.
|
274
|
-
#
|
275
|
-
# The description may be provided as a {Toys::Utils::WrappableString}, a
|
276
|
-
# single string (which will be wrapped), or an array of strings, which will
|
277
|
-
# be interpreted as string fragments that will be concatenated and wrapped.
|
278
|
-
#
|
279
|
-
# @param [Toys::Utils::WrappableString,String,Array<String>] desc
|
280
|
-
#
|
281
|
-
def desc=(desc)
|
282
|
-
@desc = Utils::WrappableString.make(desc)
|
283
|
-
end
|
284
|
-
|
285
|
-
##
|
286
|
-
# Set the long description strings.
|
287
|
-
#
|
288
|
-
# Each string may be provided as a {Toys::Utils::WrappableString}, a single
|
289
|
-
# string (which will be wrapped), or an array of strings, which will be
|
290
|
-
# interpreted as string fragments that will be concatenated and wrapped.
|
291
|
-
#
|
292
|
-
# @param [Array<Toys::Utils::WrappableString,String,Array<String>>] long_desc
|
293
|
-
#
|
294
|
-
def long_desc=(long_desc)
|
295
|
-
@long_desc = Utils::WrappableString.make_array(long_desc)
|
296
|
-
end
|
297
|
-
|
298
|
-
private
|
299
|
-
|
300
|
-
def create_default_flag_if_needed(needs_val)
|
301
|
-
return unless @flag_syntax.empty?
|
302
|
-
canonical_flag = key.to_s.downcase.tr("_", "-").gsub(/[^a-z0-9-]/, "").sub(/^-+/, "")
|
303
|
-
unless canonical_flag.empty?
|
304
|
-
flag = needs_val ? "--#{canonical_flag} VALUE" : "--#{canonical_flag}"
|
305
|
-
@flag_syntax << FlagSyntax.new(flag)
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
def remove_used_flags(used_flags, report_collisions)
|
310
|
-
@flag_syntax.select! do |fs|
|
311
|
-
fs.flags.all? do |f|
|
312
|
-
collision = used_flags.include?(f)
|
313
|
-
if collision && report_collisions
|
314
|
-
raise ToolDefinitionError,
|
315
|
-
"Cannot use flag #{f.inspect} because it is already assigned or reserved."
|
316
|
-
end
|
317
|
-
!collision
|
318
|
-
end
|
319
|
-
end
|
320
|
-
used_flags.concat(effective_flags.uniq)
|
321
|
-
end
|
322
|
-
|
323
|
-
def canonicalize(needs_val)
|
324
|
-
@flag_type = needs_val ? :value : nil
|
325
|
-
@value_type = nil
|
326
|
-
@value_label = needs_val ? "VALUE" : nil
|
327
|
-
@value_delim = " "
|
328
|
-
single_flag_syntax.reverse_each do |flag|
|
329
|
-
analyze_flag_syntax(flag)
|
330
|
-
end
|
331
|
-
double_flag_syntax.reverse_each do |flag|
|
332
|
-
analyze_flag_syntax(flag)
|
333
|
-
end
|
334
|
-
@flag_type ||= :boolean
|
335
|
-
@value_type ||= :required if @flag_type == :value
|
336
|
-
flag_syntax.each do |flag|
|
337
|
-
flag.configure_canonical(@flag_type, @value_type, @value_label, @value_delim)
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
def analyze_flag_syntax(flag)
|
342
|
-
return if flag.flag_type.nil?
|
343
|
-
if !@flag_type.nil? && @flag_type != flag.flag_type
|
344
|
-
raise ToolDefinitionError, "Cannot have both value and boolean flags for #{key.inspect}"
|
345
|
-
end
|
346
|
-
@flag_type = flag.flag_type
|
347
|
-
return unless @flag_type == :value
|
348
|
-
if !@value_type.nil? && @value_type != flag.value_type
|
349
|
-
raise ToolDefinitionError,
|
350
|
-
"Cannot have both required and optional values for flag #{key.inspect}"
|
351
|
-
end
|
352
|
-
@value_type = flag.value_type
|
353
|
-
@value_label = flag.value_label
|
354
|
-
@value_delim = flag.value_delim
|
355
|
-
end
|
356
|
-
|
357
|
-
def summarize(name)
|
358
|
-
@display_name =
|
359
|
-
name ||
|
360
|
-
double_flag_syntax.first&.canonical_str ||
|
361
|
-
single_flag_syntax.first&.canonical_str ||
|
362
|
-
key.to_s
|
363
|
-
@sort_str =
|
364
|
-
double_flag_syntax.first&.sort_str ||
|
365
|
-
single_flag_syntax.first&.sort_str ||
|
366
|
-
""
|
367
|
-
end
|
368
|
-
end
|
369
|
-
end
|
370
|
-
end
|