clive 0.8.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,35 @@
1
+ $: << File.dirname(__FILE__) + '/../..'
2
+ require 'helper'
3
+
4
+ class Clive::Arguments::ParserSubject < Clive::Arguments::Parser
5
+ attr_reader :opts
6
+ end
7
+
8
+ describe Clive::Arguments::Parser do
9
+
10
+ subject { Clive::Arguments::ParserSubject }
11
+
12
+ describe '#initialize' do
13
+ it 'normalises key names' do
14
+ subject.new(:kind => String, :in => %w(a b c)).opts.keys.must_include :type, :within
15
+ end
16
+ end
17
+
18
+ describe '#to_a' do
19
+ it 'returns an array of hashes' do
20
+ subject.new(:type => [Integer, Time]).to_a.must_equal [{:type => Integer, :name => 'arg'},
21
+ {:type => Time, :name => 'arg'}]
22
+ end
23
+ end
24
+
25
+ describe '#to_args' do
26
+ it 'returns an array of Argument instances' do
27
+ args = subject.new(:args => '<a> <b> [<c>]', :type => [Integer, Time]).to_args
28
+ args.size.must_equal 3
29
+ args[0].must_be_argument :name => :a, :type => Clive::Type::Integer
30
+ args[1].must_be_argument :name => :b, :type => Clive::Type::Time
31
+ args[2].must_be_argument :name => :c, :optional => true
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,191 @@
1
+ $: << File.dirname(__FILE__) + '/..'
2
+ require 'helper'
3
+
4
+ describe Clive::Arguments do
5
+
6
+ subject {
7
+ Clive::Arguments.create :args => '[<a>] <b> <c> [<d>]',
8
+ :type => [Integer] * 4,
9
+ :constraint => [:even?, :odd?] * 2
10
+ }
11
+
12
+ describe '.create' do
13
+ it 'parses the options passed using Parser' do
14
+ parser, opts = mock, stub
15
+ parser.expects(:to_args).returns([])
16
+ Clive::Arguments::Parser.expects(:new).with(opts).returns(parser)
17
+ Clive::Arguments.create opts
18
+ end
19
+ it 'returns a list of Argument instances' do
20
+ a = Clive::Arguments.create :args => '[<a>] <b>', :as => [Integer, nil], :in => [1..5, nil]
21
+ a[0].must_be_argument :name => :a, :optional => true, :within => 1..5,
22
+ :type => Clive::Type::Integer
23
+ a[1].must_be_argument :name => :b, :optional => false
24
+ end
25
+ end
26
+
27
+ describe '#zip' do
28
+ it 'zips arguments properly' do
29
+ def subject.simple_zip(other); zip(other).map(&:last); end
30
+
31
+ # These behaviours are definitely what should happen
32
+ subject.simple_zip(%w(1 4)).must_equal [nil, '1', '4', nil]
33
+ subject.simple_zip(%w(1 4 3)).must_equal [nil, '1', '4', '3']
34
+ subject.simple_zip(%w(2 1 4 3)).must_equal ['2', '1', '4', '3']
35
+ subject.simple_zip(%w(2 1 4)).must_equal ['2', '1', '4', nil]
36
+
37
+ # These behaviours may change
38
+ subject.simple_zip(%w(2)).must_equal [nil, nil, '2', nil]
39
+ subject.simple_zip(%w(1)).must_equal [nil, '1', nil, nil]
40
+ subject.simple_zip(%w(2 1)).must_equal [nil, nil, '2', nil]
41
+ end
42
+ end
43
+
44
+ describe '#to_s' do
45
+ subject {
46
+ Clive::Arguments.new( [
47
+ Clive::Argument.new(:a),
48
+ Clive::Argument.new(:b, :optional => true),
49
+ Clive::Argument.new(:c, :optional => true),
50
+ Clive::Argument.new(:d)
51
+ ])
52
+ }
53
+
54
+ it 'removes extra square brackets' do
55
+ subject.to_s.must_equal "<a> [<b> <c>] <d>"
56
+ end
57
+ end
58
+
59
+ describe '#min' do
60
+ it 'returns the number of non-optional arguments' do
61
+ subject.min.must_equal 2
62
+ end
63
+ end
64
+
65
+ describe '#max' do
66
+ it 'returns the total number of arguments' do
67
+ subject.max.must_equal 4
68
+ end
69
+ end
70
+
71
+ describe '#possible?' do
72
+ it 'is true if each argument is possible and list is not too long' do
73
+ subject.must_be :possible?, [2]
74
+ subject.must_be :possible?, [2, 3]
75
+ subject.must_be :possible?, [2, 3, 4]
76
+ subject.must_be :possible?, [2, 3, 4, 5]
77
+ end
78
+
79
+ it 'is false if the list is too long' do
80
+ subject.wont_be :possible?, [2, 3, 4, 5, 6]
81
+ end
82
+
83
+ it 'is true even if an argument is not possible' do
84
+ subject.must_be :possible?, ['hello']
85
+ end
86
+
87
+ it 'single' do
88
+ subject = Clive::Arguments.create :arg => '<name>'
89
+ subject.must_be :possible?, []
90
+ subject.must_be :possible?, %w(John)
91
+ subject.wont_be :possible?, %w(John Doe)
92
+ end
93
+
94
+ it 'single optional' do
95
+ subject = Clive::Arguments.create :arg => '[<name>]'
96
+ subject.must_be :possible?, []
97
+ subject.must_be :possible?, %w(John)
98
+ subject.wont_be :possible?, %w(John Doe)
99
+ end
100
+
101
+ it 'single with constraint' do
102
+ subject = Clive::Arguments.create :arg => '<name>', :constraint => proc {|i| i.size == 4 }
103
+ subject.must_be :possible?, []
104
+ subject.must_be :possible?, %w(John)
105
+ subject.wont_be :possible?, %w(James)
106
+ subject.wont_be :possible?, %w(John Doe)
107
+ end
108
+
109
+ it 'single optional with constraint' do
110
+ subject = Clive::Arguments.create :arg => '[<name>]', :constraint => proc {|i| i.size == 4 }
111
+ subject.must_be :possible?, []
112
+ subject.must_be :possible?, %w(John)
113
+ subject.wont_be :possible?, %w(James)
114
+ subject.wont_be :possible?, %w(John Doe)
115
+ end
116
+
117
+ it 'multiple surrounding' do
118
+ subject = Clive::Arguments.create :args => '<first> [<middle>] <last>'
119
+ subject.must_be :possible?, []
120
+ subject.must_be :possible?, %w(John)
121
+ subject.must_be :possible?, %w(John Doe)
122
+ subject.must_be :possible?, %w(John David Doe)
123
+ subject.wont_be :possible?, %w(John David James Doe)
124
+ end
125
+
126
+ it 'multiple middle' do
127
+ subject = Clive::Arguments.create :args => '[<first>] <middle> [<last>]'
128
+ subject.must_be :possible?, []
129
+ subject.must_be :possible?, %w(John)
130
+ subject.must_be :possible?, %w(John Doe)
131
+ subject.must_be :possible?, %w(John David Doe)
132
+ subject.wont_be :possible?, %w(John David James Doe)
133
+ end
134
+
135
+ it 'multiple surrounding with constraints' do
136
+ subject = Clive::Arguments.create :args => '<first> [<middle>] <last>',
137
+ :constraint => [proc {|i| i.size == 3 }, proc {|i| i.size == 4 }, proc {|i| i.size == 5 }]
138
+ subject.must_be :possible?, []
139
+
140
+ subject.must_be :possible?, %w(Joe) # [Joe, ..., ...]
141
+ subject.wont_be :possible?, %w(Gary) # [!!!, Gary, ...]
142
+ subject.wont_be :possible?, %w(David) # [!!!, nil, David]
143
+
144
+ subject.must_be :possible?, %w(Joe Gary) # [Joe, Gary, ...]
145
+ subject.must_be :possible?, %w(Joe David) # [Joe, ..., David]
146
+ subject.wont_be :possible?, %w(Gary David) # [!!!, Gary, David]
147
+
148
+ subject.must_be :possible?, %w(Joe Gary David) # [Joe, Gary, David]
149
+ subject.wont_be :possible?, %w(Joe Gary David Doe) # [Joe, Gary, David] Doe
150
+ end
151
+ end
152
+
153
+ describe '#valid?' do
154
+ it 'is false if the list is not #possible' do
155
+ subject.stubs(:possible?).returns(false)
156
+ subject.wont_be :valid?, [1, 2]
157
+ end
158
+
159
+ it 'is false if the list is too short' do
160
+ subject.stubs(:possible?).returns(true)
161
+ subject.wont_be :valid?, [1]
162
+ end
163
+
164
+ it 'is true if the list is #possible? and not too short' do
165
+ subject.stubs(:possible?).returns(true)
166
+ subject.must_be :valid?, [1, 2]
167
+ subject.must_be :valid?, [1, 2, 3]
168
+ subject.must_be :valid?, [0, 1, 2, 3]
169
+ end
170
+ end
171
+
172
+ describe '#create_valid' do
173
+ it 'returns the correct arguments' do
174
+ a = Clive::Arguments.create :args => '[<a>] <b> [<c>]'
175
+ a.create_valid(%w(a b c)).must_equal ['a', 'b', 'c']
176
+ a.create_valid(%w(a b)).must_equal ['a', 'b', nil]
177
+ a.create_valid(%w(a)).must_equal [nil, 'a', nil]
178
+ end
179
+
180
+ it 'coerces the arguments' do
181
+ a = Clive::Arguments.create :args => '<a> <b>', :as => [Integer, Float]
182
+ a.create_valid(%w(50.55 50.55)).must_equal [50, 50.55]
183
+ end
184
+
185
+ it 'uses defaults where needed' do
186
+ a = Clive::Arguments.create :args => '[<a>] <b> [<c>]', :defaults => ['y', nil, 'y']
187
+ a.create_valid(%w(n)).must_equal %w(y n y)
188
+ end
189
+ end
190
+
191
+ end
@@ -1,240 +1,307 @@
1
- require 'spec_helper'
1
+ $: << File.dirname(__FILE__) + '/..'
2
+ require 'helper'
2
3
 
