choosy 0.1.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/Gemfile +7 -0
- data/Gemfile.lock +25 -0
- data/LICENSE +23 -0
- data/README.markdown +393 -0
- data/Rakefile +57 -0
- data/lib/VERSION +1 -0
- data/lib/choosy/base_command.rb +59 -0
- data/lib/choosy/command.rb +32 -0
- data/lib/choosy/converter.rb +115 -0
- data/lib/choosy/dsl/base_command_builder.rb +172 -0
- data/lib/choosy/dsl/command_builder.rb +43 -0
- data/lib/choosy/dsl/option_builder.rb +155 -0
- data/lib/choosy/dsl/super_command_builder.rb +41 -0
- data/lib/choosy/errors.rb +11 -0
- data/lib/choosy/option.rb +22 -0
- data/lib/choosy/parse_result.rb +64 -0
- data/lib/choosy/parser.rb +184 -0
- data/lib/choosy/printing/color.rb +101 -0
- data/lib/choosy/printing/erb_printer.rb +23 -0
- data/lib/choosy/printing/help_printer.rb +174 -0
- data/lib/choosy/super_command.rb +77 -0
- data/lib/choosy/super_parser.rb +81 -0
- data/lib/choosy/verifier.rb +62 -0
- data/lib/choosy/version.rb +12 -0
- data/lib/choosy.rb +16 -0
- data/spec/choosy/base_command_spec.rb +11 -0
- data/spec/choosy/command_spec.rb +51 -0
- data/spec/choosy/converter_spec.rb +145 -0
- data/spec/choosy/dsl/base_command_builder_spec.rb +328 -0
- data/spec/choosy/dsl/commmand_builder_spec.rb +80 -0
- data/spec/choosy/dsl/option_builder_spec.rb +386 -0
- data/spec/choosy/dsl/super_command_builder_spec.rb +83 -0
- data/spec/choosy/parser_spec.rb +275 -0
- data/spec/choosy/printing/color_spec.rb +74 -0
- data/spec/choosy/printing/help_printer_spec.rb +117 -0
- data/spec/choosy/super_command_spec.rb +80 -0
- data/spec/choosy/super_parser_spec.rb +106 -0
- data/spec/choosy/verifier_spec.rb +180 -0
- data/spec/integration/command-A_spec.rb +37 -0
- data/spec/integration/supercommand-A_spec.rb +61 -0
- data/spec/spec_helpers.rb +30 -0
- 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
|