adhearsion 2.0.0.beta1 → 2.0.0.rc1

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 (118) hide show
  1. data/.travis.yml +2 -4
  2. data/CHANGELOG.md +34 -4
  3. data/README.markdown +2 -1
  4. data/Rakefile +22 -1
  5. data/adhearsion.gemspec +1 -0
  6. data/bin/ahn +0 -2
  7. data/features/cli_daemon.feature +2 -0
  8. data/features/cli_restart.feature +19 -0
  9. data/features/cli_start.feature +4 -6
  10. data/features/cli_stop.feature +3 -0
  11. data/features/step_definitions/app_generator_steps.rb +2 -0
  12. data/features/step_definitions/cli_steps.rb +2 -0
  13. data/features/support/aruba_helper.rb +2 -0
  14. data/features/support/env.rb +8 -46
  15. data/features/support/utils.rb +2 -0
  16. data/lib/adhearsion.rb +4 -6
  17. data/lib/adhearsion/call.rb +71 -17
  18. data/lib/adhearsion/call_controller.rb +25 -14
  19. data/lib/adhearsion/call_controller/dial.rb +34 -15
  20. data/lib/adhearsion/call_controller/input.rb +186 -144
  21. data/lib/adhearsion/call_controller/output.rb +10 -6
  22. data/lib/adhearsion/call_controller/record.rb +11 -13
  23. data/lib/adhearsion/call_controller/utility.rb +2 -0
  24. data/lib/adhearsion/calls.rb +4 -2
  25. data/lib/adhearsion/cli.rb +4 -0
  26. data/lib/adhearsion/cli_commands.rb +8 -2
  27. data/lib/adhearsion/configuration.rb +7 -3
  28. data/lib/adhearsion/console.rb +17 -17
  29. data/lib/adhearsion/events.rb +10 -4
  30. data/lib/adhearsion/foundation.rb +9 -0
  31. data/lib/adhearsion/foundation/custom_daemonizer.rb +3 -1
  32. data/lib/adhearsion/foundation/exception_handler.rb +2 -0
  33. data/lib/adhearsion/foundation/libc.rb +2 -0
  34. data/lib/adhearsion/foundation/object.rb +3 -0
  35. data/lib/adhearsion/foundation/thread_safety.rb +5 -11
  36. data/lib/adhearsion/generators.rb +2 -0
  37. data/lib/adhearsion/generators/app/app_generator.rb +2 -0
  38. data/lib/adhearsion/generators/app/templates/README.md +9 -0
  39. data/lib/adhearsion/generators/app/templates/config/adhearsion.rb +38 -16
  40. data/lib/adhearsion/generators/app/templates/config/environment.rb +2 -0
  41. data/lib/adhearsion/generators/app/templates/lib/simon_game.rb +5 -3
  42. data/lib/adhearsion/generators/controller/controller_generator.rb +2 -0
  43. data/lib/adhearsion/generators/controller/templates/lib/controller.rb +2 -0
  44. data/lib/adhearsion/generators/controller/templates/spec/controller_spec.rb +2 -0
  45. data/lib/adhearsion/generators/generator.rb +3 -1
  46. data/lib/adhearsion/generators/plugin/plugin_generator.rb +2 -0
  47. data/lib/adhearsion/initializer.rb +31 -17
  48. data/lib/adhearsion/linux_proc_name.rb +2 -0
  49. data/lib/adhearsion/logging.rb +5 -3
  50. data/lib/adhearsion/menu_dsl.rb +2 -0
  51. data/lib/adhearsion/menu_dsl/calculated_match.rb +2 -0
  52. data/lib/adhearsion/menu_dsl/calculated_match_collection.rb +2 -0
  53. data/lib/adhearsion/menu_dsl/fixnum_match_calculator.rb +2 -0
  54. data/lib/adhearsion/menu_dsl/match_calculator.rb +2 -0
  55. data/lib/adhearsion/menu_dsl/menu.rb +58 -4
  56. data/lib/adhearsion/menu_dsl/menu_builder.rb +14 -1
  57. data/lib/adhearsion/menu_dsl/range_match_calculator.rb +4 -1
  58. data/lib/adhearsion/menu_dsl/string_match_calculator.rb +2 -0
  59. data/lib/adhearsion/outbound_call.rb +2 -0
  60. data/lib/adhearsion/plugin.rb +9 -7
  61. data/lib/adhearsion/plugin/collection.rb +3 -1
  62. data/lib/adhearsion/plugin/initializer.rb +3 -1
  63. data/lib/adhearsion/process.rb +8 -2
  64. data/lib/adhearsion/punchblock_plugin.rb +3 -1
  65. data/lib/adhearsion/punchblock_plugin/initializer.rb +34 -11
  66. data/lib/adhearsion/router.rb +4 -2
  67. data/lib/adhearsion/router/route.rb +2 -0
  68. data/lib/adhearsion/script_ahn_loader.rb +2 -0
  69. data/lib/adhearsion/tasks.rb +2 -0
  70. data/lib/adhearsion/tasks/configuration.rb +2 -0
  71. data/lib/adhearsion/tasks/debugging.rb +8 -0
  72. data/lib/adhearsion/tasks/environment.rb +2 -0
  73. data/lib/adhearsion/tasks/plugins.rb +2 -0
  74. data/lib/adhearsion/tasks/testing.rb +2 -0
  75. data/lib/adhearsion/version.rb +3 -1
  76. data/pre-commit +2 -0
  77. data/spec/adhearsion/call_controller/dial_spec.rb +114 -25
  78. data/spec/adhearsion/call_controller/input_spec.rb +192 -169
  79. data/spec/adhearsion/call_controller/output_spec.rb +26 -12
  80. data/spec/adhearsion/call_controller/record_spec.rb +29 -77
  81. data/spec/adhearsion/call_controller/utility_spec.rb +69 -0
  82. data/spec/adhearsion/call_controller_spec.rb +90 -15
  83. data/spec/adhearsion/call_spec.rb +92 -24
  84. data/spec/adhearsion/calls_spec.rb +9 -7
  85. data/spec/adhearsion/configuration_spec.rb +58 -56
  86. data/spec/adhearsion/console_spec.rb +4 -2
  87. data/spec/adhearsion/events_spec.rb +9 -7
  88. data/spec/adhearsion/generators_spec.rb +3 -1
  89. data/spec/adhearsion/initializer_spec.rb +16 -14
  90. data/spec/adhearsion/logging_spec.rb +11 -9
  91. data/spec/adhearsion/menu_dsl/calculated_match_collection_spec.rb +6 -4
  92. data/spec/adhearsion/menu_dsl/calculated_match_spec.rb +6 -4
  93. data/spec/adhearsion/menu_dsl/fixnum_match_calculator_spec.rb +3 -1
  94. data/spec/adhearsion/menu_dsl/match_calculator_spec.rb +2 -0
  95. data/spec/adhearsion/menu_dsl/menu_builder_spec.rb +42 -11
  96. data/spec/adhearsion/menu_dsl/menu_spec.rb +197 -36
  97. data/spec/adhearsion/menu_dsl/range_match_calculator_spec.rb +4 -2
  98. data/spec/adhearsion/menu_dsl/string_match_calculator_spec.rb +5 -3
  99. data/spec/adhearsion/outbound_call_spec.rb +7 -5
  100. data/spec/adhearsion/plugin_spec.rb +19 -15
  101. data/spec/adhearsion/process_spec.rb +12 -7
  102. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +35 -15
  103. data/spec/adhearsion/punchblock_plugin_spec.rb +4 -1
  104. data/spec/adhearsion/router/route_spec.rb +8 -6
  105. data/spec/adhearsion/router_spec.rb +12 -10
  106. data/spec/adhearsion_spec.rb +13 -2
  107. data/spec/capture_warnings.rb +33 -0
  108. data/spec/spec_helper.rb +4 -0
  109. data/spec/support/call_controller_test_helpers.rb +2 -4
  110. data/spec/support/initializer_stubs.rb +8 -5
  111. data/spec/support/logging_helpers.rb +2 -0
  112. data/spec/support/punchblock_mocks.rb +2 -0
  113. metadata +84 -71
  114. data/EVENTS +0 -11
  115. data/lib/adhearsion/call_controller/menu.rb +0 -124
  116. data/lib/adhearsion/foundation/all.rb +0 -8
  117. data/spec/adhearsion/call_controller/menu_spec.rb +0 -120
  118. data/spec/adhearsion/menu_dsl_spec.rb +0 -12
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  module Adhearsion
@@ -5,63 +7,33 @@ module Adhearsion
5
7
  describe Input do
