choosy 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/Gemfile +7 -0
  2. data/Gemfile.lock +25 -0
  3. data/LICENSE +23 -0
  4. data/README.markdown +393 -0
  5. data/Rakefile +57 -0
  6. data/lib/VERSION +1 -0
  7. data/lib/choosy/base_command.rb +59 -0
  8. data/lib/choosy/command.rb +32 -0
  9. data/lib/choosy/converter.rb +115 -0
  10. data/lib/choosy/dsl/base_command_builder.rb +172 -0
  11. data/lib/choosy/dsl/command_builder.rb +43 -0
  12. data/lib/choosy/dsl/option_builder.rb +155 -0
  13. data/lib/choosy/dsl/super_command_builder.rb +41 -0
  14. data/lib/choosy/errors.rb +11 -0
  15. data/lib/choosy/option.rb +22 -0
  16. data/lib/choosy/parse_result.rb +64 -0
  17. data/lib/choosy/parser.rb +184 -0
  18. data/lib/choosy/printing/color.rb +101 -0
  19. data/lib/choosy/printing/erb_printer.rb +23 -0
  20. data/lib/choosy/printing/help_printer.rb +174 -0
  21. data/lib/choosy/super_command.rb +77 -0
  22. data/lib/choosy/super_parser.rb +81 -0
  23. data/lib/choosy/verifier.rb +62 -0
  24. data/lib/choosy/version.rb +12 -0
  25. data/lib/choosy.rb +16 -0
  26. data/spec/choosy/base_command_spec.rb +11 -0
  27. data/spec/choosy/command_spec.rb +51 -0
  28. data/spec/choosy/converter_spec.rb +145 -0
  29. data/spec/choosy/dsl/base_command_builder_spec.rb +328 -0
  30. data/spec/choosy/dsl/commmand_builder_spec.rb +80 -0
  31. data/spec/choosy/dsl/option_builder_spec.rb +386 -0
  32. data/spec/choosy/dsl/super_command_builder_spec.rb +83 -0
  33. data/spec/choosy/parser_spec.rb +275 -0
  34. data/spec/choosy/printing/color_spec.rb +74 -0
  35. data/spec/choosy/printing/help_printer_spec.rb +117 -0
  36. data/spec/choosy/super_command_spec.rb +80 -0
  37. data/spec/choosy/super_parser_spec.rb +106 -0
  38. data/spec/choosy/verifier_spec.rb +180 -0
  39. data/spec/integration/command-A_spec.rb +37 -0
  40. data/spec/integration/supercommand-A_spec.rb +61 -0
  41. data/spec/spec_helpers.rb +30 -0
  42. metadata +150 -0
