adhearsion 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/.travis.yml +4 -3
  2. data/CHANGELOG.md +30 -0
  3. data/README.markdown +1 -0
  4. data/adhearsion.gemspec +3 -4
  5. data/bin/ahn +0 -20
  6. data/features/cli_create.feature +1 -1
  7. data/features/cli_restart.feature +25 -1
  8. data/features/cli_start.feature +0 -2
  9. data/features/plugin_generator.feature +66 -15
  10. data/features/support/env.rb +0 -13
  11. data/lib/adhearsion.rb +26 -6
  12. data/lib/adhearsion/call.rb +42 -7
  13. data/lib/adhearsion/call_controller.rb +5 -2
  14. data/lib/adhearsion/call_controller/dial.rb +92 -50
  15. data/lib/adhearsion/call_controller/input.rb +19 -6
  16. data/lib/adhearsion/call_controller/menu_dsl/menu.rb +4 -0
  17. data/lib/adhearsion/call_controller/output.rb +143 -161
  18. data/lib/adhearsion/call_controller/output/abstract_player.rb +30 -0
  19. data/lib/adhearsion/call_controller/output/async_player.rb +26 -0
  20. data/lib/adhearsion/call_controller/output/formatter.rb +81 -0
  21. data/lib/adhearsion/call_controller/output/player.rb +25 -0
  22. data/lib/adhearsion/call_controller/record.rb +19 -2
  23. data/lib/adhearsion/events.rb +3 -0
  24. data/lib/adhearsion/foundation.rb +12 -6
  25. data/lib/adhearsion/foundation/exception_handler.rb +8 -6
  26. data/lib/adhearsion/generators/app/templates/README.md +13 -0
  27. data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +7 -1
  28. data/lib/adhearsion/generators/plugin/plugin_generator.rb +1 -0
  29. data/lib/adhearsion/generators/plugin/templates/plugin-template.gemspec.tt +3 -7
  30. data/lib/adhearsion/generators/plugin/templates/spec/spec_helper.rb.tt +0 -1
  31. data/lib/adhearsion/outbound_call.rb +15 -5
  32. data/lib/adhearsion/punchblock_plugin.rb +13 -2
  33. data/lib/adhearsion/punchblock_plugin/initializer.rb +13 -12
  34. data/lib/adhearsion/router.rb +43 -2
  35. data/lib/adhearsion/router/evented_route.rb +15 -0
  36. data/lib/adhearsion/router/openended_route.rb +16 -0
  37. data/lib/adhearsion/router/route.rb +31 -13
  38. data/lib/adhearsion/router/unaccepting_route.rb +11 -0
  39. data/lib/adhearsion/version.rb +1 -1
  40. data/pre-commit +14 -1
  41. data/spec/adhearsion/call_controller/dial_spec.rb +105 -10
  42. data/spec/adhearsion/call_controller/input_spec.rb +19 -21
  43. data/spec/adhearsion/call_controller/output/async_player_spec.rb +67 -0
  44. data/spec/adhearsion/call_controller/output/formatter_spec.rb +90 -0
  45. data/spec/adhearsion/call_controller/output/player_spec.rb +65 -0
  46. data/spec/adhearsion/call_controller/output_spec.rb +436 -190
  47. data/spec/adhearsion/call_controller/record_spec.rb +49 -6
  48. data/spec/adhearsion/call_controller_spec.rb +10 -2
  49. data/spec/adhearsion/call_spec.rb +138 -0
  50. data/spec/adhearsion/calls_spec.rb +1 -1
  51. data/spec/adhearsion/outbound_call_spec.rb +48 -8
  52. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +34 -23
  53. data/spec/adhearsion/router/evented_route_spec.rb +34 -0
  54. data/spec/adhearsion/router/openended_route_spec.rb +61 -0
  55. data/spec/adhearsion/router/route_spec.rb +26 -4
  56. data/spec/adhearsion/router/unaccepting_route_spec.rb +72 -0
  57. data/spec/adhearsion/router_spec.rb +107 -2
  58. data/spec/adhearsion_spec.rb +19 -0
  59. data/spec/capture_warnings.rb +28 -21
  60. data/spec/spec_helper.rb +2 -3
  61. data/spec/support/call_controller_test_helpers.rb +31 -30
  62. metadata +32 -29
