adhearsion-ivr 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 748ecbe4414a38d5ff3b011feac37449447b150d
4
- data.tar.gz: c15534a4e1395b758aefb698bed447875af832fd
3
+ metadata.gz: 6291bef984d7c1879749d5a74c5e663815e20c63
4
+ data.tar.gz: 10398791d0968fc7eafd71e2938c6e71527e02e7
5
5
  SHA512:
6
- metadata.gz: 326c7fd91c2940d5335fd0942b54aaf6e4d00c057f50293de0ee9fd518313408a34363879e709341f2190a1420c2660803f94eebe3ee942cd095e8dc0dd69e6e
7
- data.tar.gz: ae1d4057a6e2ad860833f31324aa14f14652866ca2876ba33d0d4e5c42d2acb4da584d40f6506ab1bc68511f1e948a3a0d2bb3218d78b1270976288f7207c0bf
6
+ metadata.gz: b2a8ea89beec6b451fd9e33d280230395cafb7016a6cb10744c0c4d63d46d69005a1d19b303e74c55b7bd5908f92b9ae3b57030b7eaa7478e81451a18ad46365
7
+ data.tar.gz: c69cb9bb091a9fa5034c45ef361ea8c6be6081489d929f4fe6f1fa7864706646d331d199894be8740fcdebb6b336ba1e7eb1e216956f0d8076e9229afc00f6d9
@@ -0,0 +1,2 @@
1
+ LineLength:
2
+ Enabled: false
@@ -1,4 +1,12 @@
1
1
  # [develop](https://github.com/adhearsion/adhearsion-ivr)
2
2
 
3
+ # [v0.2.0](https://github.com/adhearsion/adhearsion-ivr/compare/0.1.0...0.2.0) - [2015-03-27](https://rubygems.org/gems/adhearsion-ivr/versions/0.2.0)
4
+ * Feature: Added support for defining alternative prompt resolution algorithms by overriding `#prompts`
5
+ * Feature: Added support for overriding `#max_attempts`
6
+ * Feature: Added support for specifying a timeout using #timeout
7
+ * Feature: Added support for specifying a grammar URL using #grammar_url
8
+ * Feature: Added support for specifying a validation callback
9
+ * Feature: Added support for specifying a `renderer`
10
+
3
11
  # [v0.1.0](https://github.com/adhearsion/adhearsion-ivr/compare/2c7ff73f5d6471be23e291c7d6c7b61d0128e09a...0.1.0) - [2014-03-12](https://rubygems.org/gems/adhearsion-ivr/versions/0.1.0)
4
12
  * Initial release
data/README.md CHANGED
@@ -36,12 +36,12 @@ class SimplePrompt < Adhearsion::IVRController
36
36
  hangup
37
37
  end
38
38
  end
39
-
39
+
40
40
  on_failure do
41
41
  say "Sorry you failed kindergarten. Let us transfer you to our trained staff of kindergarten teachers."
42
42
  dial 'sip:kindergarten_teachers@elementaryschool.com'
43
43
  end
44
-
44
+
45
45
  def grammar
46
46
  RubySpeech::GRXML.draw do
47
47
  # ... put a valid GRXML grammar here
@@ -58,9 +58,9 @@ class EscalatedPrompt < Adhearsion::IVRController
58
58
  prompts << "Second attempt: enter a number 1 through 3"
59
59
  prompts << "Third attempt: enter a number 1 through 3. That would be the top row of your DTMF keypad. Don't get it wrong again."
60
60
  prompts << "Fourth attempt: really? Was I not clear the first 3 times? Last chance, dunce."
61
-
61
+
62
62
  max_attempts 4
63
-
63
+
64
64
  on_complete do |result|
65
65
  case result.nlsml.interpretations.first[:instance] # FIXME?
66
66
  when 1
@@ -72,12 +72,46 @@ class EscalatedPrompt < Adhearsion::IVRController
72
72
  hangup
73
73
  end
74
74
  end
