clive 0.8.1 → 1.0.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.
- data/LICENSE +1 -1
- data/README.md +328 -227
- data/lib/clive.rb +130 -50
- data/lib/clive/argument.rb +170 -0
- data/lib/clive/arguments.rb +139 -0
- data/lib/clive/arguments/parser.rb +210 -0
- data/lib/clive/base.rb +189 -0
- data/lib/clive/command.rb +342 -444
- data/lib/clive/error.rb +66 -0
- data/lib/clive/formatter.rb +57 -141
- data/lib/clive/formatter/colour.rb +37 -0
- data/lib/clive/formatter/plain.rb +172 -0
- data/lib/clive/option.rb +185 -75
- data/lib/clive/option/runner.rb +163 -0
- data/lib/clive/output.rb +141 -16
- data/lib/clive/parser.rb +180 -87
- data/lib/clive/struct_hash.rb +109 -0
- data/lib/clive/type.rb +117 -0
- data/lib/clive/type/definitions.rb +170 -0
- data/lib/clive/type/lookup.rb +23 -0
- data/lib/clive/version.rb +3 -3
- data/spec/clive/a_cli_spec.rb +245 -0
- data/spec/clive/argument_spec.rb +148 -0
- data/spec/clive/arguments/parser_spec.rb +35 -0
- data/spec/clive/arguments_spec.rb +191 -0
- data/spec/clive/command_spec.rb +276 -209
- data/spec/clive/formatter/colour_spec.rb +129 -0
- data/spec/clive/formatter/plain_spec.rb +129 -0
- data/spec/clive/option/runner_spec.rb +92 -0
- data/spec/clive/option_spec.rb +149 -23
- data/spec/clive/output_spec.rb +86 -2
- data/spec/clive/parser_spec.rb +201 -81
- data/spec/clive/struct_hash_spec.rb +82 -0
- data/spec/clive/type/definitions_spec.rb +312 -0
- data/spec/clive/type_spec.rb +107 -0
- data/spec/clive_spec.rb +60 -0
- data/spec/extras/expectations.rb +86 -0
- data/spec/extras/focus.rb +22 -0
- data/spec/helper.rb +35 -0
- metadata +56 -36
- data/lib/clive/bool.rb +0 -67
- data/lib/clive/exceptions.rb +0 -54
- data/lib/clive/flag.rb +0 -199
- data/lib/clive/switch.rb +0 -31
- data/lib/clive/tokens.rb +0 -141
- data/spec/clive/bool_spec.rb +0 -54
- data/spec/clive/flag_spec.rb +0 -117
- data/spec/clive/formatter_spec.rb +0 -108
- data/spec/clive/switch_spec.rb +0 -14
- data/spec/clive/tokens_spec.rb +0 -38
- data/spec/shared_specs.rb +0 -16
- data/spec/spec_helper.rb +0 -12
@@ -0,0 +1,312 @@
|
|
1
|
+
$: << File.dirname(__FILE__) + '/../..'
|
2
|
+
require 'helper'
|
3
|
+
|
4
|
+
describe Clive::Type::Object do
|
5
|
+
subject { Clive::Type::Object }
|
6
|
+
|
7
|
+
describe '#valid?' do
|
8
|
+
it 'is always valid' do
|
9
|
+
subject.must_be :valid?, 'a'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#typecast' do
|
14
|
+
it 'returns the argument given' do
|
15
|
+
subject.typecast('a').must_be_kind_of Object
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Clive::Type::String do
|
21
|
+
subject { Clive::Type::String }
|
22
|
+
|
23
|
+
describe '#valid?' do
|
24
|
+
it 'is valid for non nil values' do
|
25
|
+
subject.must_be :valid?, 'a'
|
26
|
+
subject.wont_be :valid?, nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#typecast' do
|
31
|
+
it 'returns a String' do
|
32
|
+
subject.typecast('a').must_be_kind_of String
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe Clive::Type::Symbol do
|
38
|
+
subject { Clive::Type::Symbol }
|
39
|
+
|
40
|
+
describe '#valid?' do
|
41
|
+
it 'is valid for non nil values' do
|
42
|
+
subject.must_be :valid?, 'a'
|
43
|
+
subject.wont_be :valid?, nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#typecast' do
|
48
|
+
it 'returns a Symbol' do
|
49
|
+
subject.typecast('a').must_be_kind_of Symbol
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe Clive::Type::Integer do
|
55
|
+
subject { Clive::Type::Integer }
|
56
|
+
|
57
|
+
describe '#valid?' do
|
58
|
+
it 'is valid for numbers' do
|
59
|
+
%w(120 120.5 .5 120e7 120.5e7).all? {|a|
|
60
|
+
subject.valid?(a) && subject.valid?('-'+a)
|
61
|
+
}.must_be_true
|
62
|
+
subject.wont_be :valid?, 'abc'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#typecast' do
|
67
|
+
it 'returns an Integer' do
|
68
|
+
r = subject.typecast('120.50e7')
|
69
|
+
r.must_be_kind_of Integer
|
70
|
+
r.must_equal 120
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe Clive::Type::StrictInteger do
|
76
|
+
subject { Clive::Type::StrictInteger }
|
77
|
+
|
78
|
+
describe '#valid?' do
|
79
|
+
it 'is valid for integers' do
|
80
|
+
%w(120 120e7).all? {|a|
|
81
|
+
subject.valid?(a) &&
|
82
|
+
subject.valid?('-'+a)
|
83
|
+
}.must_be_true
|
84
|
+
|
85
|
+
%w(120.5 .5 120.5e7).all? {|a|
|
86
|
+
subject.valid?(a) &&
|
87
|
+
subject.valid?('-'+a)
|
88
|
+
}.must_be_false
|
89
|
+
|
90
|
+
subject.wont_be :valid?, 'abc'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#typecast' do
|
95
|
+
it 'returns an Integer' do
|
96
|
+
r = subject.typecast('120.50e7')
|
97
|
+
r.must_be_kind_of Integer
|
98
|
+
r.must_equal 120
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe Clive::Type::Binary do
|
104
|
+
subject { Clive::Type::Binary }
|
105
|
+
|
106
|
+
describe '#valid?' do
|
107
|
+
it 'is valid for binary numbers' do
|
108
|
+
%w(1 11 101).all? {|a|
|
109
|
+
subject.valid?(a) &&
|
110
|
+
subject.valid?('-'+a) &&
|
111
|
+
subject.valid?('0b'+a) &&
|
112
|
+
subject.valid?('-0b'+a)
|
113
|
+
}.must_be_true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#typecast' do
|
118
|
+
it 'returns an Integer' do
|
119
|
+
r = subject.typecast('0b101')
|
120
|
+
r.must_be_kind_of Integer
|
121
|
+
r.must_equal 5
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe Clive::Type::Octal do
|
127
|
+
subject { Clive::Type::Octal }
|
128
|
+
|
129
|
+
describe '#valid?' do
|
130
|
+
it 'is valid for octal numbers' do
|
131
|
+
%w(4 62 701).all? {|a|
|
132
|
+
subject.valid?(a) &&
|
133
|
+
subject.valid?('-'+a) &&
|
134
|
+
subject.valid?('0'+a) &&
|
135
|
+
subject.valid?('0o'+a) &&
|
136
|
+
subject.valid?('-0O'+a)
|
137
|
+
}.must_be_true
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#typecast' do
|
142
|
+
it 'returns an Integer' do
|
143
|
+
r = subject.typecast('0257')
|
144
|
+
r.must_be_kind_of Integer
|
145
|
+
r.must_equal 175
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe Clive::Type::Hexadecimal do
|
151
|
+
subject { Clive::Type::Hexadecimal }
|
152
|
+
|
153
|
+
describe '#valid?' do
|
154
|
+
it 'is valid for hexadecimal numbers' do
|
155
|
+
%w(aa1 4f 66bb1).all? {|a|
|
156
|
+
subject.valid?(a) &&
|
157
|
+
subject.valid?('-'+a) &&
|
158
|
+
subject.valid?('0x'+a) &&
|
159
|
+
subject.valid?('-0X'+a)
|
160
|
+
}.must_be_true
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe '#typecast' do
|
165
|
+
it 'returns an Integer' do
|
166
|
+
r = subject.typecast('0x4f')
|
167
|
+
r.must_be_kind_of Integer
|
168
|
+
r.must_equal 79
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe Clive::Type::Float do
|
174
|
+
subject { Clive::Type::Float }
|
175
|
+
|
176
|
+
describe '#valid?' do
|
177
|
+
it 'is valid for numbers' do
|
178
|
+
%w(120 120.5 .5 120e7 120.5e7).all? {|a|
|
179
|
+
subject.valid?(a) && subject.valid?('-'+a)
|
180
|
+
}.must_be_true
|
181
|
+
subject.wont_be :valid?, 'abc'
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
describe '#typecast' do
|
186
|
+
it 'returns a Float' do
|
187
|
+
r = subject.typecast('120.50e7')
|
188
|
+
r.must_be_kind_of Float
|
189
|
+
r.must_equal 120.5e7
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe Clive::Type::Boolean do
|
195
|
+
subject { Clive::Type::Boolean }
|
196
|
+
|
197
|
+
describe '#valid?' do
|
198
|
+
it 'is valid for various true and false values' do
|
199
|
+
%w(true t yes y on false f no n off).all? {|a| subject.valid? a }.must_be_true
|
200
|
+
subject.wont_be :valid?, 'abc'
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe '#typecast' do
|
205
|
+
it 'returns a Boolean' do
|
206
|
+
subject.typecast('y').must_be_true
|
207
|
+
subject.typecast('off').must_be_false
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe Clive::Type::Pathname do
|
213
|
+
subject { Clive::Type::Pathname }
|
214
|
+
|
215
|
+
describe '#valid?' do
|
216
|
+
it 'is valid for non nil values' do
|
217
|
+
subject.must_be :valid?, '~/path'
|
218
|
+
subject.wont_be :valid?, nil
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe '#typecast' do
|
223
|
+
it 'returns a Pathname' do
|
224
|
+
r = subject.typecast('~/path')
|
225
|
+
r.must_be_kind_of Pathname
|
226
|
+
r.to_s.must_equal '~/path'
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe Clive::Type::Range do
|
232
|
+
subject { Clive::Type::Range }
|
233
|
+
|
234
|
+
describe '#valid?' do
|
235
|
+
it 'is valid for ranges' do
|
236
|
+
%w(1..5 1...5 1-5).all? {|a| subject.valid? a }.must_be_true
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe '#typecast' do
|
241
|
+
it 'returns a Range for a...z' do
|
242
|
+
r = subject.typecast('a...z')
|
243
|
+
r.must_be_kind_of Range
|
244
|
+
r.must_equal 'a'...'z'
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'returns a Range for a..z' do
|
248
|
+
r = subject.typecast('a..z')
|
249
|
+
r.must_be_kind_of Range
|
250
|
+
r.must_equal 'a'..'z'
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'returns a Range for a-z' do
|
254
|
+
r = subject.typecast('a-z')
|
255
|
+
r.must_be_kind_of Range
|
256
|
+
r.must_equal 'a'..'z'
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
describe Clive::Type::Array do
|
262
|
+
subject { Clive::Type::Array }
|
263
|
+
|
264
|
+
describe '#valid?' do
|
265
|
+
it 'is valud for arrays' do
|
266
|
+
['a,b,c', '"hello",123,true,"what a sentence"'].all? {|a|
|
267
|
+
subject.valid? a
|
268
|
+
}.must_be_true
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
describe '#typecast' do
|
273
|
+
it 'returns an Array' do
|
274
|
+
r = subject.typecast('"hello",123,true,"what a sentence"')
|
275
|
+
r.must_be_kind_of Array
|
276
|
+
r.must_equal ['"hello"', '123', 'true', '"what a sentence"']
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
describe Clive::Type::Time do
|
282
|
+
subject { Clive::Type::Time }
|
283
|
+
|
284
|
+
describe '#valid?' do
|
285
|
+
it 'is valid for times' do
|
286
|
+
%w(12:50 12:50:30).all? {|a| subject.valid?(a) }.must_be_true
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
describe '#typecast' do
|
291
|
+
it 'returns a Time' do
|
292
|
+
subject.typecast('12:50').must_be_kind_of Time
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
describe Clive::Type::Regexp do
|
298
|
+
subject { Clive::Type::Regexp }
|
299
|
+
|
300
|
+
describe '#valid?' do
|
301
|
+
it 'is valid for regular expressions' do
|
302
|
+
%w{/a/ /a[bc](1|2)/ix}.all? {|a| subject.valid?(a) }.must_be_true
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
describe '#typecast' do
|
307
|
+
it 'returns a Regexp' do
|
308
|
+
subject.typecast('/a/i').must_be_kind_of Regexp
|
309
|
+
subject.typecast('/a/ix').must_equal /a/ix
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
$: << File.dirname(__FILE__) + '/..'
|
2
|
+
require 'helper'
|
3
|
+
|
4
|
+
describe Clive::Type do
|
5
|
+
|
6
|
+
subject { Class.new(Clive::Type) }
|
7
|
+
let(:instance) { Clive::Type.new }
|
8
|
+
|
9
|
+
describe '#valid?' do
|
10
|
+
it 'returns false' do
|
11
|
+
instance.valid?('arg').must_be_false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#typecast' do
|
16
|
+
it 'returns nil' do
|
17
|
+
instance.typecast('arg').must_be_nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.find_class' do
|
22
|
+
it 'returns the correct Type subclass' do
|
23
|
+
s = Clive::Type::Integer
|
24
|
+
subject.find_class('Integer').must_equal s
|
25
|
+
subject.find_class('Clive::Integer').must_equal s
|
26
|
+
subject.find_class('I::Dont::Exist::Integer').must_equal s
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns nil if it can not be found' do
|
30
|
+
subject.find_class('What::No').must_be_nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '.match' do
|
35
|
+
it 'sets a proc given a symbol' do
|
36
|
+
sym, obj = mock, Object.new
|
37
|
+
sym.expects(:to_proc).with().returns(obj)
|
38
|
+
|
39
|
+
subject.match sym
|
40
|
+
subject.instance_variable_get(:@valid).must_equal obj
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'sets a proc given a regular expression' do
|
44
|
+
subject.match /a|b|c/
|
45
|
+
subject.instance_variable_get(:@valid).class.must_equal Proc
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '.refute' do
|
50
|
+
it 'sets a proc given a symbol' do
|
51
|
+
subject.refute :odd?
|
52
|
+
subject.instance_variable_get(:@valid).class.must_equal Proc
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'sets a proc given a regular expression' do
|
56
|
+
subject.refute /a|b|c/
|
57
|
+
subject.instance_variable_get(:@valid).class.must_equal Proc
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '.cast' do
|
62
|
+
it 'sets a symbol' do
|
63
|
+
subject.cast :to_i
|
64
|
+
subject.instance_variable_get(:@cast).must_equal [:to_i, []]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '.valid?' do
|
69
|
+
describe 'if @valid has been set' do
|
70
|
+
it 'calls the block' do
|
71
|
+
sym, prc = mock, mock
|
72
|
+
sym.expects(:to_proc).with().returns(prc)
|
73
|
+
prc.expects(:call).with('arg').returns(true)
|
74
|
+
|
75
|
+
subject.match sym
|
76
|
+
subject.valid? 'arg'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'if @valid has not been set' do
|
81
|
+
it 'calls #valid?' do
|
82
|
+
subject.any_instance.expects(:valid?).with('arg')
|
83
|
+
subject.valid? 'arg'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '.typecast' do
|
89
|
+
describe 'if @cast has been set' do
|
90
|
+
it 'uses the method set' do
|
91
|
+
arg = mock
|
92
|
+
arg.expects(:send).with(:to_i).returns(true)
|
93
|
+
|
94
|
+
subject.cast :to_i
|
95
|
+
subject.typecast arg
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe 'if @cast has not been set' do
|
100
|
+
it 'calls #typecast' do
|
101
|
+
subject.any_instance.expects(:typecast).with('arg')
|
102
|
+
subject.typecast 'arg'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
data/spec/clive_spec.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
$: << File.dirname(__FILE__)
|
2
|
+
require 'helper'
|
3
|
+
|
4
|
+
# For some reason Class.new(Clive) { Boolean } throws an error?
|
5
|
+
class IncludingCliveReferenceTest < Clive
|
6
|
+
opt :name, :as => Boolean
|
7
|
+
end
|
8
|
+
|
9
|
+
describe Clive do
|
10
|
+
|
11
|
+
describe 'inheriting Clive' do
|
12
|
+
subject { Class.new(Clive) }
|
13
|
+
|
14
|
+
it 'responds to all the methods in Base' do
|
15
|
+
(Clive::Base.instance_methods - Object.instance_methods).each do |meth|
|
16
|
+
subject.must_respond_to meth.to_sym
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'allows you to reference Types' do
|
21
|
+
IncludingCliveReferenceTest.find('--name').args.first.type.
|
22
|
+
must_equal Clive::Type::Boolean
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'allows you to get the Base instance' do
|
26
|
+
subject.instance.must_be_kind_of Clive::Base
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'initializing Clive' do
|
31
|
+
subject { Clive.new }
|
32
|
+
|
33
|
+
it 'actually initializes Clive::Base' do
|
34
|
+
subject.must_be_instance_of Clive::Base
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not allow you to reference Types' do
|
38
|
+
# For some reason this works in 1.9.2, possibly others, but it should
|
39
|
+
# definitely not be relied on to work as it will raise a NameError under
|
40
|
+
# most versions.
|
41
|
+
unless RUBY_VERSION =~ /^1.9.2/
|
42
|
+
this { Clive.new { Boolean } }.must_raise NameError
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'Clive#()' do
|
49
|
+
subject { Clive(:verbose, [:b, :bare]) }
|
50
|
+
|
51
|
+
it 'creates an option for symbols passed' do
|
52
|
+
subject.must_have_option :verbose
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'uses both names if given as an array' do
|
56
|
+
subject.find_option(:b).must_equal subject.find_option(:bare)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|