@@ -0,0 +1,90 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module Adhearsion
6
+ class CallController
7
+ module Output
8
+ describe Formatter do
9
+ subject { Formatter }
10
+
11
+ describe ".ssml_for" do
12
+ let(:prompt) { "Please stand by" }
13
+
14
+ let(:ssml) do
15
+ RubySpeech::SSML.draw { string 'Please stand by' }
16
+ end
17
+
18
+ it 'returns SSML for a text argument' do
19
+ subject.ssml_for(prompt).should be == ssml
20
+ end
21
+
22
+ it 'returns the same SSML passed in if it is SSML' do
23
+ subject.ssml_for(ssml).should be == ssml
24
+ end
25
+ end
26
+
27
+ describe ".ssml_for_collection" do
28
+ let(:collection) { ["/foo/bar.wav", 1, Time.now] }
29
+ let :ssml do
30
+ file = collection[0]
31
+ n = collection[1].to_s
32
+ t = collection[2].to_s
33
+ RubySpeech::SSML.draw do
34
+ audio :src => file
35
+ say_as(:interpret_as => 'cardinal') { n }
36
+ say_as(:interpret_as => 'time') { t }
37
+ end
38
+ end
39
+
40
+ it "should create a composite SSML document" do
41
+ subject.ssml_for_collection(collection).should be == ssml
42
+ end
43
+ end
44
+
45
+ describe ".detect_type" do
46
+ it "detects an HTTP path" do
47
+ http_path = "http://adhearsion.com/sounds/hello.mp3"
48
+ subject.detect_type(http_path).should be :audio
49
+ end
50
+
51
+ it "detects a file path" do
52
+ file_path = "file:///usr/shared/sounds/hello.mp3"
53
+ subject.detect_type(file_path).should be :audio
54
+
55
+ absolute_path = "/usr/shared/sounds/hello.mp3"
56
+ subject.detect_type(absolute_path).should be :audio
57
+
58
+ relative_path = "foo/bar"
59
+ subject.detect_type(relative_path).should_not be :audio
60
+ end
61
+
62
+ it "detects a Date object" do
63
+ today = Date.today
64
+ subject.detect_type(today).should be :time
65
+ end
66
+
67
+ it "detects a Time object" do
68
+ now = Time.now
69
+ subject.detect_type(now).should be :time
70
+ end
71
+
72
+ it "detects a DateTime object" do
73
+ today = DateTime.now
74
+ subject.detect_type(today).should be :time
75
+ end
76
+
77
+ it "detects a Numeric object" do
78
+ number = 123
79
+ subject.detect_type(number).should be :numeric
80
+ end
81
+
82
+ it "returns text as a fallback" do
83
+ output = "Hello"
84
+ subject.detect_type(output).should be :text
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,65 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module Adhearsion
6
+ class CallController
7
+ module Output
8
+ describe Player do
9
+ include CallControllerTestHelpers
10
+
11
+ let(:controller) { flexmock new_controller }
12
+
13
+ subject { Player.new controller }
14
+
15
+ describe "#output" do
16
+ let(:content) { RubySpeech::SSML.draw { string "BOO" } }
17
+
18
+ it "should execute an output component with the provided SSML content" do
19
+ expect_component_execution Punchblock::Component::Output.new(:ssml => content)
20
+ subject.output content
21
+ end
22
+
23
+ it "should allow extra options to be passed to the output component" do
24
+ component = Punchblock::Component::Output.new :ssml => content, :start_paused => true
25
+ expect_component_execution component
26
+ subject.output content, :start_paused => true
27
+ end
28
+
29
+ it "yields the component to the block before executing it" do
30
+ component = Punchblock::Component::Output.new :ssml => content, :start_paused => true
31
+ expect_component_execution component
32
+ subject.output content do |comp|
33
+ comp.start_paused = true
34
+ end
35
+ end
36
+
37
+ it "raises a PlaybackError if the component fails to start" do
38
+ expect_component_execution Punchblock::Component::Output.new(:ssml => content), Punchblock::ProtocolError
39
+ lambda { subject.output content }.should raise_error(PlaybackError)
40
+ end
41
+
42
+ it "raises a Playback Error if the component ends due to an error" do
43
+ expect_component_execution Punchblock::Component::Output.new(:ssml => content), Adhearsion::Error
44
+ lambda { subject.output content }.should raise_error(PlaybackError)
45
+ end
46
+
47
+ it "raises a Playback Error if the component ends due to an error" do
48
+ e = Call::Hangup.new
49
+ expect_component_execution Punchblock::Component::Output.new(:ssml => content), e
50
+ lambda { subject.output content }.should raise_error(e)
51
+ end
52
+ end
53
+
54
+ describe "#play_ssml" do
55
+ let(:ssml) { RubySpeech::SSML.draw { string "BOO" } }
56
+
57
+ it 'executes an Output with the correct ssml' do
58
+ expect_component_execution Punchblock::Component::Output.new(:ssml => ssml.to_s)
59
+ subject.play_ssml ssml
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -7,57 +7,102 @@ module Adhearsion
7
7
  describe Output do
8
8
  include CallControllerTestHelpers
9
9
 
10
- describe "#play_ssml" do
11
- let(:ssml) { RubySpeech::SSML.draw { string "BOO" } }
10
+ def expect_ssml_output(ssml)
11
+ expect_component_execution Punchblock::Component::Output.new(:ssml => ssml)
12
+ end
12
13
 
13
- it 'executes an Output with the correct ssml' do
14
- expect_component_execution Punchblock::Component::Output.new(:ssml => ssml.to_s)
15
- subject.play_ssml ssml
14
+ def expect_async_ssml_output(ssml)
15
+ expect_message_waiting_for_response Punchblock::Component::Output.new(:ssml => ssml)
16
+ end
17
+
18
+ describe "#player" do
19
+ it "should return a Player component targetted at the current controller" do
20
+ player = controller.player
21
+ player.should be_a Output::Player
22
+ player.controller.should be controller
16
23
  end
17
24
 
18
- describe "if an error is returned" do
19
- before do
20
- pending
21
- subject.should_receive(:execute_component_and_await_completion).once.and_raise(StandardError)
22
- end
25
+ it "should return the same player every time" do
26
+ controller.player.should be controller.player
27
+ end
28
+ end
23
29
 
24
- it 'should return false' do
25
- pending
26
- subject.play_ssml(ssml).should be false
27
- end
30
+ describe "#async_player" do
31
+ it "should return an AsyncPlayer component targetted at the current controller" do
32
+ player = controller.async_player
33
+ player.should be_a Output::AsyncPlayer
34
+ player.controller.should be controller
35
+ end
36
+
37
+ it "should return the same player every time" do
38
+ controller.async_player.should be controller.async_player
28
39
  end