6
8
  include CallControllerTestHelpers
7
9
 
8
- describe "#grammar_digits" do
9
- let(:grxml) {
10
- RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'inputdigits' do
11
- rule id: 'inputdigits', scope: 'public' do
12
- item repeat: '2' do
13
- one_of do
14
- 0.upto(9) { |d| item { d.to_s } }
15
- end
16
- end
17
- end
18
- end
19
- }
10
+ describe "#play_sound_files_for_menu" do
11
+ let(:options) { Hash.new }
12
+ let(:menu_instance) { Adhearsion::MenuDSL::Menu.new(options) }
13
+ let(:sound_file) { "press a button" }
14
+ let(:sound_files) { [sound_file] }
20
15
 
21
- it 'generates the correct GRXML grammar' do
22
- subject.grammar_digits(2).to_s.should == grxml.to_s
16
+ it "should play the sound files for the menu" do
17
+ subject.should_receive(:interruptible_play).with(sound_file).and_return("1")
18
+ subject.play_sound_files_for_menu(menu_instance, sound_files).should be == '1'
23
19
  end
24
20
 
25
- end # describe #grammar_digits
26
-
27
- describe "#grammar_accept" do
28
- let(:grxml) {
29
- RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'inputdigits' do
30
- rule id: 'inputdigits', scope: 'public' do
31
- one_of do
32
- item { '3' }
33
- item { '5' }
34
- end
35
- end
36
- end
37
- }
38
-
39
- it 'generates the correct GRXML grammar' do
40
- subject.grammar_accept('35').to_s.should == grxml.to_s
41
- end
42
-
43
- it 'filters meaningless characters out' do
44
- subject.grammar_accept('3+5').to_s.should == grxml.to_s
45
- end
46
- end # grammar_accept
47
-
48
- describe "#parse_single_dtmf" do
49
- it "correctly returns the parsed input" do
50
- subject.parse_single_dtmf("dtmf-3").should == '3'
51
- end
52
-
53
- it "correctly returns star as *" do
54
- subject.parse_single_dtmf("dtmf-star").should == '*'
21
+ it "should wait for digit if nothing is pressed during playback" do
22
+ subject.should_receive(:interruptible_play).with(sound_file).and_return(nil)
23
+ subject.should_receive(:wait_for_digit).with(menu_instance.timeout).and_return("1")
24
+ subject.play_sound_files_for_menu(menu_instance, sound_files).should be == '1'
55
25
  end
