clive 0.8.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +328 -227
  3. data/lib/clive.rb +130 -50
  4. data/lib/clive/argument.rb +170 -0
  5. data/lib/clive/arguments.rb +139 -0
  6. data/lib/clive/arguments/parser.rb +210 -0
  7. data/lib/clive/base.rb +189 -0
  8. data/lib/clive/command.rb +342 -444
  9. data/lib/clive/error.rb +66 -0
  10. data/lib/clive/formatter.rb +57 -141
  11. data/lib/clive/formatter/colour.rb +37 -0
  12. data/lib/clive/formatter/plain.rb +172 -0
  13. data/lib/clive/option.rb +185 -75
  14. data/lib/clive/option/runner.rb +163 -0
  15. data/lib/clive/output.rb +141 -16
  16. data/lib/clive/parser.rb +180 -87
  17. data/lib/clive/struct_hash.rb +109 -0
  18. data/lib/clive/type.rb +117 -0
  19. data/lib/clive/type/definitions.rb +170 -0
  20. data/lib/clive/type/lookup.rb +23 -0
  21. data/lib/clive/version.rb +3 -3
  22. data/spec/clive/a_cli_spec.rb +245 -0
  23. data/spec/clive/argument_spec.rb +148 -0
  24. data/spec/clive/arguments/parser_spec.rb +35 -0
  25. data/spec/clive/arguments_spec.rb +191 -0
  26. data/spec/clive/command_spec.rb +276 -209
  27. data/spec/clive/formatter/colour_spec.rb +129 -0
  28. data/spec/clive/formatter/plain_spec.rb +129 -0
  29. data/spec/clive/option/runner_spec.rb +92 -0
  30. data/spec/clive/option_spec.rb +149 -23
  31. data/spec/clive/output_spec.rb +86 -2
  32. data/spec/clive/parser_spec.rb +201 -81
  33. data/spec/clive/struct_hash_spec.rb +82 -0
  34. data/spec/clive/type/definitions_spec.rb +312 -0
  35. data/spec/clive/type_spec.rb +107 -0
  36. data/spec/clive_spec.rb +60 -0
  37. data/spec/extras/expectations.rb +86 -0
  38. data/spec/extras/focus.rb +22 -0
  39. data/spec/helper.rb +35 -0
  40. metadata +56 -36
  41. data/lib/clive/bool.rb +0 -67
  42. data/lib/clive/exceptions.rb +0 -54
  43. data/lib/clive/flag.rb +0 -199
  44. data/lib/clive/switch.rb +0 -31
  45. data/lib/clive/tokens.rb +0 -141
  46. data/spec/clive/bool_spec.rb +0 -54
  47. data/spec/clive/flag_spec.rb +0 -117
  48. data/spec/clive/formatter_spec.rb +0 -108
  49. data/spec/clive/switch_spec.rb +0 -14
  50. data/spec/clive/tokens_spec.rb +0 -38
  51. data/spec/shared_specs.rb +0 -16
  52. 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
@@ -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