29
40
  end
30
41
 
31
42
  describe "#play_audio" do
32
- let(:audio_file) { "/sounds/boo.wav" }
33
- let(:fallback) { "text for tts" }
43
+ let(:audio_file) { "/sounds/boo.wav" }
34
44
 
35
- let(:ssml) do
45
+ let :ssml do
36
46
  file = audio_file
37
47
  RubySpeech::SSML.draw { audio :src => file }
38
48
  end
39
49
 
40
- let(:ssml_with_fallback) do
50
+ it 'plays the correct ssml' do
51
+ expect_ssml_output ssml
52
+ subject.play_audio(audio_file).should be true
53
+ end
54
+
55
+ context "with a fallback" do
56
+ let(:fallback) { "text for tts" }
57
+
58
+ let :ssml do
59
+ file = audio_file
60
+ fallback_text = fallback
61
+ RubySpeech::SSML.draw do
62
+ audio(:src => file) { fallback_text }
63
+ end
64
+ end
65
+
66
+ it 'places the fallback in the SSML doc' do
67
+ expect_ssml_output ssml
68
+ subject.play_audio(audio_file, :fallback => fallback).should be true
69
+ end
70
+ end
71
+ end
72
+
73
+ describe "#play_audio!" do
74
+ let(:audio_file) { "/sounds/boo.wav" }
75
+
76
+ let :ssml do
41
77
  file = audio_file
42
- fallback_text = fallback
43
- RubySpeech::SSML.draw {
44
- audio(:src => file) { fallback_text }
45
- }
78
+ RubySpeech::SSML.draw { audio :src => file }
46
79
  end
47
80
 
48
81
  it 'plays the correct ssml' do
49
- subject.should_receive(:play_ssml).once.with(ssml).and_return true
50
- subject.play_audio(audio_file).should be true
82
+ expect_async_ssml_output ssml
83
+ subject.play_audio!(audio_file).should be_a Punchblock::Component::Output
51
84
  end
52
85
 
53
- it 'allows for fallback tts' do
54
- subject.should_receive(:play_ssml).once.with(ssml_with_fallback).and_return true
55
- subject.play_audio(audio_file, :fallback => fallback).should be true
86
+ context "with a fallback" do
87
+ let(:fallback) { "text for tts" }
88
+
89
+ let :ssml do
90
+ file = audio_file
91
+ fallback_text = fallback
92
+ RubySpeech::SSML.draw do
93
+ audio(:src => file) { fallback_text }
94
+ end
95
+ end
96
+
97
+ it 'places the fallback in the SSML doc' do
98
+ expect_async_ssml_output ssml
99
+ subject.play_audio!(audio_file, :fallback => fallback).should be_a Punchblock::Component::Output
100
+ end
56
101
  end
57
102
  end
58
103
 
59
104
  describe "#play_numeric" do
60
- let :expected_doc do
105
+ let :ssml do
61
106
  RubySpeech::SSML.draw do
62
107
  say_as(:interpret_as => 'cardinal') { "123" }
63
108
  end
@@ -67,7 +112,7 @@ module Adhearsion
67
112
  let(:input) { 123 }
68
113
 
69
114
  it 'plays the correct ssml' do
70
- subject.should_receive(:play_ssml).once.with(expected_doc).and_return true
115
+ expect_ssml_output ssml
71
116
  subject.play_numeric(input).should be true
72
117
  end
73
118
  end
@@ -76,7 +121,7 @@ module Adhearsion
76
121
  let(:input) { "123" }
77
122
 
78
123
  it 'plays the correct ssml' do
79
- subject.should_receive(:play_ssml).once.with(expected_doc).and_return true
124
+ expect_ssml_output ssml
80
125
  subject.play_numeric(input).should be true
81
126
  end
82
127
  end
@@ -84,14 +129,48 @@ module Adhearsion
84
129
  describe "with something that's not a number" do
85
130
  let(:input) { 'foo' }
86
131
 
87
- it 'returns nil' do
88
- subject.play_numeric(input).should be nil
132
+ it 'raises ArgumentError' do
133
+ lambda { subject.play_numeric input }.should raise_error(ArgumentError)
134
+ end
135
+ end
136
+ end
137
+
138
+ describe "#play_numeric!" do
139
+ let :ssml do
140
+ RubySpeech::SSML.draw do
141
+ say_as(:interpret_as => 'cardinal') { "123" }
142
+ end
143
+ end
144
+
145
+ describe "with a number" do
146
+ let(:input) { 123 }
147
+
148
+ it 'plays the correct ssml' do
149
+ expect_async_ssml_output ssml
150
+ subject.play_numeric!(input).should be_a Punchblock::Component::Output
151
+ end
152
+ end
153
+
154
+ describe "with a string representation of a number" do
155
+ let(:input) { "123" }
156
+
157
+ it 'plays the correct ssml' do
158
+ expect_async_ssml_output ssml
159
+ subject.play_numeric!(input).should be_a Punchblock::Component::Output
160
+ end
161
+ end
162
+
163
+ describe "with something that's not a number" do
164
+ let(:input) { 'foo' }
165
+
166
+ it 'raises ArgumentError' do
167
+ lambda { subject.play_numeric! input }.should raise_error(ArgumentError)
89
168
  end
