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
@@ -11,16 +11,16 @@ module Choosy::DSL
11
11
 
12
12
  describe :command do
13
13
  it "should add the command to the listing" do
14
- @builder.command :foo do |foo|
15
- foo.boolean :count, "The count"
14
+ @builder.command :foo do
15
+ boolean :count, "The count"
16
16
  end
17
17
 
18
18
  @command.listing.should have(1).item
19
19
  end
20
20
 
21
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"
22
+ o = @builder.command :foo do
23
+ integer :size, "The size"
24
24
  end
25
25
 
26
26
  @command.command_builders[:foo].should be(o.builder)
@@ -32,13 +32,31 @@ module Choosy::DSL
32
32
  end
33
33
 
34
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"
35
+ cmd = Choosy::Command.new :cmd do
36
+ float :float, "Float"
37
37
  end
38
38
  @builder.command cmd
39
39
  @command.listing[0].should be(cmd)
40
40
  end
41
41
  end
42
+
43
+ describe :parsimonious do
44
+ it "should not be parsimonous by default" do
45
+ @command.parsimonious?.should be_false
46
+ end
47
+
48
+ it "should set parsimonious" do
49
+ @builder.parsimonious
50
+ @command.parsimonious?.should be_true
51
+ end
52
+ end
53
+
54
+ describe :metaname do
55
+ it "should set the super command's metaname for the subcommands" do
56
+ @builder.metaname 'META'
57
+ @command.metaname.should eql('META')
58
+ end
59
+ end
42
60
 
43
61
  describe "standard options" do
44
62
  it "should also be able to set flags" do
@@ -47,6 +65,13 @@ module Choosy::DSL
47
65
  end
48
66
  end
49
67
 
68
+ describe :finalize! do
69
+ it "should set the metaname if not already set" do
70
+ @builder.finalize!
71
+ @command.metaname.should eql('COMMAND')
72
+ end
73
+ end
74
+
50
75
  describe :help do
51
76
  it "should create a help command when asked" do
52
77
  h = @builder.help
@@ -67,14 +92,14 @@ module Choosy::DSL
67
92
  it "should return the super command name when called without arguments" do
68
93
  h = @builder.help
69
94
  attempting {
70
- h.argument_validation.call([])
71
- }.should raise_error(Choosy::HelpCalled, :superfoo)
95
+ h.arguments.validation_step.call([])
96
+ }.should raise_error(Choosy::HelpCalled, nil)
72
97
  end
73
98
 
74
99
  it "should return the name of the first argument when called, as a symbol" do
75
100
  h = @builder.help
76
101
  attempting {
77
- h.argument_validation.call(['foo'])
102
+ h.arguments.validation_step.call(['foo'])
78
103
  }.should raise_error(Choosy::HelpCalled, :foo)
79
104
  end
80
105
  end
@@ -5,6 +5,8 @@ require 'choosy/dsl/command_builder'
5
5
 
6
6
  module Choosy
7
7
  class ParserBuilder
8
+ attr_reader :command, :lazy
9
+
8
10
  def initialize
9
11
  @terminals = nil
10
12
  @lazy = false
@@ -26,17 +28,22 @@ module Choosy
26
28
  self
27
29
  end
28
30
 
29
- def boolean(sym, default=nil)
31
+ def boolean(sym, default=nil, negated=nil)
30
32
  default ||= false
31
- @command.alter do |c|
32
- c.boolean(sym, sym.to_s, :default => default)
33
+ negated ||= false
34
+ @command.alter do
35
+ boolean(sym, sym.to_s, :default => default) do
36
+ if negated
37
+ negate
38
+ end
39
+ end
33
40
  end
34
41
  self
35
42
  end
36
43
 
37
44
  def single(sym)
38
- @command.alter do |c|
39
- c.single(sym, sym.to_s)
45
+ @command.alter do
46
+ single(sym, sym.to_s)
40
47
  end
41
48
  self
42
49
  end
@@ -44,9 +51,9 @@ module Choosy
44
51
  def multiple(sym, min=nil, max=nil)
45
52
  min ||= 1
46
53
  max ||= 1000
47
- @command.alter do |c|
48
- c.multiple(sym, sym.to_s) do |m|
49
- m.count :at_least => min, :at_most => max
54
+ @command.alter do
55
+ multiple(sym, sym.to_s) do
56
+ count :at_least => min, :at_most => max
50
57
  end
51
58
  end
52
59
  self