56
26
 
57
- it "correctly returns pound as #" do
58
- subject.parse_single_dtmf("dtmf-pound").should == '#'
59
- end
27
+ context "when the menu is not interruptible" do
28
+ let(:options) { { :interruptible => false } }
60
29
 
61
- it "correctly returns nil when input is nil" do
62
- subject.parse_single_dtmf(nil).should == nil
30
+ it "should play the sound files and wait for digit" do
31
+ subject.should_receive(:play).with(sound_file).and_return true
32
+ subject.should_receive(:wait_for_digit).with(menu_instance.timeout).and_return("1")
33
+ subject.play_sound_files_for_menu(menu_instance, sound_files).should be == '1'
34
+ end
63
35
  end
64
- end # describe #grammar_accept
36
+ end#play_sound_files_for_menu
65
37
 
66
38
  describe "#wait_for_digit" do
67
39
  let(:timeout) { 2 }
@@ -109,7 +81,7 @@ module Adhearsion
109
81
  it "returns the correct pressed digit" do
110
82
  expect_component_complete_event
111
83
  subject.should_receive(:execute_component_and_await_completion).once.with(Punchblock::Component::Input).and_return input_component
112
- subject.wait_for_digit(timeout).should == '5'
84
+ subject.wait_for_digit(timeout).should be == '5'
113
85
  end
