adhearsion 2.0.1 → 2.1.0

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