@@ -149,6 +156,21 @@ module Choosy
149
156
  res.options.should eql({:o => true})
150
157
  end
151
158
 
159
+ it "should handle negated boolean arguments" do
160
+ @pb.boolean(:o, false, true)
161
+ @pb.build.flags['--no-o'].should_not be_nil
162
+ end
163
+
164
+ it "should handle a negated boolean argument" do
165
+ res = @pb.boolean(:o, false, true).parse!('--no-o')
166
+ res.options.should eql({:o => false})
167
+ end
168
+
169
+ it "should handle a negated boolean argument whose default is true" do
170
+ res = @pb.boolean(:o, true, true).parse!('--no-o')
171
+ res.options.should eql({:o => true})
172
+ end
173
+
152
174
  it "should handle a boolean flag whose default is true" do
153
175
  res = @pb.boolean(:opt, true).parse!('-o')
154
176
  res.options.should eql({:opt => false})
@@ -52,23 +52,37 @@ module Choosy::Printing
52
52
  end
53
53
 
54
54
  it "should return a formatted string for just the color code when no args are given" do
55
- @c.red.should eql("e31[m")
55
+ @c.red.should eql("\e[31m")
56
56
  end
57
57
 
58
58
  it "should return a formatted string with a reset if a full string is supplied" do
59
- @c.red("this").should eql("e31[mthise0[m")
59
+ @c.red("this").should eql("\e[31mthis\e[0m")
60
60
  end
61
61
 
62
62
  it "should recognize when the foreground is being set" do
63
- @c.red("this", :foreground).should eql("e31[mthise0[m")
63
+ @c.red("this", :foreground).should eql("\e[31mthis\e[0m")
64
64
  end
65
65
 
66
66
  it "should recognize when the background is being set" do
67
- @c.red("this", :background).should eql("e41[mthise0[m")
67
+ @c.red("this", :background).should eql("\e[41mthis\e[0m")
68
68
  end
69
69
 
70
70
  it "should also handle effects" do
71
- @c.blink("this").should eql("e5[mthise0[m")
71
+ @c.blink("this").should eql("\e[5mthis\e[0m")
72
+ end
73
+
74
+ it "should fail when effects are handed too many parameters" do
75
+ attempting {
76
+ @c.blink("this", :noarg)
77
+ }.should raise_error(ArgumentError, /max 1/)
78
+ end
79
+
80
+ it "should not add an extra reset to the end if decorated more than once" do
81
+ @c.red(@c.blink("this")).should eql("\e[31m\e[5mthis\e[0m")
82
+ end
83
+
84
+ it "should be able to format multiple items" do
85
+ @c.multiple("this", [:red, :blink]).should eql("\e[5m\e[31mthis\e[0m")
72
86
  end
73
87
  end
74
88
  end
@@ -1,117 +1,196 @@
1
1
  require 'spec_helpers'
2
2
  require 'choosy/command'
3
+ require 'choosy/super_command'
3
4
  require 'choosy/printing/help_printer'
4
5
 
5
6
  module Choosy::Printing
6
7
  describe HelpPrinter do
7
8
  before :each do
8
- @h = HelpPrinter.new
9
- @c = Choosy::Command.new :foo do |foo|
10
- foo.summary "This is a summary of a command."
11
- foo.desc <<EOF
12
- This is a description of this command that should span
13
-
14
- multiple lines and carry itself beyond the average line length when actually called out from the unit tests itself so that we can correctly guage the line wrapping.
15
- EOF
16
- foo.separator
17
- foo.boolean :evaluate, "The evaluation"
18
- foo.integer :count, "The count"
19
- foo.separator
20
-
21
- foo.separator 'Indifferent options:'
22
- foo.boolean :debug, "Debug output"
23
- foo.version "1.2"
24
- foo.help
9
+ @c = Choosy::Command.new :foo do
10
+ summary "This is a fairly long summary that should wrap around the whole screen at least once, so that I can test whether it's properly formatted"
11
+
12
+ header 'DESCRIPTION'
13
+ para 'This is a description of this command that should span'
14
+ para 'Multiple lines and carry itself beyond the average line length when actually called out from the unit tests itself so that we can correctly guage the line wrapping.'
15
+
16
+ header 'OPTIONS'
17
+ boolean :evaluate, "The evaluation of some boolean something or other that really should span at least 3 lines of continuous text for testing the output of the option command."
18
+ integer :count, "The count of something that should also really span multiple lines, if possible."
19
+ boolean_ :debug, "Debug output"
20
+ version "1.2"
21
+ help
22
+
23
+ arguments do
24
+ metaname 'FOOS'
25
+ count 0..3
26
+ end
25
27
  end