114
86
 
115
87
  context "with a nil timeout" do
@@ -124,155 +96,206 @@ module Adhearsion
124
96
  end
125
97
  end # wait_for_digit
126
98
 
127
- describe "#input!" do
128
- describe "simple usage" do
129
- let(:timeout) { 3000 }
99
+ describe "#jump_to" do
100
+ let(:match_object) { flexmock(Class.new) }
101
+ let(:overrides) { Hash.new(:extension => "1") }
102
+ let(:block) { Proc.new {} }
130
103
 
131
- it "can be called with no arguments" do
132
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
133
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
134
- subject.input!
135
- end
104
+ it "calls instance_exec if the match object has a block" do
105
+ match_object.should_receive(:block).and_return(block)
106
+ subject.should_receive(:instance_exec).with(overrides[:extension], block)
107
+ subject.jump_to(match_object, overrides)
108
+ end
136
109
 
137
- it "can be called with 1 digit as an argument" do
138
- subject.should_receive(:wait_for_digit).with(nil)
139
- subject.input! 1
140
- end
110
+ it "calls invoke if the match object does not have a block" do
111
+ match_object.should_receive(:block).and_return(false)
112
+ match_object.should_receive(:match_payload).and_return(:payload)
113
+ subject.should_receive(:invoke).with(:payload, overrides)
114
+ subject.jump_to(match_object, overrides)
115
+ end
116
+ end#jump_to
141
117
 
142
- it "accepts a timeout argument" do
143
- subject.should_receive(:wait_for_digit).with(3000)
144
- subject.input! :timeout => timeout
145
- end
118
+ describe "#menu" do
119
+ let(:sound_files) { ["press", "button"] }
120
+
121
+ let(:menu_instance) do
122
+ MenuDSL::Menu.new { match(1) {} }
146
123
  end
147
124
 
148
- describe "any number of digits with a terminator" do
149
- let(:terminator) { '9' }
125
+ let(:result_done) { MenuDSL::Menu::MenuResultDone.new }
126
+ let(:result_terminated) { MenuDSL::Menu::MenuTerminated.new }
127
+ let(:result_limit_reached) { MenuDSL::Menu::MenuLimitReached.new }
128
+ let(:result_invalid) { MenuDSL::Menu::MenuResultInvalid.new }
129
+ let(:result_get_another_or_timeout) { MenuDSL::Menu::MenuGetAnotherDigitOrTimeout.new }
130
+ let(:result_get_another_or_finish) { MenuDSL::Menu::MenuGetAnotherDigitOrFinish.new(:match_object, :new_extension) }
131
+ let(:result_found) { MenuDSL::Menu::MenuResultFound.new(:match_object, :new_extension) }
150
132
 
151
- it "called with no arguments, it returns any number of digits taking a terminating digit" do
152
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
153
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
154
- subject.input!.should == '1'
155
- end
133
+ let(:status) { :foo }
134
+ let(:response) { '1234' }
156
135
 
157
- it "allows to set a different terminator" do
158
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
159
- subject.should_receive(:wait_for_digit).once.with(nil).and_return(terminator)
160
- subject.input!(:terminator => terminator).should == '1'
161
- end
136
+ before do
137
+ flexmock menu_instance, :status => status, :result => response
138
+ flexmock(MenuDSL::Menu).should_receive(:new).and_return(menu_instance)
162
139
  end
163
140
 
