opt_parse_builder 0.1.0
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 +7 -0
- data/.gitignore +2 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +35 -0
- data/LICENSE +23 -0
- data/README.md +434 -0
- data/Rakefile +13 -0
- data/examples/hello_world.rb +20 -0
- data/lib/opt_parse_builder.rb +156 -0
- data/lib/opt_parse_builder/argument.rb +62 -0
- data/lib/opt_parse_builder/argument_builder.rb +193 -0
- data/lib/opt_parse_builder/argument_bundle.rb +30 -0
- data/lib/opt_parse_builder/argument_bundle_builder.rb +34 -0
- data/lib/opt_parse_builder/argument_values.rb +60 -0
- data/lib/opt_parse_builder/banner_argument.rb +11 -0
- data/lib/opt_parse_builder/constant_argument.rb +16 -0
- data/lib/opt_parse_builder/errors.rb +10 -0
- data/lib/opt_parse_builder/formats_operand_name.rb +9 -0
- data/lib/opt_parse_builder/has_value.rb +21 -0
- data/lib/opt_parse_builder/null_argument.rb +4 -0
- data/lib/opt_parse_builder/option_argument.rb +33 -0
- data/lib/opt_parse_builder/optional_operand_argument.rb +29 -0
- data/lib/opt_parse_builder/parser.rb +345 -0
- data/lib/opt_parse_builder/parser_builder.rb +17 -0
- data/lib/opt_parse_builder/required_operand_argument.rb +32 -0
- data/lib/opt_parse_builder/separator_argument.rb +11 -0
- data/lib/opt_parse_builder/splat_operand_argument.rb +22 -0
- data/lib/opt_parse_builder/stable_sort.rb +13 -0
- data/lib/opt_parse_builder/version.rb +6 -0
- data/opt_parse_builder.gemspec +35 -0
- data/rake/bundler.rake +1 -0
- data/rake/default.rake +1 -0
- data/rake/rdoc.rake +7 -0
- data/rake/spec.rake +3 -0
- data/rake/test.rake +2 -0
- metadata +126 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module OptParseBuilder
|
2
|
+
|
3
|
+
# Yielded by OptParseBuilder.bundle_arguments to create an
|
4
|
+
# ArgumentBundle, a collection of arguments that can be treated as
|
5
|
+
# through it is one argument.
|
6
|
+
class ArgumentBundleBuilder
|
7
|
+
|
8
|
+
def initialize # :nodoc:
|
9
|
+
@argument_bundle = ArgumentBundle.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# Add an argument to the bundle. Takes either the argument to
|
13
|
+
# add, or yields an ArgumentBuilder which builds a new argument
|
14
|
+
# and adds it.
|
15
|
+
#
|
16
|
+
# If adding an existing argument, that argument may itself be an
|
17
|
+
# ArgumentBundle.
|
18
|
+
def add(argument = nil, &block)
|
19
|
+
unless argument.nil? ^ block.nil?
|
20
|
+
raise BuildError, "Need exactly 1 of arg and block"
|
21
|
+
end
|
22
|
+
if argument
|
23
|
+
@argument_bundle << argument
|
24
|
+
else
|
25
|
+
@argument_bundle << OptParseBuilder.build_argument(&block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def argument # :nodoc:
|
30
|
+
@argument_bundle.simplify
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module OptParseBuilder
|
2
|
+
|
3
|
+
# Like OpenStruct, in that it allows access as through either a Hash
|
4
|
+
# or a Struct, but raises an error if you try to read a value that
|
5
|
+
# has not been set.
|
6
|
+
#
|
7
|
+
# Strings and symbols may be interchanged freely for hash access.
|
8
|
+
#
|
9
|
+
# A value may only by set using hash syntax:
|
10
|
+
#
|
11
|
+
# arg_values = ArgumentValues.new
|
12
|
+
# arg_values[:one] = 1
|
13
|
+
# arg_values["two"] = 2
|
14
|
+
#
|
15
|
+
# But may be retrieved using hash syntax:
|
16
|
+
#
|
17
|
+
# arg_values["one"] # => 1
|
18
|
+
# arg_values[:two] # => 2
|
19
|
+
#
|
20
|
+
# or struct syntax:
|
21
|
+
#
|
22
|
+
# arg_values.one # => 1
|
23
|
+
# arg_values.two # => 2
|
24
|
+
class ArgumentValues
|
25
|
+
|
26
|
+
# Create an empty instance.
|
27
|
+
def initialize
|
28
|
+
@h = {}
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return true if the collection is empty.
|
32
|
+
def empty?
|
33
|
+
@h.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return true if the collection contains the key, which may be
|
37
|
+
# either a symbol or a string.
|
38
|
+
def has_key?(key)
|
39
|
+
@h.has_key?(key.to_sym)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Set a key to a value. The key may be either a string or a
|
43
|
+
# symbol.
|
44
|
+
def []=(key, value)
|
45
|
+
@h[key.to_sym] = value
|
46
|
+
end
|
47
|
+
|
48
|
+
# Get a value. The key may be either a string or a symbol.
|
49
|
+
# Raises KeyError if the collection does not have that key.
|
50
|
+
def [](key)
|
51
|
+
@h.fetch(key.to_sym)
|
52
|
+
end
|
53
|
+
|
54
|
+
def method_missing(method, *args) # :nodoc:
|
55
|
+
return super unless has_key?(method)
|
56
|
+
self[method]
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module OptParseBuilder
|
2
|
+
class ConstantArgument < Argument # :nodoc:
|
3
|
+
|
4
|
+
attr_reader :key
|
5
|
+
attr_reader :value
|
6
|
+
|
7
|
+
def initialize(key, value)
|
8
|
+
unless key
|
9
|
+
raise BuildError, "default requires a key"
|
10
|
+
end
|
11
|
+
@key = key
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module OptParseBuilder
|
2
|
+
|
3
|
+
# The base class for all exceptions directly raised by this library.
|
4
|
+
class Error < StandardError ; end
|
5
|
+
|
6
|
+
# Exception raised for an error when building a parser, argument or
|
7
|
+
# argument bundle.
|
8
|
+
class BuildError < Error ; end
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module OptParseBuilder
|
2
|
+
module HasValue # :nodoc:
|
3
|
+
|
4
|
+
attr_reader :key
|
5
|
+
attr_accessor :value
|
6
|
+
|
7
|
+
def init_value(key, default)
|
8
|
+
unless key
|
9
|
+
raise BuildError, "argument with value requires a key"
|
10
|
+
end
|
11
|
+
@key = key
|
12
|
+
@default = default
|
13
|
+
reset
|
14
|
+
end
|
15
|
+
|
16
|
+
def reset
|
17
|
+
@value = @default
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module OptParseBuilder
|
2
|
+
class OptionArgument < Argument # :nodoc:
|
3
|
+
|
4
|
+
include HasValue
|
5
|
+
|
6
|
+
DEFAULT_HANDLER = ->(argument, value) { argument.value = value }
|
7
|
+
|
8
|
+
def initialize(key, default, on, handler)
|
9
|
+
init_value(key, default)
|
10
|
+
@on = on
|
11
|
+
@handler = handler || DEFAULT_HANDLER
|
12
|
+
end
|
13
|
+
|
14
|
+
def apply_option(op)
|
15
|
+
op.on(*edited_on) do |value|
|
16
|
+
@handler.call(self, value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def edited_on
|
23
|
+
@on.map do |s|
|
24
|
+
if s.respond_to?(:gsub!)
|
25
|
+
s.gsub(/_DEFAULT_/, @default.to_s)
|
26
|
+
else
|
27
|
+
s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module OptParseBuilder
|
2
|
+
class OptionalOperandArgument < Argument # :nodoc:
|
3
|
+
|
4
|
+
include FormatsOperandName
|
5
|
+
include HasValue
|
6
|
+
|
7
|
+
def initialize(key, default, help_name)
|
8
|
+
init_value(key, default)
|
9
|
+
@help_name = help_name || key
|
10
|
+
end
|
11
|
+
|
12
|
+
def operand_notation
|
13
|
+
"[<#{format_operand_name(@help_name)}>]"
|
14
|
+
end
|
15
|
+
|
16
|
+
def shift_operand(argv)
|
17
|
+
@value = argv.shift
|
18
|
+
end
|
19
|
+
|
20
|
+
def optional
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def required
|
25
|
+
RequiredOperandArgument.new(@key, @default, @help_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,345 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
require_relative "stable_sort"
|
4
|
+
|
5
|
+
module OptParseBuilder
|
6
|
+
|
7
|
+
# A command-line parser. Create an instance of this by calling
|
8
|
+
# OptParseBuilder.build_parser.
|
9
|
+
#
|
10
|
+
# Note: The constructor for this class is not part of the public
|
11
|
+
# API.
|
12
|
+
class Parser
|
13
|
+
|
14
|
+
include StableSort
|
15
|
+
|
16
|
+
# Controls whether unparsed arguments are an error.
|
17
|
+
#
|
18
|
+
# If `false` (the default), then unparsed arguments cause an
|
19
|
+
# error:
|
20
|
+
#
|
21
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
22
|
+
# args.allow_unparsed_operands = false
|
23
|
+
# args.add do |arg|
|
24
|
+
# arg.key :quiet
|
25
|
+
# arg.on "-q", "--quiet", "Suppress normal output"
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# ARGV = ["-q", "/tmp/file1", "/tmp/file2"]
|
30
|
+
# arg_values = arg_parser.parse!
|
31
|
+
# # aborts with "needless argument: /tmp/file1"
|
32
|
+
#
|
33
|
+
# If `true`, then unparsed operands are not considered an error, and
|
34
|
+
# they remain unconsumed. Use this setting when you want unparsed
|
35
|
+
# operands to remain in `ARGV` so that they can be used by, for
|
36
|
+
# example, `ARGF`:
|
37
|
+
#
|
38
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
39
|
+
# args.allow_unparsed_operands = true
|
40
|
+
# args.add do |arg|
|
41
|
+
# arg.key :quiet
|
42
|
+
# arg.on "-q", "--quiet", "Suppress normal output"
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# ARGV = ["-q", "/tmp/file1", "/tmp/file2"]
|
47
|
+
# arg_values = arg_parser.parse!
|
48
|
+
# # ARGV now equals ["/tmp/file1", "/tmp/file2"]
|
49
|
+
# ARGF.each_line do |line|
|
50
|
+
# puts line unless arg_values.quiet
|
51
|
+
# end
|
52
|
+
attr_accessor :allow_unparsed_operands
|
53
|
+
|
54
|
+
def initialize # :nodoc:
|
55
|
+
@arguments = []
|
56
|
+
@allow_unparsed_operands = false
|
57
|
+
end
|
58
|
+
|
59
|
+
# Reset to the state after construction, before #parse! was called.
|
60
|
+
# Each argument is set to its default value. An argument with no
|
61
|
+
# explicit default is set to `nil`.
|
62
|
+
#
|
63
|
+
# This is called implicitly when you call #parse!, so there's seldom
|
64
|
+
# any need for it to be called explicitly.
|
65
|
+
def reset
|
66
|
+
@arguments.each(&:reset)
|
67
|
+
sort_arguments
|
68
|
+
end
|
69
|
+
|
70
|
+
# Parse arguments, consuming them from the array.
|
71
|
+
#
|
72
|
+
# After parsing, there are numerous ways to access the value of the arguments:
|
73
|
+
#
|
74
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
75
|
+
# args.add do |arg|
|
76
|
+
# arg.key :num
|
77
|
+
# arg.on "--num=N", Integer, "A number"
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
# arg_values = arg_parser.parse!(["--num=123"])
|
81
|
+
# p arg_parser[:num] # => 123
|
82
|
+
# p arg_parser["num"] # => 123
|
83
|
+
# p arg_values[:num] # => 123
|
84
|
+
# p arg_values["num"] # => 123
|
85
|
+
# p arg_values.num # => 123
|
86
|
+
#
|
87
|
+
# If there are operands (positional arguments) in the array that are
|
88
|
+
# not consumed, an error normally results. This behavior can be
|
89
|
+
# changed using #allow_unparsed_operands.
|
90
|
+
#
|
91
|
+
# The #parse! method defaults to parsing `ARGV`, which is what is
|
92
|
+
# usually wanted, but you can pass in any array of strings, as the
|
93
|
+
# above example does.
|
94
|
+
#
|
95
|
+
# Design note: A method that modifies its argument _and_ modifies
|
96
|
+
# its object _and_ returns a value is not the best design, violating
|
97
|
+
# the good principle of command-query separation. However, that
|
98
|
+
# violation is more useful in this case than it is sinful, and it's
|
99
|
+
# the only place in this library that violates that principle.
|
100
|
+
def parse!(argv = ARGV)
|
101
|
+
reset
|
102
|
+
begin
|
103
|
+
op = optparse
|
104
|
+
op.parse!(argv)
|
105
|
+
@arguments.each do |arg|
|
106
|
+
arg.shift_operand(argv)
|
107
|
+
end
|
108
|
+
unless @allow_unparsed_operands || argv.empty?
|
109
|
+
raise OptionParser::NeedlessArgument, argv.first
|
110
|
+
end
|
111
|
+
values
|
112
|
+
rescue OptionParser::ParseError => e
|
113
|
+
abort e.message
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Add a line to the banner. The banner is text that appears at the
|
118
|
+
# top of the help text.
|
119
|
+
#
|
120
|
+
# A new-line will automatically be added to the end of the line.
|
121
|
+
# Although it's called a "line," you can embed new-lines in it so
|
122
|
+
# that it is actually more than one line.
|
123
|
+
#
|
124
|
+
# This example:
|
125
|
+
#
|
126
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
127
|
+
# args.banner "This is my program"
|
128
|
+
# args.banner <<~BANNER
|
129
|
+
# There are many programs like it,
|
130
|
+
# but this program is mine.
|
131
|
+
# BANNER
|
132
|
+
# end
|
133
|
+
# arg_parser.parse!(["--help"])
|
134
|
+
#
|
135
|
+
# Results in `--help` output like this:
|
136
|
+
#
|
137
|
+
# This is my program
|
138
|
+
# There are many programs like it,
|
139
|
+
# but this program is mine.
|
140
|
+
# Usage: example [options] <path>
|
141
|
+
def banner(line)
|
142
|
+
add do |arg|
|
143
|
+
arg.banner(line)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Add a line to the separator. The separator is text that appears
|
148
|
+
# at the bottom of the help text.
|
149
|
+
#
|
150
|
+
# A new-line will automatically be added to the end of the line.
|
151
|
+
# Although it's called a "line," you can embed new-lines in it so
|
152
|
+
# that it is actually more than one line.
|
153
|
+
#
|
154
|
+
# This example:
|
155
|
+
#
|
156
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
157
|
+
# args.separator "Here I explain more about my program"
|
158
|
+
# args.separator <<~SEPARATOR
|
159
|
+
# For such a small program,
|
160
|
+
# it has a lot of text at the end.
|
161
|
+
# SEPARATOR
|
162
|
+
# end
|
163
|
+
# arg_parser.parse!(["--help"])
|
164
|
+
#
|
165
|
+
# Results in `--help` output like this:
|
166
|
+
#
|
167
|
+
# Usage: example [options] <path>
|
168
|
+
# Here I explain more about my program
|
169
|
+
# For such a small program,
|
170
|
+
# it has a lot of text at the end.
|
171
|
+
def separator(line)
|
172
|
+
add do |arg|
|
173
|
+
arg.separator(line)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Add an argument. Must be passed either the argument to add, or
|
178
|
+
# given a block. If given a block, yields an ArgumentBuilder.
|
179
|
+
#
|
180
|
+
# Example using a pre-built argument:
|
181
|
+
#
|
182
|
+
# DRY_RUN = OptParseBuilder.build_argument do |arg|
|
183
|
+
# arg.key :dry_run
|
184
|
+
# arg.on "-d", "--dry-run", "Make no changes"
|
185
|
+
# end
|
186
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
187
|
+
# args.add DRY_RUN
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
# Example using a block to build the argument in-place:
|
191
|
+
#
|
192
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
193
|
+
# args.add do |arg|
|
194
|
+
# arg.key :dry_run
|
195
|
+
# arg.on "-d", "--dry-run", "Make no changes"
|
196
|
+
# end
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# This is equivalent to:
|
200
|
+
#
|
201
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
202
|
+
# args.add OptParseBuilder.build_argument do |arg|
|
203
|
+
# arg.key :dry_run
|
204
|
+
# arg.on "-d", "--dry-run", "Make no changes"
|
205
|
+
# end
|
206
|
+
# end
|
207
|
+
#
|
208
|
+
# See the README for details of the different options available
|
209
|
+
# for an argument.
|
210
|
+
#
|
211
|
+
# Raises BuildError if the argument cannot be built or added.
|
212
|
+
def add(argument = nil, &block)
|
213
|
+
unless argument.nil? ^ block.nil?
|
214
|
+
raise BuildError, "Need exactly 1 of arg and block"
|
215
|
+
end
|
216
|
+
if argument
|
217
|
+
add_argument(argument)
|
218
|
+
else
|
219
|
+
add_argument(OptParseBuilder.build_argument(&block))
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Returns the value of an argument, given either a symbol or a
|
224
|
+
# string with its name. If the key does not exist, raises KeyError.
|
225
|
+
#
|
226
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
227
|
+
# args.add do |arg|
|
228
|
+
# arg.key :x
|
229
|
+
# arg.default 123
|
230
|
+
# end
|
231
|
+
# end
|
232
|
+
# arg_parser[:x] # => 123
|
233
|
+
# arg_parser["x"] # => 123
|
234
|
+
# arg_parser[:y] # KeyError (key not found :y)
|
235
|
+
#
|
236
|
+
# See also:
|
237
|
+
#
|
238
|
+
# * method #values - returns a collection of all argument values
|
239
|
+
# * method #has_key? - find out if the parser knows about a key
|
240
|
+
def [](key)
|
241
|
+
find_argument!(key).value
|
242
|
+
end
|
243
|
+
|
244
|
+
# Return a collection with all of the argument values. The
|
245
|
+
# collection can be accessed in several ways:
|
246
|
+
#
|
247
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
248
|
+
# args.add do |arg|
|
249
|
+
# arg.key :num
|
250
|
+
# arg.on "--num=N", Integer, "A number"
|
251
|
+
# end
|
252
|
+
# end
|
253
|
+
# arg_parser.parse!(["--num=123"])
|
254
|
+
# arg_values = arg_parser.values
|
255
|
+
# p arg_values[:num] # => 123
|
256
|
+
# p arg_values["num"] # => 123
|
257
|
+
# p arg_values.num # => 123
|
258
|
+
def values
|
259
|
+
av = ArgumentValues.new
|
260
|
+
@arguments.each do |arg|
|
261
|
+
av[arg.key] = arg.value if arg.key
|
262
|
+
end
|
263
|
+
av
|
264
|
+
end
|
265
|
+
|
266
|
+
# Return true if the parser has the named key, which may be either a
|
267
|
+
# string or a symbol.
|
268
|
+
#
|
269
|
+
# arg_parser = OptParseBuilder.build_parser do |args|
|
270
|
+
# args.add do |arg|
|
271
|
+
# arg.key :quiet
|
272
|
+
# end
|
273
|
+
# end
|
274
|
+
# arg_parser.has_key?(:quiet) # => true
|
275
|
+
# arg_parser.has_key?("quiet") # => true
|
276
|
+
# arg_parser.has_key?(:verbose) # => false
|
277
|
+
def has_key?(key)
|
278
|
+
!!find_argument(key)
|
279
|
+
end
|
280
|
+
|
281
|
+
private
|
282
|
+
|
283
|
+
def sort_arguments
|
284
|
+
stable_sort_by!(@arguments) do |arg|
|
285
|
+
case arg
|
286
|
+
when RequiredOperandArgument
|
287
|
+
1
|
288
|
+
when OptionalOperandArgument
|
289
|
+
2
|
290
|
+
when SplatOperandArgument
|
291
|
+
3
|
292
|
+
else
|
293
|
+
0
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def find_argument!(key)
|
299
|
+
argument = find_argument(key)
|
300
|
+
unless argument
|
301
|
+
raise Key, "key not found #{key.inspect}"
|
302
|
+
end
|
303
|
+
argument
|
304
|
+
end
|
305
|
+
|
306
|
+
def find_argument(key)
|
307
|
+
key = key.to_sym
|
308
|
+
@arguments.find do |arg|
|
309
|
+
arg.key == key
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def optparse
|
314
|
+
op = OptParse.new
|
315
|
+
op.banner = banner_prefix + op.banner + banner_suffix
|
316
|
+
@arguments.each { |arg| arg.apply_option(op) }
|
317
|
+
@arguments.each do |argument|
|
318
|
+
argument.separator_lines.each do |line|
|
319
|
+
op.separator(line)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
op
|
323
|
+
end
|
324
|
+
|
325
|
+
def add_argument(argument)
|
326
|
+
if argument.key && has_key?(argument.key)
|
327
|
+
raise BuildError, "duplicate key #{argument.key}"
|
328
|
+
end
|
329
|
+
@arguments.concat(argument.to_a.map(&:dup))
|
330
|
+
end
|
331
|
+
|
332
|
+
def banner_prefix
|
333
|
+
@arguments.flat_map(&:banner_lines).map do |line|
|
334
|
+
line + "\n"
|
335
|
+
end.join
|
336
|
+
end
|
337
|
+
|
338
|
+
def banner_suffix
|
339
|
+
suffix = @arguments.map(&:operand_notation).compact.join(" ")
|
340
|
+
suffix = " " + suffix unless suffix.empty?
|
341
|
+
suffix
|
342
|
+
end
|
343
|
+
|
344
|
+
end
|
345
|
+
end
|