adhearsion 2.0.0.rc4 → 2.0.0.rc5

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.
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