164
- describe "with a fixed number or digits" do
165
- it "accepts and returns three digits without a terminator" do
166
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
167
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('2')
168
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('3')
169
- subject.input!(3).should == '123'
170
- end
141
+ it "exits the function if MenuResultDone" do
142
+ menu_instance.should_receive(:should_continue?).and_return(true)
143
+ menu_instance.should_receive(:continue).and_return(result_done)
144
+ result = subject.menu sound_files
145
+ result.menu.should be menu_instance
146
+ result.response.should be response
171
147
  end
172
148
 
173
- describe "with play arguments" do
174
- let(:string_play) { "Thanks for calling" }
175
- let(:ssml_play) { RubySpeech::SSML.draw { string "Please stand by" } }
176
- let(:hash_play) { {:value => Time.parse("24/10/2011"), :strftime => "%H:%M"} }
177
- let(:hash_value) { Time.parse "24/10/2011" }
178
- let(:hash_options) { {:strftime => "%H:%M"} }
179
-
180
- it "plays a string argument" do
181
- subject.should_receive(:interruptible_play!).with(string_play)
182
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
183
- subject.input! :play => string_play
184
- end
149
+ it "exits the function if MenuTerminated" do
150
+ menu_instance.should_receive(:should_continue?).and_return(true)
151
+ menu_instance.should_receive(:continue).and_return(result_terminated)
152
+ result = subject.menu sound_files
153
+ result.menu.should be menu_instance
154
+ result.response.should be response
155
+ end
185
156
 
186
- it "plays a SSML argument" do
187
- subject.should_receive(:interruptible_play!).with(ssml_play)
188
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
189
- subject.input! :play => ssml_play
190
- end
157
+ it "exits the function if MenuLimitReached" do
158
+ menu_instance.should_receive(:should_continue?).and_return(true)
159
+ menu_instance.should_receive(:continue).and_return(result_limit_reached)
160
+ result = subject.menu sound_files
161
+ result.menu.should be menu_instance
162
+ result.response.should be response
163
+ end
191
164
 
192
- it "plays a Hash argument" do
193
- subject.should_receive(:interruptible_play!).with([hash_value, hash_options])
194
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
195
- subject.input! :play => hash_play
196
- end
165
+ it "executes failure hook and returns :failure if menu fails" do
166
+ menu_instance.should_receive(:should_continue?).and_return(false)
167
+ menu_instance.should_receive(:execute_failure_hook)
168
+ result = subject.menu sound_files
169
+ result.menu.should be menu_instance
170
+ result.response.should be response
171
+ end
197
172
 
198
- it "plays an array of mixed arguments" do
199
- subject.should_receive(:interruptible_play!).with(string_play)
200
- subject.should_receive(:interruptible_play!).with(ssml_play)
201
- subject.should_receive(:interruptible_play!).with([hash_value, hash_options])
202
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
203
- subject.input! :play => [string_play, ssml_play, hash_play]
204
- end
173
+ it "executes invalid hook if input is invalid" do
174
+ menu_instance.should_receive(:should_continue?).twice.and_return(true)
175
+ menu_instance.should_receive(:continue).and_return(result_invalid, result_done)
176
+ menu_instance.should_receive(:execute_invalid_hook)
177
+ menu_instance.should_receive(:restart!)
178
+ result = subject.menu sound_files
179
+ result.menu.should be menu_instance
180
+ result.response.should be response
181
+ end
205
182
 
206
- it "plays a string argument, takes 1 digit and returns the input" do
207
- subject.should_receive(:interruptible_play!).with(string_play).and_return('1')
208
- subject.input!(1, :play => string_play).should == '1'
209
- end
183
+ it "plays audio, then executes timeout hook if input times out" do
184
+ menu_instance.should_receive(:should_continue?).twice.and_return(true)
185
+ menu_instance.should_receive(:continue).and_return(result_get_another_or_timeout, result_done)
186
+ subject.should_receive(:play_sound_files_for_menu).with(menu_instance, sound_files).and_return(nil)
187
+ menu_instance.should_receive(:execute_timeout_hook)
188
+ menu_instance.should_receive(:restart!)
189
+ subject.menu sound_files
190
+ end
210
191
 