@@ -0,0 +1,386 @@
1
+ require 'spec_helpers'
2
+ require 'choosy'
3
+
4
+ module Choosy::DSL
5
+ describe OptionBuilder do
6
+ before :each do
7
+ @builder = OptionBuilder.new(:stub)
8
+ @option = @builder.option
9
+ end
10
+
11
+ describe :name do
12
+ it "should set the name" do
13
+ @option.name.should eql(:stub)
14
+ end
15
+ end
16
+
17
+ describe :short do
18
+ it "should set the option" do
19
+ @builder.short '-s'
20
+ @option.short_flag.should eql('-s')
21
+ end
22
+
23
+ describe "and the arity" do
24
+ it "should not be set without a parameter" do
25
+ @builder.short '-s'
26
+ @option.short_flag.should eql('-s')
27
+ @option.arity.should be(nil)
28
+ end
29
+
30
+ it "should be set on STD+ parameter" do
31
+ @builder.short '-s', 'STD+'
32
+ @option.arity.should eql(1..1000)
33
+ end
34
+
35
+ it "should set single arity on STD parameter" do
36
+ @builder.short '-s', 'STD'
37
+ @option.arity.should eql(1..1)
38
+ end
39
+
40
+ it "should not set the arity if :count has already been called" do
41
+ @builder.count 3
42
+ @builder.short '-s', 'STD'
43
+ @option.arity.should eql(3..3)
44
+ end
45
+ end
46
+
47
+ describe "and the flag parameter" do
48
+ it "on STD parameters" do
49
+ @builder.short '-s', 'STD'
50
+ @option.flag_parameter.should eql('STD')
51
+ end
52
+
53
+ it "on STD+ parameters" do
54
+ @builder.short '-s', 'STD+'
55
+ @option.flag_parameter.should eql('STD+')
56
+ end
57
+ end
58
+ end#short
59
+
60
+ describe :long do
61
+ it "should set the flag correctly" do
62
+ @builder.long '--short'
63
+ @option.long_flag.should eql('--short')
64
+ end
65
+
66
+ describe "while setting arity" do
67
+ it "should not set arity on empty" do
68
+ @builder.long '--short'
69
+ @option.arity.should be(nil)
70
+ end
71
+
72
+ it "should set the arity on STD to 1" do
73
+ @builder.long '--short', 'STD'
74
+ @option.arity.should eql(1..1)
75
+ end
76
+
77
+ it "should set the arity on STD+ to 1+" do
78
+ @builder.long '--short', 'STD+'
79
+ @option.arity.should eql(1..1000)
80
+ end
81
+ end#arity
82
+
83
+ describe "and the flag parameter" do
84
+ it "on STD parameters" do
85
+ @builder.long '-s', 'STD'
86
+ @option.flag_parameter.should eql('STD')
87
+ end
88
+
89
+ it "on STD+ parameters" do
90
+ @builder.long '-s', 'STD+'
91
+ @option.flag_parameter.should eql('STD+')
92
+ end
93
+ end
94
+ end#long
95
+
96
+ describe :flags do
97
+ it "should be able to set the short flag" do
98
+ @builder.flags '-s'
99
+ @option.short_flag.should eql('-s')
100
+ end
101
+
102
+ it "should the long flag unset when just the short flag is given" do
103
+ @builder.flags '-s'
104
+ @option.long_flag.should be(nil)
105
+ end
106
+
107
+ it "should leave the param nil when just the short flag is given" do
108
+ @builder.flags '-s'
109
+ @option.flag_parameter.should be(nil)
110
+ end
111
+
112
+ it "should be able to set the short when the long flag is given" do
113
+ @builder.flags '-s', '--short'
114
+ @option.short_flag.should eql('-s')
115
+ end
116
+
117
+ it "should be able to set the long flag when given" do
118
+ @builder.flags '-s', '--short'
119
+ @option.long_flag.should eql('--short')
120
+ end
121
+
122
+ it "should leave the parameter empty when not given" do
123
+ @builder.flags '-s', '--short'
124
+ @option.flag_parameter.should be(nil)
125
+ end
126
+
127
+ it "should set the parameter if given" do
128
+ @builder.flags '-s', '--short', 'SHORT'
129
+ @option.flag_parameter.should eql('SHORT')
130
+ end
131
+ end#flags
132
+
133
+ describe :desc do
134
+ it "should set the option correctly" do
135
+ @builder.desc "This is an option"
136
+ @option.description.should =~ /^This/
137
+ end
138
+ end#desc
139
+
140
+ describe :default do
141
+ it "should set the option" do
142
+ @builder.default :clear
143
+ @option.default_value.should eql(:clear)
144
+ end
145
+ end#default
146
+
147
+ describe :required do
148
+ it "should set the option" do
149
+ @builder.required
150
+ @option.required?.should be(true)
151
+ end
152
+
153
+ it "should set the option on non-nil/non-true" do
154
+ @builder.required 1
155
+ @option.required?.should be(false)
156
+ end
157
+
158
+ it "should set the option on false" do
159
+ @builder.required false
160
+ @option.required?.should be(false)
161
+ end
162
+ end#required
163
+
164
+ describe :param do
165
+ it "should be able to set the name of the parameter" do
166
+ @builder.param 'PARAM'
167
+ @option.flag_parameter.should eql('PARAM')
168
+ end
169
+
170
+ it "should set the arity on STD+ to 1+" do
171
+ @builder.param 'STD+'
172
+ @option.arity.should eql(1..1000)
173
+ end
174
+
175
+ it "should set the arity on STD to 1" do
176
+ @builder.param 'STD'
177
+ @option.arity.should eql(1..1)
178
+ end
179
+ end#param
180
+
181
+ describe :count do
182
+ describe "when welformed" do
183
+ it "should set :at_least the right arity" do
184
+ @builder.count :at_least => 32
185
+ @option.arity.should eql(32..1000)
186
+ end
187
+
188
+ it "should set :at_most the right arity" do
189
+ @builder.count :at_most => 31
190
+ @option.arity.should eql(1..31)
191
+ end
192
+
193
+ it "should set :once to the right arity" do
194
+ @builder.count :once
195
+ @option.arity.should eql(1..1)
196
+ end
197
+
198
+ it "should set :zero to the right arity" do
199
+ @builder.count :zero
200
+ @option.arity.should eql(0..0)
201
+ end
202
+
203
+ it "should set :none to the right arity" do
204
+ @builder.count :none
205
+ @option.arity.should eql(0..0)
206
+ end
207
+
208
+ it "should set a number exactly" do
209
+ @builder.count 3
210
+ @option.arity.should eql(3..3)
211
+ end
212
+ end
213
+
214
+ describe "when malformed" do
215
+ it "should fail when the :exactly isn't a number" do
216
+ attempting {
217
+ @builder.count :exactly => 'p'
218
+ }.should raise_error(Choosy::ConfigurationError, /number/)
219
+ end
220
+
221
+ it "should fail when the :at_most isn't a number" do
222
+ attempting {
223
+ @builder.count :at_most => 'p'
224
+ }.should raise_error(Choosy::ConfigurationError, /number/)
225
+ end
226
+
227
+ it "should fail when the :at_least isn't a number" do
228
+ attempting {
229
+ @builder.count :at_least => 'p'
230
+ }.should raise_error(Choosy::ConfigurationError, /number/)
231
+ end
232
+
233
+ it "should fail when the :count isn't a number" do
234
+ attempting {
235
+ @builder.count 'p'
236
+ }.should raise_error(Choosy::ConfigurationError, /number/)
237
+ end
238
+
239
+ it "should fail when the :at_least is greater than :at_most" do
240
+ attempting {
241
+ @builder.count :at_least => 3, :at_most => 2
242
+ }.should raise_error(Choosy::ConfigurationError, /lower bound/)
243
+ end
244
+ end
245
+ end#count
246
+
247
+ describe :cast do
248
+ it "should allow symbol casts" do
249
+ @builder.cast :int
250
+ @option.cast_to.should eql(:integer)
251
+ end
252
+
253
+ class CustomConverter
254
+ def convert(value)
255
+ end
256
+ end
257
+
258
+ it "should allow for custom conversions" do
259
+ conv = CustomConverter.new
260
+ @builder.cast conv
261
+ @option.cast_to.should be(conv)
262
+ end
263
+
264
+ it "should fail if it doesn't know about a Type" do
265
+ attempting {
266
+ @builder.cast Choosy::Error
267
+ }.should raise_error(Choosy::ConfigurationError, /Unknown conversion/)
268
+ end
269
+
270
+ it "should fail if it doesn't know about a symbol" do
271
+ attempting {
272
+ @builder.cast :unknown_type
273
+ }.should raise_error(Choosy::ConfigurationError, /Unknown conversion/)
274
+ end
275
+ end#cast
276
+
277
+ describe :fail do
278
+ it "should format the error message with both flags" do
279
+ @builder.short '-k'
280
+ @builder.long '--keep', 'KEEP'
281
+ attempting {
282
+ @builder.fail "Didn't keep anything"
283
+ }.should raise_error(Choosy::ValidationError, /-k\/--keep KEEP: Didn't keep anything/)
284
+ end
285
+
286
+ it "should set the format of the error with the short flag" do
287
+ @builder.short '-k'
288
+ attempting {
289
+ @builder.fail "Didn't keep anything"
290
+ }.should raise_error(Choosy::ValidationError, /-k: Didn't keep anything/)
291
+ end
292
+
293
+ it "should set the format of the long flag alone" do
294
+ @builder.long '--keep'
295
+ attempting {
296
+ @builder.fail "Didn't keep anything"
297
+ }.should raise_error(Choosy::ValidationError, /--keep: Didn't keep anything/)
298
+ end
299
+ end#fail
300
+
301
+ describe :validate do
302
+ it "should save the context of the validation in a Proc to call later" do
303
+ @builder.validate do
304
+ puts "Hi!"
305
+ end
306
+ @option.validation_step.should be_a(Proc)
307
+ end
308
+
309
+ it "should have access to the larger context when called" do
310
+ value = nil
311
+ @builder.validate do
312
+ value = 'here'
313
+ end
314
+ @option.validation_step.call
315
+ value.should eql('here')
316
+ end
317
+ end#validate
318
+
319
+ describe :finalize! do
320
+ it "should set the arity if not already set" do
321
+ @builder.short '-s'
322
+ @builder.finalize!
323
+ @option.arity.should eql(0..0)
324
+ end
325
+
326
+ it "should set the cast to :string on regular arguments" do
327
+ @builder.short '-s', 'SHORT'
328
+ @builder.finalize!
329
+ @option.cast_to.should eql(:string)
330
+ end
331
+
332
+ it "should set the cast to :boolean on single flags" do
333
+ @builder.short '-s'
334
+ @builder.finalize!
335
+ @option.cast_to.should eql(:boolean)
336
+ end
337
+ end#finalize!
338
+
339
+ describe :dependencies do
340
+ it "should be able to process multiple arguments" do
341
+ @builder.dependencies :a, :b
342
+ @option.dependent_options.should eql([:a, :b])
343
+ end
344
+
345
+ it "should be able to process Array arguments" do
346
+ @builder.dependencies [:a, :b]
347
+ @option.dependent_options.should eql([:a, :b])
348
+ end
349
+ end#dependencies
350
+
351
+ describe :from_hash do
352
+ it "should fail on unrecognized methods" do
353
+ attempting {
354
+ @builder.from_hash :not_a_method => "ha!"
355
+ }.should raise_error(Choosy::ConfigurationError, /Not a recognized option/)
356
+ end
357
+
358
+ it "should handle the short option" do
359
+ @builder.from_hash :short => ['-s', 'SHORT+']
360
+ @option.short_flag.should eql('-s')
361
+ end
362
+
363
+ it "should handle the desc option" do
364
+ @builder.from_hash :desc => "description"
365
+ @option.description.should eql("description")
366
+ end
367
+
368
+ it "should be able to handle multiple options" do
369
+ @builder.from_hash({:short => '-s', :desc => 'description'})
370
+ @option.short_flag.should eql('-s')
371
+ @option.description.should eql('description')
372
+ end
373
+
374
+ it "should be able to handle complicated arguments like :count" do
375
+ @builder.from_hash({:count => {:at_least => 3, :at_most => 5}})
376
+ @option.arity.should eql(3..5)
377
+ end
378
+
379
+ it "should fail when the argument isn't a hash" do
380
+ attempting {
381
+ @builder.from_hash("")
382
+ }.should raise_error(Choosy::ConfigurationError, /Only hash arguments allowed/)
383
+ end
384
+ end#from_hash
385
+ end
386
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helpers'
2
+ require 'choosy/super_command'
3
+ require 'choosy/dsl/super_command_builder'
4
+
5
+ module Choosy::DSL
6
+ describe SuperCommandBuilder do
7
+ before :each do
8
+ @command = Choosy::SuperCommand.new :superfoo
9
+ @builder = @command.builder
10
+ end
11
+
12
+ describe :command do
13
+ it "should add the command to the listing" do
14
+ @builder.command :foo do |foo|
15
+ foo.boolean :count, "The count"
16
+ end
17
+
18
+ @command.listing.should have(1).item
19
+ end
20
+
21
+ it "should add the command builder to the command_builders" do
22
+ o = @builder.command :foo do |foo|
23
+ foo.integer :size, "The size"
24
+ end
25
+
26
+ @command.command_builders[:foo].should be(o.builder)
27
+ end
28
+
29
+ it "should finalize the builder for the command" do
30
+ o = @builder.command :foo
31
+ o.printer.should_not be(nil)
32
+ end
33
+
34
+ it "should be able to accept a new command as an argument" do
35
+ cmd = Choosy::Command.new :cmd do |c|
36
+ c.float :float, "Float"
37
+ end
38
+ @builder.command cmd
39
+ @command.listing[0].should be(cmd)
40
+ end
41
+ end
42
+
43
+ describe "standard options" do
44
+ it "should also be able to set flags" do
45
+ o = @builder.boolean :count, "The count"
46
+ @command.option_builders[:count].option.name.should eql(:count)
47
+ end
48
+ end
49
+
50
+ describe :help do
51
+ it "should create a help command when asked" do
52
+ h = @builder.help
53
+ @command.listing[0].should be(h)
54
+ end
55
+
56
+ it "should set the default summary of the help command" do
57
+ h = @builder.help
58
+ h.summary.should match(/Show the info/)
59
+ end
60
+
61
+ it "should st the summary of the command when given" do
62
+ h = @builder.help "Show this help message"
63
+ h.summary.should match(/Show this/)
64
+ end
65
+
66
+ describe "when validated" do
67
+ it "should return the super command name when called without arguments" do
68
+ h = @builder.help
69
+ attempting {
70
+ h.argument_validation.call([])
71
+ }.should raise_error(Choosy::HelpCalled, :superfoo)
72
+ end
73
+
74
+ it "should return the name of the first argument when called, as a symbol" do
75
+ h = @builder.help
76
+ attempting {
77
+ h.argument_validation.call(['foo'])
78
+ }.should raise_error(Choosy::HelpCalled, :foo)
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end