argparser 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.hound.yml +4 -0
- data/.rubocop.yml +1063 -0
- data/.travis.yml +13 -0
- data/Gemfile +5 -0
- data/HISTORY.md +10 -0
- data/README.md +9 -8
- data/Rakefile +17 -0
- data/argparser.gemspec +20 -17
- data/argparser.sublime-project +27 -0
- data/lib/argparser.rb +45 -269
- data/lib/argparser/default_parser.rb +116 -0
- data/lib/argparser/option.rb +104 -0
- data/lib/argparser/tools.rb +56 -0
- data/spec/argparser_spec.rb +201 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/tools_spec.rb +28 -0
- metadata +64 -8
- data/lib/argparser/examples/example.rb +0 -32
data/.travis.yml
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- "1.8.7"
|
4
|
+
- "1.9.3"
|
5
|
+
- "2.0.0"
|
6
|
+
- "2.1" # latest 2.1.x
|
7
|
+
- "2.2" # latest 2.2.x
|
8
|
+
- "jruby-18mode"
|
9
|
+
- "jruby-19mode"
|
10
|
+
script:
|
11
|
+
CODECLIMATE_REPO_TOKEN=3a1b48c656a57cdd02824699a1352f8a0648e9b41f3df18323b8c48bab22b5ce bundle exec rake test
|
12
|
+
branches:
|
13
|
+
- "master"
|
data/Gemfile
ADDED
data/HISTORY.md
ADDED
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# argparser
|
2
|
-
|
2
|
+
Yet another ruby command line argument parser library.
|
3
|
+
|
4
|
+
[![Build Status](https://travis-ci.org/sinm/argparser.svg?branch=master)](https://travis-ci.org/sinm/argparser) [![Gem Version](https://badge.fury.io/rb/argparser.svg)](http://badge.fury.io/rb/argparser) [![Dependency Status](https://gemnasium.com/sinm/argparser.svg)](https://gemnasium.com/sinm/argparser) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/sinm/argparser/master/LICENSE.txt) [![Code Climate](https://codeclimate.com/github/sinm/argparser/badges/gpa.svg)](https://codeclimate.com/github/sinm/argparser) [![Test Coverage](https://codeclimate.com/github/sinm/argparser/badges/coverage.svg)](https://codeclimate.com/github/sinm/argparser) [![Inline docs](http://inch-ci.org/github/sinm/argparser.svg?branch=master)](http://inch-ci.org/github/sinm/argparser)
|
3
5
|
|
4
6
|
## Installation
|
5
|
-
`gem install argparser
|
7
|
+
`gem install argparser` as usual.
|
6
8
|
|
7
9
|
## Usage by example
|
8
10
|
Suppose there's a file named `example.rb` like this:
|
@@ -41,6 +43,8 @@ puts args['mode'].value.inspect # So we could use our options...
|
|
41
43
|
puts args['file'].value # Prints contents of a file
|
42
44
|
````
|
43
45
|
|
46
|
+
This file located here: `lib/argparser/examples/example.rb`.
|
47
|
+
|
44
48
|
Now, let's look at the output of example given in various cases.
|
45
49
|
|
46
50
|
`$ ruby example.rb` is unsufficient:
|
@@ -82,12 +86,12 @@ Unknown option: a
|
|
82
86
|
````
|
83
87
|
|
84
88
|
## Consider more rules
|
85
|
-
* `--help` and `--version` options provided for free unless specified
|
86
|
-
* printed
|
89
|
+
* `--help` and `--version` options provided for free unless specified
|
90
|
+
* printed synopsis provided for free unless specified
|
87
91
|
* `:default` used if option has :argument and no value given, lowest priority
|
88
92
|
* `:env => 'ENV_VAR'` to pick default value from ENV, high priority
|
89
93
|
* `:eval => 'ruby expr'` to pick default from eval(...), useful for read defaults from config files, so it has low priority
|
90
|
-
*
|
94
|
+
* `--` argument honored
|
91
95
|
|
92
96
|
## Documentation
|
93
97
|
This README is all i could say in a rush. No other documentation provided at this moment, see the sources.
|
@@ -97,6 +101,3 @@ Don't hesistate to leave a report.
|
|
97
101
|
|
98
102
|
## License
|
99
103
|
MIT for now.
|
100
|
-
|
101
|
-
## TODO
|
102
|
-
* Go steal milk for the hazards applied.
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
Rake::TestTask.new :test do |t|
|
5
|
+
# t.test_files = FileList['spec/*_spec.rb']
|
6
|
+
t.pattern = 'spec/**/*_spec.rb'
|
7
|
+
t.libs.push 'spec'
|
8
|
+
end
|
9
|
+
|
10
|
+
task :build do
|
11
|
+
system('gem build argparser.gemspec')
|
12
|
+
# gem push argparser-1.0.0.gem
|
13
|
+
# gem uninstall argparser
|
14
|
+
# gem install argparser-1.0.0.gem
|
15
|
+
end
|
16
|
+
|
17
|
+
task :default => :test
|
data/argparser.gemspec
CHANGED
@@ -1,19 +1,22 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
Gem::Specification.new do |
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = 'argparser'
|
4
|
+
s.version = '1.0.1'
|
5
|
+
s.authors = ['sinm']
|
6
|
+
s.email = 'sinm.sinm@gmail.com'
|
7
|
+
s.summary = 'Yet another ruby command line argument parser library'
|
8
|
+
s.description = '== Yet another ruby command line argument parser library'
|
9
|
+
s.homepage = 'https://github.com/sinm/argparser'
|
10
|
+
s.license = 'MIT'
|
11
|
+
s.files = `git ls-files -z`.split("\x0")
|
12
|
+
s.test_files = `git ls-files -z spec/`.split("\0")
|
13
|
+
s.require_paths = ['lib']
|
14
|
+
# s.extra_rdoc_files = 'README.md'
|
15
|
+
# s.rdoc_options << '--title' << 'argparser' <<
|
16
|
+
# '--main' << 'README' <<
|
17
|
+
# '--markup' << 'markdown' <<
|
18
|
+
# '--line-numbers'
|
19
|
+
s.add_development_dependency 'bundler', '~> 1'
|
20
|
+
s.add_development_dependency 'rake', '~> 10'
|
21
|
+
s.add_development_dependency 'minitest', '~> 4'
|
19
22
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
{
|
2
|
+
"folders":
|
3
|
+
[
|
4
|
+
{
|
5
|
+
"path": "."
|
6
|
+
}
|
7
|
+
],
|
8
|
+
"build_systems":
|
9
|
+
[
|
10
|
+
{
|
11
|
+
"name": "Run tests",
|
12
|
+
"cmd": ["bundle", "exec", "rake", "test"],
|
13
|
+
"selector": "source.rb"
|
14
|
+
}
|
15
|
+
],
|
16
|
+
"settings":
|
17
|
+
{
|
18
|
+
"ensure_newline_at_eof_on_save": true,
|
19
|
+
"rulers":
|
20
|
+
[
|
21
|
+
80
|
22
|
+
],
|
23
|
+
"tab_size": 2,
|
24
|
+
"translate_tabs_to_spaces": true,
|
25
|
+
"trim_trailing_white_space_on_save": true
|
26
|
+
}
|
27
|
+
}
|
data/lib/argparser.rb
CHANGED
@@ -1,28 +1,16 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
def hash2vars!(hash)
|
4
|
-
hash.each do |k, v|
|
5
|
-
next unless self.respond_to?(k)
|
6
|
-
instance_variable_set("@#{k}", v)
|
7
|
-
end
|
8
|
-
end
|
1
|
+
# coding: utf-8
|
2
|
+
require 'stringio'
|
9
3
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
hash }
|
14
|
-
end
|
15
|
-
|
16
|
-
def safe_return(str)
|
17
|
-
eval(str)
|
18
|
-
rescue Exception
|
19
|
-
# intentionally left blank
|
20
|
-
end
|
21
|
-
end
|
4
|
+
require 'argparser/tools'
|
5
|
+
require 'argparser/option'
|
6
|
+
require 'argparser/default_parser'
|
22
7
|
|
23
8
|
class ArgParser
|
24
|
-
include
|
25
|
-
|
9
|
+
include Tools
|
10
|
+
include DefaultParser
|
11
|
+
|
12
|
+
# Output messages used in the #terminate method
|
13
|
+
OUT_VERSION = '%s%s %s'
|
26
14
|
OUT_COPYRIGHT = 'Copyright (C) %s'
|
27
15
|
OUT_LICENSE = 'License: %s'
|
28
16
|
OUT_HOMEPAGE = '%s home page: %s'
|
@@ -40,7 +28,7 @@ class ArgParser
|
|
40
28
|
OUT_OPTION_EXPECTED = 'Expected option: %s'
|
41
29
|
OUT_ARGUMENT_EXPECTED = 'Expected argument: %s'
|
42
30
|
OUT_UNIQUE_NAME = 'Option name should be unique: %s'
|
43
|
-
|
31
|
+
OUT_INVALID_OPTION = 'Invalid value for option: %s'
|
44
32
|
OPT_ENOUGH = '--'
|
45
33
|
|
46
34
|
# These options don't display their synopsis and given for free unless
|
@@ -49,76 +37,6 @@ class ArgParser
|
|
49
37
|
OPT_VERSION = 'version'
|
50
38
|
OPTS_RESERVED = [OPT_HELP, OPT_VERSION]
|
51
39
|
|
52
|
-
class Option
|
53
|
-
include Tulz
|
54
|
-
attr_reader :names # Names of an option (short, long, etc.)
|
55
|
-
attr_reader :argument # Name of an argument, if present
|
56
|
-
attr_reader :help # Help string for an option
|
57
|
-
attr_reader :validate # Lambda(option, parser) to validate an option
|
58
|
-
attr_reader :default # Default value for an option
|
59
|
-
attr_reader :input # Option is an input argument
|
60
|
-
attr_reader :required # Option required
|
61
|
-
attr_reader :multiple # Option may occure multiple times
|
62
|
-
attr_reader :count # Option occucences
|
63
|
-
attr_reader :env # Default option set by this ENV VAR, if any
|
64
|
-
attr_reader :eval # Default option set by this eval,
|
65
|
-
# superseded by :env, if any
|
66
|
-
# So, in order: value - env - eval - default
|
67
|
-
attr_accessor :value # Values of an option, Array if multiple
|
68
|
-
|
69
|
-
def name
|
70
|
-
names.first
|
71
|
-
end
|
72
|
-
|
73
|
-
def initialize(o_manifest)
|
74
|
-
hash2vars!(o_manifest)
|
75
|
-
@names = Array(names).map(&:to_s).sort{|n1, n2| n1.size <=> n2.size}
|
76
|
-
@value = [] if multiple
|
77
|
-
@count = 0
|
78
|
-
end
|
79
|
-
|
80
|
-
def set_value(v)
|
81
|
-
@count += 1
|
82
|
-
multiple ? (@value << v).flatten! : @value = v
|
83
|
-
end
|
84
|
-
|
85
|
-
def value?
|
86
|
-
multiple ? !value.compact.empty? : !!value
|
87
|
-
end
|
88
|
-
|
89
|
-
def to_s
|
90
|
-
str = ''
|
91
|
-
str += (count ? count.to_s : ' ')
|
92
|
-
str += (argument ? 'A' : ' ')
|
93
|
-
str += (validate ? 'V' : ' ')
|
94
|
-
str += (default ? 'D' : ' ')
|
95
|
-
str += (input ? 'I' : ' ')
|
96
|
-
str += (required ? 'R' : ' ')
|
97
|
-
str += (multiple ? 'M' : ' ')
|
98
|
-
str += " #{names.inspect}"
|
99
|
-
str += " #{value.inspect}" if value
|
100
|
-
end
|
101
|
-
|
102
|
-
def synopsis
|
103
|
-
if input
|
104
|
-
s = name.dup
|
105
|
-
s << '...' if multiple
|
106
|
-
s = "[#{s}]" if !required
|
107
|
-
return s
|
108
|
-
else
|
109
|
-
s = names.map{|n| n.size == 1 ? "-#{n}" : "--#{n}"}.join(', ')
|
110
|
-
s << " #{argument}" if argument
|
111
|
-
s = "[#{s}]" if !required
|
112
|
-
s << '...' if multiple
|
113
|
-
return s
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def validate!(parser)
|
118
|
-
!validate || validate.call(self, parser)
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
40
|
attr_reader :program # Program name, REQUIRED
|
123
41
|
attr_reader :package # Set to nil if there's no package
|
124
42
|
attr_reader :version # Follow semantic versioning rules, REQUIRED
|
@@ -129,9 +47,10 @@ class ArgParser
|
|
129
47
|
attr_reader :homepage # Package or, if absent, program's home page
|
130
48
|
attr_reader :synopsis # Print this if present or construct from options
|
131
49
|
attr_reader :help # Print this if present or construct from options
|
132
|
-
attr_reader :options #
|
133
|
-
# see ArgParser::Option class'
|
50
|
+
attr_reader :options # Array of options,
|
51
|
+
# see ArgParser::Option class' attr_readers
|
134
52
|
|
53
|
+
# Returns option by any of its names given
|
135
54
|
def [](name)
|
136
55
|
options.find{|o| o.names.include?(name)}
|
137
56
|
end
|
@@ -142,13 +61,10 @@ class ArgParser
|
|
142
61
|
end
|
143
62
|
|
144
63
|
def initialize(manifest)
|
145
|
-
manifest = {
|
146
|
-
:options => []
|
147
|
-
}.merge(safe_return('$config.manifest') || {}).merge(manifest)
|
64
|
+
manifest = (safe_return('$config.manifest') || {}).merge(manifest)
|
148
65
|
hash2vars!(manifest)
|
149
|
-
@options = (manifest[:options] || manifest['options'] ||
|
150
|
-
Option.new(o)
|
151
|
-
end
|
66
|
+
@options = (manifest[:options] || manifest['options'] || []).
|
67
|
+
map {|o| o.kind_of?(Option) ? o : Option.new(o)}
|
152
68
|
if !self['help']
|
153
69
|
options << Option.new(:names => OPT_HELP,
|
154
70
|
:help => 'Print this help and exit.',
|
@@ -165,190 +81,50 @@ class ArgParser
|
|
165
81
|
end
|
166
82
|
end
|
167
83
|
|
168
|
-
def
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
end
|
174
|
-
|
175
|
-
is = inputs
|
176
|
-
is.each_with_index do |i, index|
|
177
|
-
if index < is.length-1 and i.multiple
|
178
|
-
terminate(2, OUT_MULTIPLE_INPUTS % i.name)
|
179
|
-
end
|
180
|
-
if i.names.size > 1
|
181
|
-
terminate(2, OUT_MULTIPLE_NAMES % i.name)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
first_optional = is.index{|i| !i.required} || is.size
|
185
|
-
last_required = is.rindex{|i| i.required} || 0
|
186
|
-
if last_required > first_optional
|
187
|
-
terminate(2, OUT_REQUIRED % is[last_required].name)
|
188
|
-
end
|
189
|
-
|
190
|
-
names = {}
|
191
|
-
options.each do |option|
|
192
|
-
option.names.each do |name|
|
193
|
-
if name.strip.empty?
|
194
|
-
terminate(2, OUT_OPTION_NULL)
|
195
|
-
end
|
196
|
-
if names.has_key?(name)
|
197
|
-
terminate(2, OUT_UNIQUE_NAME % name)
|
198
|
-
end
|
199
|
-
names[name] = option
|
200
|
-
end
|
201
|
-
if option.required && option.default
|
202
|
-
terminate(2, OUT_REQUIRED_DEFAULT % option.name)
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
OPTS_RESERVED.each { |o|
|
207
|
-
next unless arguments.include?("--#{o}")
|
208
|
-
o = self[o]
|
209
|
-
o.set_value(nil)
|
210
|
-
o.validate!(self)
|
211
|
-
}
|
212
|
-
|
213
|
-
args = arguments.dup
|
214
|
-
enough = false
|
215
|
-
while (a = args.shift)
|
216
|
-
if a == OPT_ENOUGH
|
217
|
-
enough = true
|
218
|
-
elsif enough || (a =~ /^[^-]/) || (a == '-') # input argument
|
219
|
-
if (input = inputs.find{|i| !i.value || i.multiple})
|
220
|
-
input.set_value(a)
|
221
|
-
else
|
222
|
-
terminate(2, OUT_UNEXPECTED_ARGUMENT % a)
|
223
|
-
end
|
224
|
-
elsif a =~ /^--(.+)/ # long option
|
225
|
-
if $1.size > 1 && option = self[$1]
|
226
|
-
if option.argument
|
227
|
-
if args.empty?
|
228
|
-
terminate(2, $stderr.puts(OUT_OPTION_ARGUMENT_EXPECTED % a))
|
229
|
-
end
|
230
|
-
option.set_value(args.shift)
|
231
|
-
else
|
232
|
-
option.set_value(nil)
|
233
|
-
end
|
234
|
-
else
|
235
|
-
terminate(2, OUT_UNKNOWN_OPTION % $1)
|
236
|
-
end
|
237
|
-
elsif a =~ /^-([^-].*)/ # short option, may combine and has an arg at end
|
238
|
-
(opts = $1).chars.to_a.each_with_index do |char, index|
|
239
|
-
if (option = self[char])
|
240
|
-
if option.argument
|
241
|
-
if opts.size-1 == index
|
242
|
-
if args.empty?
|
243
|
-
terminate(2, OUT_OPTION_ARGUMENT_EXPECTED % a)
|
244
|
-
else
|
245
|
-
option.set_value(args.shift)
|
246
|
-
end
|
247
|
-
else
|
248
|
-
option.set_value(opts[index+1..-1])
|
249
|
-
break
|
250
|
-
end
|
251
|
-
else
|
252
|
-
option.set_value(nil)
|
253
|
-
end
|
254
|
-
else
|
255
|
-
terminate(2, OUT_UNKNOWN_OPTION % char)
|
256
|
-
end
|
257
|
-
end
|
258
|
-
else
|
259
|
-
terminate(2, OUT_UNKNOWN_OPTION % a)
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
options.each do |option|
|
264
|
-
if !option.value? && (option.argument || option.input) &&
|
265
|
-
((option.env && (e = ENV[option.env])) ||
|
266
|
-
(option.eval && (e = safe_return(option.eval))) ||
|
267
|
-
(!!option.default && (e = option.default)))
|
268
|
-
option.set_value(e)
|
269
|
-
end
|
270
|
-
if !option.multiple && option.count > 1
|
271
|
-
terminate(2, OUT_SINGLE_OPTION % option.name)
|
272
|
-
elsif option.required && option.count < 1
|
273
|
-
if option.input
|
274
|
-
terminate(2, OUT_ARGUMENT_EXPECTED % option.name)
|
275
|
-
else
|
276
|
-
terminate(2, OUT_OPTION_EXPECTED % option.name)
|
277
|
-
end
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
|
-
options.each { |o|
|
282
|
-
next if o.validate!(self)
|
283
|
-
terminate(2, INVALID_OPTION % o.name)
|
284
|
-
}
|
285
|
-
self
|
84
|
+
def terminate(code, str)
|
85
|
+
s = StringIO.new
|
86
|
+
s.puts(printed_synopsis) if code != 0
|
87
|
+
s.puts(str[-1] == "\n" ? str.chop : str)
|
88
|
+
on_exit(code, s.string)
|
286
89
|
end
|
287
90
|
|
288
|
-
def
|
289
|
-
|
290
|
-
|
291
|
-
if str
|
292
|
-
stream.print(str)
|
293
|
-
stream.puts() unless str[-1] == "\n"
|
294
|
-
end
|
295
|
-
exit!(code)
|
91
|
+
def on_exit(code, message)
|
92
|
+
(code == 0 ? $stdout : $stderr).print(message)
|
93
|
+
exit(code)
|
296
94
|
end
|
297
95
|
|
298
96
|
def printed_version
|
299
|
-
|
300
|
-
|
301
|
-
str
|
302
|
-
str
|
303
|
-
str
|
97
|
+
str = StringIO.new
|
98
|
+
pk = (pk = @package) ? " (#{pk})" : ''
|
99
|
+
str.puts(OUT_VERSION % [program, pk, version])
|
100
|
+
str.puts(OUT_COPYRIGHT % copyright) if copyright
|
101
|
+
str.puts(OUT_LICENSE % license) if license
|
102
|
+
str.string
|
304
103
|
end
|
305
104
|
|
306
105
|
def printed_help
|
307
|
-
str =
|
308
|
-
str
|
106
|
+
str = StringIO.new
|
107
|
+
str.puts(printed_synopsis)
|
108
|
+
str.puts(info) if info
|
309
109
|
if help
|
310
|
-
str
|
110
|
+
str.puts(help)
|
311
111
|
else
|
312
|
-
|
313
|
-
|
314
|
-
next unless h = o.help
|
315
|
-
h << "\n\tDefaults to: #{o.default}" if o.default
|
316
|
-
opts << [o.synopsis, h]
|
317
|
-
end
|
318
|
-
inputs.each do |i|
|
319
|
-
next unless i.help
|
320
|
-
help = i.help
|
321
|
-
help << "\n\tDefaults to: #{i.default}" if i.default
|
322
|
-
opts << [i.synopsis, help]
|
323
|
-
end
|
324
|
-
opts.each do |o|
|
325
|
-
str << "%s\n\t%s\n" % [o.first, o.last]
|
112
|
+
(options.select{|o| !o.input} + inputs).each do |o|
|
113
|
+
str.puts(o.printed_help)
|
326
114
|
end
|
327
115
|
# term_width = ENV['COLUMNS'] || `tput columns` || 80
|
328
|
-
#
|
329
|
-
# help_width = term_width - (
|
116
|
+
# width = opts.reduce(0){|max, o| (sz = o.first.size) > max ? sz : max}
|
117
|
+
# help_width = term_width - (width += 1)
|
330
118
|
# if help_width < 32...
|
331
119
|
end
|
332
|
-
str
|
333
|
-
|
334
|
-
str
|
335
|
-
str
|
120
|
+
str.puts(OUT_BUGS % bugs) if bugs
|
121
|
+
str.puts(OUT_HOMEPAGE % [(package||program), homepage]) if homepage
|
122
|
+
str.string
|
336
123
|
end
|
337
124
|
|
338
125
|
def printed_synopsis
|
339
126
|
s = synopsis ||
|
340
|
-
(options.select{|o| !o.input} + inputs).map{|o|
|
341
|
-
|
342
|
-
"#{program} #{s}"
|
343
|
-
end
|
344
|
-
|
345
|
-
if __FILE__ == $0 # Some selftests... while hakin in an editor
|
346
|
-
$stdout.sync = true
|
347
|
-
$stderr.sync = true
|
348
|
-
ARGV = %w[--abcm first]
|
349
|
-
example = File.read('argparser/examples/example.rb')
|
350
|
-
example = example.split("\n")[1..-1].join("\n") # Cut 'require' string
|
351
|
-
eval(example) # Last line
|
127
|
+
(options.select{|o| !o.input} + inputs).map{|o| o.synopsis}.join(' ')
|
128
|
+
"Usage: #{program} #{s}"
|
352
129
|
end
|
353
|
-
|
354
|
-
end # the very end
|
130
|
+
end
|