211
- it "plays a string argument, takes 2 digits and returns the input" do
212
- subject.should_receive(:interruptible_play!).with(string_play).and_return('1')
213
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
214
- subject.input!(2, :play => string_play).should == '11'
215
- end
192
+ it "plays audio, then adds digit to digit buffer if input is received" do
193
+ menu_instance.should_receive(:should_continue?).twice.and_return(true)
194
+ menu_instance.should_receive(:continue).and_return(result_get_another_or_timeout, result_done)
195
+ subject.should_receive(:play_sound_files_for_menu).with(menu_instance, sound_files).and_return("1")
196
+ menu_instance.should_receive(:<<).with("1")
197
+ subject.menu sound_files
198
+ end
216
199
 
217
- it "plays a string argument, allows for any number of digit and an accept key" do
218
- subject.should_receive(:interruptible_play!).with(string_play).and_return('1').ordered
219
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('2').ordered
220
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#').ordered
221
- subject.input!(:play => string_play).should == '12'
222
- end
200
+ it "plays audio, then jumps to payload when input is finished" do
201
+ menu_instance.should_receive(:should_continue?).and_return(true)
202
+ menu_instance.should_receive(:continue).and_return(result_get_another_or_finish)
203
+ subject.should_receive(:play_sound_files_for_menu).with(menu_instance, sound_files).and_return(nil)
204
+ subject.should_receive(:jump_to).with(:match_object, :extension => :new_extension)
205
+ subject.menu sound_files
206
+ end
223
207
 
224
- it "plays an array of mixed arguments, stops playing when a key is pressed, and returns the input" do
225
- subject.should_receive(:interruptible_play!).and_return(nil, '1', StandardError.new("should not be called"))
226
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
227
- subject.input!(:play => [string_play, ssml_play, hash_play]).should == '1'
228
- end
229
- end # describe with play arguments
208
+ it "jumps to payload when result is found" do
209
+ menu_instance.should_receive(:should_continue?).and_return(true)
210
+ menu_instance.should_receive(:continue).and_return(result_found)
211
+ subject.should_receive(:jump_to).with(:match_object, :extension => :new_extension)
212
+ result = subject.menu sound_files
213
+ result.menu.should be menu_instance
214
+ result.response.should be response
215
+ end
230
216
 
231
- describe "non interruptible play" do
232
- let(:string_play) { "Thanks for calling" }
217
+ context "if a digit limit is specified" do
218
+ it "should raise an ArgumentError"
219
+ end
233
220
 
234
- it "calls play! when passed :interruptible => false" do
235
- subject.should_receive(:play!).with(string_play)
236
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
237
- subject.input! :play => string_play, :interruptible => false
238
- end
221
+ context "if a terminator digit is specified" do
222
+ it "should raise an ArgumentError"
223
+ end
224
+
225
+ end#describe
226
+
227
+ describe "#ask" do
228
+ let(:sound_files) { ["press", "button"] }
229
+
230
+ context "mocking out the menu" do
231
+ let(:menu_instance) { MenuDSL::Menu.new :limit => 2 }
232
+
233
+ let(:result_done) { MenuDSL::Menu::MenuResultDone.new }
234
+ let(:result_terminated) { MenuDSL::Menu::MenuTerminated.new }
235
+ let(:result_limit_reached) { MenuDSL::Menu::MenuLimitReached.new }
236
+ let(:result_invalid) { MenuDSL::Menu::MenuResultInvalid.new }
237
+ let(:result_get_another_or_timeout) { MenuDSL::Menu::MenuGetAnotherDigitOrTimeout.new }
238
+ let(:result_get_another_or_finish) { MenuDSL::Menu::MenuGetAnotherDigitOrFinish.new(:match_object, :new_extension) }
239
+ let(:result_found) { MenuDSL::Menu::MenuResultFound.new(:match_object, :new_extension) }
239
240
 
240
- it "still collects digits when passed :interruptible => false" do
241
- subject.should_receive(:play!).with(string_play)
242
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('1')
243
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
244
- subject.input!(:play => string_play, :interruptible => false).should == '1'
241
+ let(:status) { :foo }
242
+ let(:response) { '1234' }
243
+
244
+ before do
245
+ flexmock menu_instance, :status => status, :result => response
246
+ flexmock(MenuDSL::Menu).should_receive(:new).and_return(menu_instance)
245
247
  end