90
169
  end
91
170
  end
92
171
 
93
172
  describe "#play_time" do
94
- let :expected_doc do
173
+ let :ssml do
95
174
  content = input.to_s
96
175
  opts = expected_say_as_options
97
176
  RubySpeech::SSML.draw do
@@ -104,7 +183,7 @@ module Adhearsion
104
183
  let(:expected_say_as_options) { {:interpret_as => 'time'} }
105
184
 
106
185
  it 'plays the correct SSML' do
107
- subject.should_receive(:play_ssml).once.with(expected_doc).and_return true
186
+ expect_ssml_output ssml
108
187
  subject.play_time(input).should be true
109
188
  end
110
189
  end
@@ -114,7 +193,7 @@ module Adhearsion
114
193
  let(:expected_say_as_options) { {:interpret_as => 'date'} }
115
194
 
116
195
  it 'plays the correct SSML' do
117
- subject.should_receive(:play_ssml).once.with(expected_doc).and_return true
196
+ expect_ssml_output ssml
118
197
  subject.play_time(input).should be true
119
198
  end
120
199
  end
@@ -125,7 +204,7 @@ module Adhearsion
125
204
  let(:expected_say_as_options) { {:interpret_as => 'date', :format => format} }
126
205
 
127
206
  it 'plays the correct SSML' do
128
- subject.should_receive(:play_ssml).once.with(expected_doc).and_return true
207
+ expect_ssml_output ssml
129
208
  subject.play_time(input, :format => format).should be true
130
209
  end
131
210
  end
@@ -137,7 +216,7 @@ module Adhearsion
137
216
  let(:expected_say_as_options) { {:interpret_as => 'date'} }
138
217
 
139
218
  it 'plays the correct SSML' do
140
- subject.should_receive(:play_ssml).once.with(expected_doc).and_return true
219
+ expect_ssml_output ssml
141
220
  subject.play_time(base_input, :strftime => strftime).should be true
142
221
  end
143
222
  end
@@ -150,7 +229,7 @@ module Adhearsion
150
229
  let(:expected_say_as_options) { {:interpret_as => 'date', :format => format} }
151
230
 
152
231
  it 'plays the correct SSML' do
153
- subject.should_receive(:play_ssml).once.with(expected_doc).and_return true
232
+ expect_ssml_output ssml
154
233
  subject.play_time(base_input, :format => format, :strftime => strftime).should be true
155
234
  end
156
235
  end
@@ -158,87 +237,198 @@ module Adhearsion
158
237
  describe "with an object other than Time, DateTime, or Date" do
159
238
  let(:input) { "foo" }
160
239
 
161
- it 'returns false' do
162
- subject.play_time(input).should be false
240
+ it 'raises ArgumentError' do
241
+ lambda { subject.play_time input }.should raise_error(ArgumentError)
242
+ end
243
+ end
244
+ end
245
+
246
+ describe "#play_time!" do
247
+ let :ssml do
248
+ content = input.to_s
249
+ opts = expected_say_as_options
250
+ RubySpeech::SSML.draw do
251
+ say_as(opts) { content }
252
+ end
253
+ end
254
+
255
+ describe "with a time" do
256
+ let(:input) { Time.parse("12/5/2000") }
257
+ let(:expected_say_as_options) { {:interpret_as => 'time'} }
258
+
259
+ it 'plays the correct SSML' do
260
+ expect_async_ssml_output ssml
261
+ subject.play_time!(input).should be_a Punchblock::Component::Output
262
+ end
263
+ end
264
+
265
+ describe "with a date" do
266
+ let(:input) { Date.parse('2011-01-23') }
267
+ let(:expected_say_as_options) { {:interpret_as => 'date'} }
268
+
269
+ it 'plays the correct SSML' do
270
+ expect_async_ssml_output ssml
271
+ subject.play_time!(input).should be_a Punchblock::Component::Output
272
+ end
273
+ end
274
+
275
+ describe "with a date and a say_as format" do
276
+ let(:input) { Date.parse('2011-01-23') }
277
+ let(:format) { "d-m-y" }
278
+ let(:expected_say_as_options) { {:interpret_as => 'date', :format => format} }
279
+
280
+ it 'plays the correct SSML' do
281
+ expect_async_ssml_output ssml
282
+ subject.play_time!(input, :format => format).should be_a Punchblock::Component::Output
283
+ end
284
+ end
285
+
286
+ describe "with a date and a strftime option" do
287
+ let(:strftime) { "%d-%m-%Y" }
288
+ let(:base_input) { Date.parse('2011-01-23') }
289
+ let(:input) { base_input.strftime(strftime) }
290
+ let(:expected_say_as_options) { {:interpret_as => 'date'} }
291
+
292
+ it 'plays the correct SSML' do
293
+ expect_async_ssml_output ssml
294
+ subject.play_time!(base_input, :strftime => strftime).should be_a Punchblock::Component::Output
295
+ end
296
+ end
297
+
298
+ describe "with a date, a format option and a strftime option" do
299
+ let(:strftime) { "%d-%m-%Y" }
300
+ let(:format) { "d-m-y" }
301
+ let(:base_input) { Date.parse('2011-01-23') }
302
+ let(:input) { base_input.strftime(strftime) }
303
+ let(:expected_say_as_options) { {:interpret_as => 'date', :format => format} }
304
+
305
+ it 'plays the correct SSML' do
306
+ expect_async_ssml_output ssml
307
+ subject.play_time!(base_input, :format => format, :strftime => strftime).should be_a Punchblock::Component::Output
308
+ end
309
+ end
310
+
311
+ describe "with an object other than Time, DateTime, or Date" do
312
+ let(:input) { "foo" }
313
+
314
+ it 'raises ArgumentError' do
315
+ lambda { subject.play_time! input }.should raise_error(ArgumentError)
163
316
  end
