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.
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