26
- end
27
28
 
28
- it "should know the width of the screen, if possible, or set a default [COULD BREAK ON YOUR MACHINE]" do
29
- @h.columns.should satisfy {|c| c >= HelpPrinter::DEFAULT_COLUMN_COUNT }
30
- end
29
+ @b = @c.builder
31
30
 
32
- it "should know the lenght the screen, if possible, or set a default [COULD BREAK ON YOUR MACHINE]" do
33
- @h.lines.should satisfy {|l| l >= HelpPrinter::DEFAULT_LINE_COUNT }
34
- end
31
+ @s = Choosy::SuperCommand.new :super do
32
+ printer :standard, :color => true, :header_styles => [:bold, :blue]
33
+ command @c
34
+ metaname 'CMDS'
35
35
 
36
- it "should now how to format a usage string" do
37
- o = capture :stdout do
38
- @h.print_usage(@c)
36
+ boolean :bold, "Bold"
39
37
  end
40
38
 
41
- o.should eql("USAGE: foo [OPTIONS]\n")
39
+ @h = @s.printer
42
40
  end
43
41
 
44
- it "should show the usage string if it accepts extra arguments" do
45
- @c.alter do |foo|
46
- foo.arguments do |args|
47
- end
42
+ describe :print_usage do
43
+ it "should know how to format a regular command" do
44
+ @h.color.disable!
45
+ @h.columns = 60
46
+ @h.print_usage(@c)
47
+
48
+ @h.buffer.should eql("Usage: foo [-e|--evaluate] [-c|--count=COUNT] [--debug]
49
+ [--version] [-h|--help] FOOS\n")
48
50
  end
49
51
 
50
- o = capture :stdout do
51
- @h.print_usage(@c)
52
+ it "should know how to format a super command" do
53
+ @h.color.disable!
54
+ @h.columns = 60
55
+ @h.print_usage(@s)
56
+
57
+ @h.buffer.should eql("Usage: super [-b|--bold] CMDS\n")
52
58
  end
59
+ end
53
60
 
54
- o.should eql("USAGE: foo [OPTIONS] [ARGS]\n")
61
+ it "should write a header, properly colored" do
62
+ @h.print_header("option")
63
+ @h.buffer.should eql("\e[34m\e[1moption\e[0m")
55
64
  end
56
65
 
57
- it "should print a newline on an empty separator" do
58
- o = capture :stdout do
59
- @h.print_separator("")
60
- end
66
+ it "should print out a formatted header" do
67
+ @h.print_element(@c.listing[0])
68
+ @h.buffer.should eql("\n\e[34m\e[1mDESCRIPTION\e[0m\n")
69
+ end
61
70
 
62
- o.should eql("\n\n")
71
+ it "should print out a formatting element correctly" do
72
+ @h.print_element(@c.listing[1])
73
+ @h.buffer.should eql("\n This is a description of this command that should span\n")
63
74
  end
64
75
 
65
- it "should print a line with separator text" do
66
- o = capture :stdout do
67
- @h.print_separator("this line")
68
- end
76
+ it "should wrap lines in a paragraph correctly" do
77
+ @h.columns = 70
78
+ @h.print_element(@c.listing[2])
79
+ @h.buffer.should eql("\n Multiple lines and carry itself beyond the average line length when
80
+ actually called out from the unit tests itself so that we can
81
+ correctly guage the line wrapping.\n")
82
+ end
83
+
84
+ it "should print out an option on multiple lines" do
85
+ @h.columns = 70
86
+ @h.print_option(@c.listing[4], '-e, --evaluate', ' ' * 20)
87
+ @h.buffer.should eql(' -e, --evaluate The evaluation of some boolean something or other
88
+ that really should span at least 3 lines of
89
+ continuous text for testing the output of the
90
+ option command.
91
+ ')
92
+ end
69
93
 
70
- o.should eql("\nthis line\n")
94
+ it "should print out any commands that are present" do
95
+ @h.columns = 70
96
+ @h.print_command(@c, 'foo', ' ')
97
+ @h.buffer.should eql(" foo This is a fairly long summary that should wrap around the
98
+ whole screen at least once, so that I can test whether it's
99
+ properly formatted\n")
71
100
  end
72
101
 
73
- it "should print out a command" do
74
- o = capture :stdout do
75
- @h.print_command(@c)
102
+ describe "for the usage line" do
103
+ it "should format a full boolean option" do
104
+ o = @b.boolean :bold, "bold"
105
+ @h.usage_option(o).should eql("[-b|--bold]")
76
106
  end
77
107
 
78
- o.should eql(" foo\tThis is a summary of a command.\n")
79
- end
108
+ it "should format a partial boolean option" do
109
+ o = @b.boolean_ :bold, "bold"
110
+ @h.usage_option(o).should eql('[--bold]')
111
+ end
80
112
 
81
- it "should print the summary, if present" do
82
- o = capture :stdout do
83
- @h.print_summary(@c.summary)
113
+ it "should format a short boolean option" do
114
+ o = @b.option :bold do
115
+ short '-b'
116
+ end
117
+ @h.usage_option(o).should eql('[-b]')
84
118
  end
85
119
 
86
- o.should eql(" This is a summary of a command.\n")
87
- end
120
+ it "should format a negation of a boolean option" do
121
+ o = @b.boolean :bold, "Bold!!" do
122
+ negate 'un'
123
+ end
124
+ @h.usage_option(o).should eql('[-b|--bold|--un-bold]')
125
+ end
126
+
127
+ it "should format a full single option" do
128
+ o = @b.single :color, "color"
129
+ @h.usage_option(o).should eql('[-c|--color=COLOR]')
130
+ end
88
131
 
89
- it "should print out an option on 2 lines." do
90
- o = capture :stdout do
91
- @h.print_option(@c.listing[2])
132
+ it "should format a parial boolean option" do
133
+ o = @b.single_ :color, "color"
134
+ @h.usage_option(o).should eql('[--color=COLOR]')
135
+ end
136
+
137
+ it "shoudl format a full multiple option" do
138
+ o = @b.multiple :colors, "c"
139
+ @h.usage_option(o).should eql('[-c|--colors COLORS+]')
92
140
  end
93
141
 
94
- o.should eql(" -c, --count COUNT\n The count\n")
142
+ it "should format a partial multiple option" do
143
+ o = @b.multiple_ :colors, "c"
144
+ @h.usage_option(o).should eql('[--colors COLORS+]')
145
+ end
95
146
  end
96
-
97
- it "should print out any commands that are present"
98
147
 
99
- it "should print out the description" do
100
- @h.columns = 80
101
- o = capture :stdout do
102
- @h.print_description(@c.description)
148
+ describe "for the option line" do
149
+ it "should format a full boolean option" do
150
+ o = @b.boolean :bold, "b"
151
+ @h.regular_option(o).should eql('-b, --bold')
103
152
  end
104
153
 
105
- o.should eql(<<EOF
154
+ it "should format a partial boolean option" do
155
+ o = @b.boolean_ :bold, "b"
156
+ @h.regular_option(o).should eql(' --bold')
157
+ end
106
158
 
107
- DESCRIPTION
108
- This is a description of this command that should span
159
+ it "should format a short boolean option" do
160
+ o = @b.option :bold do |b|
161
+ b.short '-b'
162
+ end
109
163
 
110
- multiple lines and carry itself beyond the average line length when actually
111
- called out from the unit tests itself so that we can correctly guage the line
112
- wrapping.
113
- EOF
114
- )
164
+ @h.regular_option(o).should eql('-b')
165
+ end
166
+
167
+ it "should format a negation of an option" do
168
+ o = @b.boolean :bold, "Bold" do
169
+ negate 'un'
170
+ end
171
+
172
+ @h.regular_option(o).should eql('-b, --[un-]bold')
173
+ end
174
+
175
+ it "should format a full single option" do
176
+ o = @b.single :color, "color"
177
+ @h.regular_option(o).should eql('-c, --color COLOR')
178
+ end
179
+
180
+ it "should format a partial single option" do
181
+ o = @b.single_ :color, "color"
182
+ @h.regular_option(o).should eql(' --color COLOR')
183
+ end
184
+
185
+ it "should format a full multiple option" do
186
+ o = @b.multiple :colors, "colors"
187
+ @h.regular_option(o).should eql('-c, --colors COLORS+')
188
+ end
189
+
190
+ it "should format a partial multiple option" do
191
+ o = @b.multiple_ :colors, "colors"
192
+ @h.regular_option(o).should eql(' --colors COLORS+')
193
+ end
115
194
  end
116
195
  end
117
196
  end