164
317
  end
165
318
  end
166
319
 
167
320
  describe '#play' do
168
321
  describe "with a single string" do
169
- let(:file) { "cents-per-minute" }
322
+ let(:audio_file) { "/foo/bar.wav" }
323
+ let :ssml do
324
+ file = audio_file
325
+ RubySpeech::SSML.draw { audio :src => file }
326
+ end
170
327
 
171
328
  it 'plays the audio file' do
172
- subject.should_receive(:play_ssml_for).once.with(file).and_return true
173
- subject.play(file).should be true
329
+ expect_ssml_output ssml
330
+ subject.play(audio_file).should be true
174
331
  end
175
332
  end
176
333
 
177
- describe "with multiple strings" do
178
- let(:args) { ['rock', 'paperz', 'scissors'] }
179
-
180
- it 'plays multiple files' do
181
- args.each do |file|
182
- subject.should_receive(:play_ssml_for).once.with(file).and_return true
334
+ describe "with multiple arguments" do
335
+ let(:args) { ["/foo/bar.wav", 1, Time.now] }
336
+ let :ssml do
337
+ file = args[0]
338
+ n = args[1].to_s
339
+ t = args[2].to_s
340
+ RubySpeech::SSML.draw do
341
+ audio :src => file
342
+ say_as(:interpret_as => 'cardinal') { n }
343
+ say_as(:interpret_as => 'time') { t }
183
344
  end
345
+ end
184
346
 
347
+ it 'plays all arguments in one document' do
348
+ expect_ssml_output ssml
185
349
  subject.play(*args).should be true
186
350
  end
351
+ end
187
352
 
188
- describe "if an audio file cannot be found" do
189
- before do
190
- pending
191
- subject.should_receive(:play_audio).with(args[0]).and_return(true).ordered
192
- subject.should_receive(:play_audio).with(args[1]).and_return(false).ordered
193
- subject.should_receive(:play_audio).with(args[2]).and_return(true).ordered
194
- end
353
+ describe "with a number" do
354
+ let(:argument) { 123 }
195
355
 
196
- it 'should return false' do
197
- subject.play(*args).should be false
356
+ let(:ssml) do
357
+ number = argument.to_s
358
+ RubySpeech::SSML.draw do
359
+ say_as(:interpret_as => 'cardinal') { number }
198
360
  end
199
361
  end
200
- end
201
362
 
202
- describe "with a number" do
203
363
  it 'plays the number' do
204
- subject.should_receive(:play_ssml_for).with(123).and_return(true)
205
- subject.play(123).should be true
364
+ expect_ssml_output ssml
365
+ subject.play(argument).should be true
206
366
  end
207
367
  end
208
368
 
209
369
  describe "with a string representation of a number" do
370
+ let(:argument) { '123' }
371
+
372
+ let(:ssml) do
373
+ number = argument
374
+ RubySpeech::SSML.draw do
375
+ say_as(:interpret_as => 'cardinal') { number }
376
+ end
377
+ end
378
+
210
379
  it 'plays the number' do
211
- subject.should_receive(:play_ssml_for).with('123').and_return(true)
212
- subject.play('123').should be true
380
+ expect_ssml_output ssml
381
+ subject.play(argument).should be true
213
382
  end
214
383
  end
215
384
 
216
385
  describe "with a time" do
217
- let(:time) { Time.parse("12/5/2000") }
386
+ let(:time) { Time.parse "12/5/2000" }
387
+
388
+ let(:ssml) do
389
+ t = time.to_s
390
+ RubySpeech::SSML.draw do
391
+ say_as(:interpret_as => 'time') { t }
392
+ end
393
+ end
218
394
 
219
395
  it 'plays the time' do
220
- subject.should_receive(:play_ssml_for).with(time).and_return(true)
396
+ expect_ssml_output ssml
221
397
  subject.play(time).should be true
222
398
  end
223
399
  end
224
400
 
225
401
  describe "with a date" do
226
- let(:date) { Date.parse('2011-01-23') }
402
+ let(:date) { Date.parse '2011-01-23' }
403
+ let(:ssml) do
404
+ d = date.to_s
405
+ RubySpeech::SSML.draw do
406
+ say_as(:interpret_as => 'date') { d }
407
+ end
408
+ end
227
409
 
228
410
  it 'plays the time' do
229
- subject.should_receive(:play_ssml_for).with(date).and_return(true)
411
+ expect_ssml_output ssml
230
412
  subject.play(date).should be true
231
413
  end
232
414
  end
233
415
 
234
416
  describe "with an array containing a Date/DateTime/Time object and a hash" do
235
- let(:date) { Date.parse('2011-01-23') }
417
+ let(:date) { Date.parse '2011-01-23' }
236
418
  let(:format) { "d-m-y" }
237
419
  let(:strftime) { "%d-%m%Y" }
238
420
 
421
+ let :ssml do
422
+ d = date.strftime strftime
423
+ f = format
424
+ RubySpeech::SSML.draw do
425
+ say_as(:interpret_as => 'date', :format => f) { d }
426
+ end
427
+ end
428
+
239
429
  it 'plays the time with the specified format and strftime' do
