ark-cli 0.4.4 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +180 -0
- data/lib/ark/cli.rb +9 -487
- data/lib/ark/cli/interface.rb +173 -0
- data/lib/ark/cli/option.rb +118 -0
- data/lib/ark/cli/report.rb +32 -0
- data/lib/ark/cli/spec.rb +183 -0
- metadata +15 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40d1e78d63af56864533187b51ab27bdf514cdcd
|
4
|
+
data.tar.gz: 7cc02dba83f021e537314dfccc03bc77592e39c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b80df1a67863e975e5d46633e9128a6fd6392a2bd1233e0b905e09d5b1158c347185ec12987561a6cc16229a8fa947dbacf1b7e3fd7a501e191e248280d7329b
|
7
|
+
data.tar.gz: c710c95aed57880c6a3f5cf01331f859ab766ef10850950466567725b1a14c36718ba0226ed08b30479fb86f78367df3b59ce75be726d265190e16906d92eccf
|
data/README.md
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
# ark-cli
|
2
|
+
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/ark-cli.svg)](http://badge.fury.io/rb/ark-cli)
|
4
|
+
|
5
|
+
__ark-cli__ is a Ruby library for handling command line options and
|
6
|
+
arguments. See below for basic usage. Full documentation can be found at
|
7
|
+
http://www.rubydoc.info/github/grimheart/ark-cli
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
## Declaring an interface
|
12
|
+
|
13
|
+
The usual way to use ark-cli is to call `Ark::CLI.report`. This convenience
|
14
|
+
method builds a new interface and returns a `Report` object for inspection.
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
require 'ark/cli'
|
18
|
+
|
19
|
+
# Declare an interface and parse the command line
|
20
|
+
# Returns a Report instance for inspection as `r`
|
21
|
+
r = Ark::CLI.report do |s|
|
22
|
+
s.name 'example'
|
23
|
+
s.args 'host', 'path'
|
24
|
+
s.desc "An example demonstrating usage of ark-cli"
|
25
|
+
|
26
|
+
s.opt :verbose, :v,
|
27
|
+
desc: "Increase verbosity"
|
28
|
+
|
29
|
+
s.opt :port, :p,
|
30
|
+
args: 'number',
|
31
|
+
desc: "Specify an alternate port number"
|
32
|
+
end
|
33
|
+
|
34
|
+
r.args # Get all arguments received, including trailing args
|
35
|
+
r.arg[:host] # Get the value of the `host` argument
|
36
|
+
r.opt[:port] # Get the value of the `port` option
|
37
|
+
r.count[:v] # Get the number of times an option was toggled
|
38
|
+
```
|
39
|
+
|
40
|
+
The `CLI.report` method yields a `Spec` instance, which we'll call `s`. Calls to
|
41
|
+
this instance will define how the command line is parsed. The online usage
|
42
|
+
information will also be generated from this spec.
|
43
|
+
|
44
|
+
`s` has four important methods:
|
45
|
+
|
46
|
+
### Name and description
|
47
|
+
|
48
|
+
The `name` method sets the name of the program to use in usage information. It
|
49
|
+
expects a string. This should probably be the same as the name of the
|
50
|
+
executable.
|
51
|
+
|
52
|
+
The `desc` method sets a description of the program for generating usage
|
53
|
+
information. It expects a string.
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
s.name 'example'
|
57
|
+
s.desc "An example demonstrating usage of ark-cli"
|
58
|
+
```
|
59
|
+
|
60
|
+
### Declaring arguments
|
61
|
+
|
62
|
+
The `args` method defines what arguments the program will expect.
|
63
|
+
|
64
|
+
Declaring two named, expected arguments:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
s.args 'host', 'port'
|
68
|
+
```
|
69
|
+
|
70
|
+
Declare defaults with a colon after the argument name, like `'host:localhost'`.
|
71
|
+
Arguments with default values are optional - no error will be raised if they
|
72
|
+
aren't given.
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
s.args 'file:~/.dcf'
|
76
|
+
s.args 'host', 'port:22', "user:#{ENV['USER']}"
|
77
|
+
```
|
78
|
+
|
79
|
+
Declaring a variadic interface with a glob, `'dest...'`
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
s.args 'target', 'dest...'
|
83
|
+
```
|
84
|
+
|
85
|
+
### Declaring options
|
86
|
+
|
87
|
+
The `opt` method defines options.
|
88
|
+
|
89
|
+
Flags are simple options without arguments:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
s.opt :verbose, :v,
|
93
|
+
desc: "Increase verbosity"
|
94
|
+
```
|
95
|
+
|
96
|
+
Flags are false by default and set true when given on the command line. A count
|
97
|
+
is kept of the number of times the flag was specified, and stored in the report
|
98
|
+
as `r.count`. The `desc` field is used to generate usage information.
|
99
|
+
|
100
|
+
Options can also take arguments:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
s.opt :port, :p,
|
104
|
+
args: 'number',
|
105
|
+
desc: "Specify an alternate port number"
|
106
|
+
```
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
## Inspecting the `Report` object
|
111
|
+
|
112
|
+
The `Ark::CLI#report` method returns a `Report` instance which we can inspect
|
113
|
+
for information parsed from the command line.
|
114
|
+
|
115
|
+
Supposing `r` is a returned `Report` instance, we can get all arguments with the
|
116
|
+
`r.args` method. This will include any trailing arguments.
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
host, path = r.args
|
120
|
+
```
|
121
|
+
|
122
|
+
Get the value of a named argument with the `r.arg` method:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
host = r.arg[:host]
|
126
|
+
path = r.arg[:path]
|
127
|
+
```
|
128
|
+
|
129
|
+
Inspect the value of an option with `r.opt`:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
verbose = r.opt[:v]
|
133
|
+
port = r.opt[:port]
|
134
|
+
```
|
135
|
+
|
136
|
+
Get a count of the number of times a flag was specified with `r.count`:
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
verbosity = r.count[:verbose]
|
140
|
+
```
|
141
|
+
|
142
|
+
Get an array of trailing arguments with `r.trailing`:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
path1, path2 = r.trailing
|
146
|
+
```
|
147
|
+
|
148
|
+
|
149
|
+
|
150
|
+
## Usage information
|
151
|
+
|
152
|
+
A help option is defined for all interfaces with the `-h` and `--help` flags.
|
153
|
+
When the help option is given, the program will print usage information and exit
|
154
|
+
immediately. Usage information is constructed from the `Spec` built during the
|
155
|
+
CLI declaration.
|
156
|
+
|
157
|
+
Usage information for the above declaration would look like this:
|
158
|
+
|
159
|
+
example [OPTION...] HOST PATH
|
160
|
+
|
161
|
+
An example demonstrating usage of ark-cli
|
162
|
+
|
163
|
+
OPTIONS:
|
164
|
+
|
165
|
+
-h --help
|
166
|
+
Print usage information
|
167
|
+
|
168
|
+
-v --verbose
|
169
|
+
Increase verbosity
|
170
|
+
|
171
|
+
-p --port NUMBER
|
172
|
+
Specify an alternate port number
|
173
|
+
|
174
|
+
|
175
|
+
|
176
|
+
## Example script
|
177
|
+
|
178
|
+
A working example script with comments can be found at `example/hello.rb` --
|
179
|
+
invoke the script with the `--help` option for usage information.
|
180
|
+
|
data/lib/ark/cli.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# ark-cli - a
|
1
|
+
# ark-cli - a command line interface library for Ruby
|
2
2
|
# Copyright 2015 Macquarie Sharpless <macquarie.sharpless@gmail.com>
|
3
3
|
#
|
4
4
|
# This program is free software: you can redistribute it and/or modify
|
@@ -18,6 +18,11 @@
|
|
18
18
|
require 'ark/utility'
|
19
19
|
include Ark::Log
|
20
20
|
|
21
|
+
require_relative 'cli/interface.rb'
|
22
|
+
require_relative 'cli/option.rb'
|
23
|
+
require_relative 'cli/spec.rb'
|
24
|
+
require_relative 'cli/report.rb'
|
25
|
+
|
21
26
|
|
22
27
|
module Ark # :nodoc:
|
23
28
|
|
@@ -25,499 +30,16 @@ module Ark # :nodoc:
|
|
25
30
|
#
|
26
31
|
# Call #begin to define a new interface and parse the command line. See
|
27
32
|
# +README.md+ or +example/hello.rb+ for more information.
|
28
|
-
|
29
|
-
# Represents an option and stores the option's current state, as well as
|
30
|
-
# usage information.
|
31
|
-
class Option
|
32
|
-
# Initialize a new Option instance
|
33
|
-
# [+keys+] A list of names this option will be identified by
|
34
|
-
# [+args+] A list of argument named this option will expect
|
35
|
-
# [+desc+] A short description of this option
|
36
|
-
def initialize(long, short=nil, args=nil, desc=nil)
|
37
|
-
@long = long
|
38
|
-
@short = short
|
39
|
-
@args = args || []
|
40
|
-
@vals = []
|
41
|
-
@flag = false
|
42
|
-
@count = 0
|
43
|
-
@desc = desc || ''
|
44
|
-
end
|
45
|
-
# A count of how many times this option has been given on the command line.
|
46
|
-
# Useful for flags that might be specified repeatedly, like +-vvv+ to raise
|
47
|
-
# verbosity three times.
|
48
|
-
attr_reader :count
|
49
|
-
# A short description of the option, if given
|
50
|
-
attr_reader :desc
|
51
|
-
# Long name for this option
|
52
|
-
attr_reader :long
|
53
|
-
# Short name for this option
|
54
|
-
attr_reader :short
|
55
|
-
|
56
|
-
# Return the number of arguments this option expects
|
57
|
-
def arity()
|
58
|
-
return @args.length
|
59
|
-
end
|
60
|
-
|
61
|
-
# Return a count of how many arguments this option still expects
|
62
|
-
def vals_needed()
|
63
|
-
if self.flag?
|
64
|
-
return 0
|
65
|
-
else
|
66
|
-
return @args.length - @vals.length
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# True if this option has received all the arguments it expects, or if this
|
71
|
-
# option expects no arguments
|
72
|
-
def full?
|
73
|
-
return self.vals_needed == 0
|
74
|
-
end
|
75
|
-
|
76
|
-
# True if this option expects no arguments; opposite of #has_args?
|
77
|
-
def flag?
|
78
|
-
return @args.empty?
|
79
|
-
end
|
80
|
-
|
81
|
-
# Toggle this option to the true state and increment the toggle count. Only
|
82
|
-
# valid for options which expect no argument (flags). Attempting to toggle
|
83
|
-
# a option with expected arguments will raise an error.
|
84
|
-
def toggle()
|
85
|
-
if self.flag?
|
86
|
-
@count += 1
|
87
|
-
@flag = true
|
88
|
-
else
|
89
|
-
raise StandardError, "Tried to toggle an option which expects an argument"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Pass an argument +arg+ to this option
|
94
|
-
def push(arg)
|
95
|
-
@vals << arg
|
96
|
-
end
|
97
|
-
|
98
|
-
# Return the current value of this option
|
99
|
-
def value()
|
100
|
-
if self.flag?
|
101
|
-
return @flag
|
102
|
-
else
|
103
|
-
if self.full? && @vals.length == 1
|
104
|
-
return @vals[0]
|
105
|
-
elsif self.full?
|
106
|
-
return @vals
|
107
|
-
else
|
108
|
-
return nil
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
# True if this option expects an argument. Opposite of #flag?
|
114
|
-
def has_args?
|
115
|
-
return @args.length > 0
|
116
|
-
end
|
117
|
-
|
118
|
-
# Return basic usage information: the option's names and arguments
|
119
|
-
def header()
|
120
|
-
if self.flag?
|
121
|
-
args = ''
|
122
|
-
else
|
123
|
-
args = ' ' + @args.join(', ').upcase
|
124
|
-
end
|
125
|
-
short = @short ? "-#{@short} " : ''
|
126
|
-
return "#{short}--#{@long}#{args}"
|
127
|
-
end
|
128
|
-
|
129
|
-
# Represent this option as a string
|
130
|
-
def to_s()
|
131
|
-
return "(#{self.header})"
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
|
136
|
-
class CLI
|
137
|
-
|
138
|
-
# Raised when the command line is malformed
|
139
|
-
class SyntaxError < ArgumentError
|
140
|
-
end
|
141
|
-
|
33
|
+
module CLI
|
142
34
|
# Convenience method for interface declarations. Yields the CLI instance and
|
143
35
|
# then returns it after parsing. Equivalent to instantiating a CLI instance
|
144
36
|
# with #new, modifying it, and then calling #parse
|
145
37
|
#
|
146
38
|
# +args+ is an array of strings, which defaults to ARGV
|
147
39
|
def self.report(args=ARGV, &block)
|
148
|
-
|
149
|
-
return
|
150
|
-
end
|
151
|
-
|
152
|
-
# Initialize a CLI instance.
|
153
|
-
#
|
154
|
-
# +args+ must be an array of strings, like ARGV
|
155
|
-
def initialize(args, &block)
|
156
|
-
self.rebuild(args, &block)
|
157
|
-
end
|
158
|
-
|
159
|
-
attr_reader :report
|
160
|
-
|
161
|
-
def rebuild(input=ARGV, &block)
|
162
|
-
@input = input
|
163
|
-
@spec = Spec.new
|
164
|
-
yield @spec
|
165
|
-
@spec.opt :help, :h, desc: "Print usage information"
|
166
|
-
self.parse
|
167
|
-
end
|
168
|
-
|
169
|
-
# Parse the command line
|
170
|
-
def parse()
|
171
|
-
taking_options = true
|
172
|
-
last_opt = nil
|
173
|
-
refargs = @spec.get_args.clone
|
174
|
-
|
175
|
-
@report = Report.new()
|
176
|
-
|
177
|
-
@input.each do |word|
|
178
|
-
dbg "Parsing '#{word}'"
|
179
|
-
if last_opt && last_opt.has_args? && !last_opt.full?
|
180
|
-
dbg "Got argument '#{word}' for '#{last_opt}'", 1
|
181
|
-
last_opt.push(word)
|
182
|
-
else
|
183
|
-
if word[/^-/] && taking_options
|
184
|
-
if word[/^-[^-]/]
|
185
|
-
dbg "Identified short option(s)", 1
|
186
|
-
shorts = word[/[^-]+$/].split('')
|
187
|
-
shorts.each_with_index do |short, i|
|
188
|
-
last_short = i == (shorts.length - 1)
|
189
|
-
opt = @spec.get_opt(short)
|
190
|
-
last_opt = opt
|
191
|
-
if opt.has_args? && shorts.length > 1 && !last_short
|
192
|
-
raise SyntaxError, "Error: -#{short} in compound option '#{word}' expects an argument"
|
193
|
-
elsif opt.flag?
|
194
|
-
opt.toggle()
|
195
|
-
dbg "Toggled flag '#{opt}'", 1
|
196
|
-
end
|
197
|
-
end
|
198
|
-
elsif word[/^--/]
|
199
|
-
dbg "Identified long option", 1
|
200
|
-
key = word[/[^-]+$/]
|
201
|
-
opt = @spec.get_opt(key)
|
202
|
-
last_opt = opt
|
203
|
-
if opt.flag?
|
204
|
-
opt.toggle()
|
205
|
-
dbg "Toggled #{opt}", 1
|
206
|
-
end
|
207
|
-
end
|
208
|
-
else
|
209
|
-
dbg "Parsed output arg", 1
|
210
|
-
taking_options = false
|
211
|
-
@report.args << word
|
212
|
-
key = refargs.shift
|
213
|
-
if key
|
214
|
-
if key == @spec.get_variad
|
215
|
-
@report.arg[key] = []
|
216
|
-
@report.arg[key] << word
|
217
|
-
else
|
218
|
-
@report.arg[key] = word
|
219
|
-
end
|
220
|
-
elsif @spec.is_variadic?
|
221
|
-
@report.arg[@spec.get_variad] << word
|
222
|
-
else
|
223
|
-
@report.trailing << word
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
@spec.get_opts.each do |name, opt|
|
229
|
-
@report.opt[name] = opt.value
|
230
|
-
@report.count[name] = opt.count
|
231
|
-
end
|
232
|
-
@spec.get_args.each do |name|
|
233
|
-
if @report.arg[name].nil?
|
234
|
-
if @spec.has_default?(name)
|
235
|
-
@report.arg[name] = @spec.get_default(name)
|
236
|
-
@report.args << @report.arg[name]
|
237
|
-
end
|
238
|
-
end
|
239
|
-
end
|
240
|
-
if @report.opt[:help]
|
241
|
-
self.print_usage()
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
# Construct usage information
|
246
|
-
def usage()
|
247
|
-
tb = TextBuilder.new()
|
248
|
-
|
249
|
-
tb.next 'USAGE:'
|
250
|
-
tb.push @spec.get_name if @spec.get_name
|
251
|
-
|
252
|
-
tb.push '[OPTION'
|
253
|
-
tb.add '...' if @spec.has_options?
|
254
|
-
tb.add ']'
|
255
|
-
|
256
|
-
if @spec.has_args?
|
257
|
-
if @spec.is_variadic?
|
258
|
-
singles = @spec.get_args[0..-2].map do |a|
|
259
|
-
if @spec.has_default?(a)
|
260
|
-
a = "[#{a}]"
|
261
|
-
end
|
262
|
-
a.upcase
|
263
|
-
end
|
264
|
-
tb.push singles
|
265
|
-
v = @spec.get_args.last.upcase
|
266
|
-
tb.push "[#{v}1 #{v}2...]"
|
267
|
-
else
|
268
|
-
argmap = @spec.get_args.map do |a|
|
269
|
-
if @spec.has_default?(a)
|
270
|
-
a = "[#{a}]"
|
271
|
-
end
|
272
|
-
a.upcase
|
273
|
-
end
|
274
|
-
tb.push argmap
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
if @spec.get_desc
|
279
|
-
tb.skip @spec.get_desc
|
280
|
-
tb.wrap(indent: 4)
|
281
|
-
end
|
282
|
-
|
283
|
-
tb.skip 'OPTIONS:'
|
284
|
-
tb.skip
|
285
|
-
|
286
|
-
@spec.get_opts.values.uniq.each do |opt|
|
287
|
-
tb.indent 4
|
288
|
-
tb.push opt.header
|
289
|
-
if opt.desc
|
290
|
-
tb.next
|
291
|
-
tb.indent 8
|
292
|
-
tb.push opt.desc
|
293
|
-
end
|
294
|
-
tb.skip
|
295
|
-
end
|
296
|
-
|
297
|
-
return tb.print
|
298
|
-
end
|
299
|
-
|
300
|
-
# Print usage information and exit
|
301
|
-
def print_usage()
|
302
|
-
puts self.usage
|
303
|
-
exit 0
|
304
|
-
end
|
305
|
-
end
|
306
|
-
|
307
|
-
class Spec
|
308
|
-
|
309
|
-
# Raised when a nonexistent option is received
|
310
|
-
class NoSuchOptionError < ArgumentError
|
311
|
-
end
|
312
|
-
|
313
|
-
# Raised when there is a syntax error in the args declaration
|
314
|
-
class ArgumentSyntaxError < ArgumentError
|
315
|
-
end
|
316
|
-
|
317
|
-
# Initialize a bare interface spec
|
318
|
-
def initialize()
|
319
|
-
@args = []
|
320
|
-
@options = {}
|
321
|
-
@variadic = false
|
322
|
-
@option_listing = false
|
323
|
-
@trailing_error = false
|
324
|
-
end
|
325
|
-
# If true, the full option list will always be displayed in the usage info
|
326
|
-
# header
|
327
|
-
attr_reader :option_listing
|
328
|
-
# If true, an error will be raised if trailing arguments are given
|
329
|
-
attr_reader :trailing_error
|
330
|
-
|
331
|
-
private
|
332
|
-
|
333
|
-
def strip(arg)
|
334
|
-
return arg[/^(.+?)(\.\.\.$|_$|$)/, 1]
|
335
|
-
end
|
336
|
-
|
337
|
-
def optional?(arg)
|
338
|
-
return !arg[/_$/].nil?
|
339
|
-
end
|
340
|
-
|
341
|
-
def variadic?(arg)
|
342
|
-
return !arg[/\.\.\.$/].nil?
|
343
|
-
end
|
344
|
-
|
345
|
-
def parse_arg(arg, default: nil, last: false)
|
346
|
-
stripped = strip(arg)
|
347
|
-
@args << stripped
|
348
|
-
if optional?(arg)
|
349
|
-
@optional << stripped
|
350
|
-
end
|
351
|
-
unless default.nil?
|
352
|
-
@defaults[stripped] = default
|
353
|
-
end
|
354
|
-
if variadic?(arg)
|
355
|
-
if last
|
356
|
-
@variadic = true
|
357
|
-
@variad = stripped
|
358
|
-
else
|
359
|
-
raise ArgumentSyntaxError,
|
360
|
-
"Variadic arguments must come last. Offending variad is '#{arg}'"
|
361
|
-
end
|
362
|
-
end
|
363
|
-
end
|
364
|
-
|
365
|
-
public
|
366
|
-
|
367
|
-
def get_name
|
368
|
-
return @name
|
369
|
-
end
|
370
|
-
|
371
|
-
def get_desc
|
372
|
-
return @desc
|
373
|
-
end
|
374
|
-
|
375
|
-
def get_args
|
376
|
-
return @args
|
377
|
-
end
|
378
|
-
|
379
|
-
def get_opts
|
380
|
-
return @options
|
381
|
-
end
|
382
|
-
|
383
|
-
def is_variadic?
|
384
|
-
return @variadic
|
385
|
-
end
|
386
|
-
|
387
|
-
def get_variad
|
388
|
-
return @variad
|
389
|
-
end
|
390
|
-
|
391
|
-
def get_defaults
|
392
|
-
return @defaults
|
393
|
-
end
|
394
|
-
|
395
|
-
# Get an Option object for the given option +name+
|
396
|
-
def get_opt(name)
|
397
|
-
name = name.to_sym
|
398
|
-
if !@options.keys.member?(name)
|
399
|
-
raise NoSuchOptionError, "Error, no such option: '#{name}'"
|
400
|
-
end
|
401
|
-
return @options[name]
|
402
|
-
end
|
403
|
-
|
404
|
-
def is_optional?(arg)
|
405
|
-
@optional.member?(arg.to_s)
|
406
|
-
end
|
407
|
-
|
408
|
-
def has_default?(arg)
|
409
|
-
@defaults.key?(arg.to_s)
|
410
|
-
end
|
411
|
-
|
412
|
-
def get_default(arg)
|
413
|
-
@defaults[arg.to_s]
|
40
|
+
i = Interface.new(args, &block)
|
41
|
+
return i.report
|
414
42
|
end
|
415
|
-
|
416
|
-
def has_args?
|
417
|
-
@args.length > 0
|
418
|
-
end
|
419
|
-
|
420
|
-
def has_options?
|
421
|
-
@options.values.uniq.length > 1
|
422
|
-
end
|
423
|
-
|
424
|
-
# Specify general information about the program
|
425
|
-
# [+name+] Name of the program
|
426
|
-
# [+desc+] Short description of the program
|
427
|
-
# [+args+] A list of named arguments
|
428
|
-
def header(name: nil, desc: nil, args: [])
|
429
|
-
self.name(name)
|
430
|
-
self.desc(desc)
|
431
|
-
self.args(args)
|
432
|
-
end
|
433
|
-
|
434
|
-
# Set the name of the program to +str+
|
435
|
-
def name(str)
|
436
|
-
@name = str.to_s if str
|
437
|
-
end
|
438
|
-
|
439
|
-
# Set the description of the program to +str+
|
440
|
-
def desc(str)
|
441
|
-
@desc = str.to_s if str
|
442
|
-
end
|
443
|
-
|
444
|
-
# Define what arguments the program will accept
|
445
|
-
def args(*input)
|
446
|
-
@args = []
|
447
|
-
@optional = []
|
448
|
-
@defaults = {}
|
449
|
-
|
450
|
-
input.flatten.each_with_index do |item, i|
|
451
|
-
list_last = (input.length - (i + 1)) == 0
|
452
|
-
if item.is_a?(Hash)
|
453
|
-
item.each_with_index do |pair,ii|
|
454
|
-
k = pair[0].to_s
|
455
|
-
v = pair[1]
|
456
|
-
hash_last = (item.length - (ii + 1)) == 0
|
457
|
-
last = hash_last && list_last
|
458
|
-
parse_arg(k, default: v, last: last)
|
459
|
-
end
|
460
|
-
else
|
461
|
-
parse_arg(item, last: list_last)
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
|
-
@refargs = @args.clone
|
466
|
-
end
|
467
|
-
|
468
|
-
# Define an Option
|
469
|
-
# [+keys+] A list of names for this option
|
470
|
-
# [+args+] A list of arguments the option expects
|
471
|
-
# [+desc+] A short description of the option, used to provide usage info
|
472
|
-
def opt(long, short=nil, args: nil, desc: nil)
|
473
|
-
long = long.to_sym
|
474
|
-
short = short.to_sym if short
|
475
|
-
args = [args] if args.is_a?(String)
|
476
|
-
args.map!(&:to_sym) if args
|
477
|
-
o = Option.new(long, short, args, desc)
|
478
|
-
@options[long] = o
|
479
|
-
@options[short] = o if short
|
480
|
-
end
|
481
|
-
|
482
|
-
# Force the full option list display in the usage info, no matter how many
|
483
|
-
# options the program has
|
484
|
-
def force_option_list()
|
485
|
-
@option_list = true
|
486
|
-
end
|
487
|
-
|
488
|
-
# The parser will raise an error on finding trailing arguments (default
|
489
|
-
# behavior is to ignore and stuff the trailing args into Report.trailing_args)
|
490
|
-
def raise_on_trailing()
|
491
|
-
@trailing_error = true
|
492
|
-
end
|
493
|
-
|
494
|
-
end
|
495
|
-
|
496
|
-
class Report
|
497
|
-
def initialize()
|
498
|
-
@args = []
|
499
|
-
@named_args = {}
|
500
|
-
@trailing_args = []
|
501
|
-
@counts = {}
|
502
|
-
@options = {}
|
503
|
-
end
|
504
|
-
|
505
|
-
def args
|
506
|
-
return @args
|
507
|
-
end
|
508
|
-
def arg
|
509
|
-
return @named_args
|
510
|
-
end
|
511
|
-
def trailing
|
512
|
-
return @trailing_args
|
513
|
-
end
|
514
|
-
def opt
|
515
|
-
return @options
|
516
|
-
end
|
517
|
-
def count
|
518
|
-
return @counts
|
519
|
-
end
|
520
|
-
|
521
43
|
end
|
522
44
|
|
523
45
|
end # module Ark
|
@@ -0,0 +1,173 @@
|
|
1
|
+
module Ark
|
2
|
+
module CLI
|
3
|
+
|
4
|
+
class Interface
|
5
|
+
|
6
|
+
# Raised when the command line is malformed
|
7
|
+
class SyntaxError < ArgumentError
|
8
|
+
end
|
9
|
+
|
10
|
+
# Initialize an Interface instance.
|
11
|
+
#
|
12
|
+
# +args+ must be an array of strings, like ARGV
|
13
|
+
def initialize(args, &block)
|
14
|
+
self.rebuild(args, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :report
|
18
|
+
|
19
|
+
def rebuild(input=ARGV, &block)
|
20
|
+
@input = input
|
21
|
+
@spec = Spec.new
|
22
|
+
yield @spec
|
23
|
+
@spec.opt :help, :h, desc: "Print usage information"
|
24
|
+
self.parse
|
25
|
+
end
|
26
|
+
|
27
|
+
# Parse the command line
|
28
|
+
def parse()
|
29
|
+
taking_options = true
|
30
|
+
last_opt = nil
|
31
|
+
refargs = @spec.get_args.clone
|
32
|
+
|
33
|
+
@report = Report.new()
|
34
|
+
|
35
|
+
@input.each do |word|
|
36
|
+
dbg "Parsing '#{word}'"
|
37
|
+
if last_opt && last_opt.has_args? && !last_opt.full?
|
38
|
+
dbg "Got argument '#{word}' for '#{last_opt}'", 1
|
39
|
+
last_opt.push(word)
|
40
|
+
else
|
41
|
+
if word[/^-/] && taking_options
|
42
|
+
if word[/^-[^-]/]
|
43
|
+
dbg "Identified short option(s)", 1
|
44
|
+
shorts = word[/[^-]+$/].split('')
|
45
|
+
shorts.each_with_index do |short, i|
|
46
|
+
last_short = i == (shorts.length - 1)
|
47
|
+
opt = @spec.get_opt(short)
|
48
|
+
last_opt = opt
|
49
|
+
if opt.has_args? && shorts.length > 1 && !last_short
|
50
|
+
raise SyntaxError, "Error: -#{short} in compound option '#{word}' expects an argument"
|
51
|
+
elsif opt.flag?
|
52
|
+
opt.toggle()
|
53
|
+
dbg "Toggled flag '#{opt}'", 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
elsif word[/^--/]
|
57
|
+
dbg "Identified long option", 1
|
58
|
+
key = word[/[^-]+$/]
|
59
|
+
opt = @spec.get_opt(key)
|
60
|
+
last_opt = opt
|
61
|
+
if opt.flag?
|
62
|
+
opt.toggle()
|
63
|
+
dbg "Toggled #{opt}", 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
else
|
67
|
+
dbg "Parsed output arg", 1
|
68
|
+
taking_options = false
|
69
|
+
@report.args << word
|
70
|
+
key = refargs.shift
|
71
|
+
if key
|
72
|
+
if key == @spec.get_variad
|
73
|
+
@report.arg[key] = []
|
74
|
+
@report.arg[key] << word
|
75
|
+
else
|
76
|
+
@report.arg[key] = word
|
77
|
+
end
|
78
|
+
elsif @spec.is_variadic?
|
79
|
+
@report.arg[@spec.get_variad] << word
|
80
|
+
else
|
81
|
+
@report.trailing << word
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
@spec.get_opts.each do |name, opt|
|
87
|
+
@report.opt[name] = opt.value
|
88
|
+
@report.count[name] = opt.count
|
89
|
+
end
|
90
|
+
@spec.get_args.each do |name|
|
91
|
+
if @report.arg[name].nil?
|
92
|
+
if @spec.has_default?(name)
|
93
|
+
@report.arg[name] = @spec.get_default(name)
|
94
|
+
@report.args << @report.arg[name]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
if @report.opt[:help]
|
99
|
+
self.print_usage()
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Construct usage information
|
104
|
+
def usage()
|
105
|
+
tb = TextBuilder.new()
|
106
|
+
|
107
|
+
tb.next 'USAGE:'
|
108
|
+
tb.push @spec.get_name if @spec.get_name
|
109
|
+
|
110
|
+
if @spec.get_opts.values.uniq.length < 5 || @spec.option_listing
|
111
|
+
@spec.get_opts.values.uniq.each do |opt|
|
112
|
+
tb.push "[#{opt.header}]"
|
113
|
+
end
|
114
|
+
else
|
115
|
+
tb.push '[OPTION...]'
|
116
|
+
end
|
117
|
+
|
118
|
+
if @spec.has_args?
|
119
|
+
if @spec.is_variadic?
|
120
|
+
singles = @spec.get_args[0..-2].map do |a|
|
121
|
+
if @spec.has_default?(a)
|
122
|
+
a = "[#{a}]"
|
123
|
+
end
|
124
|
+
a.upcase
|
125
|
+
end
|
126
|
+
tb.push singles
|
127
|
+
v = @spec.get_args.last.upcase
|
128
|
+
tb.push "[#{v}1 #{v}2...]"
|
129
|
+
else
|
130
|
+
argmap = @spec.get_args.map do |a|
|
131
|
+
if @spec.has_default?(a)
|
132
|
+
a = "[#{a}]"
|
133
|
+
end
|
134
|
+
a.upcase
|
135
|
+
end
|
136
|
+
tb.push argmap
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
tb.wrap indent: 7, indent_after: true, segments: true
|
141
|
+
|
142
|
+
if @spec.get_desc
|
143
|
+
tb.skip @spec.get_desc
|
144
|
+
tb.wrap(indent: 4)
|
145
|
+
end
|
146
|
+
|
147
|
+
tb.skip 'OPTIONS:'
|
148
|
+
tb.skip
|
149
|
+
|
150
|
+
@spec.get_opts.values.uniq.each do |opt|
|
151
|
+
tb.indent 4
|
152
|
+
tb.push opt.header
|
153
|
+
if opt.desc
|
154
|
+
tb.next
|
155
|
+
tb.indent 8
|
156
|
+
tb.push opt.desc
|
157
|
+
end
|
158
|
+
tb.skip
|
159
|
+
end
|
160
|
+
|
161
|
+
return tb.print
|
162
|
+
end
|
163
|
+
|
164
|
+
# Print usage information and exit
|
165
|
+
def print_usage()
|
166
|
+
puts self.usage
|
167
|
+
exit 0
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
end # module CLI
|
172
|
+
end # module Ark
|
173
|
+
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Ark
|
2
|
+
module CLI
|
3
|
+
|
4
|
+
# Represents an option and stores the option's current state, as well as
|
5
|
+
# usage information.
|
6
|
+
class Option
|
7
|
+
|
8
|
+
# Initialize a new Option instance
|
9
|
+
# [+keys+] A list of names this option will be identified by
|
10
|
+
# [+args+] A list of argument named this option will expect
|
11
|
+
# [+desc+] A short description of this option
|
12
|
+
def initialize(long, short=nil, args=nil, desc=nil)
|
13
|
+
@long = long
|
14
|
+
@short = short
|
15
|
+
@args = args || []
|
16
|
+
@vals = []
|
17
|
+
@flag = false
|
18
|
+
@count = 0
|
19
|
+
@desc = desc || ''
|
20
|
+
end
|
21
|
+
|
22
|
+
# A count of how many times this option has been given on the command line.
|
23
|
+
# Useful for flags that might be specified repeatedly, like +-vvv+ to raise
|
24
|
+
# verbosity three times.
|
25
|
+
attr_reader :count
|
26
|
+
|
27
|
+
# A short description of the option, if given
|
28
|
+
attr_reader :desc
|
29
|
+
|
30
|
+
# Long name for this option
|
31
|
+
attr_reader :long
|
32
|
+
|
33
|
+
# Short name for this option
|
34
|
+
attr_reader :short
|
35
|
+
|
36
|
+
# Return the number of arguments this option expects
|
37
|
+
def arity()
|
38
|
+
return @args.length
|
39
|
+
end
|
40
|
+
|
41
|
+
# Return a count of how many arguments this option still expects
|
42
|
+
def vals_needed()
|
43
|
+
if self.flag?
|
44
|
+
return 0
|
45
|
+
else
|
46
|
+
return @args.length - @vals.length
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# True if this option has received all the arguments it expects, or if this
|
51
|
+
# option expects no arguments
|
52
|
+
def full?
|
53
|
+
return self.vals_needed == 0
|
54
|
+
end
|
55
|
+
|
56
|
+
# True if this option expects no arguments; opposite of #has_args?
|
57
|
+
def flag?
|
58
|
+
return @args.empty?
|
59
|
+
end
|
60
|
+
|
61
|
+
# Toggle this option to the true state and increment the toggle count. Only
|
62
|
+
# valid for options which expect no argument (flags). Attempting to toggle
|
63
|
+
# a option with expected arguments will raise an error.
|
64
|
+
def toggle()
|
65
|
+
if self.flag?
|
66
|
+
@count += 1
|
67
|
+
@flag = true
|
68
|
+
else
|
69
|
+
raise StandardError, "Tried to toggle an option which expects an argument"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Pass an argument +arg+ to this option
|
74
|
+
def push(arg)
|
75
|
+
@vals << arg
|
76
|
+
end
|
77
|
+
|
78
|
+
# Return the current value of this option
|
79
|
+
def value()
|
80
|
+
if self.flag?
|
81
|
+
return @flag
|
82
|
+
else
|
83
|
+
if self.full? && @vals.length == 1
|
84
|
+
return @vals[0]
|
85
|
+
elsif self.full?
|
86
|
+
return @vals
|
87
|
+
else
|
88
|
+
return nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# True if this option expects an argument. Opposite of #flag?
|
94
|
+
def has_args?
|
95
|
+
return @args.length > 0
|
96
|
+
end
|
97
|
+
|
98
|
+
# Return basic usage information: the option's names and arguments
|
99
|
+
def header()
|
100
|
+
if self.flag?
|
101
|
+
args = ''
|
102
|
+
else
|
103
|
+
args = ' ' + @args.join(', ').upcase
|
104
|
+
end
|
105
|
+
short = @short ? "-#{@short} " : ''
|
106
|
+
return "#{short}--#{@long}#{args}"
|
107
|
+
end
|
108
|
+
|
109
|
+
# Represent this option as a string
|
110
|
+
def to_s()
|
111
|
+
return "(#{self.header})"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
end # module CLI
|
117
|
+
end # module Ark
|
118
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Ark
|
2
|
+
module CLI
|
3
|
+
|
4
|
+
class Report
|
5
|
+
def initialize()
|
6
|
+
@args = []
|
7
|
+
@named_args = {}
|
8
|
+
@trailing_args = []
|
9
|
+
@counts = {}
|
10
|
+
@options = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def args
|
14
|
+
return @args
|
15
|
+
end
|
16
|
+
def arg
|
17
|
+
return @named_args
|
18
|
+
end
|
19
|
+
def trailing
|
20
|
+
return @trailing_args
|
21
|
+
end
|
22
|
+
def opt
|
23
|
+
return @options
|
24
|
+
end
|
25
|
+
def count
|
26
|
+
return @counts
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end # module CLI
|
31
|
+
end # module Ark
|
32
|
+
|
data/lib/ark/cli/spec.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
module Ark
|
2
|
+
module CLI
|
3
|
+
|
4
|
+
class Spec
|
5
|
+
|
6
|
+
# Raised when a nonexistent option is received
|
7
|
+
class NoSuchOptionError < ArgumentError
|
8
|
+
end
|
9
|
+
|
10
|
+
# Raised when there is a syntax error in the args declaration
|
11
|
+
class ArgumentSyntaxError < ArgumentError
|
12
|
+
end
|
13
|
+
|
14
|
+
# Initialize a bare interface spec
|
15
|
+
def initialize()
|
16
|
+
@args = []
|
17
|
+
@options = {}
|
18
|
+
@variadic = false
|
19
|
+
@option_listing = false
|
20
|
+
@trailing_error = false
|
21
|
+
end
|
22
|
+
|
23
|
+
# If true, the full option list will always be displayed in the usage info
|
24
|
+
# header
|
25
|
+
attr_reader :option_listing
|
26
|
+
|
27
|
+
# If true, an error will be raised if trailing arguments are given
|
28
|
+
attr_reader :trailing_error
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def strip(arg)
|
33
|
+
return arg[/^(\S+?)(:|\.\.\.|$)/, 1]
|
34
|
+
end
|
35
|
+
|
36
|
+
def defaulted?(arg)
|
37
|
+
return !arg[/^\S+?:.+/].nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse_default(arg)
|
41
|
+
return arg[/^.+?:(.+)/, 1]
|
42
|
+
end
|
43
|
+
|
44
|
+
def variadic?(arg)
|
45
|
+
return !arg[/\.\.\.$/].nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_arg(arg, default: nil, last: false)
|
49
|
+
stripped = strip(arg)
|
50
|
+
@args << stripped
|
51
|
+
if defaulted?(arg)
|
52
|
+
@defaults[stripped] = parse_default(arg)
|
53
|
+
end
|
54
|
+
if variadic?(arg)
|
55
|
+
if last
|
56
|
+
@variadic = true
|
57
|
+
@variad = stripped
|
58
|
+
else
|
59
|
+
raise ArgumentSyntaxError,
|
60
|
+
"Variadic arguments must come last. Offending variad is '#{arg}'"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
public
|
66
|
+
|
67
|
+
def get_name
|
68
|
+
return @name
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_desc
|
72
|
+
return @desc
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_args
|
76
|
+
return @args
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_options?
|
80
|
+
@options.values.uniq.length > 1
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_opts
|
84
|
+
return @options
|
85
|
+
end
|
86
|
+
|
87
|
+
# Get an Option object for the given option +name+
|
88
|
+
def get_opt(name)
|
89
|
+
name = name.to_sym
|
90
|
+
if !@options.keys.member?(name)
|
91
|
+
raise NoSuchOptionError, "Error, no such option: '#{name}'"
|
92
|
+
end
|
93
|
+
return @options[name]
|
94
|
+
end
|
95
|
+
|
96
|
+
def is_variadic?
|
97
|
+
return @variadic
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_variad
|
101
|
+
return @variad
|
102
|
+
end
|
103
|
+
|
104
|
+
def has_default?(arg)
|
105
|
+
@defaults.key?(arg.to_s)
|
106
|
+
end
|
107
|
+
|
108
|
+
def get_defaults
|
109
|
+
return @defaults
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_default(arg)
|
113
|
+
@defaults[arg.to_s]
|
114
|
+
end
|
115
|
+
|
116
|
+
def has_args?
|
117
|
+
@args.length > 0
|
118
|
+
end
|
119
|
+
|
120
|
+
# Specify general information about the program
|
121
|
+
# [+name+] Name of the program
|
122
|
+
# [+desc+] Short description of the program
|
123
|
+
# [+args+] A list of named arguments
|
124
|
+
def header(name: nil, desc: nil, args: [])
|
125
|
+
self.name(name)
|
126
|
+
self.desc(desc)
|
127
|
+
self.args(args)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Set the name of the program to +str+
|
131
|
+
def name(str)
|
132
|
+
@name = str.to_s if str
|
133
|
+
end
|
134
|
+
|
135
|
+
# Set the description of the program to +str+
|
136
|
+
def desc(str)
|
137
|
+
@desc = str.to_s if str
|
138
|
+
end
|
139
|
+
|
140
|
+
# Define what arguments the program will accept
|
141
|
+
def args(*input)
|
142
|
+
@args = []
|
143
|
+
@defaults = {}
|
144
|
+
|
145
|
+
input.flatten.each_with_index do |item, i|
|
146
|
+
last = (input.length - (i + 1)) == 0
|
147
|
+
parse_arg(item, last: last)
|
148
|
+
end
|
149
|
+
|
150
|
+
@refargs = @args.clone
|
151
|
+
end
|
152
|
+
|
153
|
+
# Define an Option
|
154
|
+
# [+keys+] A list of names for this option
|
155
|
+
# [+args+] A list of arguments the option expects
|
156
|
+
# [+desc+] A short description of the option, used to provide usage info
|
157
|
+
def opt(long, short=nil, args: nil, desc: nil)
|
158
|
+
long = long.to_sym
|
159
|
+
short = short.to_sym if short
|
160
|
+
args = [args] if args.is_a?(String)
|
161
|
+
args.map!(&:to_sym) if args
|
162
|
+
o = Option.new(long, short, args, desc)
|
163
|
+
@options[long] = o
|
164
|
+
@options[short] = o if short
|
165
|
+
end
|
166
|
+
|
167
|
+
# Force the full option list display in the usage info, no matter how many
|
168
|
+
# options the program has
|
169
|
+
def force_option_list()
|
170
|
+
@option_list = true
|
171
|
+
end
|
172
|
+
|
173
|
+
# The parser will raise an error on finding trailing arguments (default
|
174
|
+
# behavior is to ignore and stuff the trailing args into Report.trailing_args)
|
175
|
+
def raise_on_trailing()
|
176
|
+
@trailing_error = true
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
end # module CLI
|
182
|
+
end # module Ark
|
183
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ark-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Macquarie Sharpless
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ark-util
|
@@ -16,31 +16,36 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.3'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.
|
22
|
+
version: 0.3.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '0.
|
29
|
+
version: '0.3'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.
|
32
|
+
version: 0.3.0
|
33
33
|
description: |
|
34
|
-
A
|
35
|
-
|
36
|
-
|
34
|
+
A library for parsing options and arguments from the commandline. Parses ARGV
|
35
|
+
and returns an object holding information about what options were set on the
|
36
|
+
commandline, and what arguments were given.
|
37
37
|
email:
|
38
38
|
- macquarie.sharpless@gmail.com
|
39
39
|
executables: []
|
40
40
|
extensions: []
|
41
41
|
extra_rdoc_files: []
|
42
42
|
files:
|
43
|
+
- README.md
|
43
44
|
- lib/ark/cli.rb
|
45
|
+
- lib/ark/cli/interface.rb
|
46
|
+
- lib/ark/cli/option.rb
|
47
|
+
- lib/ark/cli/report.rb
|
48
|
+
- lib/ark/cli/spec.rb
|
44
49
|
homepage: https://github.com/grimheart/ark-cli
|
45
50
|
licenses:
|
46
51
|
- GPL-3.0
|
@@ -64,5 +69,5 @@ rubyforge_project:
|
|
64
69
|
rubygems_version: 2.4.5
|
65
70
|
signing_key:
|
66
71
|
specification_version: 4
|
67
|
-
summary:
|
72
|
+
summary: Command line interface library
|
68
73
|
test_files: []
|