246
- end # describe non interruptible play
247
248
 
248
- describe "speak functionality" do
249
- let(:string_speak) { "Thanks for calling" }
249
+ it "exits the function if MenuResultDone" do
250
+ menu_instance.should_receive(:continue).and_return(result_done)
251
+ result = subject.ask sound_files
252
+ result.menu.should be menu_instance
253
+ result.response.should be response
254
+ end
250
255
 
251
- it "speaks passed text" do
252
- subject.should_receive(:interruptible_play!).with(string_speak, {})
253
- subject.input! :speak => {:text => string_speak }
256
+ it "exits the function if MenuTerminated" do
257
+ menu_instance.should_receive(:continue).and_return(result_terminated)
258
+ result = subject.ask sound_files
259
+ result.menu.should be menu_instance
260
+ result.response.should be response
254
261
  end
255
262
 
256
- it "speaks passed text and collect digits" do
257
- subject.should_receive(:interruptible_play!).with(string_speak, {}).and_return('1')
258
- subject.should_receive(:wait_for_digit).once.with(nil).and_return('#')
259
- subject.input!(:speak => {:text => string_speak }).should == '1'
263
+ it "exits the function if MenuLimitReached" do
264
+ menu_instance.should_receive(:continue).and_return(result_limit_reached)
265
+ result = subject.ask sound_files
266
+ result.menu.should be menu_instance
267
+ result.response.should be response
260
268
  end
261
- end
262
269
 
263
- it 'throws an exception when playback fails'
264
- end # describe input!
270
+ it "plays audio, then executes timeout hook if input times out" do
271
+ menu_instance.should_receive(:continue).and_return(result_get_another_or_timeout, result_done)
272
+ subject.should_receive(:play_sound_files_for_menu).with(menu_instance, sound_files).and_return(nil)
273
+ menu_instance.should_receive(:execute_timeout_hook)
274
+ menu_instance.should_receive(:restart!)
275
+ subject.ask sound_files
276
+ end
265
277
 
266
- describe "#input" do
267
- let(:string_play) { "Thanks for calling" }
278
+ it "plays audio, then adds digit to digit buffer if input is received" do
279
+ menu_instance.should_receive(:continue).and_return(result_get_another_or_timeout, result_done)
280
+ subject.should_receive(:play_sound_files_for_menu).with(menu_instance, sound_files).and_return("1")
281
+ menu_instance.should_receive(:<<).with("1")
282
+ subject.ask sound_files
283
+ end
284
+ end
268
285
 
269
- it "just calls #input!" do
270
- subject.should_receive(:input!).with(:play => string_play).and_return(nil)
271
- subject.input! :play => string_play
286
+ context "with a block passed" do
287
+ it "should set that block as the buffer validator" do
288
+ foo = nil
289
+ subject.should_receive(:play_sound_files_for_menu).and_return("1")
290
+ subject.ask sound_files, :limit => 0 do |buffer|
291
+ foo = :bar
292
+ end.menu.execute_validator_hook
293
+ foo.should be == :bar
294
+ end
272
295
  end
273
296
 
274
- it 'does not throw exceptions when playback fails'
275
- end # describe input
276
- end
297
+ end#describe
298
+
299
+ end#shared
277
300
  end
278
301
  end
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  module Adhearsion
@@ -267,17 +269,23 @@ module Adhearsion
267
269
 
268
270
  it "raises an exception if play fails" do
269
271
  subject.should_receive(:play).once.and_return false
270
- expect { subject.play!(non_existing) }.to raise_error(Adhearsion::PlaybackError)
272
+ expect { subject.play!(non_existing) }.to raise_error(Output::PlaybackError)
271
273
  end
272
274
  end
273
275
 
274
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
281
+
282
+ describe "#say" do
275
283
  describe "with a RubySpeech document" do