240
- subject.should_receive(:play_ssml_for).with(date, {:format => format, :strftime => strftime}).and_return(true)
241
- subject.play({:value => date, :format => format, :strftime => strftime}).should be true
430
+ expect_ssml_output ssml
431
+ subject.play(:value => date, :format => format, :strftime => strftime).should be true
242
432
  end
243
433
  end
244
434
 
@@ -246,125 +436,157 @@ module Adhearsion
246
436
  let(:ssml) { RubySpeech::SSML.draw { string "Hello world" } }
247
437
 
248
438
  it "plays the SSML without generating" do
249
- subject.should_receive(:play_ssml).with(ssml).and_return(true)
439
+ expect_ssml_output ssml
250
440
  subject.play(ssml).should be true
251
441
  end
252
442
  end
253
443
  end
254
444
 
255
- describe "#play!" do
256
- let(:prompt) { "Press any button." }
257
- let(:second_prompt) { "Or press nothing." }
258
- let(:non_existing) { "http://adhearsion.com/nonexistingfile.mp3" }
445
+ describe '#play!' do
446
+ describe "with a single string" do
447
+ let(:audio_file) { "/foo/bar.wav" }
448
+ let :ssml do
449
+ file = audio_file
450
+ RubySpeech::SSML.draw { audio :src => file }
451
+ end
259
452
 
260
- it "calls play a single time" do
261
- subject.should_receive(:play).once.with(prompt).and_return(true)
262
- subject.play!(prompt)
453
+ it 'plays the audio file' do
454
+ expect_async_ssml_output ssml
455
+ subject.play!(audio_file).should be_a Punchblock::Component::Output
456
+ end
263
457
  end
264
458
 
265
- it "calls play two times" do
266
- subject.should_receive(:play).once.with(prompt, second_prompt).and_return(true)
267
- subject.play!(prompt, second_prompt)
268
- end
459
+ describe "with multiple arguments" do
460
+ let(:args) { ["/foo/bar.wav", 1, Time.now] }
461
+ let :ssml do
462
+ file = args[0]
463
+ n = args[1].to_s
464
+ t = args[2].to_s
465
+ RubySpeech::SSML.draw do
466
+ audio :src => file
467
+ say_as(:interpret_as => 'cardinal') { n }
468
+ say_as(:interpret_as => 'time') { t }
469
+ end
470
+ end
269
471
 
270
- it "raises an exception if play fails" do
271
- subject.should_receive(:play).once.and_return false
272
- expect { subject.play!(non_existing) }.to raise_error(Output::PlaybackError)
472
+ it 'plays all arguments in one document' do
473
+ expect_async_ssml_output ssml
474
+ subject.play!(*args).should be_a Punchblock::Component::Output
475
+ end
273
476
  end
274
- end
275
477
 
276
- describe "#speak" do
277
- it "should be an alias for #say" do
278
- subject.method(:speak).should be == subject.method(:say)
279
- end
280
- end
478
+ describe "with a number" do
479
+ let(:argument) { 123 }
281
480
 
282
- describe "#say" do
283
- describe "with a RubySpeech document" do
284
- it 'plays the correct SSML' do
285
- ssml = RubySpeech::SSML.draw { string "Hello world" }
286
- expect_component_execution Punchblock::Component::Output.new(:ssml => ssml)
287
- subject.say(ssml).should be_a Punchblock::Component::Output
481
+ let(:ssml) do
482
+ number = argument.to_s
483
+ RubySpeech::SSML.draw do
484
+ say_as(:interpret_as => 'cardinal') { number }
485
+ end
288
486
  end
289
- end
290
487
 
291
- describe "with a string" do
292
- it 'outputs the correct text' do
293
- str = "Hello world"
294
- ssml = RubySpeech::SSML.draw { string str }
295
- expect_component_execution Punchblock::Component::Output.new(:ssml => ssml)
296
- subject.say(str).should be_a Punchblock::Component::Output
488
+ it 'plays the number' do
489
+ expect_async_ssml_output ssml
490
+ subject.play!(argument).should be_a Punchblock::Component::Output
297
491
  end
298
492
  end
299
493
 
300
- describe "converts the argument to a string" do
301
- it 'calls output with a string' do
302
- argument = 123
303
- ssml = RubySpeech::SSML.draw { string '123' }
304
- expect_component_execution Punchblock::Component::Output.new(:ssml => ssml)
305
- subject.say(argument).should be_a Punchblock::Component::Output
494
+ describe "with a string representation of a number" do
495
+ let(:argument) { '123' }
496
+
497
+ let(:ssml) do
498
+ number = argument
499
+ RubySpeech::SSML.draw do
500
+ say_as(:interpret_as => 'cardinal') { number }
501
+ end
502
+ end
503
+
504
+ it 'plays the number' do
505
+ expect_async_ssml_output ssml
506
+ subject.play!(argument).should be_a Punchblock::Component::Output
306
507
  end
307
508
  end
308
- end
309
509
 
310
- describe "#ssml_for" do
311
- let(:prompt) { "Please stand by" }
510
+ describe "with a time" do
511
+ let(:time) { Time.parse "12/5/2000" }
312
512
 
313
- let(:ssml) do
314
- RubySpeech::SSML.draw do
315
- string 'Please stand by'
513
+ let(:ssml) do
514
+ t = time.to_s
515
+ RubySpeech::SSML.draw do
516
+ say_as(:interpret_as => 'time') { t }
517
+ end
316
518
  end
