adhearsion 2.0.0.rc4 → 2.0.0.rc5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/adhearsion.gemspec +1 -1
  3. data/bin/ahn +0 -3
  4. data/lib/adhearsion.rb +7 -4
  5. data/lib/adhearsion/call.rb +1 -1
  6. data/lib/adhearsion/call_controller.rb +1 -0
  7. data/lib/adhearsion/call_controller/menu_dsl.rb +19 -0
  8. data/lib/adhearsion/call_controller/menu_dsl/calculated_match.rb +43 -0
  9. data/lib/adhearsion/call_controller/menu_dsl/calculated_match_collection.rb +45 -0
  10. data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +22 -0
  11. data/lib/adhearsion/call_controller/menu_dsl/match_calculator.rb +40 -0
  12. data/lib/adhearsion/call_controller/menu_dsl/menu.rb +203 -0
  13. data/lib/adhearsion/call_controller/menu_dsl/menu_builder.rb +84 -0
  14. data/lib/adhearsion/call_controller/menu_dsl/range_match_calculator.rb +60 -0
  15. data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +25 -0
  16. data/lib/adhearsion/cli.rb +0 -1
  17. data/lib/adhearsion/router/route.rb +2 -2
  18. data/lib/adhearsion/version.rb +1 -1
  19. data/spec/adhearsion/call_controller/input_spec.rb +1 -1
  20. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_collection_spec.rb +60 -0
  21. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_spec.rb +61 -0
  22. data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +37 -0
  23. data/spec/adhearsion/call_controller/menu_dsl/match_calculator_spec.rb +17 -0
  24. data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +151 -0
  25. data/spec/adhearsion/call_controller/menu_dsl/menu_spec.rb +373 -0
  26. data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +32 -0
  27. data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +40 -0
  28. metadata +91 -91
  29. data/lib/adhearsion/menu_dsl.rb +0 -17
  30. data/lib/adhearsion/menu_dsl/calculated_match.rb +0 -41
  31. data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +0 -43
  32. data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +0 -20
  33. data/lib/adhearsion/menu_dsl/match_calculator.rb +0 -38
  34. data/lib/adhearsion/menu_dsl/menu.rb +0 -201
  35. data/lib/adhearsion/menu_dsl/menu_builder.rb +0 -82
  36. data/lib/adhearsion/menu_dsl/range_match_calculator.rb +0 -58
  37. data/lib/adhearsion/menu_dsl/string_match_calculator.rb +0 -23
  38. data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +0 -58
  39. data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +0 -59
  40. data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +0 -35
  41. data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +0 -15
  42. data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +0 -149
  43. data/spec/adhearsion/menu_dsl/menu_spec.rb +0 -371
  44. data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +0 -30
  45. data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +0 -38