75
-
75
+
76
+ on_failure do
77
+ say "Sorry you failed kindergarten. Let us transfer you to our trained staff of kindergarten teachers."
78
+ dial 'sip:kindergarten_teachers@elementaryschool.com'
79
+ end
80
+
81
+ def grammar
82
+ RubySpeech::GRXML.draw do
83
+ # ... put a valid GRXML grammar here
84
+ end
85
+ end
86
+ end
87
+ ```
88
+
89
+ An example with input validation:
90
+
91
+ ```Ruby
92
+ class InputValidation < Adhearsion::IVRController
93
+ prompts << "Please enter your favorite fruit"
94
+
95
+ on_complete do |result|
96
+ case result.interpretation
97
+ when "apple"
98
+ pass AppleController
99
+ when "orange"
100
+ pass OrangeController
101
+ else
102
+ pass OtherController
103
+ end
104
+ end
105
+
76
106
  on_failure do
77
107
  say "Sorry you failed kindergarten. Let us transfer you to our trained staff of kindergarten teachers."
78
108
  dial 'sip:kindergarten_teachers@elementaryschool.com'
79
109
  end
80
-
110
+
111
+ validate do
112
+ ["apple", "orange", "banana", "tomato"].include? @result.interpretation
113
+ end
114
+
81
115
  def grammar
82
116
  RubySpeech::GRXML.draw do
83
117
  # ... put a valid GRXML grammar here
@@ -97,9 +131,47 @@ class I18nEscalatedPrompts < Adhearsion::IVRController
97
131
  prompts << -> { [ t(:fourth_attempt), t(:this_is_your_final_attempt) ] }
98
132
  # Future improvement: we could potentially also include the previous input
99
133
  # in the re-prompts, but that isn't implemented now
100
-
134
+
101
135
  max_attempts 4