317
- end
318
519
 
319
- it 'returns SSML for a text argument' do
320
- subject.ssml_for(prompt).should be == ssml
520
+ it 'plays the time' do
521
+ expect_async_ssml_output ssml
522
+ subject.play!(time).should be_a Punchblock::Component::Output
523
+ end
321
524
  end
322
525
 
323
- it 'returns the same SSML passed in if it is SSML' do
324
- subject.ssml_for(ssml) == ssml
325
- end
326
- end
526
+ describe "with a date" do
527
+ let(:date) { Date.parse '2011-01-23' }
528
+ let(:ssml) do
529
+ d = date.to_s
530
+ RubySpeech::SSML.draw do
531
+ say_as(:interpret_as => 'date') { d }
532
+ end
533
+ end
327
534
 
328
- describe "#detect_type" do
329
- it "detects an HTTP path" do
330
- http_path = "http://adhearsion.com/sounds/hello.mp3"
331
- subject.detect_type(http_path).should be :audio
535
+ it 'plays the time' do
536
+ expect_async_ssml_output ssml
537
+ subject.play!(date).should be_a Punchblock::Component::Output
538
+ end
332
539
  end
333
540
 
334
- it "detects a file path" do
335
- file_path = "file:///usr/shared/sounds/hello.mp3"
336
- subject.detect_type(file_path).should be :audio
541
+ describe "with an array containing a Date/DateTime/Time object and a hash" do
542
+ let(:date) { Date.parse '2011-01-23' }
543
+ let(:format) { "d-m-y" }
544
+ let(:strftime) { "%d-%m%Y" }
337
545
 
338
- absolute_path = "/usr/shared/sounds/hello.mp3"
339
- subject.detect_type(absolute_path).should be :audio
546
+ let :ssml do
547
+ d = date.strftime strftime
548
+ f = format
549
+ RubySpeech::SSML.draw do
550
+ say_as(:interpret_as => 'date', :format => f) { d }
551
+ end
552
+ end
340
553
 
341
- relative_path = "foo/bar"
342
- subject.detect_type(relative_path).should_not be :audio
554
+ it 'plays the time with the specified format and strftime' do
555
+ expect_async_ssml_output ssml
556
+ subject.play!(:value => date, :format => format, :strftime => strftime).should be_a Punchblock::Component::Output
557
+ end
343
558
  end
344
559
 
345
- it "detects a Date object" do
346
- today = Date.today
347
- subject.detect_type(today).should be :time
348
- end
560
+ describe "with an SSML document" do
561
+ let(:ssml) { RubySpeech::SSML.draw { string "Hello world" } }
349
562
 
350
- it "detects a Time object" do
351
- now = Time.now
352
- subject.detect_type(now).should be :time
563
+ it "plays the SSML without generating" do
564
+ expect_async_ssml_output ssml
565
+ subject.play!(ssml).should be_a Punchblock::Component::Output
566
+ end
353
567
  end
568
+ end
569
+
570
+ describe "#interruptible_play" do
571
+ let(:output1) { "one two" }
572
+ let(:output2) { "three four" }
573
+ let(:non_existing) { "http://adhearsion.com/nonexistingfile.mp3" }
354
574
 
355
- it "detects a DateTime object" do
356
- today = DateTime.now
357
- subject.detect_type(today).should be :time
575
+ it "plays two outputs in succession" do
576
+ subject.should_receive(:stream_file).twice
577
+ digit = subject.interruptible_play output1, output2
578
+ digit.should be_nil
358
579
  end
359
580
 
360
- it "detects a Numeric object" do
361
- number = 123
362
- subject.detect_type(number).should be :numeric
581
+ it "stops at the first play when input is received" do
582
+ subject.should_receive(:stream_file).once.and_return(2)
583
+ digit = subject.interruptible_play output1, output2
584
+ digit.should be == 2
363
585
  end
364
586
 
365
- it "returns text as a fallback" do
366
- output = "Hello"
367
- subject.detect_type(output).should be :text
587
+ it 'raises an exception when output is unsuccessful' do
588
+ subject.should_receive(:stream_file).once.and_raise Output::PlaybackError, "Output failed"
589
+ expect { subject.interruptible_play non_existing }.to raise_error(Output::PlaybackError)
368
590
  end
369
591
  end
370
592
 
@@ -372,21 +594,21 @@ module Adhearsion
372
594
  let(:allowed_digits) { '35' }
373
595
  let(:prompt) { "Press 3 or 5 to make something happen." }
374
596
 
375
- let(:ssml) {
597
+ let(:ssml) do
376
598
  RubySpeech::SSML.draw do
377
599
  string "Press 3 or 5 to make something happen."
378
600
  end
379
- }
601
+ end
380
602
 
381
- let(:grammar) {
382
- RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'acceptdigits' do
603
+ let(:grammar) do
604
+ RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'acceptdigits' do
383
605
  rule id: 'acceptdigits' do
384
606
  one_of do
385
607
  allowed_digits.each { |d| item { d.to_s } }
386
608
  end
387
609
  end
388
610
  end
389
- }
611
+ end
390
612
 