276
284
  it 'plays the correct SSML' do
277
285
  doc = RubySpeech::SSML.draw { string "Hello world" }
278
286
  subject.should_receive(:play_ssml).once.with(doc, {}).and_return true
279
287
  subject.should_receive(:output).never
280
- subject.speak(doc).should be true
288
+ subject.say(doc).should be true
281
289
  end
282
290
  end
283
291
 
@@ -286,7 +294,7 @@ module Adhearsion
286
294
  string = "Hello world"
287
295
  subject.should_receive(:play_ssml).once.with(string, {})
288
296
  subject.should_receive(:output).once.with(:text, string, {}).and_return true
289
- subject.speak(string).should be true
297
+ subject.say(string).should be true
290
298
  end
291
299
  end
292
300
 
@@ -296,7 +304,7 @@ module Adhearsion
296
304
  argument = 123
297
305
  subject.should_receive(:play_ssml).once.with(argument, {})
298
306
  subject.should_receive(:output).once.with(:text, expected_string, {}).and_return true
299
- subject.speak(argument)
307
+ subject.say(argument)
300
308
  end
301
309
  end
302
310
  end
@@ -311,7 +319,7 @@ module Adhearsion
311
319
  end
312
320
 
313
321
  it 'returns SSML for a text argument' do
314
- subject.ssml_for(prompt).should == ssml
322
+ subject.ssml_for(prompt).should be == ssml
315
323
  end
316
324
 
317
325
  it 'returns the same SSML passed in if it is SSML' do
@@ -326,8 +334,14 @@ module Adhearsion
326
334
  end
327
335
 
328
336
  it "detects a file path" do
329
- http_path = "/usr/shared/sounds/hello.mp3"
330
- subject.detect_type(http_path).should be :audio
337
+ file_path = "file:///usr/shared/sounds/hello.mp3"
338
+ subject.detect_type(file_path).should be :audio
339
+
340
+ absolute_path = "/usr/shared/sounds/hello.mp3"
341
+ subject.detect_type(absolute_path).should be :audio
342
+
343
+ relative_path = "foo/bar"
344
+ subject.detect_type(relative_path).should_not be :audio
331
345
  end
332
346
 
333
347
  it "detects a Date object" do
@@ -424,7 +438,7 @@ module Adhearsion
424
438
  expect_component_complete_event
425
439
  flexmock(Punchblock::Component::Output).new_instances.should_receive(:stop!)
426
440
  subject.should_receive(:execute_component_and_await_completion).once.with(output_component)
427
- subject.stream_file(prompt, allowed_digits).should == '5'
441
+ subject.stream_file(prompt, allowed_digits).should be == '5'
428
442
  end
429
443
  end # describe #stream_file
430
444
 
@@ -445,8 +459,8 @@ module Adhearsion
445
459
  end
446
460
 
447
461
  it 'raises an exception when output is unsuccessful' do
448
- subject.should_receive(:stream_file).once.and_raise PlaybackError, "Output failed"
449
- expect { subject.interruptible_play!(non_existing) }.to raise_error(Adhearsion::PlaybackError)
462
+ subject.should_receive(:stream_file).once.and_raise Output::PlaybackError, "Output failed"
463
+ expect { subject.interruptible_play!(non_existing) }.to raise_error(Output::PlaybackError)
450
464
  end
451
465
  end # describe interruptible_play!
452
466
 
@@ -466,8 +480,8 @@ module Adhearsion
466
480
  end
467
481
 
468
482
  it "should not raise an exception when output is unsuccessful" do
469
- subject.should_receive(:stream_file).once.and_raise PlaybackError, "Output failed"
470
- lambda { subject.interruptible_play non_existing }.should_not raise_error(Adhearsion::PlaybackError)
483
+ subject.should_receive(:stream_file).once.and_raise Output::PlaybackError, "Output failed"
484
+ lambda { subject.interruptible_play non_existing }.should_not raise_error(Output::PlaybackError)
471
485
  end
472
486
  end # describe interruptible_play
473
487