adhearsion 2.1.2 → 2.1.3
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.
- 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
|