choosy 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/README.markdown +229 -221
  2. data/Rakefile +21 -3
  3. data/examples/bar.rb +44 -0
  4. data/examples/foo.rb +198 -0
  5. data/examples/superfoo.rb +125 -0
  6. data/lib/VERSION +1 -1
  7. data/lib/choosy/argument.rb +51 -0
  8. data/lib/choosy/base_command.rb +22 -7
  9. data/lib/choosy/command.rb +12 -4
  10. data/lib/choosy/dsl/argument_builder.rb +88 -0
  11. data/lib/choosy/dsl/base_command_builder.rb +71 -56
  12. data/lib/choosy/dsl/command_builder.rb +14 -2
  13. data/lib/choosy/dsl/option_builder.rb +43 -83
  14. data/lib/choosy/dsl/super_command_builder.rb +37 -9
  15. data/lib/choosy/option.rb +13 -11
  16. data/lib/choosy/parse_result.rb +8 -27
  17. data/lib/choosy/parser.rb +20 -16
  18. data/lib/choosy/printing/color.rb +39 -21
  19. data/lib/choosy/printing/erb_printer.rb +12 -3
  20. data/lib/choosy/printing/formatting_element.rb +17 -0
  21. data/lib/choosy/printing/help_printer.rb +204 -117
  22. data/lib/choosy/printing/terminal.rb +53 -0
  23. data/lib/choosy/super_command.rb +6 -6
  24. data/lib/choosy/super_parser.rb +26 -15
  25. data/lib/choosy/verifier.rb +61 -6
  26. data/spec/choosy/base_command_spec.rb +27 -2
  27. data/spec/choosy/command_spec.rb +31 -9
  28. data/spec/choosy/dsl/argument_builder_spec.rb +180 -0
  29. data/spec/choosy/dsl/base_command_builder_spec.rb +87 -44
  30. data/spec/choosy/dsl/commmand_builder_spec.rb +15 -4
  31. data/spec/choosy/dsl/option_builder_spec.rb +101 -191
  32. data/spec/choosy/dsl/super_command_builder_spec.rb +34 -9
  33. data/spec/choosy/parser_spec.rb +30 -8
  34. data/spec/choosy/printing/color_spec.rb +19 -5
  35. data/spec/choosy/printing/help_printer_spec.rb +152 -73
  36. data/spec/choosy/printing/terminal_spec.rb +27 -0
  37. data/spec/choosy/super_command_spec.rb +17 -17
  38. data/spec/choosy/super_parser_spec.rb +20 -10
  39. data/spec/choosy/verifier_spec.rb +137 -47
  40. data/spec/integration/command-A_spec.rb +6 -6
  41. data/spec/integration/command-B_spec.rb +45 -0
  42. data/spec/integration/supercommand-A_spec.rb +33 -27
  43. data/spec/integration/supercommand-B_spec.rb +32 -0
  44. data/spec/spec_helpers.rb +8 -5
  45. metadata +95 -54
@@ -0,0 +1,27 @@
1
+ require 'spec_helpers'
2
+ require 'choosy/printing/terminal'
3
+
4
+ module Choosy::Printing
5
+ class TerminalTest
6
+ include Terminal
7
+ end
8
+
9
+ describe Terminal do
10
+ before :each do
11
+ @t = TerminalTest.new
12
+ end
13
+
14
+ it "should know the width of the screen, if possible, or set a default [COULD BREAK ON YOUR MACHINE]" do
15
+ @t.columns.should satisfy {|c| c >= Terminal::DEFAULT_COLUMN_COUNT }
16
+ end
17
+
18
+ it "should know the lenght the screen, if possible, or set a default [COULD BREAK ON YOUR MACHINE]" do
19
+ @t.lines.should satisfy {|l| l >= Terminal::DEFAULT_LINE_COUNT }
20
+ end
21
+
22
+ it "should allow for setting the column width" do
23
+ @t.columns = 40
24
+ @t.columns.should eql(40)
25
+ end
26
+ end
27
+ end
@@ -9,8 +9,8 @@ module Choosy
9
9
 
10
10
  describe :parse! do
11
11
  it "should be able to print out the version number" do
12
- @c.alter do |c|
13
- c.version "superblah"
12
+ @c.alter do
13
+ version "superblah"
14
14
  end
15
15
 
16
16
  o = capture :stdout do
@@ -21,27 +21,27 @@ module Choosy
21
21
  end
22
22
 
23
23
  it "should print out the supercommand help message" do