@@ -1,58 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Adhearsion
4
- module MenuDSL
5
-
6
- class RangeMatchCalculator < MatchCalculator
7
-
8
- def initialize(pattern, match_payload)
9
- raise unless pattern.first.kind_of?(Numeric) && pattern.last.kind_of?(Numeric)
10
- super
11
- end
12
-
13
- def match(query)
14
- numerical_query = coerce_to_numeric query
15
- if numerical_query
16
- exact_match = pattern.include?(numerical_query) ? query : nil
17
- potential_matches = numbers_in_range_like numerical_query
18
- potential_matches.reject! { |m| m.to_s == exact_match.to_s } if exact_match
19
-
20
- new_calculated_match :query => query, :exact_matches => exact_match,
21
- :potential_matches => potential_matches
22
- else
23
- CalculatedMatch.failed_match! pattern, query, match_payload
24
- end
25
- end
26
-
27
- private
28
-
29
- # Returns all numbers in the range (@pattern) that +begin with+ the number given
30
- # as the first arguement.
31
- #
32
- # NOTE: If you're having trouble reading what this method is actually doing. It's
33
- # effectively a much more efficient version of this:
34
- #
35
- # pattern.to_a.select { |x| x.to_s.starts_with? num.to_s }.flatten
36
- #
37
- # Huge thanks to Dave Troy (http://davetroy.blogspot.com) for this awesomely
38
- # efficient code!
39
- def numbers_in_range_like(num)
40
- return (pattern === 0 ? [0] : nil) if num == 0
41
- raise ArgumentError unless num.kind_of?(Numeric)
42
- Array.new.tap do |matches|
43
- first, last = pattern.first, pattern.last
44
- power = 0
45
- while num < last
46
- ones_count = 10**power - 1
47
- range = ([num, first].max..[num + ones_count, last].min).to_a
48
- matches.concat range
49
- num *= 10
50
- power += 1
51
- end
52
- end
53
- end
54
-
55
- end # class RangeMatchCalculator
56
-
57
- end
58
- end
@@ -1,23 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Adhearsion
4
- module MenuDSL
5
-
6
- class StringMatchCalculator < MatchCalculator
7
-
8
- def match(query)
9
- args = { :query => query, :exact_matches => nil, :potential_matches => nil }
10
-
11
- if pattern == query.to_s
12
- args[:exact_matches] = [pattern]
13
- elsif pattern.starts_with? query.to_s
14
- args[:potential_matches] = [pattern]
15
- end
16
-
17
- new_calculated_match args
18
- end
19
-
20
- end # class StringMatchCalculator
21
-
22
- end
23
- end
@@ -1,58 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- module Adhearsion
6
- module MenuDSL
7
- describe CalculatedMatchCollection do
8
- def mock_with_potential_matches(potential_matches)
9
- CalculatedMatch.new :potential_matches => potential_matches
10
- end
11
-
12
- def mock_with_exact_matches(exact_matches)
13
- CalculatedMatch.new :exact_matches => exact_matches
14
- end
15
-
16
- def mock_with_potential_and_exact_matches(potential_matches, exact_matches)
17
- CalculatedMatch.new :potential_matches => potential_matches,
18
- :exact_matches => exact_matches
19
- end
20
-
21
- it "the <<() method should collect the potential matches into the actual_potential_matches Array" do
22
- mock_matches_array_1 = [:foo, :bar, :qaz],
23
- mock_matches_array_2 = [10, 20, 30]
24
- mock_matches_1 = mock_with_potential_matches mock_matches_array_1
25
- mock_matches_2 = mock_with_potential_matches mock_matches_array_2
26
-
27
- subject << mock_matches_1
28
- subject.actual_potential_matches.should be == mock_matches_array_1
29
-
30
- subject << mock_matches_2
31
- subject.actual_potential_matches.should be == mock_matches_array_1 + mock_matches_array_2
32
- end
33
-
34
- it "the <<() method should collect the exact matches into the actual_exact_matches Array" do
35
- mock_matches_array_1 = [:blam, :blargh],
36
- mock_matches_array_2 = [5,4,3,2,1]
37
- mock_matches_1 = mock_with_exact_matches mock_matches_array_1
38
- mock_matches_2 = mock_with_exact_matches mock_matches_array_2
39
-
40
- subject << mock_matches_1
41
- subject.actual_exact_matches.should be == mock_matches_array_1
42
-
43
- subject << mock_matches_2
44
- subject.actual_exact_matches.should be == mock_matches_array_1 + mock_matches_array_2
45
- end
46
-
47
- it "if any exact matches exist, the exact_match?() method should return true" do
48
- subject << mock_with_exact_matches([1,2,3])
49
- subject.exact_match?.should be true
50
- end
51
-
52
- it "if any potential matches exist, the potential_match?() method should return true" do
53
- subject << mock_with_potential_matches([1,2,3])
54
- subject.potential_match?.should be true
55
- end
56
- end
57
- end
58
- end
@@ -1,59 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- module Adhearsion
6
- module MenuDSL
7
- describe CalculatedMatch do
8
- it "should make accessible the context name" do
9
- CalculatedMatch.new(:match_payload => :foobar).match_payload.should be :foobar
10
- end
11
-
12
- it "should make accessible the original pattern" do
13
- CalculatedMatch.new(:pattern => :something).pattern.should be :something
14
- end
15
-
16
- it "should make accessible the matched query" do
17
- CalculatedMatch.new(:query => 123).query.should be 123
18
- end
19
-
20
- it "#type_of_match should return :exact, :potential, or nil" do
21
- CalculatedMatch.new(:potential_matches => [1]).type_of_match.should be :potential
22
- CalculatedMatch.new(:exact_matches => [3,3]).type_of_match.should be :exact
23
- CalculatedMatch.new(:exact_matches => [8,3], :potential_matches => [0,9]).type_of_match.should be :exact
24
- end
25
-
26
- it "#exact_match? should return true if the match was exact" do
27
- CalculatedMatch.new(:exact_matches => [0,3,5]).exact_match?.should be true
28
- end
29
-
30
- it "#potential_match? should return true if the match was exact" do
31
- CalculatedMatch.new(:potential_matches => [88,99,77]).potential_match?.should be true
32
- end
33
-
34
- it "#failed_match? should return false if the match was exact" do
35
- CalculatedMatch.new(:potential_matches => [88,99,77]).failed_match?.should be false
36
- end
37
-
38
- it "#exact_matches should return an array of exact matches" do
39
- CalculatedMatch.new(:exact_matches => [0,3,5]).exact_matches.should be == [0,3,5]
40
- end
41
-
42
- it "#potential_matches should return an array of potential matches" do
43
- CalculatedMatch.new(:potential_matches => [88,99,77]).potential_matches.should be == [88,99,77]
44
- end
45
-
46
- it "::failed_match! should return a match that *really* failed" do
47
- failure = CalculatedMatch.failed_match! 10..20, 30, :match_payload_does_not_matter
48
- failure.exact_match?.should_not be true
49
- failure.potential_match?.should_not be true
50
- failure.failed_match?.should be true
51
- failure.type_of_match.should be nil
52
-
53
- failure.match_payload.should be :match_payload_does_not_matter
54
- failure.pattern.should be == (10..20)
55
- failure.query.should be == 30
56
- end
57
- end
58
- end
59
- end
@@ -1,35 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- module Adhearsion
6
- module MenuDSL
7
- describe FixnumMatchCalculator do
8
- let(:match_payload) { :main }
9
-
10
- it "a potential match scenario" do
11
- calculator = FixnumMatchCalculator.new(444, match_payload)
12
- match = calculator.match 4
13
- match.potential_match?.should be true
14
- match.exact_match?.should_not be true
15
- match.potential_matches.should be == [444]
16
- end
17
-
18
- it "a multi-digit exact match scenario" do
19
- calculator = FixnumMatchCalculator.new(5555, match_payload)
20
- calculator.match(5555).exact_match?.should be true
21
- end
22
-
23
- it "a single-digit exact match scenario" do
24
- calculator = FixnumMatchCalculator.new(1, match_payload)
25
- calculator.match(1).exact_match?.should be true
26
- end
27
-
28
- it "the context name given to the calculator should be passed on the CalculatedMatch" do
29
- match_payload = :icanhascheezburger
30
- calculator = FixnumMatchCalculator.new(1337, match_payload)
31
- calculator.match(1337).match_payload.should be match_payload
32
- end
33
- end
34
- end
35
- end
@@ -1,15 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- module Adhearsion
6
- module MenuDSL
7
- describe MatchCalculator do
8
- describe ".build_with_pattern" do
9
- it "should return an appropriate subclass instance based on the pattern's class" do
10
- MatchCalculator.build_with_pattern(1..2, :main).should be_an_instance_of RangeMatchCalculator
11
- end
12
- end
13
- end
14
- end
15
- end
@@ -1,149 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- module Adhearsion
6
- module MenuDSL
7
-
8
- describe MenuBuilder do
9
- subject{ MenuDSL::MenuBuilder.new }
10
-
11
- describe "#build" do
12
- it "sets the context and instance_eval's the block" do
13
- flexmock(subject).should_receive(:foo).with(:bar)
14
- subject.build do
15
- foo :bar
16
- end
17
- end
18
- end#build
19
-
20
- describe "#match" do
21
- let(:match_block) { Proc.new() {} }
22
-
23
- it "raises an exception if called without a CallController and no block" do
24
- expect { subject.match 1 }.to raise_error(ArgumentError)
25
- end
26
-
27
- it "raises an exception if given both a payload and a block" do
28
- expect { subject.match(1, Object) {} }.to raise_error(ArgumentError)
29
- end
30
-
31
- it "raises an exception if given no patterns" do
32
- expect { subject.match() {} }.to raise_error(ArgumentError, "You cannot call this method without patterns.")
33
- end
34
-
35
- it "creates a pattern based on a payload" do
36
- flexmock(MenuDSL::MatchCalculator).should_receive(:build_with_pattern).with("1", Object)
37
- subject.match "1", Object
38
- end
39
-
40
- it "creates a pattern based on a block" do
41
- flexmock(MenuDSL::MatchCalculator).should_receive(:build_with_pattern).with("1", nil, match_block)
42
- subject.match("1", &match_block)
43
- end
44
-
45
- it "creates multiple patterns if multiple arguments are passed in" do
46
- flexmock(MenuDSL::MatchCalculator).should_receive(:build_with_pattern).with(1, Object)
47
- flexmock(MenuDSL::MatchCalculator).should_receive(:build_with_pattern).with(2, Object)
48
- subject.match(1, 2, Object)
49
- end
50
- end#match
51
-
52
- describe "#has_matchers?" do
53
- context "with no matchers specified" do
54
- its(:has_matchers?) { should be false }
55
- end
56
-
57
- context "with at least one matcher specified" do
58
- before do
59
- subject.match(1) {}
60
- end
61
-
62
- its(:has_matchers?) { should be true }
63
- end
64
- end
65
-
66
- describe "#weighted_match_calculators" do
67
- let(:expected_pattern) { MenuDSL::MatchCalculator.build_with_pattern("1", Object) }
68
-
69
- it "returns the generated patterns" do
70
- flexmock(MenuDSL::MatchCalculator).should_receive(:build_with_pattern).with("1", Object).and_return(expected_pattern)
71
- subject.match("1", Object)
72
- subject.weighted_match_calculators.should be == [expected_pattern]
73
- end
74
- end#weighted_match_calculators
75
-
76
- describe "#invalid" do
77
- let(:callback) { Proc.new() {} }
78
-
79
- it "raises an error if not passed a block" do
80
- expect { subject.invalid }.to raise_error(LocalJumpError)
81
- end
82
-
83
- it "sets the invalid callback" do
84
- subject.invalid(&callback)
85
- subject.menu_callbacks[:invalid].should be == callback
86
- end
87
- end#invalid
88
-
89
- describe "#timeout" do
90
- let(:callback) { Proc.new() {} }
91
-
92
- it "raises an error if not passed a block" do
93
- expect { subject.timeout }.to raise_error(LocalJumpError)
94
- end
95
-
96
- it "sets the timeout callback" do
97
- subject.timeout(&callback)
98
- subject.menu_callbacks[:timeout].should be == callback
99
- end
100
- end#timeout
101
-
102
- describe "#failure" do
103
- let(:callback) { Proc.new() {} }
104
-
105
- it "raises an error if not passed a block" do
106
- expect { subject.failure }.to raise_error(LocalJumpError)
107
- end
108
-
109
- it "sets the failure callback" do
110
- subject.failure(&callback)
111
- subject.menu_callbacks[:failure].should be == callback
112
- end
113
- end#failure
114
-
115
- describe "#validator" do
116
- let(:callback) { Proc.new() {} }
117
-
118
- it "raises an error if not passed a block" do
119
- expect { subject.validator }.to raise_error(LocalJumpError)
120
- end
121
-
122
- it "sets the invalid callback" do
123
- subject.validator(&callback)
124
- subject.menu_callbacks[:validator].should be == callback
125
- end
126
- end#invalid
127
-
128
- describe "#execute_hook_for" do
129
- it "executes the correct hook" do
130
- bar = nil
131
- subject.invalid do |baz|
132
- bar = baz
133
- end
134
- subject.execute_hook_for(:invalid, "1")
135
- bar.should be == "1"
136
- end
137
- end#execute_hook_for
138
-
139
- describe "#calculate_matches_for" do
140
- it "returns a calculated match collection" do
141
- subject.match("1", Object)
142
- subject.calculate_matches_for("1").should be_a CalculatedMatchCollection
143
- end
144
- end
145
-
146
- end# describe MenuBuilder
147
-
148
- end# module MenuDSL
149
- end
@@ -1,371 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'spec_helper'
4
-
5
- module Adhearsion
6
- module MenuDSL
7
- describe Menu do
8
-
9
- let(:options) { Hash.new }
10
- subject { Menu.new(options) }
11
-
12
- describe "#initialize" do
13
- its(:tries_count) { should be == 0 }
14
-
15
- context 'when no timeout is set' do
16
- it "should have the default timeout" do
17
- subject.timeout.should be == 5
18
- end
19
- end
20
-
21
- context 'when a timeout is set' do
22
- let(:options) {
23
- {:timeout => 20}
24
- }
25
-
26
- it 'should have the passed timeout' do
27
- subject.timeout.should be == 20
28
- end
29
- end
30
-
31
- context 'when no max number of tries is set' do
32
- it "should have the default max number of tries" do
33
- subject.max_number_of_tries.should be == 1
34
- end
35
- end
36
-
37
- context 'when a max number of tries is set' do
38
- let(:options) {
39
- {:tries => 3}
40
- }
41
-
42
- it 'should have the passed max number of tries' do
43
- subject.max_number_of_tries.should be == 3
44
- end
45
- end
46
-
47
- context 'when no terminator is set' do
48
- it "should have no terminator" do
49
- subject.terminator.should be == ''
50
- end
51
-
52
- it 'should not validate successfully' do
53
- lambda { subject.validate }.should raise_error(Menu::InvalidStructureError)
54
- end
55
- end
56
-
57
- context 'when a terminator is set' do
58
- let(:options) {
59
- {:terminator => 3}
60
- }
61
-
62
- it 'should have the passed terminator' do
63
- subject.terminator.should be == '3'
64
- end
65
-
66
- it 'should validate(:basic) successfully' do
67
- subject.validate(:basic).should be true
68
- end
69
-
70
- it 'should not validate successfully' do
71
- lambda { subject.validate }.should raise_error(Menu::InvalidStructureError)
72
- end
73
- end
74
-
75
- context 'when no limit is set' do
76
- it "should have no limit" do
77
- subject.limit.should be nil
78
- end
79
-
80
- it 'should not validate successfully' do
81
- lambda { subject.validate }.should raise_error(Menu::InvalidStructureError)
82
- end
83
- end
84
-
85
- context 'when a limit is set' do
86
- let(:options) {
87
- {:limit => 3}
88
- }
89
-
90
- it 'should have the passed limit' do
91
- subject.limit.should be == 3
92
- end
93
-
94
- it 'should validate(:basic) successfully' do
95
- subject.validate(:basic).should be true
96
- end
97
-
98
- it 'should not validate successfully' do
99
- lambda { subject.validate }.should raise_error(Menu::InvalidStructureError)
100
- end
101
- end
102
-
103
- context 'when no interruptibility is set' do
104
- it "should be interruptible" do
105
- subject.interruptible.should be true
106
- end
107
- end
108
-
109
- context 'when interruptible is set false' do
110
- let(:options) {
111
- {:interruptible => false}
112
- }
113
-
114
- it 'should be interruptible' do
115
- subject.interruptible.should be false
116
- end
117
- end
118
-
119
- context 'when matchers are specified' do
120
- subject do
121
- Menu.new do
122
- match(1) { }
123
- end
124
- end
125
-
126
- it 'should validate successfully' do
127
- subject.validate.should be true
128
- end
129
-
130
- it 'should not validate(:basic) successfully' do
131
- lambda { subject.validate :basic }.should raise_error(Menu::InvalidStructureError)
132
- end
133
- end
134
-
135
- context 'menu builder setup' do
136
- its(:builder) { should be_a MenuBuilder }
137
-
138
- it "should evaluate the block on the builder object" do
139
- mock_menu_builder = flexmock(MenuBuilder.new)
140
- flexmock(MenuBuilder).should_receive(:new).and_return(mock_menu_builder)
141
- mock_menu_builder.should_receive(:match).once.with(1)
142
- Menu.new { match 1 }
143
- end
144
- end
145
-
146
- end # describe #initialize
147
-
148
- describe "#digit_buffer" do
149
- its(:digit_buffer) { should be_a Menu::ClearableStringBuffer }
150
- its(:digit_buffer) { should be == "" }
151
- end
152
-
153
- describe "#<<" do
154
- it "should add a digit to the buffer" do
155
- subject << 'a'
156
- subject.digit_buffer.should be == 'a'
157
- subject.result.should be == 'a'
158
- end
159
- end
160
-
161
- describe "#digit_buffer_empty?" do
162
- it "returns true if buffer is empty" do
163
- subject.digit_buffer_empty?.should be == true
164
- end
165
-
166
- it "returns false if buffer is not empty" do
167
- subject << 1
168
- subject.digit_buffer_empty?.should be == false
169
- end
170
- end
171
-
172
- describe "#digit_buffer_string" do
173
- it "returns the digit buffer as a string" do
174
- subject << 1
175
- subject.digit_buffer_string.should be == "1"
176
- end
177
- end
178
-
179
- describe "#should_continue?" do
180
- it "returns true if the number of tries is less than the maximum" do
181
- subject.max_number_of_tries.should be == 1
182
- subject.tries_count.should be == 0
183
- subject.should_continue?.should be == true
184
- end
185
- end
186
-
187
- describe "#restart!" do
188
- it "increments tries and clears the digit buffer" do
189
- subject << 1
190
- subject.restart!
191
- subject.tries_count.should be == 1
192
- subject.digit_buffer_empty?.should be == true
193
- end
194
- end
195
-
196
- describe "#execute_invalid_hook" do
197
- it "calls the builder's execute_hook_for with :invalid" do
198
- mock_menu_builder = flexmock(MenuBuilder.new)
199
- flexmock(MenuBuilder).should_receive(:new).and_return(mock_menu_builder)
200
- mock_menu_builder.should_receive(:execute_hook_for).with(:invalid, "")
201
- menu_instance = Menu.new
202
- menu_instance.execute_invalid_hook
203
- end
204
- end
205
-
206
- describe "#execute_timeout_hook" do
207
- it "calls the builder's execute_hook_for with :timeout" do
208
- mock_menu_builder = flexmock(MenuBuilder.new)
209
- flexmock(MenuBuilder).should_receive(:new).and_return(mock_menu_builder)
210
- mock_menu_builder.should_receive(:execute_hook_for).with(:timeout, "")
211
- menu_instance = Menu.new
212
- menu_instance.execute_timeout_hook
213
- end
214
- end
215
-
216
- describe "#execute_failure_hook" do
217
- it "calls the builder's execute_hook_for with :failure" do
218
- mock_menu_builder = flexmock(MenuBuilder.new)
219
- flexmock(MenuBuilder).should_receive(:new).and_return(mock_menu_builder)
220
- mock_menu_builder.should_receive(:execute_hook_for).with(:failure, "")
221
- menu_instance = Menu.new
222
- menu_instance.execute_failure_hook
223
- end
224
- end
225
-
226
- describe "#execute_validator_hook" do
227
- it "calls the builder's execute_hook_for with :validator" do
228
- mock_menu_builder = flexmock(MenuBuilder.new)
229
- flexmock(MenuBuilder).should_receive(:new).and_return(mock_menu_builder)
230
- mock_menu_builder.should_receive(:execute_hook_for).with(:validator, "")
231
- menu_instance = Menu.new
232
- menu_instance.execute_validator_hook
233
- end
234
- end
235
-
236
- describe "#continue" do
237
- class MockControllerA; end
238
- class MockControllerB; end
239
- class MockControllerC; end
240
- let(:options) { {} }
241
- let(:menu_instance) {
242
- Menu.new options do
243
- match 1, MockControllerA
244
- match 21, MockControllerA
245
- match 23, MockControllerA
246
- match 3, MockControllerB
247
- match 3..5, MockControllerC
248
- match 33, MockControllerA
249
- match 6, MockControllerC
250
- match 6..8, MockControllerA
251
- end
252
- }
253
-
254
- it "returns a MenuGetAnotherDigitOrTimeout if the digit buffer is empty" do
255
- subject.continue.should be_a Menu::MenuGetAnotherDigitOrTimeout
256
- menu_instance.status.should be nil
257
- end
258
-
259
- it "asks for another digit if it has potential matches" do
260
- menu_instance << 2
261
- menu_instance.continue.should be_a Menu::MenuGetAnotherDigitOrTimeout
262
- menu_instance.status.should be == :potential
263
- end
264
-
265
- it "returns a MenuResultInvalid if there are no matches" do
266
- menu_instance << 9
267
- menu_instance.continue.should be_a Menu::MenuResultInvalid
268
- menu_instance.status.should be == :invalid
269
- end
270
-
271
- it "returns the first exact match when it has exact and potentials" do
272
- menu_instance << 3
273
- menu_result = menu_instance.continue
274
- menu_result.should be_a Menu::MenuGetAnotherDigitOrFinish
275
- menu_result.match_object.should be == MockControllerB
276
- menu_result.new_extension.should be == "3"
277
- menu_instance.status.should be == :multi_matched
278
- end
279
-
280
- it "returns a MenuResultFound if it has exact matches" do
281
- menu_instance << 6
282
- menu_result = menu_instance.continue
283
- menu_result.should be_a Menu::MenuResultFound
284
- menu_instance.status.should be == :matched
285
- end
286
-
287
- it "returns the first exact match when it has only exact matches" do
288
- menu_instance << 6
289
- menu_result = menu_instance.continue
290
- menu_result.should be_a Menu::MenuResultFound
291
- menu_result.match_object.match_payload.should be == MockControllerC
292
- menu_result.match_object.pattern.to_s.should be == "6"
293
- end
294
-
295
- context "with no matchers" do
296
- let(:menu_instance) { Menu.new options }
297
-
298
- context "when a terminator digit is set" do
299
- let(:options) { { :terminator => '#' } }
300
-
301
- it "buffers until the terminator is issued then returns a MenuTerminated and sets the status to :terminated, removing the terminator from the buffer" do
302
- menu_instance << 2
303
- menu_instance << 4
304
- menu_instance.continue.should be_a Menu::MenuGetAnotherDigitOrTimeout
305
- menu_instance.status.should be == :potential
306
- menu_instance << '#'
307
- menu_instance.continue.should be_a Menu::MenuTerminated
308
- menu_instance.continue.should be_a Menu::MenuResultDone
309
- menu_instance.status.should be == :terminated
310
- menu_instance.result.should be == '24'
311
- end
312
- end
313
-
314
- context "when a digit limit is set" do
315
- let(:options) { { :limit => 3 } }
316
-
317
- it "buffers until the limit is reached, then returns MenuLimitReached and sets the status to :limited" do
318
- menu_instance << 2
319
- menu_instance << 4
320
- menu_instance.continue.should be_a Menu::MenuGetAnotherDigitOrTimeout
321
- menu_instance.status.should be == :potential
322
- menu_instance << 2
323
- menu_instance.continue.should be_a Menu::MenuLimitReached
324
- menu_instance.continue.should be_a Menu::MenuResultDone
325
- menu_instance.status.should be == :limited
326
- menu_instance.result.should be == '242'
327
- end
328
- end
329
-
330
- context "when a validator is defined" do
331
- let(:menu_instance) do
332
- Menu.new options do
333
- validator { |buffer| buffer == "242" }
334
- end
335
- end
336
-
337
- it "buffers until the validator returns true, then returns MenuValidatorTerminated and sets the status to :validator_terminated" do
338
- menu_instance << 2
339
- menu_instance << 4
340
- menu_instance.continue.should be_a Menu::MenuGetAnotherDigitOrTimeout
341
- menu_instance.status.should be == :potential
342
- menu_instance << 2
343
- menu_instance.continue.should be_a Menu::MenuValidatorTerminated
344
- menu_instance.continue.should be_a Menu::MenuResultDone
345
- menu_instance.status.should be == :validator_terminated
346
- menu_instance.result.should be == '242'
347
- end
348
- end
349
- end
350
-
351
- end#continue
352
-
353
- describe Menu::ClearableStringBuffer do
354
- subject { Menu::ClearableStringBuffer.new }
355
-
356
- it "adds a string to itself" do
357
- subject << 'b'
358
- subject << 'c'
359
- subject.should be == 'bc'
360
- end
361
-
362
- it "clears itself" do
363
- subject << 'a'
364
- subject.clear!
365
- subject.should be == ""
366
- end
367
- end
368
-
369
- end # describe Menu
370
- end
371
- end