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.
@@ -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.
@@ -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.11.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"
@@ -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
- call = current_actor
326
- controller ||= CallController.new call, &block
327
- Thread.new do
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
- new_controller = catch :pass_controller do
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
@@ -118,6 +118,7 @@ module Adhearsion
118
118
 
119
119
  if new_call.alive? && new_call.active?
120
120
  logger.debug "#dial joining call #{new_call.id} to #{@call.id}"
121
+ @call.answer
121
122
  new_call.join @call
122
123
  status.answer!
123
124
  end
@@ -20,11 +20,25 @@ module Adhearsion
20
20
  end
21
21
 
22
22
  def detect_type(output)
23
- result = nil
24
- result = :time if [Date, Time, DateTime].include? output.class
25
- result = :numeric if output.kind_of?(Numeric) || output =~ /^\d+$/
26
- result = :audio if !result && (/^\//.match(output.to_s) || URI::regexp.match(output.to_s))
27
- result ||= :text
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 (milliseconds) for a recording.
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 (milliseconds) 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 (milliseconds) of a period of silence after callers have spoken to conclude they finished.
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,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- class <%= @controller_name %> < Adhearsion::CallController
3
+ class <%= @controller_name.camelcase %> < Adhearsion::CallController
4
4
  def run
5
5
  end
6
6
  end
@@ -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({})
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Adhearsion
4
- VERSION = '2.1.2'
4
+ VERSION = '2.1.3'
5
5
  end
@@ -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
- it "returns text as a fallback" do
83
- output = "Hello"
84
- subject.detect_type(output).should be :text
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 => 5000
15
+ :max_duration => max_duration
15
16
  }
16
17
  end
17
- let(:component) { Punchblock::Component::Record.new options }
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(options).and_return component
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(options).and_return component
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(options).and_return component
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
- CallController.exec subject
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
- CallController.exec subject
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 'CallController' }
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 #execute on the controller instance" do
745
- flexmock(CallController).should_receive(:exec).once.with mock_controller
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
- flexmock(CallController).should_receive(:exec).once.with CallController
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
@@ -46,7 +46,7 @@ module Adhearsion
46
46
  context "by dead call object" do
47
47
  before do
48
48
  @call_id = deleted_call.id
49
- deleted_call.kill
49
+ Celluloid::Actor.kill deleted_call
50
50
  deleted_call.should_not be_alive
51
51
  subject.remove_inactive_call deleted_call
52
52
  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('Call', :id => call_id).tap { |call| call.should_ignore_missing } }
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.2
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-09-16 00:00:00.000000000 Z
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.11.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.11.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: -3730460706990513122
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: -3730460706990513122
642
+ hash: -4325641181526579229
637
643
  requirements: []
638
644
  rubyforge_project:
639
645
  rubygems_version: 1.8.23