24
- @c.alter do |c|
25
- c.help
24
+ @c.alter do
25
+ help
26
26
  end
27
27
 
28
28
  o = capture :stdout do
29
29
  @c.parse!([])
30
30
  end
31
31
 
32
- o.should match(/USAGE:/)
32
+ o.should match(/Usage:/)
33
33
  end
34
34
 
35
35
  it "should print out a subcommand help message" do
36
- @c.alter do |c|
37
- c.help
38
- c.command :bar do |bar|
39
- bar.boolean :count, "The count"
36
+ @c.alter do
37
+ help
38
+ command :bar do
39
+ boolean :count, "The count"
40
40
  end
41
41
  end
42
42
 
43
43
  o = capture :stdout do
44
- @c.parse!(['help', 'bar'])
44
+ @c.parse! ['help', 'bar']
45
45
  end
46
46
 
47
47
  o.should match(/--count/)
@@ -50,9 +50,9 @@ module Choosy
50
50
 
51
51
  describe :execute! do
52
52
  it "should fail when no executor is present" do
53
- @c.alter do |c|
54
- c.command :bar do |bar|
55
- bar.boolean :count, "The count"
53
+ @c.alter do
54
+ command :bar do
55
+ boolean :count, "The count"
56
56
  end
57
57
  end
58
58
 
@@ -63,10 +63,10 @@ module Choosy
63
63
 
64
64
  it "should call the executors" do
65
65
  count = 0
66
- @c.alter do |c|
67
- c.command :bar do |bar|
68
- bar.integer :count, "The count"
69
- bar.executor do |opts, args|
66
+ @c.alter do
67
+ command :bar do
68
+ integer :count, "The count"
69
+ executor do |opts, args|
70
70
  count = opts[:count]
71
71
  end
72
72
  end
@@ -1,6 +1,7 @@
1
1
  require 'spec_helpers'
2
2
  require 'choosy/super_parser'
3
3
  require 'choosy/super_command'
4
+ require 'choosy/dsl/super_command_builder'
4
5
 
5
6
  module Choosy
6
7
  class SuperParserBuilder
@@ -8,12 +9,11 @@ module Choosy
8
9
 
9
10
  def initialize
10
11
  @super = Choosy::SuperCommand.new :super
11
- @parsimonious = false
12
12
  end
13
13
 
14
14
  def command(name)
15
- @super.alter do |a|
16
- a.command name do |c|
15
+ @super.alter do
16
+ command name do |c|
17
17
  yield c if block_given?
18
18
  end
19
19
  end
@@ -21,8 +21,8 @@ module Choosy
21
21
  end
22
22
 
23
23
  def single(name)
24
- @super.alter do |a|
25
- a.single name, name.to_s
24
+ @super.alter do
25
+ single name, name.to_s
26
26
  end
27
27
  self
28
28
  end
@@ -33,11 +33,13 @@ module Choosy
33
33
  end
34
34
 
35
35
  def parsimonious!
36
- @parsimonious = true
37
- end
36
+ @super.alter do
37
+ parsimonious
38
+ end
39
+ end
38
40
 
39
41
  def build
40
- SuperParser.new(@super, @parsimonious)
42
+ SuperParser.new(@super)
41
43
  end
42
44
  end
43
45
 
@@ -69,7 +71,7 @@ module Choosy
69
71
  @p.super.builder.help
70
72
  attempting {
71
73
  @p.parse!()
72
- }.should raise_error(Choosy::HelpCalled, :super)
74
+ }.should raise_error(Choosy::HelpCalled, Choosy::DSL::SuperCommandBuilder::SUPER)
73
75
  end
74
76
  end
75
77
 
@@ -88,7 +90,15 @@ module Choosy
88
90
  end
89
91
 
90
92
  it "should collect other names of commands as arguments" do
91
- @p.command(:bar).command(:baz).parse!('bar', 'baz').subresults.should have(1).item
93
+ @p.command(:bar) do |c|
94
+ c.arguments
95
+ end.command(:baz).parse!('bar', 'baz').subresults.should have(1).item
96
+ end
97
+
98
+ it "should fail when the first command doesn't take arguments" do
99
+ attempting {
100
+ @p.command(:bar).command(:baz).parse!('bar', 'baz')
101
+ }.should raise_error(Choosy::ValidationError, /bar: no arguments allowed: baz/)
92
102
  end
93
103
  end
94
104
 
@@ -26,30 +26,40 @@ module Choosy
26
26
 
27
27
  before :each do
28
28
  reset!
29
- @res = ParseResult.new(@c)
29
+ @res = ParseResult.new(@c, false)
30
30
  end