3
4
  describe Clive::Command do
4
5
 
5
- context "when creating a base command" do
6
- subject { Clive::Command.setup(Class.new) {} }
7
- end
8
-
9
- subject {
10
- Clive::Command.new([:co, :comm], "A command", Class.new) do
11
- bool(:boo) {}
12
- switch(:swi) {}
13
- flag(:fla) {}
14
- command(:com) {}
15
- end
16
- }
17
-
18
- it_behaves_like "an option"
19
-
20
- describe "#initialize" do
21
- subject {
22
- Clive::Command.new([:com], "A command", Class.new) do
23
- flag(:test)
24
- end
6
+ it 'can take arguments' do
7
+ command = Clive::Command.create([:test], '', :arg => '<dir>')
8
+
9
+ state = {:test => {}}
10
+ command.run(state, ['~/somewhere'])
11
+ state[:test][:args].must_equal '~/somewhere'
12
+ end
13
+
14
+ it 'can run a block with arguments' do
15
+ command = Clive::Command.create [], '', :arg => '<dir>' do
16
+ action { puts dir }
17
+ end
18
+
19
+ this { command.run({}, ['~/somewhere']) }.must_output "~/somewhere\n"
20
+ end
21
+
22
+ describe '#initialize' do
23
+ subject {
24
+ Clive::Command.new([:c,:b,:a],
25
+ 'A command',
26
+ :head => true,
27
+ :args => '<a> [<b>]',
28
+ :as => [Integer, nil],
29
+ :group => 'Cool commands',
30
+ :help => true,
31
+ :name => 'file.rb')
25
32
  }
26
-
27
- it "generates a help header" do
28
- File.stub!(:basename).and_return("test")
29
- subject.instance_variable_get("@header").should == "Usage: test com [options]"
30
- end
31
-
32
- it "generates an option missing proc" do
33
- proc = subject.instance_variable_get("@option_missing")
34
- expect {
35
- proc.call("hey")
36
- }.should raise_error Clive::NoOptionError
37
- end
38
-
39
- it "doesn't run the block given" do
40
- subject.flags.size.should == 0
41
- end
42
-
43
- it "generates a help switch" do
44
- subject.switches.map {|i| i.names}.should include ["h", "help"]
45
- end
46
- end
47
-
48
- describe "#bools" do
49
- it "returns an array of bools" do
50
- subject.find
51
- subject.bools.each do |i|
52
- i.should be_kind_of Clive::Bool
53
- end
33
+
34
+ it 'sets the names' do
35
+ subject.names.must_equal [:c,:b,:a]
36
+ end
37
+
38
+ it 'sets the description' do
39
+ subject.description.must_equal 'A command'
40
+ end
41
+
42
+ it 'sets the options' do
43
+ subject.config[:head].must_be_true
44
+ subject.config[:group].must_equal 'Cool commands'
45
+ end
46
+
47
+ it 'sets the arguments' do
48
+ subject.args.size.must_equal 2
49
+ subject.args.map(&:name).must_equal [:a, :b]
50
+ end
51
+
52
+ it 'sets a default header' do
53
+ subject.instance_variable_get(:@header).call.must_equal 'Usage: file.rb c,b,a [options]'
54
+ end
55
+
56
+ it 'sets a default footer' do
57
+ subject.instance_variable_get(:@footer).must_equal ''
58
+ end
59
+
60
+ it 'adds the help option' do
61
+ subject.must_be :has?, '--help'
62
+ subject.must_be :has?, '-h'
63
+ end
64
+
65
+ it 'resets the current description' do
66
+ subject.instance_variable_get(:@_last_desc).must_equal ''
54
67
  end
55
68
  end
56
-
57
- describe "#switches" do
58
- it "returns an array of switches" do
59
- subject.find
60
- subject.switches.each do |i|
61
- i.should be_kind_of Clive::Switch
62
- end
69
+
70
+ describe '#name' do
71
+ it 'returns the first, in order when defined, name' do
72
+ command = Clive::Command.new [:efg, :abc, :zxy]
73
+ command.name.must_equal :efg
63
74
  end
64
75
  end
65
-
66
- describe "#flags" do
67
- it "returns an array of flags" do
68
- subject.find
69
- subject.flags.each do |i|
70
- i.should be_kind_of Clive::Flag
71
- end
76
+
77
+ describe '#to_s' do
78
+ it 'returns the names joined' do
79
+ command = Clive::Command.new [:a, :b, :c]
80
+ command.to_s.must_equal 'a,b,c'
72
81
  end
73
82
  end
74
-
75
- describe "#find" do
76
- it "runs the block for the command" do
77
- subject.flags.size.should == 0
78
- subject.find
79
- subject.flags.size.should == 1
80
- end
81
-
82
- it "sets the block to nil" do
83
- subject.find
84
- subject.block.should be_nil
85
- end
86
- end
87
-
88
- describe "#run" do
89
- it "returns an array of unused arguments" do
90
- subject.find
91
- subject.run(%w(--swi what)).should == ['what']
92
- end
93
- end
94
-
95
- describe "#to_h" do
96
- it "returns a hash of data for help formatting" do
97
- hsh = {'names' => subject.names, 'desc' => subject.desc}
98
- subject.to_h.should == hsh
99
- end
100
- end
101
-
102
- describe "#command" do
103
- it "creates a new command" do
104
- expect {
105
- subject.command(:comm)
106
- }.should change {subject.commands.size}.by(1)
107
- end
108
-
109
- it "resets the current description" do
110
- subject.desc 'A command'
111
- subject.command(:comm)
112
- subject.current_desc.should == ""
113
- end
114
- end
115
-
116
- describe "#switch" do
117
- it "creates a new switch" do
118
- expect {
119
- subject.switch(:s, :switch)
120
- }.should change {subject.switches.size}.by(1)
121
- end
122
-
123
- it "resets the current description" do
124
- subject.desc 'A switch'
125
- subject.switch(:s, :switch)
126
- subject.current_desc.should == ""
127
- end
128
- end
129
-
130
- describe "#flag" do
131
- it "creates a new flag" do
132
- expect {
133
- subject.flag(:f, :flag)
134
- }.should change {subject.flags.size}.by(1)
135
- end
136
-
137
- it "resets the current description" do
138
- subject.desc 'A flag'
139
- subject.flag(:f, :flag)
140
- subject.current_desc.should == ""
141
- end
142
- end
143
-
144
- describe "#bool" do
145
- it "creates two bool switches" do
146
- expect {
147
- subject.bool(:b, :bool)
148
- }.should change {subject.bools.size}.by(2)
149
- end
150
-
151
- it "resets the current description" do
152
- subject.desc 'A bool'
153
- subject.bool(:b, :bool)
154
- subject.current_desc.should == ""
155
- end
156
- end
157
-
158
- describe "#desc" do
159
- context "when called with no arguments" do
160
- it "returns the description for the command" do
161
- subject.desc.should == "A command"
83
+
84
+ describe '#run_block' do
85
+ it 'runs the block passed to command' do
86
+ command = Clive::Command.new do
87
+ print 'Hey I was ran'
162
88
  end
89
+ this { command.run_block({}) }.must_output 'Hey I was ran'
163
90
  end
164
-
165
- context "when called with an argument" do
166
- it "sets the current description" do
167
- subject.desc "A new desc"
168
- subject.instance_variable_get("@current_desc").should == "A new desc"
169
- end
91
+
92
+ it 'returns a possibly modified state' do
93
+ state = {}
94
+ command = Clive::Command.new { set :a, true }
95
+ state.wont_have :key?, :a
96
+ command.run_block(state)
97
+ state.must_have :key?, :a
98
+ end
99
+ end
100
+
101
+ describe '#header' do
102
+ it 'sets the header' do
103
+ command = Clive::Command.new
104
+ command.header 'A header'
105
+ command.instance_variable_get(:@header).must_equal 'A header'
106
+ end
107
+ end
108
+
109
+ describe '#footer' do
110
+ it 'sets the footer' do
111
+ command = Clive::Command.new
112
+ command.footer 'A footer'
113
+ command.instance_variable_get(:@footer).must_equal 'A footer'
114
+ end
115
+ end
116
+
117
+ describe '#config' do
118
+ it 'sets options' do
119
+ command = Clive::Command.new
120
+ command.config :name => 'my cool app'
121
+ command.config[:name].must_equal 'my cool app'
122
+ end
123
+ end
124
+
125
+ describe '#set' do
126
+ it 'sets a value to the state hash' do
127
+ command = Clive::Command.new
128
+ command.instance_variable_set :@state, {}
129
+ command.set :a, true
130
+ command.instance_variable_get(:@state).must_equal :a => true
131
+ end
132
+ end
133
+
134
+ describe '#option' do
135
+ it 'creates an option' do
136
+ command = Clive::Command.new
137
+ command.option :O, :opt, 'An option', :tail => true
138
+
139
+ opt = command.find('-O')
140
+ opt.name.must_equal :opt
141
+ opt.description.must_equal 'An option'
142
+ opt.config.must_contain :tail => true
143
+ end
144
+ end
145
+
146
+ describe '#boolean' do
147
+ it 'creates a new boolean option' do
148
+ command = Clive::Command.new
149
+ command.boolean :auto, 'Auto build', :head => true
150
+
151
+ bool = command.find('--auto')
152
+ bool.name.must_equal :auto
153
+ bool.description.must_equal 'Auto build'
154
+ bool.config.must_contain :head => true
155
+ bool.config[:boolean].must_be_true
156
+ end
157
+ end
158
+
159
+ describe '#action' do
160
+ it 'stores a block' do
161
+ command = Clive::Command.new
162
+ block = proc {}
163
+ command.action &block
164
+ command.instance_variable_get(:@block).to_s.must_equal block.to_s
170
165
  end
171
166
  end
172
-
173
- describe "#option_missing" do
174
- it "sets the option missing proc" do
175
- proc = lambda {|n| puts "What? #{name} doesn't exist" }
176
- subject.option_missing(&proc)
177
- subject.instance_variable_get("@option_missing").should == proc
167
+
168
+ describe '#description' do
169
+ it 'sets the description' do
170
+ command = Clive::Command.new
171
+ command.description 'Some description'
172
+ command.instance_variable_get(:@_last_desc).must_equal 'Some description'
173
+ end
174
+
175
+ it 'gets the description' do
176
+ command = Clive::Command.new [], 'A command'
177
+ command.description.must_equal 'A command'
178
178
  end
179
179
  end
180
-
181
- describe "#header" do
182
- it "sets the header" do
183
- subject.header "A header"
184
- subject.instance_variable_get("@header").should == "A header"
180
+
181
+ describe '#find' do
182
+ subject {
183
+ Clive::Command.create [:command] do
184
+ bool :F, :force
185
+ opt :auto_build
186
+ end
187
+ }
188
+
189
+ it 'finds boolean options' do
190
+ subject.find('--force').name.must_equal :force
191
+ end
192
+
193
+ it 'finds short options' do
194
+ subject.find('-F').name.must_equal :force
195
+ end
196
+
197
+ it 'does not find short negative boolean options' do
198
+ subject.find('--no-F').must_be_nil
199
+ end
200
+
201
+ it 'does not find negative boolean options' do
202
+ subject.find('--no-force').must_be_nil
203
+ end
204
+
205
+ it 'finds options with multiple words in name' do
206
+ subject.find('--auto_build').name.must_equal :auto_build
207
+ end
208
+
209
+ it 'finds options with dashes in name' do
210
+ subject.find('--auto-build').name.must_equal :auto_build
211
+ end
212
+
213
+ it 'does not find non existent options' do
214
+ subject.find('--no-auto-build').must_be_nil
215
+ subject.find('--unreal').must_be_nil
185
216
  end
186
217
  end
187
-
188
- describe "#footer" do
189
- it "sets the footer" do
190
- subject.footer "A footer"
191
- subject.instance_variable_get("@footer").should == "A footer"
218
+
219
+ describe '#find_option' do
220
+ subject {
221
+ Clive::Command.create do
222
+ bool :F, :force
223
+ opt :auto_build
224
+ end
225
+ }
226
+
227
+ it 'finds boolean options' do
228
+ subject.find_option(:force).name.must_equal :force
229
+ end
230
+
231
+ it 'finds short options' do
232
+ subject.find_option(:F).name.must_equal :force
233
+ end
234
+
235
+ it 'does not find short negative boolean options' do
236
+ subject.find_option(:no_F).must_be_nil
237
+ end
238
+
239
+ it 'does not find negative boolean options' do
240
+ subject.find_option(:no_force).must_be_nil
241
+ end
242
+
243
+ it 'finds options with multiple words in name' do
244
+ subject.find_option(:auto_build).name.must_equal :auto_build
245
+ end
246
+
247
+ it 'does not find non existent options' do
248
+ subject.find_option(:no_auto_build).must_be_nil
249
+ subject.find_option(:unreal).must_be_nil
192
250
  end
193
251
  end
194
-
195
- describe "#build_help" do
196
- it "adds a switch for help" do
197
- subject.options = []
198
- subject.options.should be_empty
199
- subject.build_help
200
- subject.options.map(&:names).should include ['h', 'help']
252
+
253
+ describe '#has?' do
254
+ it 'tries to find the option' do
255
+ command = Clive::Command.new
256
+ command.expects(:find).with('--option').returns(Clive::Option.new)
257
+ command.has?('--option').must_be_true
201
258
  end
202
259
  end
203
-
204
- describe "#help" do
205
- it "returns a string of help" do
206
- help = <<EOS
207
- Usage: rspec co, comm [options]
208
260
 
209
- Options:
210
- -h, --help \e[90mDisplay help\e[0m
211
- EOS
212
-
213
- subject.help.should == help
261
+ describe '#group' do
262
+ it 'sets the group for options created' do
263
+ command = Clive::Command.create do
264
+ group 'Testing'
265
+ opt :test
266
+ group 'Changed'
267
+ opt :change
268
+ opt :manual, :group => 'Set'
269
+ end
270
+
271
+ command.find_option(:test).config[:group].must_equal 'Testing'
272
+ command.find_option(:change).config[:group].must_equal 'Changed'
273
+ command.find_option(:manual).config[:group].must_equal 'Set'
214
274
  end
215
275
  end
216
-
217
- describe "#help_formatter" do
218
- context "when called with a symbol" do
219
- it "uses the named formatter" do
220
- before = subject.instance_variable_get("@formatter")
221
- subject.help_formatter(:white)
222
- subject.instance_variable_get("@formatter").should_not == before
276
+
277
+ describe '#end_group' do
278
+ it 'calls #group with nil' do
279
+ command = Clive::Command.create do
280
+ group 'Testing'
281
+ option :test
282
+ end_group
283
+ option :none
223
284
  end
285
+
286
+ command.find_option(:none).config[:group].must_be_nil
224
287
  end
225
-
226
- context "when called with argumentss and a block" do
227
- it "creates a new help formatter" do
228
- subject.help_formatter :width => 40, :prepend => 5 do |h|
229
- h.switch "switch"
230
- h.bool "bool"
231
- h.flag "flag"
232
- h.command "command"
233
- end
234
- formatter = subject.instance_variable_get("@formatter")
235
- formatter.width.should == 40
288
+ end
289
+
290
+ describe '#help' do
291
+ it 'builds a help string using the defined formatter' do
292
+ f = mock
293
+ command = Clive::Command.create [], "", :formatter => f, :help => true do
294
+ header 'Top'
295
+ footer 'Bottom'
236
296
  end
297
+
298
+ f.expects(:header=).with('Top')
299
+ f.expects(:footer=).with('Bottom')
300
+ f.expects(:options=).with([command.find_option(:help)])
301
+ f.expects(:to_s).with()
302
+
303
+ command.help
237
304
  end
238
305
  end
239
306
 
240
- end
307
+ end