391
613
  let(:output_component) {
392
614
  Punchblock::Component::Output.new :ssml => ssml.to_s
@@ -399,7 +621,7 @@ module Adhearsion
399
621
 
400
622
  #test does pass and method works, but not sure if the empty method is a good idea
401
623
  it "plays the correct output" do
402
- def subject.write_and_await_response(input_component)
624
+ def controller.write_and_await_response(input_component)
403
625
  # it is actually a no-op here
404
626
  end
405
627
 
@@ -420,7 +642,7 @@ module Adhearsion
420
642
  it "returns a single digit amongst the allowed when pressed" do
421
643
  flexmock(Punchblock::Event::Complete).new_instances.should_receive(:reason => flexmock(:interpretation => 'dtmf-5', :name => :input))
422
644
 
423
- def subject.write_and_await_response(input_component)
645
+ def controller.write_and_await_response(input_component)
424
646
  input_component.trigger_event_handler Punchblock::Event::Complete.new
425
647
  end
426
648
 
@@ -435,54 +657,78 @@ module Adhearsion
435
657
 
436
658
  expect_component_complete_event
437
659
  flexmock(Punchblock::Component::Output).new_instances.should_receive(:stop!)
438
- subject.should_receive(:execute_component_and_await_completion).once.with(output_component)
660
+ expect_component_execution output_component
439
661
  subject.stream_file(prompt, allowed_digits).should be == '5'
440
662
  end
441
- end # describe #stream_file
442
-
443
-
444
- describe "#interruptible_play!" do
445
- let(:output1) { "one two" }
446
- let(:output2) { "three four" }
447
- let(:non_existing) { "http://adhearsion.com/nonexistingfile.mp3" }
663
+ end
448
664
 
449
- it "plays two outputs in succession" do
450
- subject.should_receive(:stream_file).twice
451
- subject.interruptible_play! output1, output2
665
+ describe "#say" do
666
+ describe "with a RubySpeech document" do
667
+ it 'plays the correct SSML' do
668
+ ssml = RubySpeech::SSML.draw { string "Hello world" }
669
+ expect_ssml_output ssml
670
+ subject.say(ssml).should be_a Punchblock::Component::Output
671
+ end
452
672
  end
453
673
 
454
- it "stops at the first play when input is received" do
455
- subject.should_receive(:stream_file).once.and_return(2)
456
- subject.interruptible_play! output1, output2
674
+ describe "with a string" do
675
+ it 'outputs the correct text' do
676
+ str = "Hello world"
677
+ ssml = RubySpeech::SSML.draw { string str }
678
+ expect_ssml_output ssml
679
+ subject.say(str).should be_a Punchblock::Component::Output
680
+ end
457
681
  end
458
682
 
459
- it 'raises an exception when output is unsuccessful' do
460
- subject.should_receive(:stream_file).once.and_raise Output::PlaybackError, "Output failed"
461
- expect { subject.interruptible_play!(non_existing) }.to raise_error(Output::PlaybackError)
683
+ describe "converts the argument to a string" do
684
+ it 'calls output with a string' do
685
+ argument = 123
686
+ ssml = RubySpeech::SSML.draw { string '123' }
687
+ expect_ssml_output ssml
688
+ subject.say(argument).should be_a Punchblock::Component::Output
689
+ end
462
690
  end
463
- end # describe interruptible_play!
691
+ end
464
692
 
465
- describe "#interruptible_play" do
466
- let(:output1) { "one two" }
467
- let(:output2) { "three four" }
468
- let(:non_existing) { "http://adhearsion.com/nonexistingfile.mp3" }
693
+ describe "#speak" do
694
+ it "should be an alias for #say" do
695
+ subject.method(:speak).should be == subject.method(:say)
696
+ end
697
+ end
469
698
 
470
- it "plays two outputs in succession" do
471
- subject.should_receive(:interruptible_play!).twice
472
- subject.interruptible_play output1, output2
699
+ describe "#say!" do
700
+ describe "with a RubySpeech document" do
701
+ it 'plays the correct SSML' do
702
+ ssml = RubySpeech::SSML.draw { string "Hello world" }
703
+ expect_async_ssml_output ssml
704
+ subject.say!(ssml).should be_a Punchblock::Component::Output
705
+ end
473
706
  end
474
707
 
475
- it "stops at the first play when input is received" do
476
- subject.should_receive(:interruptible_play!).once.and_return(2)
477
- subject.interruptible_play output1, output2
708
+ describe "with a string" do
709
+ it 'outputs the correct text' do
710
+ str = "Hello world"
711
+ ssml = RubySpeech::SSML.draw { string str }
712
+ expect_async_ssml_output ssml
713
+ subject.say!(str).should be_a Punchblock::Component::Output
714
+ end
478
715
  end
479
716
 
480
- it "should not raise an exception when output is unsuccessful" do
481
- subject.should_receive(:stream_file).once.and_raise Output::PlaybackError, "Output failed"
482
- lambda { subject.interruptible_play non_existing }.should_not raise_error(Output::PlaybackError)
717
+ describe "converts the argument to a string" do
718
+ it 'calls output with a string' do
719
+ argument = 123
720
+ ssml = RubySpeech::SSML.draw { string '123' }
721
+ expect_async_ssml_output ssml
722
+ subject.say!(argument).should be_a Punchblock::Component::Output
723
+ end
483
724
  end
484
- end # describe interruptible_play
725
+ end
485
726
 
727
+ describe "#speak!" do
728
+ it "should be an alias for #say!" do
729
+ subject.method(:speak!).should be == subject.method(:say!)
730
+ end
731
+ end
486
732
  end
487
733
  end
488
734
  end