31
31
 
32
- describe :verify_options! do
32
+ describe :verify! do
33
33
  it "should not try to validate arguments if not set" do
34
34
  b.boolean :debug, "Debug"
35
+ b.arguments do
36
+ count 0..10
37
+ end
38
+
35
39
  @res.args << "a"
36
40
  attempting {
37
- v.verify_options!(@res)
41
+ v.verify!(@res)
38
42
  }.should_not raise_error
39
43
  end
40
44
  end
41
45
 
42
- describe :verify_arguments! do
43
- it "should validate arguments if asked" do
44
- b.arguments do |args|
45
- raise RuntimeError.new('Called!')
46
+ describe :required? do
47
+ it "should fail when an option is required but not provided" do
48
+ o = b.string :str, "String" do
49
+ required
46
50
  end
51
+ attempting {
52
+ v.required?(o, @res)
53
+ }.should raise_error(Choosy::ValidationError, /required/)
54
+ end
47
55
 
56
+ it "should succeed when nothing is required" do
57
+ o = b.string :str, "String"
48
58
  attempting {
49
- v.verify_arguments!(@res)
50
- }.should raise_error(RuntimeError, 'Called!')
59
+ v.required?(o, @res)
60
+ }.should_not raise_error
51
61
  end
52
- end
62
+ end#required?
53
63
 
54
64
  describe :populate! do
55
65
  it "should fill in default boolean values to false if unset" do
@@ -93,13 +103,66 @@ module Choosy
93
103
  v.populate!(o, @res)
94
104
  @res.options.should be_empty
95
105
  end
96
- end#populate_defaults!
106
+ end#populate!
107
+
108
+ describe :convert! do
109
+ it "should convert files" do
110
+ o = b.file :afile, "A File"
111
+ @res[:afile] = __FILE__
112
+ v.convert!(o, @res)
113
+ @res[:afile].path.should eql(__FILE__)
114
+ end
115
+
116
+ class CustomConverter
117
+ def convert(value)
118
+ value.to_i
119
+ end
120
+ end
121
+
122
+ it "should convert a custom type" do
123
+ o = b.single :an_int, "An int" do
124
+ cast CustomConverter.new
125
+ end
126
+ @res[:an_int] = "1"
127
+
128
+ v.convert!(o, @res)
129
+ @res[:an_int].should eql(1)
130
+ end
131
+ end#convert!
132
+
133
+ describe :restricted? do
134
+ it "should verify that arguments are restricted to a certain subset for a single valued option" do
135
+ o = b.option :value do
136
+ flags '-v', '--value', 'VALUE'
137
+ desc "Description"
138
+ cast :symbol
139
+ only :a, :b, :c
140
+ end
141
+
142
+ @res[:value] = :d
143
+ attempting {
144
+ v.restricted?(o, @res)
145
+ }.should raise_error(Choosy::ValidationError, "unrecognized value (only 'a', 'b', 'c' allowed): 'd'")
146
+ end
147
+
148
+ it "should verify that all arguments are restricted for a muli-valued option" do
149
+ o = b.option :value do
150
+ long '--value', 'VALUES+'
151
+ only :a, :b, :c
152
+ end
153
+
154
+ @res[:value] = [:a, :b, :c, :d]
155
+ attempting {
156
+ v.restricted?(o, @res)
157
+ }.should raise_error(Choosy::ValidationError, "unrecognized value (only 'a', 'b', 'c' allowed): 'd'")
158
+ end
159
+ end
97
160
 
98
161
  describe :validate! do
99
162
  it "should call the validate proc associated with each option" do
100
- o = b.string :line, "Line" do |l|
101
- l.validate do |arg|
102
- l.fail "Validated!"
163
+ o = b.string :line, "Line" do
164
+ validate do |arg, options|
165
+ die "Validated!"
103
166
  end
104
167
  end
105
168
  @res[:line] = "line"
@@ -110,9 +173,9 @@ module Choosy
110
173
  end
111
174
 
112
175
  it "should not call the proc on empty arguments" do
113
- o = b.strings :line, "Line" do |l|
114
- l.validate do |arg|
115
- l.fail "Validated!"
176
+ o = b.strings :line, "Line" do
177
+ validate do |arg|
178
+ die "Validated!"
116
179
  end
117
180
  end
118
181
  @res[:line] = []
@@ -124,7 +187,7 @@ module Choosy
124
187
  it "should not call the proc when the arguments are null" do
125
188
  o = b.string :line, "Line" do |l|