102
-
136
+ timeout 30
137
+
138
+ on_complete do |result|
139
+ case result.nlsml.interpretations.first[:instance] # FIXME?
140
+ when 1
141
+ pass OneController
142
+ when 2
143
+ pass TwoController
144
+ when 3
145
+ say "Yuk yuk yuk"
146
+ hangup
147
+ end
148
+ end
149
+
150
+ on_failure do
151
+ say "Sorry you failed kindergarten. Let us transfer you to our trained staff of kindergarten teachers."
152
+ dial 'sip:kindergarten_teachers@elementaryschool.com'
153
+ end
154
+
155
+ def grammar
156
+ RubySpeech::GRXML.draw do
157
+ # ... put a valid GRXML grammar here
158
+ end
159
+ end
160
+ end
161
+ ```
162
+
163
+ ## Method overriding in subclasses
164
+
165
+ If you need to set the configuration for the menu at runtime, `#prompts`, `#timeout`, `#max_attempts` and `renderer` can be defined on the subclass to provide the needed values, as you can see in the following example.
166
+
167
+ The examples assumes the values have been placed in call variables by an earlier controller, which is also a practical use case for overriding methods.
168
+
169
+ `renderer` values are the same accepted by the various Adhearsion output methods.
170
+
171
+ ```Ruby
172
+ class OverriddenPrompt < Adhearsion::IVRController
173
+ prompts << "Please enter a number 1 through 3"
174
+
103
175
  on_complete do |result|
104
176
  case result.nlsml.interpretations.first[:instance] # FIXME?
105
177
  when 1
@@ -111,12 +183,28 @@ class I18nEscalatedPrompts < Adhearsion::IVRController
111
183
  hangup
112
184
  end
113
185
  end
114
-
186
+
115
187
  on_failure do
116
188
  say "Sorry you failed kindergarten. Let us transfer you to our trained staff of kindergarten teachers."
117
189
  dial 'sip:kindergarten_teachers@elementaryschool.com'
118
190
  end
119
-
191
+
192
+ def prompts
193
+ ["Please enter a number 1 through 3", "You should enter a number 1 through 3"]
194
+ end
195
+
196
+ def timeout
197
+ call[:menu_timeout]
198
+ end
199
+
200
+ def renderer
201
+ :unimrcp
202
+ end
203
+
204
+ def max_attempts
205
+ call[:menu_retries]
206
+ end
207
+
120
208
  def grammar
121
209
  RubySpeech::GRXML.draw do
122
210
  # ... put a valid GRXML grammar here
@@ -23,6 +23,30 @@ module Adhearsion
23
23
  end
24
24
  end
25
25
 
26
+ # timeout in seconds for each menu attempt
27
+ def timeout(num = nil)
28
+ if num
29
+ @timeout = num
30
+ else
31
+ @timeout || nil
32
+ end
33
+ end
34
+
35
+ # renderer to use for the prompts
36
+ def renderer(engine = nil)
37
+ if engine
38
+ @renderer = engine
39
+ else
40
+ @renderer || nil
41
+ end
42
+ end
43
+
44
+ # called to verify matched input is valid - should be truthy for valid input, falsey otherwise.
45
+ def validate_input(&block)
46
+ @validate_callback = block
47
+ end
48
+ attr_reader :validate_callback
49
+
26
50
  # called when the caller successfully provides input
27
51
  def on_complete(&block)
28
52
  @completion_callback = block
@@ -37,13 +61,15 @@ module Adhearsion
37
61
  end
38
62
 
39
63
  state_machine initial: :prompting do
40
- event(:match) { transition prompting: :complete }
64
+ event(:match) { transition prompting: :validation }
65
+ event(:valid) { transition validation: :complete }
66
+ event(:invalid) { transition validation: :input_error }
41
67
  event(:reprompt) { transition input_error: :prompting }
42
68
  event(:nomatch) { transition prompting: :input_error }
43
69
  event(:noinput) { transition prompting: :input_error }
44
70
  event(:failure) { transition prompting: :failure, input_error: :failure }
45
71
 
46
- after_transition :prompting => :input_error do |controller|
72
+ after_transition any => :input_error do |controller|
47
73
  controller.increment_errors
48
74
  if controller.continue?
49
75
  controller.reprompt!
@@ -52,11 +78,19 @@ module Adhearsion
52
78
  end
53
79
  end
54
80
 
81
+ after_transition any => :validation do |controller|
82
+ if controller.validate_callback
83
+ controller.valid!
84
+ else
85
+ controller.invalid!
86
+ end
87
+ end
88
+
55
89
  after_transition any => :prompting do |controller|
56
90
  controller.deliver_prompt
57
91
  end
58
92
 
59
- after_transition :prompting => :complete do |controller|
93
+ after_transition any => :complete do |controller|
60
94
  controller.completion_callback
61
95
  end
62
96
 
@@ -71,11 +105,22 @@ module Adhearsion
71
105
  end
72
106
 
73
107
  def deliver_prompt
74
- prompt = self.class.prompts[@errors] || self.class.prompts.last
108
+ prompt = prompts[@errors] || prompts.last
75
109
  prompt = instance_exec(&prompt) if prompt.respond_to? :call
76
110
  logger.debug "Prompt: #{prompt.inspect}"
77
111
 
78
- @result = ask prompt, grammar: grammar, mode: :voice
112
+ if grammar
113
+ ask_options = { grammar: grammar, mode: :voice }
114
+ elsif grammar_url
115
+ ask_options = { grammar_url: grammar_url, mode: :voice }
116
+ else
117
+ fail NotImplementedError, 'You must override #grammar or #grammar_url and provide an input grammar'
118
+ end
119
+
120
+ ask_options[:timeout] = timeout if timeout
121
+ ask_options[:output_options] = { renderer: renderer } if renderer
122
+
123
+ @result = ask prompt, ask_options
79
124
  logger.debug "Got result #{@result.inspect}"
80
125
  case @result.status
81
126
  when :match
@@ -84,19 +129,39 @@ module Adhearsion
84
129
  logger.info "Prompt was stopped forcibly. Exiting cleanly..."
85
130
  when :hangup
86
131
  logger.info "Call was hung up mid-prompt. Exiting controller flow..."
87
- raise Adhearsion::Call::Hangup
132
+ fail Adhearsion::Call::Hangup
88
133
  when :nomatch
89
134
  nomatch!
90
135
  when :noinput
91
136
  noinput!
92
137
  else
93
- raise "Unrecognized result status: #{@result.status}"
138
+ fail "Unrecognized result status: #{@result.status}"
94
139
  end
95
140
  @result
96
141
  end
97
142
 
98
143
  def grammar
99
- raise NotImplementedError, "You must override #grammar and provide a grammar"
144
+ nil
145
+ end
146
+
147
+ def grammar_url
148
+ nil
149
+ end
150
+
151
+ def prompts
152
+ self.class.prompts
153
+ end
154
+
155
+ def max_attempts
156
+ self.class.max_attempts
157
+ end
158
+
159
+ def timeout
160
+ self.class.timeout
161
+ end
162
+
163
+ def renderer
164
+ self.class.renderer
100
165
  end
101
166
 
102
167
  def increment_errors
@@ -104,7 +169,15 @@ module Adhearsion
104
169
  end
105
170
 
106
171
  def continue?
107
- @errors < self.class.max_attempts
172
+ @errors < max_attempts
173
+ end
174
+
175
+ def validate_callback
176
+ if self.class.validate_callback
177
+ instance_exec &self.class.validate_callback
178
+ else
179
+ true
180
+ end
108
181
  end
109
182
 
110
183
  def completion_callback
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  class AdhearsionIVR
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -25,6 +25,10 @@ describe Adhearsion::IVRController do
25
25
  say apology_announcement
26
26
  end
27
27
 
28
+ validate_input do
29
+ @result.utterance == 'Paris'
30
+ end
31
+
28
32
  def grammar
29
33
  :some_grammar
30
34
  end
@@ -71,35 +75,35 @@ describe Adhearsion::IVRController do
71
75
  end
72
76
  end
73
77
 
74
- context "when an utterance is received" do
78
+ context 'when an utterance is received' do
75
79
  before do
76
80
  controller.should_receive(:ask).once.with(expected_prompts[0], grammar: expected_grammar, mode: :voice).and_return result
77
81
  end
78
82
 
79
- context "that is a match" do
83
+ context 'that is a match' do
80
84
  let(:result) { match_result }
81
85
 
82
- it "passes the Result object to the on_complete block" do
86
+ it 'passes the Result object to the on_complete block' do
83
87
  controller.should_receive(:say).once.with "Let's go to Paris"
84
88
  controller.run
85
89
  end
86
90
  end
87
91
 
88
- context "that is a noinput" do
92
+ context 'that is a noinput' do
89
93
  let(:result) { noinput_result }
90
94
 
91
- context "followed by a match" do
95
+ context 'followed by a match' do
92
96
  before do
93
97
  controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return match_result
94
98
  end
95
99
 
96
- it "re-prompts using the next prompt, and then passes the second Result to the on_complete block" do
100
+ it 're-prompts using the next prompt, and then passes the second Result to the on_complete block' do
97
101
  controller.should_receive(:say).once.with "Let's go to Paris"
98
102
  controller.run
99
103
  end
100
104
  end
101
105
 
102
- context "when there are not enough prompts available for all retries" do
106
+ context 'when there are not enough prompts available for all retries' do
103
107
  let(:expected_prompts) { [SecureRandom.uuid, SecureRandom.uuid] }
104
108
 
105
109
  before do
@@ -107,26 +111,26 @@ describe Adhearsion::IVRController do
107
111
  controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return match_result
108
112
  end
109
113
 
110
- it "reuses the last prompt" do
114
+ it 'reuses the last prompt' do
111
115
  controller.should_receive(:say).once.with "Let's go to Paris"
112
116
  controller.run
113
117
  end
114
118
  end
115
119
 
116
- context "until it hits the maximum number of attempts" do
117
- context "using the default of 3 attempts" do
120
+ context 'until it hits the maximum number of attempts' do
121
+ context 'using the default of 3 attempts' do
118
122
  before do
119
123
  controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return result
120
124
  controller.should_receive(:ask).once.with(expected_prompts[2], grammar: expected_grammar, mode: :voice).and_return result
121
125
  end
122
126
 
123
- it "invokes the on_failure block" do
127
+ it 'invokes the on_failure block' do
124
128
  controller.should_receive(:say).once.with apology_announcement
125
129
  controller.run
126
130
  end
127
131
  end
128
132
 
129
- context "when that value is different from the default" do
133
+ context 'when that value is different from the default' do
130
134
  let(:controller_class) do
131
135
  expected_prompts = self.expected_prompts
132
136
  apology_announcement = self.apology_announcement
@@ -156,7 +160,7 @@ describe Adhearsion::IVRController do
156
160
  controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return result
157
161
  end
158
162
 
159
- it "invokes the on_failure block" do
163
+ it 'invokes the on_failure block' do
160
164
  controller.should_receive(:say).once.with apology_announcement
161
165
  controller.run
162
166
  end
@@ -164,25 +168,25 @@ describe Adhearsion::IVRController do
164
168
  end
165
169
  end
166
170
 
167
- context "that is a nomatch" do
171
+ context 'that is a nomatch' do
168
172
  let(:result) do
169
173
  AdhearsionASR::Result.new.tap do |res|
170
174
  res.status = :nomatch
171
175
  end
172
176
  end
173
177
 
174
- context "followed by a match" do
178
+ context 'followed by a match' do
175
179
  before do
176
180
  controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return match_result
177
181
  end
178
182
 
179
- it "re-prompts using the next prompt, and then passes the second Result to the on_complete block" do
183
+ it 're-prompts using the next prompt, and then passes the second Result to the on_complete block' do
180
184
  controller.should_receive(:say).once.with "Let's go to Paris"
181
185
  controller.run
182
186
  end
183
187
  end
184
188
 
185
- context "when there are not enough prompts available for all retries" do
189
+ context 'when there are not enough prompts available for all retries' do
186
190
  let(:expected_prompts) { [SecureRandom.uuid, SecureRandom.uuid] }
187
191
 
188
192
  before do
@@ -190,26 +194,26 @@ describe Adhearsion::IVRController do
190
194
  controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return match_result
191
195
  end
192
196
 
193
- it "reuses the last prompt" do
197
+ it 'reuses the last prompt' do
194
198
  controller.should_receive(:say).once.with "Let's go to Paris"
195
199
  controller.run
196
200
  end
197
201
  end
198
202
 
199
- context "until it hits the maximum number of attempts" do
200
- context "using the default of 3 attempts" do
203
+ context 'until it hits the maximum number of attempts' do
204
+ context 'using the default of 3 attempts' do
201
205
  before do
202
206
  controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return result
203
207
  controller.should_receive(:ask).once.with(expected_prompts[2], grammar: expected_grammar, mode: :voice).and_return result
204
208
  end
205
209
 
206
- it "invokes the on_failure block" do
210
+ it 'invokes the on_failure block' do
207
211
  controller.should_receive(:say).once.with apology_announcement
208
212
  controller.run
209
213
  end
210
214
  end
211
215
 
212
- context "when that value is different from the default" do
216
+ context 'when that value is different from the default' do
213
217
  let(:controller_class) do
214
218
  expected_prompts = self.expected_prompts
215
219
  apology_announcement = self.apology_announcement
@@ -239,7 +243,46 @@ describe Adhearsion::IVRController do
239
243
  controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return result
240
244
  end
241
245
 
242
- it "invokes the on_failure block" do
246
+ it 'invokes the on_failure block' do
247
+ controller.should_receive(:say).once.with apology_announcement
248
+ controller.run
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ context 'that fails validation' do
255
+ let(:invalid_result) do
256
+ AdhearsionASR::Result.new.tap do |res|
257
+ res.status = :match
258
+ res.mode = :voice
259
+ res.confidence = 1
260
+ res.utterance = 'London'
261
+ res.interpretation = 'London'
262
+ res.nlsml = nlsml
263
+ end
264
+ end
265
+ let(:result) { invalid_result }
266
+
267
+ context 'followed by a succesful validation' do
268
+ before do
269
+ controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return match_result
270
+ end
271
+
272
+ it 're-prompt, and then passes the valid result to the on_complete block' do
273
+ controller.should_receive(:say).once.with "Let's go to Paris"
274
+ controller.run
275
+ end
276
+ end
277
+
278
+ context 'until it hits the maximum number of attempts' do
279
+ context 'using the default of 3 attempts' do
280
+ before do
281
+ controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return result
282
+ controller.should_receive(:ask).once.with(expected_prompts[2], grammar: expected_grammar, mode: :voice).and_return result
283
+ end
284
+
285
+ it 'invokes the on_failure block' do
243
286
  controller.should_receive(:say).once.with apology_announcement
244
287
  controller.run
245
288
  end
@@ -247,7 +290,7 @@ describe Adhearsion::IVRController do
247
290
  end
248
291
  end
249
292
 
250
- context "that is a hangup" do
293
+ context 'that is a hangup' do
251
294
  let(:controller_class) do
252
295
  expected_prompts = self.expected_prompts
253
296
 
@@ -257,11 +300,11 @@ describe Adhearsion::IVRController do
257
300
  end
258
301
 
259
302
  on_complete do |result|
260
- raise "Got complete"
303
+ fail 'Got complete'
261
304
  end
262
305
 
263
306
  on_failure do
264
- raise "Got failure"
307
+ fail 'Got failure'
265
308
  end
266
309
 
267
310
  def grammar
@@ -276,12 +319,12 @@ describe Adhearsion::IVRController do
276
319
  end
277
320
  end
278
321
 
279
- it "raises Adhearsion::Call::Hangup" do
322
+ it 'raises Adhearsion::Call::Hangup' do
280
323
  expect { controller.run }.to raise_error(Adhearsion::Call::Hangup)
281
324
  end
282
325
  end
283
326
 
284
- context "that is a stop" do
327
+ context 'that is a stop' do
285
328
  let(:controller_class) do
286
329
  expected_prompts = self.expected_prompts
287
330
 
@@ -291,11 +334,11 @@ describe Adhearsion::IVRController do
291
334
  end
292
335
 
293
336
  on_complete do |result|
294
- raise "Got complete"
337
+ fail 'Got complete'
295
338
  end
296
339
 
297
340
  on_failure do
298
- raise "Got failure"
341
+ fail 'Got failure'
299
342
  end
300
343
 
301
344
  def grammar
@@ -310,13 +353,13 @@ describe Adhearsion::IVRController do
310
353
  end
311
354
  end
312
355
 
313
- it "falls through silently" do
356
+ it 'falls through silently' do
314
357
  controller.run
315
358
  end
316
359
  end
317
360
  end
318
361
 
319
- context "when the prompts are callable" do
362
+ context 'when the prompts are callable' do
320
363
  let(:controller_class) do
321
364
  Class.new(Adhearsion::IVRController) do
322
365
  prompts << -> { thing }
@@ -338,7 +381,7 @@ describe Adhearsion::IVRController do
338
381
  end
339
382
  end
340
383
 
341
- it "should evaluate the prompt repeatedly in the context of the controller instance" do
384
+ it 'should evaluate the prompt repeatedly in the context of the controller instance' do
342
385
  controller.should_receive(:ask).once.with('one', grammar: expected_grammar, mode: :voice).and_return noinput_result
343
386
  controller.should_receive(:ask).once.with('two', grammar: expected_grammar, mode: :voice).and_return noinput_result
344
387
  controller.should_receive(:ask).once.with('three', grammar: expected_grammar, mode: :voice).and_return noinput_result
@@ -346,10 +389,32 @@ describe Adhearsion::IVRController do
346
389
  end
347
390
  end
348
391
 
349
- context "when no grammar is provided" do
392
+ context 'when a grammar is referenced by url' do
393
+ let(:test_grammar_url) { 'http://localhost/grammar.grxml' }
394
+ let(:controller_class) do
395
+ Class.new(Adhearsion::IVRController) do
396
+ prompts << 'Hello'
397
+ max_attempts 1
398
+
399
+ on_failure do
400
+ end
401
+
402
+ def grammar_url
403
+ 'http://localhost/grammar.grxml'
404
+ end
405
+ end
406
+ end
407
+
408
+ it 'should call #ask with the correct option' do
409
+ controller.should_receive(:ask).once.with('Hello', grammar_url: test_grammar_url, mode: :voice).and_return noinput_result
410
+ controller.run
411
+ end
412
+ end
413
+
414
+ context 'when no grammar is provided' do
350
415
  let(:controller_class) do
351
416
  Class.new(Adhearsion::IVRController) do
352
- prompts << "Hello"
417
+ prompts << 'Hello'
353
418
 
354
419
  on_complete do |result|
355
420
  end
@@ -359,15 +424,15 @@ describe Adhearsion::IVRController do
359
424
  end
360
425
  end
361
426
 
362
- it "should raise NotImplementedError" do
427
+ it 'should raise NotImplementedError' do
363
428
  expect { controller.run }.to raise_error(NotImplementedError)
364
429
  end
365
430
  end
366
431
 
367
- context "when no complete callback is provided" do
432
+ context 'when no complete callback is provided' do
368
433
  let(:controller_class) do
369
434
  Class.new(Adhearsion::IVRController) do
370
- prompts << "Hello"
435
+ prompts << 'Hello'
371
436
 
372
437
  def grammar
373
438
  :some_grammar
@@ -375,16 +440,89 @@ describe Adhearsion::IVRController do
375
440
  end
376
441
  end
377
442
 
378
- it "should simply return the result" do
443
+ it 'should simply return the result' do
379
444
  controller.should_receive(:ask).once.with('Hello', grammar: expected_grammar, mode: :voice).and_return match_result
380
445
  controller.run.should be(match_result)
381
446
  end
447
+
448
+ it 'should simply return the last result' do
449
+ controller.should_receive(:ask).once.with('Hello', grammar: expected_grammar, mode: :voice).and_return noinput_result
450
+ controller.should_receive(:ask).once.with('Hello', grammar: expected_grammar, mode: :voice).and_return noinput_result
451
+ controller.should_receive(:ask).once.with('Hello', grammar: expected_grammar, mode: :voice).and_return noinput_result
452
+ controller.run.should be(noinput_result)
453
+ end
454
+ end
455
+
456
+ context 'when the call is dead' do
457
+ before { call.terminate }
458
+
459
+ it 'executing the controller should raise Adhearsion::Call::Hangup' do
460
+ expect { subject.run }.to raise_error Adhearsion::Call::Hangup
461
+ end
382
462
  end
383
463
 
384
- context "when no complete callback is provided" do
464
+ context 'when overriding prompts' do
465
+ let(:override_prompts) { [SecureRandom.uuid, SecureRandom.uuid, SecureRandom.uuid] }
466
+
467
+ before do
468
+ override_prompts = self.override_prompts
469
+ controller_class.send :define_method, :prompts do
470
+ override_prompts
471
+ end
472
+ end
473
+
474
+ context 'with a successful match' do
475
+ let(:result) { match_result }
476
+
477
+ it 'plays the correct prompt' do
478
+ controller.should_receive(:ask).once.with(override_prompts[0], grammar: expected_grammar, mode: :voice).and_return result
479
+ controller.should_receive(:say).once.with "Let's go to Paris"
480
+ controller.run
481
+ end
482
+ end
483
+ end
484
+
485
+ context 'when overriding max_attempts' do
486
+ let(:max_attempts_number) { 2 }
487
+
488
+ before do
489
+ max_attempts_number = self.max_attempts_number
490
+ controller_class.send :define_method, :max_attempts do
491
+ max_attempts_number
492
+ end
493
+ end
494
+
495
+ context 'with a different number of attempts than the default and failed input' do
496
+ it 'plays the apology announcement after receiving the correct number of failed inputs' do
497
+ controller.should_receive(:ask).once.with(expected_prompts[0], grammar: expected_grammar, mode: :voice).and_return noinput_result
498
+ controller.should_receive(:ask).once.with(expected_prompts[1], grammar: expected_grammar, mode: :voice).and_return noinput_result
499
+ controller.should_receive(:say).once.with apology_announcement
500
+ controller.run
501
+ end
502
+ end
503
+ end
504
+
505
+ context 'when specifying a timeout for the menu' do
506
+ let(:expected_timeout) { 27 }
385
507
  let(:controller_class) do
508
+ expected_prompts = self.expected_prompts
509
+ apology_announcement = self.apology_announcement
510
+ expected_timeout = self.expected_timeout
511
+
386
512
  Class.new(Adhearsion::IVRController) do
387
- prompts << "Hello"
513
+ expected_prompts.each do |prompt|
514
+ prompts << prompt
515
+ end
516
+
517
+ timeout expected_timeout
518
+
519
+ on_complete do |result|
520
+ say "Let's go to #{result.utterance}"
521
+ end
522
+
523
+ on_failure do
524
+ say apology_announcement
525
+ end
388
526
 
389
527
  def grammar
390
528
  :some_grammar
@@ -392,19 +530,62 @@ describe Adhearsion::IVRController do
392
530
  end
393
531
  end
394
532
 
395
- it "should simply return the last result" do
396
- controller.should_receive(:ask).once.with('Hello', grammar: expected_grammar, mode: :voice).and_return noinput_result
397
- controller.should_receive(:ask).once.with('Hello', grammar: expected_grammar, mode: :voice).and_return noinput_result
398
- controller.should_receive(:ask).once.with('Hello', grammar: expected_grammar, mode: :voice).and_return noinput_result
399
- controller.run.should be(noinput_result)
533
+ it 'passes the correct timeout value to the #ask method' do
534
+ controller.should_receive(:ask).once.with(expected_prompts[0], grammar: expected_grammar, mode: :voice, timeout: expected_timeout).and_return match_result
535
+ controller.should_receive(:say).once.with "Let's go to Paris"
536
+ controller.run
400
537
  end
401
538
  end
402
539
 
403
- context "when the call is dead" do
404
- before { call.terminate }
540
+ context 'when specifying a renderer for the menu' do
541
+ let(:expected_renderer) { :some_renderer }
542
+ let(:controller_class) do
543
+ expected_prompts = self.expected_prompts
544
+ apology_announcement = self.apology_announcement
545
+ expected_renderer = self.expected_renderer
405
546
 
406
- it "executing the controller should raise Adhearsion::Call::Hangup" do
407
- expect { subject.run }.to raise_error Adhearsion::Call::Hangup
547
+ Class.new(Adhearsion::IVRController) do
548
+ expected_prompts.each do |prompt|
549
+ prompts << prompt
550
+ end
551
+
552
+ renderer expected_renderer
553
+
554
+ on_complete do |result|
555
+ say "Let's go to #{result.utterance}"
556
+ end
557
+
558
+ on_failure do
559
+ say apology_announcement
560
+ end
561
+
562
+ def grammar
563
+ :some_grammar
564
+ end
565
+ end
566
+ end
567
+
568
+ it 'passes the correct renderer value to the #ask method' do
569
+ controller.should_receive(:ask).once.with(expected_prompts[0], grammar: expected_grammar, mode: :voice, output_options: { renderer: expected_renderer }).and_return match_result
570
+ controller.should_receive(:say).once.with "Let's go to Paris"
571
+ controller.run
572
+ end
573
+ end
574
+
575
+ context 'when overriding the class method for prompt_timeout' do
576
+ let(:overridden_timeout) { 29 }
577
+
578
+ before do
579
+ overridden_timeout = self.overridden_timeout
580
+ controller_class.send :define_method, :timeout do
581
+ overridden_timeout
582
+ end
583
+ end
584
+
585
+ it 'passes the correct timeout value to the #ask method' do
586
+ controller.should_receive(:ask).once.with(expected_prompts[0], grammar: expected_grammar, mode: :voice, timeout: overridden_timeout).and_return match_result
587
+ controller.should_receive(:say).once.with "Let's go to Paris"
588
+ controller.run
408
589
  end
409
590
  end
410
591
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adhearsion-ivr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Klang
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-03-12 00:00:00.000000000 Z
12
+ date: 2015-03-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: adhearsion
@@ -131,6 +131,7 @@ extensions: []
131
131
  extra_rdoc_files: []
132
132
  files:
133
133
  - ".gitignore"
134
+ - ".hound.yml"
134
135
  - ".rspec"
135
136
  - ".travis.yml"
136
137
  - CHANGELOG.md
@@ -166,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
167
  version: '0'
167
168
  requirements: []
168
169
  rubyforge_project:
169
- rubygems_version: 2.2.0
170
+ rubygems_version: 2.4.5
170
171
  signing_key:
171
172
  specification_version: 4
172
173
  summary: IVR building blocks for Adhearsion applications