ejt_command_line 0.0.1
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 +15 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +4 -0
- data/ejt_command_line.gemspec +24 -0
- data/lib/ejt_command_line/version.rb +3 -0
- data/lib/ejt_command_line.rb +268 -0
- data/spec/command_line_spec.rb +358 -0
- data/spec/command_line_spec.rb~ +359 -0
- data/spec/spec_helper.rb +8 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MDQzM2QzNDU0NGE4MzhiOWZhMDc1ZGE0YjA3MDQzZTNkMDQ3Y2MzZA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NmIxZDE2MTE0ZjZiNzQ5OWI4MjFhZTU0MGQwZTU2M2IyMDYxZTBlNA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NDQ2MDc2ZmEzZjY2ODZjNTAyNTQwNzNlMjM3YThjYWFiM2IwNjc0ZmQwNGQ4
|
10
|
+
MDdhODFjYjM4YTk5N2M1ZWM3ODRjNGEzZGM2YmRiMzU1MTNiYjRlNjEwN2U2
|
11
|
+
YTQ2MGRmOGMyM2FhMDI4ZTU4NjkyMjBmZGM0NTJiYjQ4OTkwMzg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NTdlNzU2NTYwMmNiY2RmZDIxM2I5ZjNiYmZiOWJkZDY3ODc2ZTA0OGZhYTJh
|
14
|
+
MWY5MDllZDNkNWVlZjVjYzZlNjE5Y2NjN2UzMDU4YTM2NDBkNGI0ODZkNzAz
|
15
|
+
YWU2OTJlYWI4ZGYzMTViMjIxNzcwYWQzMWQ3MjU1YTdmMzc2NTU=
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Joe Thornber
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# EjtCommandLine
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'ejt_command_line'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install ejt_command_line
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ejt_command_line/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "ejt_command_line"
|
8
|
+
spec.version = EjtCommandLine::VERSION
|
9
|
+
spec.authors = ["Joe Thornber"]
|
10
|
+
spec.email = ["ejt@redhat.com"]
|
11
|
+
spec.description = %q{Yet another command line parser. Allows you define argument types}
|
12
|
+
spec.summary = %q{Command line parser}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "GPL"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
end
|
@@ -0,0 +1,268 @@
|
|
1
|
+
require "ejt_command_line/version"
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
#----------------------------------------------------------------
|
5
|
+
|
6
|
+
module CommandLine
|
7
|
+
# from prelude
|
8
|
+
def bracket_(release)
|
9
|
+
r = nil
|
10
|
+
begin
|
11
|
+
r = yield
|
12
|
+
ensure
|
13
|
+
release.call
|
14
|
+
end
|
15
|
+
r
|
16
|
+
end
|
17
|
+
|
18
|
+
#----------------------------------------------------------------
|
19
|
+
|
20
|
+
class CommandLineError < StandardError
|
21
|
+
end
|
22
|
+
|
23
|
+
class ParseError < CommandLineError
|
24
|
+
end
|
25
|
+
|
26
|
+
class ConfigureError < CommandLineError
|
27
|
+
end
|
28
|
+
|
29
|
+
#----------------------------------------------------------------
|
30
|
+
|
31
|
+
def simple_switch_parser(*aliases)
|
32
|
+
ArrayParser::choice(*aliases)
|
33
|
+
end
|
34
|
+
|
35
|
+
def value_switch_parser(*aliases, &block)
|
36
|
+
p = sequence(choice(*aliases), value(&block))
|
37
|
+
end
|
38
|
+
|
39
|
+
#----------------------------------------------------------------
|
40
|
+
|
41
|
+
class Switch
|
42
|
+
attr_reader :flags, :parser
|
43
|
+
|
44
|
+
def initialize(flags, parser = nil)
|
45
|
+
@flags = flags
|
46
|
+
@parser = parser
|
47
|
+
end
|
48
|
+
|
49
|
+
def has_flag?(flag)
|
50
|
+
@flags.member?(flag)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Command
|
55
|
+
attr_reader :switches
|
56
|
+
|
57
|
+
def initialize
|
58
|
+
@switches = []
|
59
|
+
@mutually_exclusive_sets = [] # list of lists of syms
|
60
|
+
@mandatory = []
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_switches(syms)
|
64
|
+
@switches += syms
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_mutually_exclusive_set(syms)
|
68
|
+
@mutually_exclusive_sets << syms.to_set
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_mandatory_switch(sym)
|
72
|
+
@mandatory << sym
|
73
|
+
end
|
74
|
+
|
75
|
+
def check_mutual_exclusion(syms)
|
76
|
+
nr_sets = @mutually_exclusive_sets.size
|
77
|
+
set_counts = Array.new(nr_sets, [])
|
78
|
+
|
79
|
+
syms.each do |s|
|
80
|
+
# is it in an exclusive set?
|
81
|
+
0.upto(nr_sets - 1) do |n|
|
82
|
+
if @mutually_exclusive_sets[n].member?(s)
|
83
|
+
set_counts[n] << s
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
0.upto(nr_sets - 1) do |n|
|
89
|
+
if set_counts[n].size > 1
|
90
|
+
msg = "mutually exclusive options used:\n"
|
91
|
+
set_counts[n].each {|sym| msg += " #{sym}\n"}
|
92
|
+
raise ParseError, msg
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def check_mandatory(syms)
|
98
|
+
missing = []
|
99
|
+
|
100
|
+
@mandatory.each do |m|
|
101
|
+
unless syms.member?(m)
|
102
|
+
missing << m
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
if missing.size > 0
|
107
|
+
msg = "missing mandatory switches:\n"
|
108
|
+
missing.each do |m|
|
109
|
+
msg += " #{m}\n"
|
110
|
+
end
|
111
|
+
|
112
|
+
raise ParseError, msg
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class Parser
|
118
|
+
GLOBAL_SYM = :global__
|
119
|
+
|
120
|
+
def initialize(&block)
|
121
|
+
@switches = {}
|
122
|
+
@global_switches = []
|
123
|
+
@value_types = {}
|
124
|
+
@commands = Hash.new {|hash, key| Command.new}
|
125
|
+
@current_command = @commands[GLOBAL_SYM]
|
126
|
+
|
127
|
+
configure(&block) if block
|
128
|
+
end
|
129
|
+
|
130
|
+
def configure(&block)
|
131
|
+
self.instance_eval(&block)
|
132
|
+
end
|
133
|
+
|
134
|
+
def value_type(sym, &parser)
|
135
|
+
if @value_types.member?(sym)
|
136
|
+
raise ConfigureError, "duplicate value type '#{sym}'"
|
137
|
+
end
|
138
|
+
|
139
|
+
@value_types[sym] = parser
|
140
|
+
end
|
141
|
+
|
142
|
+
def simple_switch(sym, *flags)
|
143
|
+
@switches[sym] = Switch.new(flags)
|
144
|
+
end
|
145
|
+
|
146
|
+
def value_switch(sym, value_sym, *flags)
|
147
|
+
@switches[sym] = Switch.new(flags, get_value_parser(value_sym))
|
148
|
+
end
|
149
|
+
|
150
|
+
def global(&block)
|
151
|
+
command(GLOBAL_SYM, &block)
|
152
|
+
end
|
153
|
+
|
154
|
+
def command(sym, &block)
|
155
|
+
old = @current_command
|
156
|
+
@current_command = @commands[sym] = Command.new
|
157
|
+
|
158
|
+
if block
|
159
|
+
release = lambda {@current_command = old}
|
160
|
+
bracket_(release) do
|
161
|
+
self.instance_eval(&block)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def switches(*syms)
|
167
|
+
check_switches_are_defined(syms)
|
168
|
+
@current_command.add_switches(syms)
|
169
|
+
end
|
170
|
+
|
171
|
+
def one_of(*syms)
|
172
|
+
check_switches_are_defined(syms)
|
173
|
+
@current_command.add_switches(syms)
|
174
|
+
@current_command.add_mutually_exclusive_set(syms)
|
175
|
+
end
|
176
|
+
|
177
|
+
def mandatory(sym)
|
178
|
+
syms = [sym]
|
179
|
+
check_switches_are_defined(syms)
|
180
|
+
@current_command.add_switches(syms)
|
181
|
+
@current_command.add_mandatory_switch(sym)
|
182
|
+
end
|
183
|
+
|
184
|
+
def parse(handler, *args)
|
185
|
+
command, opts, plain_args = parse_(args)
|
186
|
+
handler.send(command, opts, plain_args)
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
def parse_value(arg, s, args)
|
191
|
+
if s.parser
|
192
|
+
if args.size == 0
|
193
|
+
raise ParseError, "no value specified for switch '#{arg}'"
|
194
|
+
end
|
195
|
+
|
196
|
+
value = args.shift
|
197
|
+
begin
|
198
|
+
s.parser.call(value)
|
199
|
+
rescue => e
|
200
|
+
raise ParseError, "couldn't parse value '#{arg}=#{value}'\n#{e}"
|
201
|
+
end
|
202
|
+
else
|
203
|
+
true
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def parse_(args)
|
208
|
+
in_command = false
|
209
|
+
opts = {}
|
210
|
+
plain_args = []
|
211
|
+
valid_switches = @commands[GLOBAL_SYM].switches
|
212
|
+
command = :global_command
|
213
|
+
|
214
|
+
while args.size > 0 do
|
215
|
+
arg = args.shift
|
216
|
+
|
217
|
+
if arg =~ /^-/
|
218
|
+
sym, s = find_switch(valid_switches, arg)
|
219
|
+
opts[sym] = parse_value(arg, s, args)
|
220
|
+
|
221
|
+
else
|
222
|
+
cmd = arg.intern
|
223
|
+
|
224
|
+
if !in_command && @commands.member?(cmd)
|
225
|
+
command = cmd
|
226
|
+
valid_switches = @commands[cmd].switches
|
227
|
+
in_command = true
|
228
|
+
else
|
229
|
+
plain_args << arg
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
@commands[command].check_mutual_exclusion(opts.keys)
|
235
|
+
@commands[command].check_mandatory(opts.keys)
|
236
|
+
[command, opts, plain_args]
|
237
|
+
end
|
238
|
+
|
239
|
+
def check_switches_are_defined(syms)
|
240
|
+
syms.each do |sym|
|
241
|
+
raise ConfigureError, "unknown switch '#{sym}'" unless @switches.member?(sym)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def find_switch(valid_switches, switch)
|
246
|
+
catch :found do
|
247
|
+
valid_switches.each do |sym|
|
248
|
+
s = @switches[sym]
|
249
|
+
if s.has_flag?(switch)
|
250
|
+
throw :found, [sym, s]
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
raise ParseError, "unexpected switch '#{switch}'"
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def get_value_parser(sym)
|
259
|
+
if @value_types.member?(sym)
|
260
|
+
@value_types[sym]
|
261
|
+
else
|
262
|
+
raise ConfigureError, "unknown value type '#{sym}'"
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
#----------------------------------------------------------------
|
@@ -0,0 +1,358 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
include CommandLine
|
4
|
+
|
5
|
+
#----------------------------------------------------------------
|
6
|
+
|
7
|
+
describe "Parser" do
|
8
|
+
before :each do
|
9
|
+
@clh = Parser.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def help_switch
|
13
|
+
@clh.simple_switch :help, '--help', '-h'
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "creation" do
|
17
|
+
it "should take a config block" do
|
18
|
+
block_watcher = mock()
|
19
|
+
block_watcher.should_receive(:executed)
|
20
|
+
|
21
|
+
clh = Parser.new do
|
22
|
+
value_type :string do |str|
|
23
|
+
str
|
24
|
+
end
|
25
|
+
|
26
|
+
block_watcher.executed
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "value types" do
|
32
|
+
it "should allow you to register new value types" do
|
33
|
+
@clh.configure do
|
34
|
+
value_type :string do |str|
|
35
|
+
str
|
36
|
+
end
|
37
|
+
|
38
|
+
value_type :int do |str|
|
39
|
+
str.to_i
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should fail it you try and define a duplicate value type" do
|
45
|
+
@clh.value_type :string do |str|
|
46
|
+
str
|
47
|
+
end
|
48
|
+
|
49
|
+
expect do
|
50
|
+
@clh.value_type :string do |str|
|
51
|
+
str
|
52
|
+
end
|
53
|
+
end.to raise_error(ConfigureError, /string/)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "switches are defined separately from commands" do
|
58
|
+
it "should let you define binary switch" do
|
59
|
+
help_switch
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should fail if you try and define a switch that takes an unknown value type" do
|
63
|
+
expect {@clh.value_switch :resize_to, :volume_size, '--resize-to'}.to raise_error(ConfigureError, /volume_size/)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should let you define an option that takes a single value" do
|
67
|
+
@clh.configure do
|
68
|
+
value_type :volume_size do |str|
|
69
|
+
str.to_i
|
70
|
+
end
|
71
|
+
|
72
|
+
value_switch :resize_to, :volume_size, '--resize-to'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "global switches" do
|
78
|
+
it "should let you bind global switch" do
|
79
|
+
help_switch
|
80
|
+
@clh.configure do
|
81
|
+
global do
|
82
|
+
switches :help
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should raise an error if the switch hasn't been previously defined" do
|
88
|
+
expect do
|
89
|
+
@clh.global do
|
90
|
+
switches :become_sentient
|
91
|
+
end
|
92
|
+
end.to raise_error(ConfigureError)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "sub commands" do
|
97
|
+
it "should let you register a command" do
|
98
|
+
@clh.configure do
|
99
|
+
command(:create) {}
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should let you omit the block for a command" do
|
104
|
+
@clh.configure do
|
105
|
+
command :create
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should let you bind switches" do
|
110
|
+
@clh.configure do
|
111
|
+
simple_switch :grow_to, '--grow-to'
|
112
|
+
simple_switch :grow_by, '--grow-by'
|
113
|
+
simple_switch :shrink_to, '--shrink-to'
|
114
|
+
simple_switch :shrink_by, '--shrink-by'
|
115
|
+
|
116
|
+
command :resize do
|
117
|
+
switches :grow_to, :grow_by, :shrink_to, :shrink_by
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "parsing" do
|
124
|
+
describe "global command" do
|
125
|
+
it "should handle no switches" do
|
126
|
+
handler = mock()
|
127
|
+
handler.should_receive(:global_command).with({}, [])
|
128
|
+
@clh.parse(handler)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should raise a ParseError if an unrecognised switch is used" do
|
132
|
+
handler = mock()
|
133
|
+
expect {@clh.parse(handler, '--go-back-in-time')}.to raise_error(ParseError, /--go-back-in-time/)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should handle binary switches" do
|
137
|
+
handler = mock()
|
138
|
+
handler.should_receive(:global_command).with({:help => true}, [])
|
139
|
+
|
140
|
+
@clh.configure do
|
141
|
+
simple_switch :help, '--help', '-h'
|
142
|
+
global do
|
143
|
+
switches :help
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
@clh.parse(handler, '-h')
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should handle multiple binary switches" do
|
151
|
+
handler = mock()
|
152
|
+
handler.should_receive(:global_command).with({:help => true, :ro => true}, [])
|
153
|
+
|
154
|
+
@clh.configure do
|
155
|
+
simple_switch :help, '--help', '-h'
|
156
|
+
simple_switch :ro, '--read-only', '-r'
|
157
|
+
|
158
|
+
global do
|
159
|
+
switches :help, :ro
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
@clh.parse(handler, '-h', '--read-only')
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should handle valued switches" do
|
167
|
+
handler = mock()
|
168
|
+
|
169
|
+
@clh.configure do
|
170
|
+
value_type :int do |str|
|
171
|
+
str.to_i
|
172
|
+
end
|
173
|
+
|
174
|
+
value_switch :count, :int, '--count', '-c'
|
175
|
+
|
176
|
+
global do
|
177
|
+
switches :count
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
handler.should_receive(:global_command).
|
182
|
+
with({:count => 17}, [])
|
183
|
+
@clh.parse(handler, '--count', '17')
|
184
|
+
|
185
|
+
handler.should_receive(:global_command).
|
186
|
+
with({:count => 17}, ['one', 'two'])
|
187
|
+
@clh.parse(handler, 'one', '-c', '17', 'two')
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should raise an ArgumentError if no value is given for a valued switch" do
|
191
|
+
handler = mock()
|
192
|
+
|
193
|
+
@clh.configure do
|
194
|
+
value_type :int do |str|
|
195
|
+
str.to_i
|
196
|
+
end
|
197
|
+
|
198
|
+
value_switch :count, :int, '--count', '-c'
|
199
|
+
|
200
|
+
global do
|
201
|
+
switches :count
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
expect do
|
206
|
+
@clh.parse(handler, '--count')
|
207
|
+
end.to raise_error(ParseError, /count/)
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should filter non-switches out" do
|
211
|
+
handler = mock()
|
212
|
+
handler.should_receive(:global_command).
|
213
|
+
with({:help => true, :ro => true}, ['my_file', 'my_other_file'])
|
214
|
+
|
215
|
+
@clh.configure do
|
216
|
+
simple_switch :help, '--help', '-h'
|
217
|
+
simple_switch :ro, '--read-only', '-r'
|
218
|
+
|
219
|
+
global do
|
220
|
+
switches :help, :ro
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
@clh.parse(handler, '-h', 'my_file', '--read-only', 'my_other_file')
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "simple commands" do
|
229
|
+
it "should handle commands that take no switches" do
|
230
|
+
@clh.configure do
|
231
|
+
command :create do
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
handler = mock()
|
236
|
+
handler.should_receive(:create).with({}, ['fred'])
|
237
|
+
@clh.parse(handler, 'create', 'fred')
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
describe "commands" do
|
242
|
+
before :each do
|
243
|
+
@clh.configure do
|
244
|
+
value_type :int do |str|
|
245
|
+
str.to_i
|
246
|
+
end
|
247
|
+
|
248
|
+
value_switch :grow_to, :int, '--grow-to'
|
249
|
+
value_switch :grow_by, :int, '--grow-by'
|
250
|
+
value_switch :shrink_to, :int, '--shrink-to'
|
251
|
+
value_switch :shrink_by, :int, '--shrink-by'
|
252
|
+
|
253
|
+
command :resize do
|
254
|
+
switches :grow_to, :grow_by, :shrink_to, :shrink_by
|
255
|
+
end
|
256
|
+
|
257
|
+
command :shrink do
|
258
|
+
switches :grow_to, :grow_by, :shrink_to, :shrink_by
|
259
|
+
end
|
260
|
+
|
261
|
+
command :grow do
|
262
|
+
switches :grow_to, :grow_by, :shrink_to, :shrink_by
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
it "should allow you to define a sub command" do
|
268
|
+
handler = mock()
|
269
|
+
handler.should_receive(:resize).with({:grow_to => 12345}, ['fred'])
|
270
|
+
@clh.parse(handler, 'resize', '--grow-to', '12345', 'fred')
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should prevent you calling two sub commands on the same line" do
|
274
|
+
handler = mock()
|
275
|
+
handler.should_receive(:resize).
|
276
|
+
with({:grow_to => 1234, :shrink_to => 2345}, ['shrink', 'fred'])
|
277
|
+
@clh.parse(handler, 'resize', '--grow-to', '1234', 'shrink', '--shrink-to', '2345', 'fred')
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
describe "exclusive switches" do
|
282
|
+
before :each do
|
283
|
+
@clh.configure do
|
284
|
+
value_type :int do |str|
|
285
|
+
str.to_i
|
286
|
+
end
|
287
|
+
|
288
|
+
value_switch :grow_to, :int, '--grow-to'
|
289
|
+
value_switch :grow_by, :int, '--grow-by'
|
290
|
+
value_switch :shrink_to, :int, '--shrink-to'
|
291
|
+
value_switch :shrink_by, :int, '--shrink-by'
|
292
|
+
|
293
|
+
command :resize do
|
294
|
+
one_of :grow_to, :grow_by, :shrink_to, :shrink_by
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
it "should parse one exclusive switch" do
|
300
|
+
handler = mock()
|
301
|
+
handler.should_receive(:resize).
|
302
|
+
with({:grow_to => 1234}, ['fred'])
|
303
|
+
@clh.parse(handler, 'resize', '--grow-to', '1234', 'fred')
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should raise a ParseError if more than one switch from an exclusive set is defined" do
|
307
|
+
handler = mock()
|
308
|
+
expect do
|
309
|
+
@clh.parse(handler, 'resize', '--grow-to', '1234', '--shrink-by', '2345', 'fred')
|
310
|
+
end.to raise_error(ParseError, /mutually exclusive/)
|
311
|
+
# FIXME: would be nice to see the actual flags in the exception
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should let you define more than one exclusive set" do
|
315
|
+
pending
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
it "should handle --foo=<value>" do
|
320
|
+
pending "todo"
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
describe "mandatory switches" do
|
325
|
+
before :each do
|
326
|
+
@clh.configure do
|
327
|
+
value_type :int do |str|
|
328
|
+
str.to_i
|
329
|
+
end
|
330
|
+
|
331
|
+
value_switch :grow_to, :int, '--grow-to'
|
332
|
+
value_switch :grow_by, :int, '--grow-by'
|
333
|
+
value_switch :shrink_to, :int, '--shrink-to'
|
334
|
+
value_switch :shrink_by, :int, '--shrink-by'
|
335
|
+
|
336
|
+
command :resize do
|
337
|
+
mandatory :grow_to
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should parse ok if mandatory switch is given" do
|
343
|
+
handler = mock()
|
344
|
+
handler.should_receive(:resize).
|
345
|
+
with({:grow_to => 3}, ['fred'])
|
346
|
+
@clh.parse(handler, 'resize', '--grow-to', '3', 'fred')
|
347
|
+
end
|
348
|
+
|
349
|
+
it "should raise a ParseError if a mandatory switch is omitted" do
|
350
|
+
handler = mock()
|
351
|
+
expect do
|
352
|
+
@clh.parse(handler, 'resize', 'fred')
|
353
|
+
end.to raise_error(ParseError, /grow_to/)
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
#----------------------------------------------------------------
|
@@ -0,0 +1,359 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'lib/command_line'
|
3
|
+
|
4
|
+
include CommandLine
|
5
|
+
|
6
|
+
#----------------------------------------------------------------
|
7
|
+
|
8
|
+
describe "Parser" do
|
9
|
+
before :each do
|
10
|
+
@clh = Parser.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def help_switch
|
14
|
+
@clh.simple_switch :help, '--help', '-h'
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "creation" do
|
18
|
+
it "should take a config block" do
|
19
|
+
block_watcher = mock()
|
20
|
+
block_watcher.should_receive(:executed)
|
21
|
+
|
22
|
+
clh = Parser.new do
|
23
|
+
value_type :string do |str|
|
24
|
+
str
|
25
|
+
end
|
26
|
+
|
27
|
+
block_watcher.executed
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "value types" do
|
33
|
+
it "should allow you to register new value types" do
|
34
|
+
@clh.configure do
|
35
|
+
value_type :string do |str|
|
36
|
+
str
|
37
|
+
end
|
38
|
+
|
39
|
+
value_type :int do |str|
|
40
|
+
str.to_i
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should fail it you try and define a duplicate value type" do
|
46
|
+
@clh.value_type :string do |str|
|
47
|
+
str
|
48
|
+
end
|
49
|
+
|
50
|
+
expect do
|
51
|
+
@clh.value_type :string do |str|
|
52
|
+
str
|
53
|
+
end
|
54
|
+
end.to raise_error(ConfigureError, /string/)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "switches are defined separately from commands" do
|
59
|
+
it "should let you define binary switch" do
|
60
|
+
help_switch
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should fail if you try and define a switch that takes an unknown value type" do
|
64
|
+
expect {@clh.value_switch :resize_to, :volume_size, '--resize-to'}.to raise_error(ConfigureError, /volume_size/)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should let you define an option that takes a single value" do
|
68
|
+
@clh.configure do
|
69
|
+
value_type :volume_size do |str|
|
70
|
+
str.to_i
|
71
|
+
end
|
72
|
+
|
73
|
+
value_switch :resize_to, :volume_size, '--resize-to'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "global switches" do
|
79
|
+
it "should let you bind global switch" do
|
80
|
+
help_switch
|
81
|
+
@clh.configure do
|
82
|
+
global do
|
83
|
+
switches :help
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should raise an error if the switch hasn't been previously defined" do
|
89
|
+
expect do
|
90
|
+
@clh.global do
|
91
|
+
switches :become_sentient
|
92
|
+
end
|
93
|
+
end.to raise_error(ConfigureError)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "sub commands" do
|
98
|
+
it "should let you register a command" do
|
99
|
+
@clh.configure do
|
100
|
+
command(:create) {}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should let you omit the block for a command" do
|
105
|
+
@clh.configure do
|
106
|
+
command :create
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should let you bind switches" do
|
111
|
+
@clh.configure do
|
112
|
+
simple_switch :grow_to, '--grow-to'
|
113
|
+
simple_switch :grow_by, '--grow-by'
|
114
|
+
simple_switch :shrink_to, '--shrink-to'
|
115
|
+
simple_switch :shrink_by, '--shrink-by'
|
116
|
+
|
117
|
+
command :resize do
|
118
|
+
switches :grow_to, :grow_by, :shrink_to, :shrink_by
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "parsing" do
|
125
|
+
describe "global command" do
|
126
|
+
it "should handle no switches" do
|
127
|
+
handler = mock()
|
128
|
+
handler.should_receive(:global_command).with({}, [])
|
129
|
+
@clh.parse(handler)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should raise a ParseError if an unrecognised switch is used" do
|
133
|
+
handler = mock()
|
134
|
+
expect {@clh.parse(handler, '--go-back-in-time')}.to raise_error(ParseError, /--go-back-in-time/)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should handle binary switches" do
|
138
|
+
handler = mock()
|
139
|
+
handler.should_receive(:global_command).with({:help => true}, [])
|
140
|
+
|
141
|
+
@clh.configure do
|
142
|
+
simple_switch :help, '--help', '-h'
|
143
|
+
global do
|
144
|
+
switches :help
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
@clh.parse(handler, '-h')
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should handle multiple binary switches" do
|
152
|
+
handler = mock()
|
153
|
+
handler.should_receive(:global_command).with({:help => true, :ro => true}, [])
|
154
|
+
|
155
|
+
@clh.configure do
|
156
|
+
simple_switch :help, '--help', '-h'
|
157
|
+
simple_switch :ro, '--read-only', '-r'
|
158
|
+
|
159
|
+
global do
|
160
|
+
switches :help, :ro
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
@clh.parse(handler, '-h', '--read-only')
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should handle valued switches" do
|
168
|
+
handler = mock()
|
169
|
+
|
170
|
+
@clh.configure do
|
171
|
+
value_type :int do |str|
|
172
|
+
str.to_i
|
173
|
+
end
|
174
|
+
|
175
|
+
value_switch :count, :int, '--count', '-c'
|
176
|
+
|
177
|
+
global do
|
178
|
+
switches :count
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
handler.should_receive(:global_command).
|
183
|
+
with({:count => 17}, [])
|
184
|
+
@clh.parse(handler, '--count', '17')
|
185
|
+
|
186
|
+
handler.should_receive(:global_command).
|
187
|
+
with({:count => 17}, ['one', 'two'])
|
188
|
+
@clh.parse(handler, 'one', '-c', '17', 'two')
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should raise an ArgumentError if no value is given for a valued switch" do
|
192
|
+
handler = mock()
|
193
|
+
|
194
|
+
@clh.configure do
|
195
|
+
value_type :int do |str|
|
196
|
+
str.to_i
|
197
|
+
end
|
198
|
+
|
199
|
+
value_switch :count, :int, '--count', '-c'
|
200
|
+
|
201
|
+
global do
|
202
|
+
switches :count
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
expect do
|
207
|
+
@clh.parse(handler, '--count')
|
208
|
+
end.to raise_error(ParseError, /count/)
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should filter non-switches out" do
|
212
|
+
handler = mock()
|
213
|
+
handler.should_receive(:global_command).
|
214
|
+
with({:help => true, :ro => true}, ['my_file', 'my_other_file'])
|
215
|
+
|
216
|
+
@clh.configure do
|
217
|
+
simple_switch :help, '--help', '-h'
|
218
|
+
simple_switch :ro, '--read-only', '-r'
|
219
|
+
|
220
|
+
global do
|
221
|
+
switches :help, :ro
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
@clh.parse(handler, '-h', 'my_file', '--read-only', 'my_other_file')
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe "simple commands" do
|
230
|
+
it "should handle commands that take no switches" do
|
231
|
+
@clh.configure do
|
232
|
+
command :create do
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
handler = mock()
|
237
|
+
handler.should_receive(:create).with({}, ['fred'])
|
238
|
+
@clh.parse(handler, 'create', 'fred')
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
describe "commands" do
|
243
|
+
before :each do
|
244
|
+
@clh.configure do
|
245
|
+
value_type :int do |str|
|
246
|
+
str.to_i
|
247
|
+
end
|
248
|
+
|
249
|
+
value_switch :grow_to, :int, '--grow-to'
|
250
|
+
value_switch :grow_by, :int, '--grow-by'
|
251
|
+
value_switch :shrink_to, :int, '--shrink-to'
|
252
|
+
value_switch :shrink_by, :int, '--shrink-by'
|
253
|
+
|
254
|
+
command :resize do
|
255
|
+
switches :grow_to, :grow_by, :shrink_to, :shrink_by
|
256
|
+
end
|
257
|
+
|
258
|
+
command :shrink do
|
259
|
+
switches :grow_to, :grow_by, :shrink_to, :shrink_by
|
260
|
+
end
|
261
|
+
|
262
|
+
command :grow do
|
263
|
+
switches :grow_to, :grow_by, :shrink_to, :shrink_by
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should allow you to define a sub command" do
|
269
|
+
handler = mock()
|
270
|
+
handler.should_receive(:resize).with({:grow_to => 12345}, ['fred'])
|
271
|
+
@clh.parse(handler, 'resize', '--grow-to', '12345', 'fred')
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should prevent you calling two sub commands on the same line" do
|
275
|
+
handler = mock()
|
276
|
+
handler.should_receive(:resize).
|
277
|
+
with({:grow_to => 1234, :shrink_to => 2345}, ['shrink', 'fred'])
|
278
|
+
@clh.parse(handler, 'resize', '--grow-to', '1234', 'shrink', '--shrink-to', '2345', 'fred')
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
describe "exclusive switches" do
|
283
|
+
before :each do
|
284
|
+
@clh.configure do
|
285
|
+
value_type :int do |str|
|
286
|
+
str.to_i
|
287
|
+
end
|
288
|
+
|
289
|
+
value_switch :grow_to, :int, '--grow-to'
|
290
|
+
value_switch :grow_by, :int, '--grow-by'
|
291
|
+
value_switch :shrink_to, :int, '--shrink-to'
|
292
|
+
value_switch :shrink_by, :int, '--shrink-by'
|
293
|
+
|
294
|
+
command :resize do
|
295
|
+
one_of :grow_to, :grow_by, :shrink_to, :shrink_by
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
it "should parse one exclusive switch" do
|
301
|
+
handler = mock()
|
302
|
+
handler.should_receive(:resize).
|
303
|
+
with({:grow_to => 1234}, ['fred'])
|
304
|
+
@clh.parse(handler, 'resize', '--grow-to', '1234', 'fred')
|
305
|
+
end
|
306
|
+
|
307
|
+
it "should raise a ParseError if more than one switch from an exclusive set is defined" do
|
308
|
+
handler = mock()
|
309
|
+
expect do
|
310
|
+
@clh.parse(handler, 'resize', '--grow-to', '1234', '--shrink-by', '2345', 'fred')
|
311
|
+
end.to raise_error(ParseError, /mutually exclusive/)
|
312
|
+
# FIXME: would be nice to see the actual flags in the exception
|
313
|
+
end
|
314
|
+
|
315
|
+
it "should let you define more than one exclusive set" do
|
316
|
+
pending
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should handle --foo=<value>" do
|
321
|
+
pending "todo"
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
describe "mandatory switches" do
|
326
|
+
before :each do
|
327
|
+
@clh.configure do
|
328
|
+
value_type :int do |str|
|
329
|
+
str.to_i
|
330
|
+
end
|
331
|
+
|
332
|
+
value_switch :grow_to, :int, '--grow-to'
|
333
|
+
value_switch :grow_by, :int, '--grow-by'
|
334
|
+
value_switch :shrink_to, :int, '--shrink-to'
|
335
|
+
value_switch :shrink_by, :int, '--shrink-by'
|
336
|
+
|
337
|
+
command :resize do
|
338
|
+
mandatory :grow_to
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
it "should parse ok if mandatory switch is given" do
|
344
|
+
handler = mock()
|
345
|
+
handler.should_receive(:resize).
|
346
|
+
with({:grow_to => 3}, ['fred'])
|
347
|
+
@clh.parse(handler, 'resize', '--grow-to', '3', 'fred')
|
348
|
+
end
|
349
|
+
|
350
|
+
it "should raise a ParseError if a mandatory switch is omitted" do
|
351
|
+
handler = mock()
|
352
|
+
expect do
|
353
|
+
@clh.parse(handler, 'resize', 'fred')
|
354
|
+
end.to raise_error(ParseError, /grow_to/)
|
355
|
+
end
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
#----------------------------------------------------------------
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ejt_command_line
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joe Thornber
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-05-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Yet another command line parser. Allows you define argument types
|
56
|
+
email:
|
57
|
+
- ejt@redhat.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .gitignore
|
63
|
+
- .rspec
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- ejt_command_line.gemspec
|
69
|
+
- lib/ejt_command_line.rb
|
70
|
+
- lib/ejt_command_line/version.rb
|
71
|
+
- spec/command_line_spec.rb
|
72
|
+
- spec/command_line_spec.rb~
|
73
|
+
- spec/spec_helper.rb
|
74
|
+
homepage: ''
|
75
|
+
licenses:
|
76
|
+
- GPL
|
77
|
+
metadata: {}
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ! '>='
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubyforge_project:
|
94
|
+
rubygems_version: 2.0.3
|
95
|
+
signing_key:
|
96
|
+
specification_version: 4
|
97
|
+
summary: Command line parser
|
98
|
+
test_files:
|
99
|
+
- spec/command_line_spec.rb
|
100
|
+
- spec/command_line_spec.rb~
|
101
|
+
- spec/spec_helper.rb
|