126
189
  l.validate do |arg|
127
- l.fail "Validated!"
190
+ die "Validated!"
128
191
  end
129
192
  end
130
193
  @res[:line] = nil
@@ -132,49 +195,76 @@ module Choosy
132
195
  v.validate!(o, @res)
133
196
  @res[:line].should be(nil)
134
197
  end
135
- end#validate!
136
198
 
137
- describe :required? do
138
- it "should fail when an option is required but not provided" do
139
- o = b.string :str, "String" do |s|
140
- s.required
199
+ it "should call the proc with the additional option param" do
200
+ o = b.string :line, "Line" do
201
+ validate do |arg, options|
202
+ options[:populated] = arg
203
+ options[:line] = "this"
204
+ end
141
205
  end
142
- attempting {
143
- v.required?(o, @res)
144
- }.should raise_error(Choosy::ValidationError, /Required/)
206
+ @res[:line] = 'blah'
207
+
208
+ v.validate!(o, @res)
209
+ @res[:populated].should eql('blah')
210
+ @res[:line].should eql("this")
145
211
  end
212
+ end#validate!
213
+
214
+ describe :verify_arguments! do
215
+ it "should validate arguments if asked" do
216
+ b.arguments do
217
+ validate do |args, option|
218
+ raise RuntimeError.new('Called!')
219
+ end
220
+ end
221
+ @res.args << 'a'
146
222
 
147
- it "should succeed when nothing is required" do
148
- o = b.string :str, "String"
149
223
  attempting {
150
- v.required?(o, @res)
151
- }.should_not raise_error
224
+ v.verify_arguments!(@res)
225
+ }.should raise_error(RuntimeError, 'Called!')
152
226
  end
153
- end
154
227
 
155
- describe :convert! do
156
- it "should convert files" do
157
- o = b.file :afile, "A File"
158
- @res[:afile] = __FILE__
159
- v.convert!(o, @res)
160
- @res[:afile].path.should eql(__FILE__)
228
+ it "should validate that the argument count isn't too few" do
229
+ b.arguments do
230
+ count 2
231
+ end
232
+ @res.args << "a"
233
+
234
+ attempting {
235
+ v.verify_arguments!(@res)
236
+ }.should raise_error(Choosy::ValidationError, /too few arguments/)
161
237
  end
162
238
 
163
- class CustomConverter
164
- def convert(value)
165
- value.to_i
239
+ it "should validate that the argument count isn't too many" do
240
+ b.arguments do
241
+ count 1
166
242
  end
243
+ @res.args << "a"
244
+ @res.args << "b"
245
+
246
+ attempting {
247
+ v.verify_arguments!(@res)
248
+ }.should raise_error(Choosy::ValidationError, /too many arguments/)
167
249
  end
168
250
 
169
- it "should convert a custom type" do
170
- o = b.single :an_int, "An int" do |i|
171
- i.cast CustomConverter.new
251
+ it "should succed when the argument count is in an acceptable range" do
252
+ b.arguments do
253
+ count 1..3
172
254
  end
173
- @res[:an_int] = "1"
255
+ @res.args << "1"
174
256
 
175
- v.convert!(o, @res)
176
- @res[:an_int].should eql(1)
257
+ attempting {
258
+ v.verify_arguments!(@res)
259
+ }.should_not raise_error
177
260
  end
178
- end#convert!
261
+
262
+ it "should fail when no arguments are allowed" do
263
+ @res.args << 'a'
264
+ attempting {
265
+ v.verify_arguments!(@res)
266
+ }.should raise_error(Choosy::ValidationError, /no arguments allowed/)
267
+ end
268
+ end
179
269
  end
180
270
  end
@@ -4,11 +4,11 @@ require 'choosy'
4
4
  describe "Command A" do
5
5
 
6
6
  before :each do
7
- @cmd = Choosy::Command.new :A do |a|
8
- a.integer :count, "The count"
9
- a.boolean :bold, "Bold the output"
10
- a.version "blah"
11
- a.help
7
+ @cmd = Choosy::Command.new :A do
8
+ integer :count, "The count"
9
+ boolean :bold, "Bold the output"
10
+ version "blah"
11
+ help
12
12
  end
13
13
  end
14
14
 
@@ -17,7 +17,7 @@ describe "Command A" do
17
17
  @cmd.parse! ['--help']
18
18
  end
19
19
 
20
- o.should match /USAGE:/
20
+ o.should match /Usage:/
21
21
  end
22
22
 
23
23
  it "should handle multiple arguments" do