adhearsion 2.1.2 → 2.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +8 -0
- data/adhearsion.gemspec +1 -1
- data/features/controller_generator.feature +15 -0
- data/lib/adhearsion/call.rb +4 -12
- data/lib/adhearsion/call_controller.rb +28 -7
- data/lib/adhearsion/call_controller/dial.rb +1 -0
- data/lib/adhearsion/call_controller/output/formatter.rb +19 -5
- data/lib/adhearsion/call_controller/record.rb +6 -3
- data/lib/adhearsion/generators/controller/templates/lib/controller.rb +1 -1
- data/lib/adhearsion/generators/controller/templates/spec/controller_spec.rb +2 -2
- data/lib/adhearsion/version.rb +1 -1
- data/spec/adhearsion/call_controller/dial_spec.rb +9 -0
- data/spec/adhearsion/call_controller/output/formatter_spec.rb +4 -3
- data/spec/adhearsion/call_controller/record_spec.rb +9 -5
- data/spec/adhearsion/call_controller_spec.rb +2 -2
- data/spec/adhearsion/call_spec.rb +5 -4
- data/spec/adhearsion/calls_spec.rb +1 -1
- data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +1 -1
- metadata +12 -6
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# [develop](https://github.com/adhearsion/adhearsion)
|
2
2
|
|
3
|
+
# [2.1.3](https://github.com/adhearsion/adhearsion/compare/v2.1.2...v2.1.3) - [2012-10-11](https://rubygems.org/gems/adhearsion/versions/2.1.3)
|
4
|
+
* Bugfix: Originating call is now answered before joining calls using `CallController#dial`
|
5
|
+
* Bugfix: Output controller methods no longer falsely detect a string with a colon as a URI for an audio file
|
6
|
+
* Bugfix: `CallController#record` takes timeout in seconds instead of milliseconds
|
7
|
+
* Bugfix: Generating controllers given lower case names now works properly
|
8
|
+
* Update: Bump Celluloid dependency
|
9
|
+
* CS: Log when a controller is executed on a call
|
10
|
+
|
3
11
|
# [2.1.2](https://github.com/adhearsion/adhearsion/compare/v2.1.1...v2.1.2) - [2012-09-16](https://rubygems.org/gems/adhearsion/versions/2.1.2)
|
4
12
|
* Bugfix: Celluloid 0.12.x dependency now disallowed due to incompatible API changes.
|
5
13
|
* Bugfix: Generated Gemfiles no longer pessimistically locked. Matches promise of SemVer compliance.
|
data/adhearsion.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.add_runtime_dependency 'activesupport', ["~> 3.0"]
|
21
21
|
s.add_runtime_dependency 'adhearsion-loquacious', ["~> 1.9"]
|
22
22
|
s.add_runtime_dependency 'bundler', ["~> 1.0"]
|
23
|
-
s.add_runtime_dependency 'celluloid', ["~> 0.
|
23
|
+
s.add_runtime_dependency 'celluloid', ["~> 0.12", ">= 0.12.1"]
|
24
24
|
s.add_runtime_dependency 'countdownlatch'
|
25
25
|
s.add_runtime_dependency 'deep_merge'
|
26
26
|
s.add_runtime_dependency 'ffi', ["~> 1.0"]
|
@@ -17,3 +17,18 @@ Feature: Adhearsion controller generator
|
|
17
17
|
|
18
18
|
And the file "lib/test_controller.rb" should contain "class TestController < Adhearsion::CallController"
|
19
19
|
And the file "spec/test_controller_spec.rb" should contain "describe TestController"
|
20
|
+
|
21
|
+
Scenario: Generate a controller with lower-case name
|
22
|
+
When I run `ahn create path/somewhere`
|
23
|
+
And I cd to "path/somewhere"
|
24
|
+
And I run `ahn generate controller test_controller`
|
25
|
+
Then the following directories should exist:
|
26
|
+
| lib |
|
27
|
+
| spec |
|
28
|
+
|
29
|
+
And the following files should exist:
|
30
|
+
| lib/test_controller.rb |
|
31
|
+
| spec/test_controller_spec.rb |
|
32
|
+
|
33
|
+
And the file "lib/test_controller.rb" should contain "class TestController < Adhearsion::CallController"
|
34
|
+
And the file "spec/test_controller_spec.rb" should contain "describe TestController"
|
data/lib/adhearsion/call.rb
CHANGED
@@ -321,18 +321,10 @@ module Adhearsion
|
|
321
321
|
end
|
322
322
|
|
323
323
|
def execute_controller(controller = nil, completion_callback = nil, &block)
|
324
|
-
raise ArgumentError if controller && block_given?
|
325
|
-
|
326
|
-
controller
|
327
|
-
|
328
|
-
catching_standard_errors do
|
329
|
-
begin
|
330
|
-
CallController.exec controller
|
331
|
-
ensure
|
332
|
-
completion_callback.call call if completion_callback
|
333
|
-
end
|
334
|
-
end
|
335
|
-
end.tap { |t| Adhearsion::Process.important_threads << t }
|
324
|
+
raise ArgumentError, "Cannot supply a controller and a block at the same time" if controller && block_given?
|
325
|
+
controller ||= CallController.new current_actor, &block
|
326
|
+
logger.info "Executing controller #{controller.inspect}"
|
327
|
+
controller.bg_exec completion_callback
|
336
328
|
end
|
337
329
|
|
338
330
|
# @private
|
@@ -41,12 +41,7 @@ module Adhearsion
|
|
41
41
|
# @param [CallController] controller
|
42
42
|
#
|
43
43
|
def exec(controller)
|
44
|
-
|
45
|
-
controller.execute!
|
46
|
-
nil
|
47
|
-
end
|
48
|
-
|
49
|
-
exec new_controller if new_controller
|
44
|
+
controller.exec
|
50
45
|
end
|
51
46
|
|
52
47
|
#
|
@@ -76,6 +71,32 @@ module Adhearsion
|
|
76
71
|
@call, @metadata, @block = call, metadata || {}, block
|
77
72
|
end
|
78
73
|
|
74
|
+
#
|
75
|
+
# Execute the controller, allowing passing control to another controller
|
76
|
+
#
|
77
|
+
def exec(controller = self)
|
78
|
+
new_controller = catch :pass_controller do
|
79
|
+
controller.execute!
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
83
|
+
exec new_controller if new_controller
|
84
|
+
end
|
85
|
+
|
86
|
+
def bg_exec(completion_callback = nil)
|
87
|
+
Thread.new do
|
88
|
+
catching_standard_errors do
|
89
|
+
exec_with_callback completion_callback
|
90
|
+
end
|
91
|
+
end.tap { |t| Adhearsion::Process.important_threads << t }
|
92
|
+
end
|
93
|
+
|
94
|
+
def exec_with_callback(completion_callback = nil)
|
95
|
+
exec
|
96
|
+
ensure
|
97
|
+
completion_callback.call call if completion_callback
|
98
|
+
end
|
99
|
+
|
79
100
|
# @private
|
80
101
|
def execute!(*options)
|
81
102
|
call.register_controller! self
|
@@ -243,7 +264,7 @@ module Adhearsion
|
|
243
264
|
|
244
265
|
# @private
|
245
266
|
def inspect
|
246
|
-
"#<#{self.class} call=#{call.id}, metadata=#{metadata.inspect}>"
|
267
|
+
"#<#{self.class} call=#{call.alive? ? call.id : ''}, metadata=#{metadata.inspect}>"
|
247
268
|
end
|
248
269
|
end#class
|
249
270
|
end
|
@@ -20,11 +20,25 @@ module Adhearsion
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def detect_type(output)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
case output
|
24
|
+
when Date, Time, DateTime
|
25
|
+
:time
|
26
|
+
when Numeric, /^\d+$/
|
27
|
+
:numeric
|
28
|
+
when /^\//, ->(string) { uri? string }
|
29
|
+
:audio
|
30
|
+
else
|
31
|
+
:text
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def uri?(string)
|
36
|
+
uri = URI.parse string
|
37
|
+
!!uri.scheme
|
38
|
+
rescue URI::BadURIError
|
39
|
+
false
|
40
|
+
rescue URI::InvalidURIError
|
41
|
+
false
|
28
42
|
end
|
29
43
|
|
30
44
|
#
|
@@ -21,11 +21,11 @@ module Adhearsion
|
|
21
21
|
# @option options [Boolean, Optional] :async Execute asynchronously. Defaults to false
|
22
22
|
# @option options [Boolean, Optional] :start_beep Indicates whether subsequent record will be preceded with a beep. Default is true.
|
23
23
|
# @option options [Boolean, Optional] :start_paused Whether subsequent record will start in PAUSE mode. Default is false.
|
24
|
-
# @option options [String, Optional] :max_duration Indicates the maximum duration (
|
24
|
+
# @option options [String, Optional] :max_duration Indicates the maximum duration (seconds) for a recording.
|
25
25
|
# @option options [String, Optional] :format File format used during recording.
|
26
26
|
# @option options [String, Optional] :format File format used during recording.
|
27
|
-
# @option options [String, Optional] :initial_timeout Controls how long (
|
28
|
-
# @option options [String, Optional] :final_timeout Controls the length (
|
27
|
+
# @option options [String, Optional] :initial_timeout Controls how long (seconds) the recognizer should wait after the end of the prompt for the caller to speak before sending a Recorder event.
|
28
|
+
# @option options [String, Optional] :final_timeout Controls the length (seconds) of a period of silence after callers have spoken to conclude they finished.
|
29
29
|
# @option options [Boolean, Optional] :interruptible Allows the recording to be terminated by any single DTMF key, default is false
|
30
30
|
#
|
31
31
|
# @return Punchblock::Component::Record
|
@@ -35,6 +35,9 @@ module Adhearsion
|
|
35
35
|
interruptible = options.delete :interruptible
|
36
36
|
interrupt_key = '0123456789#*'
|
37
37
|
stopper_component = nil
|
38
|
+
[:max_duration, :initial_timeout, :final_timeout].each do |k|
|
39
|
+
options[k] = options[k].to_i * 1000 if options[k]
|
40
|
+
end
|
38
41
|
|
39
42
|
component = Punchblock::Component::Record.new options
|
40
43
|
component.register_event_handler Punchblock::Event::Complete do |event|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
describe <%= @controller_name %> do
|
3
|
+
describe <%= @controller_name.camelcase %> do
|
4
4
|
|
5
5
|
let(:mock_call) { mock 'Call', :to => '1112223333', :from => "2223334444" }
|
6
6
|
let(:metadata) { {} }
|
7
|
-
subject { <%= @controller_name %>.new(mock_call, metadata) }
|
7
|
+
subject { <%= @controller_name.camelcase %>.new(mock_call, metadata) }
|
8
8
|
|
9
9
|
it "should have empty metadata" do
|
10
10
|
subject.metadata.should eq({})
|
data/lib/adhearsion/version.rb
CHANGED
@@ -89,6 +89,7 @@ module Adhearsion
|
|
89
89
|
end
|
90
90
|
|
91
91
|
it "joins the new call to the existing one on answer" do
|
92
|
+
flexmock(call).should_receive(:answer).once
|
92
93
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
93
94
|
|
94
95
|
dial_in_thread
|
@@ -102,6 +103,7 @@ module Adhearsion
|
|
102
103
|
end
|
103
104
|
|
104
105
|
it "hangs up the new call when the dial unblocks" do
|
106
|
+
flexmock(call).should_receive(:answer).once
|
105
107
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
106
108
|
|
107
109
|
dial_in_thread
|
@@ -148,6 +150,7 @@ module Adhearsion
|
|
148
150
|
|
149
151
|
context "when the call is answered and joined" do
|
150
152
|
it "has an overall dial status of :answer" do
|
153
|
+
flexmock(call).should_receive(:answer).once
|
151
154
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
152
155
|
|
153
156
|
t = dial_in_thread
|
@@ -208,6 +211,7 @@ module Adhearsion
|
|
208
211
|
end
|
209
212
|
|
210
213
|
it "dials all parties and joins the first one to answer, hanging up the rest" do
|
214
|
+
flexmock(call).should_receive(:answer).once
|
211
215
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
212
216
|
flexmock(second_other_mock_call).should_receive(:hangup).once
|
213
217
|
|
@@ -232,6 +236,7 @@ module Adhearsion
|
|
232
236
|
end
|
233
237
|
|
234
238
|
it "unblocks when the joined call unjoins, allowing it to proceed further" do
|
239
|
+
flexmock(call).should_receive(:answer).once
|
235
240
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
236
241
|
flexmock(second_other_mock_call).should_receive(:hangup).once
|
237
242
|
|
@@ -344,6 +349,7 @@ module Adhearsion
|
|
344
349
|
|
345
350
|
context "when a call is answered and joined, and the other ends with an error" do
|
346
351
|
it "has an overall dial status of :answer" do
|
352
|
+
flexmock(call).should_receive(:answer).once
|
347
353
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
348
354
|
flexmock(second_other_mock_call).should_receive(:hangup).once
|
349
355
|
|
@@ -392,6 +398,7 @@ module Adhearsion
|
|
392
398
|
describe "if someone answers before the timeout elapses" do
|
393
399
|
it "should not abort until the far end hangs up" do
|
394
400
|
flexmock(other_mock_call).should_receive(:dial).once.with(to, hsh(:timeout => timeout))
|
401
|
+
flexmock(call).should_receive(:answer).once
|
395
402
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
396
403
|
flexmock(other_mock_call).should_receive(:hangup).once
|
397
404
|
flexmock(OutboundCall).should_receive(:new).and_return other_mock_call
|
@@ -464,6 +471,7 @@ module Adhearsion
|
|
464
471
|
it "should join the calls if the call is still active after execution of the call controller" do
|
465
472
|
flexmock(other_mock_call).should_receive(:hangup).once
|
466
473
|
other_mock_call['confirm'] = true
|
474
|
+
flexmock(call).should_receive(:answer).once
|
467
475
|
flexmock(other_mock_call).should_receive(:join).once.with(call)
|
468
476
|
|
469
477
|
t = dial_in_thread
|
@@ -485,6 +493,7 @@ module Adhearsion
|
|
485
493
|
other_mock_call << mock_end
|
486
494
|
end
|
487
495
|
other_mock_call['confirm'] = false
|
496
|
+
flexmock(call).should_receive(:answer).never
|
488
497
|
flexmock(other_mock_call).should_receive(:join).never.with(call)
|
489
498
|
|
490
499
|
t = dial_in_thread
|
@@ -79,9 +79,10 @@ module Adhearsion
|
|
79
79
|
subject.detect_type(number).should be :numeric
|
80
80
|
end
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
82
|
+
["Foo", "Foo bar", "The answer: foo", "The answer could be foo/bar"].each do |string|
|
83
|
+
it "detects '#{string}' as text" do
|
84
|
+
subject.detect_type(string).should be :text
|
85
|
+
end
|
85
86
|
end
|
86
87
|
end
|
87
88
|
end
|
@@ -8,19 +8,23 @@ module Adhearsion
|
|
8
8
|
include CallControllerTestHelpers
|
9
9
|
|
10
10
|
describe "#record" do
|
11
|
+
let(:max_duration) { 5 }
|
11
12
|
let(:options) do
|
12
13
|
{
|
13
14
|
:start_beep => true,
|
14
|
-
:max_duration =>
|
15
|
+
:max_duration => max_duration
|
15
16
|
}
|
16
17
|
end
|
17
|
-
let(:
|
18
|
+
let(:parsed_options) do
|
19
|
+
options.merge(max_duration: max_duration * 1000)
|
20
|
+
end
|
21
|
+
let(:component) { Punchblock::Component::Record.new parsed_options }
|
18
22
|
let(:response) { Punchblock::Event::Complete.new }
|
19
23
|
|
20
24
|
describe "with :async => true and an :on_complete callback" do
|
21
25
|
before do
|
22
26
|
component
|
23
|
-
flexmock(Punchblock::Component::Record).should_receive(:new).once.with(
|
27
|
+
flexmock(Punchblock::Component::Record).should_receive(:new).once.with(parsed_options).and_return component
|
24
28
|
expect_message_waiting_for_response component
|
25
29
|
@rec = Queue.new
|
26
30
|
subject.record(options.merge(async: true)) { |rec| @rec.push rec }
|
@@ -63,7 +67,7 @@ module Adhearsion
|
|
63
67
|
describe "with :async => false" do
|
64
68
|
before do
|
65
69
|
component
|
66
|
-
flexmock(Punchblock::Component::Record).should_receive(:new).once.with(
|
70
|
+
flexmock(Punchblock::Component::Record).should_receive(:new).once.with(parsed_options).and_return component
|
67
71
|
expect_component_execution component
|
68
72
|
@rec = Queue.new
|
69
73
|
subject.record(options.merge(:async => false)) { |rec| @rec.push rec }
|
@@ -113,7 +117,7 @@ module Adhearsion
|
|
113
117
|
describe "check for the return value" do
|
114
118
|
it "returns a Record component" do
|
115
119
|
component
|
116
|
-
flexmock(Punchblock::Component::Record).should_receive(:new).once.with(
|
120
|
+
flexmock(Punchblock::Component::Record).should_receive(:new).once.with(parsed_options).and_return component
|
117
121
|
expect_component_execution component
|
118
122
|
subject.record(options.merge(:async => false)).should be == component
|
119
123
|
component.request!
|
@@ -177,7 +177,7 @@ module Adhearsion
|
|
177
177
|
call.should_receive(:answer).once.ordered
|
178
178
|
subject.should_receive(:after).never.ordered
|
179
179
|
|
180
|
-
|
180
|
+
subject.exec
|
181
181
|
end
|
182
182
|
|
183
183
|
it "should execute after_call callbacks before passing control" do
|
@@ -185,7 +185,7 @@ module Adhearsion
|
|
185
185
|
subject.should_receive(:foobar).once.ordered
|
186
186
|
call.should_receive(:answer).once.ordered
|
187
187
|
|
188
|
-
|
188
|
+
subject.exec
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
@@ -735,20 +735,21 @@ module Adhearsion
|
|
735
735
|
|
736
736
|
describe "#execute_controller" do
|
737
737
|
let(:latch) { CountDownLatch.new 1 }
|
738
|
-
let(:mock_controller) { flexmock
|
738
|
+
let(:mock_controller) { flexmock CallController.new(subject) }
|
739
739
|
|
740
740
|
before do
|
741
741
|
flexmock subject.wrapped_object, :write_and_await_response => true
|
742
742
|
end
|
743
743
|
|
744
|
-
it "should call #
|
745
|
-
|
744
|
+
it "should call #bg_exec on the controller instance" do
|
745
|
+
mock_controller.should_receive(:exec).once
|
746
746
|
subject.execute_controller mock_controller, lambda { |call| latch.countdown! }
|
747
747
|
latch.wait(3).should be_true
|
748
748
|
end
|
749
749
|
|
750
750
|
it "should use the passed block as a controller if none is specified" do
|
751
|
-
|
751
|
+
mock_controller.should_receive(:exec).once
|
752
|
+
flexmock(CallController).should_receive(:new).once.and_return mock_controller
|
752
753
|
subject.execute_controller nil, lambda { |call| latch.countdown! } do
|
753
754
|
foo
|
754
755
|
end
|
@@ -55,7 +55,7 @@ module Adhearsion
|
|
55
55
|
|
56
56
|
let(:call_id) { rand }
|
57
57
|
let(:offer) { Punchblock::Event::Offer.new.tap { |o| o.target_call_id = call_id } }
|
58
|
-
let(:mock_call) { flexmock
|
58
|
+
let(:mock_call) { flexmock Call.new, :id => call_id }
|
59
59
|
|
60
60
|
describe "starts the client with the default values" do
|
61
61
|
subject { initialize_punchblock }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adhearsion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2012-
|
15
|
+
date: 2012-10-11 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: activesupport
|
@@ -69,7 +69,10 @@ dependencies:
|
|
69
69
|
requirements:
|
70
70
|
- - ~>
|
71
71
|
- !ruby/object:Gem::Version
|
72
|
-
version: 0.
|
72
|
+
version: '0.12'
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.12.1
|
73
76
|
type: :runtime
|
74
77
|
prerelease: false
|
75
78
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -77,7 +80,10 @@ dependencies:
|
|
77
80
|
requirements:
|
78
81
|
- - ~>
|
79
82
|
- !ruby/object:Gem::Version
|
80
|
-
version: 0.
|
83
|
+
version: '0.12'
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 0.12.1
|
81
87
|
- !ruby/object:Gem::Dependency
|
82
88
|
name: countdownlatch
|
83
89
|
requirement: !ruby/object:Gem::Requirement
|
@@ -624,7 +630,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
624
630
|
version: '0'
|
625
631
|
segments:
|
626
632
|
- 0
|
627
|
-
hash: -
|
633
|
+
hash: -4325641181526579229
|
628
634
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
629
635
|
none: false
|
630
636
|
requirements:
|
@@ -633,7 +639,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
633
639
|
version: '0'
|
634
640
|
segments:
|
635
641
|
- 0
|
636
|
-
hash: -
|
642
|
+
hash: -4325641181526579229
|
637
643
|
requirements: []
|
638
644
|
rubyforge_project:
|
639
645
|
rubygems_version: 1.8.23
|