punchblock 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +3 -0
- data/lib/punchblock/component/input.rb +38 -2
- data/lib/punchblock/translator/asterisk/call.rb +4 -0
- data/lib/punchblock/translator/asterisk/component/asterisk/input.rb +116 -0
- data/lib/punchblock/translator/asterisk/component/asterisk.rb +1 -0
- data/lib/punchblock/translator/asterisk/component.rb +1 -1
- data/lib/punchblock/version.rb +1 -1
- data/punchblock.gemspec +2 -2
- data/spec/punchblock/component/input_spec.rb +15 -0
- data/spec/punchblock/translator/asterisk/call_spec.rb +36 -0
- data/spec/punchblock/translator/asterisk/component/asterisk/input_spec.rb +268 -0
- data/spec/spec_helper.rb +4 -0
- metadata +47 -44
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# develop
|
2
2
|
|
3
|
+
# v0.8.1 - 2012-01-09
|
4
|
+
* Feature: Support DTMF Input components on Asterisk
|
5
|
+
|
3
6
|
# v0.8.0 - 2012-01-06
|
4
7
|
* Feature: Expose Blather's connection timeout config when creating a Connection::XMPP
|
5
8
|
* Bugfix: Remove some deprecated Tropo extension components
|
@@ -315,6 +315,10 @@ module Punchblock
|
|
315
315
|
read_attr :mode, :to_sym
|
316
316
|
end
|
317
317
|
|
318
|
+
def mode=(other)
|
319
|
+
write_attr :mode, other
|
320
|
+
end
|
321
|
+
|
318
322
|
##
|
319
323
|
# @return [Float] A measure of the confidence of the result, between 0-1
|
320
324
|
#
|
@@ -322,23 +326,55 @@ module Punchblock
|
|
322
326
|
read_attr :confidence, :to_f
|
323
327
|
end
|
324
328
|
|
329
|
+
def confidence=(other)
|
330
|
+
write_attr :confidence, other
|
331
|
+
end
|
332
|
+
|
325
333
|
##
|
326
334
|
# @return [String] An intelligent interpretation of the meaning of the response.
|
327
335
|
#
|
328
336
|
def interpretation
|
329
|
-
|
337
|
+
interpretation_node.text
|
338
|
+
end
|
339
|
+
|
340
|
+
def interpretation=(other)
|
341
|
+
interpretation_node.content = other
|
330
342
|
end
|
331
343
|
|
332
344
|
##
|
333
345
|
# @return [String] The exact response gained
|
334
346
|
#
|
335
347
|
def utterance
|
336
|
-
|
348
|
+
utterance_node.text
|
349
|
+
end
|
350
|
+
|
351
|
+
def utterance=(other)
|
352
|
+
utterance_node.content = other
|
337
353
|
end
|
338
354
|
|
339
355
|
def inspect_attributes # :nodoc:
|
340
356
|
[:mode, :confidence, :interpretation, :utterance] + super
|
341
357
|
end
|
358
|
+
|
359
|
+
private
|
360
|
+
|
361
|
+
def interpretation_node
|
362
|
+
child_node_with_name 'interpretation'
|
363
|
+
end
|
364
|
+
|
365
|
+
def utterance_node
|
366
|
+
child_node_with_name 'utterance'
|
367
|
+
end
|
368
|
+
|
369
|
+
def child_node_with_name(name)
|
370
|
+
node = find_first "ns:#{name}", :ns => self.class.registered_ns
|
371
|
+
|
372
|
+
unless node
|
373
|
+
self << (node = RayoNode.new(name, self.document))
|
374
|
+
node.namespace = self.class.registered_ns
|
375
|
+
end
|
376
|
+
node
|
377
|
+
end
|
342
378
|
end
|
343
379
|
|
344
380
|
class NoMatch < Event::Complete::Reason
|
@@ -4,6 +4,7 @@ module Punchblock
|
|
4
4
|
module Translator
|
5
5
|
class Asterisk
|
6
6
|
class Call
|
7
|
+
include HasGuardedHandlers
|
7
8
|
include Celluloid
|
8
9
|
|
9
10
|
attr_reader :id, :channel, :translator, :agi_env
|
@@ -42,6 +43,7 @@ module Punchblock
|
|
42
43
|
pb_logger.debug "Could not find component for AMI event: #{ami_event}"
|
43
44
|
end
|
44
45
|
end
|
46
|
+
trigger_handler :ami, ami_event
|
45
47
|
end
|
46
48
|
|
47
49
|
def execute_command(command)
|
@@ -66,6 +68,8 @@ module Punchblock
|
|
66
68
|
execute_agi_command command
|
67
69
|
when Punchblock::Component::Output
|
68
70
|
execute_component Component::Asterisk::Output, command
|
71
|
+
when Punchblock::Component::Input
|
72
|
+
execute_component Component::Asterisk::Input, command
|
69
73
|
end
|
70
74
|
end
|
71
75
|
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Punchblock
|
2
|
+
module Translator
|
3
|
+
class Asterisk
|
4
|
+
module Component
|
5
|
+
module Asterisk
|
6
|
+
class Input < Component
|
7
|
+
|
8
|
+
attr_reader :grammar, :buffer
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@media_engine = call.translator.media_engine
|
12
|
+
@buffer = ""
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute
|
16
|
+
initial_timeout = @component_node.initial_timeout || -1
|
17
|
+
@inter_digit_timeout = @component_node.inter_digit_timeout || -1
|
18
|
+
|
19
|
+
return with_error 'option error', 'A grammar document is required.' unless @component_node.grammar
|
20
|
+
return with_error 'option error', 'A mode value other than DTMF is unsupported on Asterisk.' unless @component_node.mode == :dtmf
|
21
|
+
return with_error 'option error', 'An initial timeout value that is negative (and not -1) is invalid.' unless initial_timeout >= -1
|
22
|
+
return with_error 'option error', 'An inter-digit timeout value that is negative (and not -1) is invalid.' unless @inter_digit_timeout >= -1
|
23
|
+
|
24
|
+
send_ref
|
25
|
+
|
26
|
+
case @media_engine
|
27
|
+
when :asterisk, nil
|
28
|
+
@grammar = @component_node.grammar.value.clone
|
29
|
+
grammar.inline!
|
30
|
+
grammar.tokenize!
|
31
|
+
grammar.normalize_whitespace
|
32
|
+
|
33
|
+
begin_initial_timer initial_timeout/1000 unless initial_timeout == -1
|
34
|
+
|
35
|
+
component = current_actor
|
36
|
+
|
37
|
+
@active = true
|
38
|
+
|
39
|
+
call.register_handler :ami, :name => 'DTMF' do |event|
|
40
|
+
component.process_dtmf! event['Digit'] if event['End'] == 'Yes'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def process_dtmf(digit)
|
46
|
+
return unless @active
|
47
|
+
pb_logger.trace "Processing incoming DTMF digit #{digit}"
|
48
|
+
buffer << digit
|
49
|
+
cancel_initial_timer
|
50
|
+
case (match = grammar.match buffer.dup)
|
51
|
+
when RubySpeech::GRXML::Match
|
52
|
+
pb_logger.trace "Found a match against buffer #{buffer}"
|
53
|
+
complete success_reason(match)
|
54
|
+
when RubySpeech::GRXML::NoMatch
|
55
|
+
pb_logger.trace "Buffer #{buffer} does not match grammar"
|
56
|
+
complete Punchblock::Component::Input::Complete::NoMatch.new
|
57
|
+
when RubySpeech::GRXML::PotentialMatch
|
58
|
+
pb_logger.trace "Buffer #{buffer} potentially matches grammar. Waiting..."
|
59
|
+
reset_inter_digit_timer
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def begin_initial_timer(timeout)
|
66
|
+
pb_logger.trace "Setting initial timer for #{timeout} seconds"
|
67
|
+
@initial_timer = after timeout do
|
68
|
+
pb_logger.trace "Initial timer expired."
|
69
|
+
complete Punchblock::Component::Input::Complete::NoInput.new
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def cancel_initial_timer
|
74
|
+
return unless @initial_timer
|
75
|
+
@initial_timer.cancel
|
76
|
+
@initial_timer = nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def reset_inter_digit_timer
|
80
|
+
return if @inter_digit_timeout == -1
|
81
|
+
@inter_digit_timer ||= begin
|
82
|
+
pb_logger.trace "Setting inter-digit timer for #{@inter_digit_timeout/1000} seconds"
|
83
|
+
after @inter_digit_timeout/1000 do
|
84
|
+
pb_logger.trace "Inter digit-timer expired."
|
85
|
+
complete Punchblock::Component::Input::Complete::NoMatch.new
|
86
|
+
end
|
87
|
+
end
|
88
|
+
pb_logger.trace "Resetting inter-digit timer"
|
89
|
+
@inter_digit_timer.reset
|
90
|
+
end
|
91
|
+
|
92
|
+
def cancel_inter_digit_timer
|
93
|
+
return unless @inter_digit_timer
|
94
|
+
@inter_digit_timer.cancel
|
95
|
+
@inter_digit_timer = nil
|
96
|
+
end
|
97
|
+
|
98
|
+
def success_reason(match)
|
99
|
+
Punchblock::Component::Input::Complete::Success.new :mode => match.mode,
|
100
|
+
:confidence => match.confidence,
|
101
|
+
:utterance => match.utterance,
|
102
|
+
:interpretation => match.interpretation
|
103
|
+
end
|
104
|
+
|
105
|
+
def complete(reason)
|
106
|
+
@active = false
|
107
|
+
cancel_initial_timer
|
108
|
+
cancel_inter_digit_timer
|
109
|
+
send_event complete_event(reason)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/punchblock/version.rb
CHANGED
data/punchblock.gemspec
CHANGED
@@ -30,10 +30,10 @@ Gem::Specification.new do |s|
|
|
30
30
|
s.add_runtime_dependency %q<has-guarded-handlers>, [">= 0.1.0"]
|
31
31
|
s.add_runtime_dependency %q<celluloid>, [">= 0.6.0"]
|
32
32
|
s.add_runtime_dependency %q<ruby_ami>, [">= 0.1.3"]
|
33
|
-
s.add_runtime_dependency %q<ruby_speech>, [">= 0.
|
33
|
+
s.add_runtime_dependency %q<ruby_speech>, [">= 0.5.1"]
|
34
34
|
|
35
35
|
s.add_development_dependency %q<bundler>, ["~> 1.0.0"]
|
36
|
-
s.add_development_dependency %q<rspec>, ["
|
36
|
+
s.add_development_dependency %q<rspec>, ["~> 2.7.0"]
|
37
37
|
s.add_development_dependency %q<ci_reporter>, [">= 1.6.3"]
|
38
38
|
s.add_development_dependency %q<yard>, ["~> 0.6.0"]
|
39
39
|
s.add_development_dependency %q<rcov>, [">= 0"]
|
@@ -192,6 +192,21 @@ module Punchblock
|
|
192
192
|
its(:confidence) { should == 0.45 }
|
193
193
|
its(:interpretation) { should == '1234' }
|
194
194
|
its(:utterance) { should == 'one two three four' }
|
195
|
+
|
196
|
+
describe "when setting options in initializer" do
|
197
|
+
subject do
|
198
|
+
Input::Complete::Success.new :mode => :dtmf,
|
199
|
+
:confidence => 1,
|
200
|
+
:utterance => '123',
|
201
|
+
:interpretation => 'dtmf-1 dtmf-2 dtmf-3'
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
its(:mode) { should == :dtmf }
|
206
|
+
its(:confidence) { should == 1 }
|
207
|
+
its(:utterance) { should == '123' }
|
208
|
+
its(:interpretation) { should == 'dtmf-1 dtmf-2 dtmf-3' }
|
209
|
+
end
|
195
210
|
end
|
196
211
|
|
197
212
|
describe Input::Complete::NoMatch do
|
@@ -130,6 +130,28 @@ module Punchblock
|
|
130
130
|
subject.process_ami_event ami_event
|
131
131
|
end
|
132
132
|
end
|
133
|
+
|
134
|
+
context 'with a handler registered for a matching event' do
|
135
|
+
let :ami_event do
|
136
|
+
RubyAMI::Event.new('DTMF').tap do |e|
|
137
|
+
e['Digit'] = '4'
|
138
|
+
e['Start'] = 'Yes'
|
139
|
+
e['End'] = 'No'
|
140
|
+
e['Uniqueid'] = "1320842458.8"
|
141
|
+
e['Channel'] = "SIP/1234-00000000"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
let(:response) { mock 'Response' }
|
146
|
+
|
147
|
+
it 'should execute the handler' do
|
148
|
+
response.expects(:call).once.with ami_event
|
149
|
+
subject.register_handler :ami, :name => 'DTMF' do |event|
|
150
|
+
response.call event
|
151
|
+
end
|
152
|
+
subject.process_ami_event ami_event
|
153
|
+
end
|
154
|
+
end
|
133
155
|
end
|
134
156
|
|
135
157
|
describe '#execute_command' do
|
@@ -211,6 +233,20 @@ module Punchblock
|
|
211
233
|
end
|
212
234
|
end
|
213
235
|
|
236
|
+
context 'with an Input component' do
|
237
|
+
let :command do
|
238
|
+
Punchblock::Component::Input.new
|
239
|
+
end
|
240
|
+
|
241
|
+
let(:mock_action) { mock 'Component::Asterisk::Input', :id => 'foo' }
|
242
|
+
|
243
|
+
it 'should create an AGI command component actor and execute it asynchronously' do
|
244
|
+
Component::Asterisk::Input.expects(:new).once.with(command, subject).returns mock_action
|
245
|
+
mock_action.expects(:execute!).once
|
246
|
+
subject.execute_command command
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
214
250
|
context 'with a component command' do
|
215
251
|
let(:component_id) { 'foobar' }
|
216
252
|
|
@@ -0,0 +1,268 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Punchblock
|
4
|
+
module Translator
|
5
|
+
class Asterisk
|
6
|
+
module Component
|
7
|
+
module Asterisk
|
8
|
+
describe Input do
|
9
|
+
let(:media_engine) { nil }
|
10
|
+
let(:translator) { Punchblock::Translator::Asterisk.new mock('AMI'), mock('Client'), media_engine }
|
11
|
+
let(:call) { Punchblock::Translator::Asterisk::Call.new 'foo', translator }
|
12
|
+
let(:command_options) { nil }
|
13
|
+
|
14
|
+
let :command do
|
15
|
+
Punchblock::Component::Input.new command_options
|
16
|
+
end
|
17
|
+
|
18
|
+
let :grammar do
|
19
|
+
RubySpeech::GRXML.draw :mode => 'dtmf', :root => 'pin' do
|
20
|
+
rule id: 'digit' do
|
21
|
+
one_of do
|
22
|
+
0.upto(9) { |d| item { d.to_s } }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
rule id: 'pin', scope: 'public' do
|
27
|
+
item repeat: '2' do
|
28
|
+
ruleref uri: '#digit'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
let :command_options do
|
35
|
+
{
|
36
|
+
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
subject { Input.new command, call }
|
41
|
+
|
42
|
+
describe '#execute' do
|
43
|
+
before { command.request! }
|
44
|
+
|
45
|
+
context 'with a media engine of :unimrcp' do
|
46
|
+
pending
|
47
|
+
let(:media_engine) { :unimrcp }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with a media engine of :asterisk' do
|
51
|
+
let(:media_engine) { :asterisk }
|
52
|
+
|
53
|
+
let(:command_opts) { {} }
|
54
|
+
|
55
|
+
let :command_options do
|
56
|
+
{ :mode => :dtmf, :grammar => { :value => grammar } }.merge(command_opts)
|
57
|
+
end
|
58
|
+
|
59
|
+
def ami_event_for_dtmf(digit, position)
|
60
|
+
RubyAMI::Event.new('DTMF').tap do |e|
|
61
|
+
e['Digit'] = digit.to_s
|
62
|
+
e['Start'] = position == :start ? 'Yes' : 'No'
|
63
|
+
e['End'] = position == :end ? 'Yes' : 'No'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def send_ami_events_for_dtmf(digit)
|
68
|
+
call.process_ami_event ami_event_for_dtmf(digit, :start)
|
69
|
+
call.process_ami_event ami_event_for_dtmf(digit, :end)
|
70
|
+
end
|
71
|
+
|
72
|
+
let(:reason) { command.complete_event(5).reason }
|
73
|
+
|
74
|
+
describe "receiving DTMF events" do
|
75
|
+
before { subject.execute }
|
76
|
+
|
77
|
+
context "when a match is found" do
|
78
|
+
before do
|
79
|
+
send_ami_events_for_dtmf 1
|
80
|
+
send_ami_events_for_dtmf 2
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should send a success complete event with the relevant data" do
|
84
|
+
reason.should == Punchblock::Component::Input::Complete::Success.new(:mode => :dtmf, :confidence => 1, :utterance => '12', :interpretation => 'dtmf-1 dtmf-2', :component_id => subject.id)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when the match is invalid" do
|
89
|
+
before do
|
90
|
+
send_ami_events_for_dtmf 1
|
91
|
+
send_ami_events_for_dtmf '#'
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should send a nomatch complete event" do
|
95
|
+
reason.should == Punchblock::Component::Input::Complete::NoMatch.new(:component_id => subject.id)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe 'grammar' do
|
101
|
+
context 'unset' do
|
102
|
+
let(:command_opts) { { :grammar => nil } }
|
103
|
+
it "should return an error and not execute any actions" do
|
104
|
+
subject.execute
|
105
|
+
error = ProtocolError.new 'option error', 'A grammar document is required.'
|
106
|
+
command.response(0.1).should == error
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'mode' do
|
112
|
+
context 'unset' do
|
113
|
+
let(:command_opts) { { :mode => nil } }
|
114
|
+
it "should return an error and not execute any actions" do
|
115
|
+
subject.execute
|
116
|
+
error = ProtocolError.new 'option error', 'A mode value other than DTMF is unsupported on Asterisk.'
|
117
|
+
command.response(0.1).should == error
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'any' do
|
122
|
+
let(:command_opts) { { :mode => :any } }
|
123
|
+
it "should return an error and not execute any actions" do
|
124
|
+
subject.execute
|
125
|
+
error = ProtocolError.new 'option error', 'A mode value other than DTMF is unsupported on Asterisk.'
|
126
|
+
command.response(0.1).should == error
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'speech' do
|
131
|
+
let(:command_opts) { { :mode => :speech } }
|
132
|
+
it "should return an error and not execute any actions" do
|
133
|
+
subject.execute
|
134
|
+
error = ProtocolError.new 'option error', 'A mode value other than DTMF is unsupported on Asterisk.'
|
135
|
+
command.response(0.1).should == error
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe 'terminator' do
|
141
|
+
pending
|
142
|
+
end
|
143
|
+
|
144
|
+
describe 'recognizer' do
|
145
|
+
pending
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'initial-timeout' do
|
149
|
+
context 'a positive number' do
|
150
|
+
let(:command_opts) { { :initial_timeout => 1000 } }
|
151
|
+
|
152
|
+
it "should not cause a NoInput if first input is received in time" do
|
153
|
+
subject.execute
|
154
|
+
send_ami_events_for_dtmf 1
|
155
|
+
sleep 1.5
|
156
|
+
send_ami_events_for_dtmf 2
|
157
|
+
reason.should be_a Punchblock::Component::Input::Complete::Success
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should cause a NoInput complete event to be sent after the timeout" do
|
161
|
+
subject.execute
|
162
|
+
sleep 1.5
|
163
|
+
send_ami_events_for_dtmf 1
|
164
|
+
send_ami_events_for_dtmf 2
|
165
|
+
reason.should be_a Punchblock::Component::Input::Complete::NoInput
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context '-1' do
|
170
|
+
let(:command_opts) { { :initial_timeout => -1 } }
|
171
|
+
|
172
|
+
it "should not start a timer" do
|
173
|
+
subject.wrapped_object.expects(:begin_initial_timer).never
|
174
|
+
subject.execute
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context 'unset' do
|
179
|
+
let(:command_opts) { { :initial_timeout => nil } }
|
180
|
+
|
181
|
+
it "should not start a timer" do
|
182
|
+
subject.wrapped_object.expects(:begin_initial_timer).never
|
183
|
+
subject.execute
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'a negative number other than -1' do
|
188
|
+
let(:command_opts) { { :initial_timeout => -1000 } }
|
189
|
+
|
190
|
+
it "should return an error and not execute any actions" do
|
191
|
+
subject.execute
|
192
|
+
error = ProtocolError.new 'option error', 'An initial timeout value that is negative (and not -1) is invalid.'
|
193
|
+
command.response(0.1).should == error
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe 'inter-digit-timeout' do
|
199
|
+
context 'a positive number' do
|
200
|
+
let(:command_opts) { { :inter_digit_timeout => 1000 } }
|
201
|
+
|
202
|
+
it "should not prevent a Match if input is received in time" do
|
203
|
+
subject.execute
|
204
|
+
sleep 1.5
|
205
|
+
send_ami_events_for_dtmf 1
|
206
|
+
sleep 0.5
|
207
|
+
send_ami_events_for_dtmf 2
|
208
|
+
reason.should be_a Punchblock::Component::Input::Complete::Success
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should cause a NoMatch complete event to be sent after the timeout" do
|
212
|
+
subject.execute
|
213
|
+
sleep 1.5
|
214
|
+
send_ami_events_for_dtmf 1
|
215
|
+
sleep 1.5
|
216
|
+
send_ami_events_for_dtmf 2
|
217
|
+
reason.should be_a Punchblock::Component::Input::Complete::NoMatch
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context '-1' do
|
222
|
+
let(:command_opts) { { :inter_digit_timeout => -1 } }
|
223
|
+
|
224
|
+
it "should not start a timer" do
|
225
|
+
subject.wrapped_object.expects(:begin_inter_digit_timer).never
|
226
|
+
subject.execute
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
context 'unset' do
|
231
|
+
let(:command_opts) { { :inter_digit_timeout => nil } }
|
232
|
+
|
233
|
+
it "should not start a timer" do
|
234
|
+
subject.wrapped_object.expects(:begin_inter_digit_timer).never
|
235
|
+
subject.execute
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
context 'a negative number other than -1' do
|
240
|
+
let(:command_opts) { { :inter_digit_timeout => -1000 } }
|
241
|
+
|
242
|
+
it "should return an error and not execute any actions" do
|
243
|
+
subject.execute
|
244
|
+
error = ProtocolError.new 'option error', 'An inter-digit timeout value that is negative (and not -1) is invalid.'
|
245
|
+
command.response(0.1).should == error
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
describe 'sensitivity' do
|
251
|
+
pending
|
252
|
+
end
|
253
|
+
|
254
|
+
describe 'min-confidence' do
|
255
|
+
pending
|
256
|
+
end
|
257
|
+
|
258
|
+
describe 'max-silence' do
|
259
|
+
pending
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -10,6 +10,10 @@ RSpec.configure do |config|
|
|
10
10
|
config.mock_with :mocha
|
11
11
|
config.filter_run :focus => true
|
12
12
|
config.run_all_when_everything_filtered = true
|
13
|
+
|
14
|
+
config.before :suite do |variable|
|
15
|
+
Punchblock.logger = Logger.new(STDOUT)
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
def parse_stanza(xml)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: punchblock
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,11 +11,11 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-01-
|
14
|
+
date: 2012-01-09 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: niceogiri
|
18
|
-
requirement: &
|
18
|
+
requirement: &2156232960 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
21
|
- - ! '>='
|
@@ -23,10 +23,10 @@ dependencies:
|
|
23
23
|
version: 0.0.4
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
version_requirements: *
|
26
|
+
version_requirements: *2156232960
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: blather
|
29
|
-
requirement: &
|
29
|
+
requirement: &2156230140 !ruby/object:Gem::Requirement
|
30
30
|
none: false
|
31
31
|
requirements:
|
32
32
|
- - ! '>='
|
@@ -34,10 +34,10 @@ dependencies:
|
|
34
34
|
version: 0.5.12
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
|
-
version_requirements: *
|
37
|
+
version_requirements: *2156230140
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: activesupport
|
40
|
-
requirement: &
|
40
|
+
requirement: &2156227040 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ! '>='
|
@@ -45,10 +45,10 @@ dependencies:
|
|
45
45
|
version: 2.1.0
|
46
46
|
type: :runtime
|
47
47
|
prerelease: false
|
48
|
-
version_requirements: *
|
48
|
+
version_requirements: *2156227040
|
49
49
|
- !ruby/object:Gem::Dependency
|
50
50
|
name: state_machine
|
51
|
-
requirement: &
|
51
|
+
requirement: &2156223280 !ruby/object:Gem::Requirement
|
52
52
|
none: false
|
53
53
|
requirements:
|
54
54
|
- - ! '>='
|
@@ -56,10 +56,10 @@ dependencies:
|
|
56
56
|
version: 1.0.1
|
57
57
|
type: :runtime
|
58
58
|
prerelease: false
|
59
|
-
version_requirements: *
|
59
|
+
version_requirements: *2156223280
|
60
60
|
- !ruby/object:Gem::Dependency
|
61
61
|
name: future-resource
|
62
|
-
requirement: &
|
62
|
+
requirement: &2156218340 !ruby/object:Gem::Requirement
|
63
63
|
none: false
|
64
64
|
requirements:
|
65
65
|
- - ! '>='
|
@@ -67,10 +67,10 @@ dependencies:
|
|
67
67
|
version: 0.0.2
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
|
-
version_requirements: *
|
70
|
+
version_requirements: *2156218340
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: has-guarded-handlers
|
73
|
-
requirement: &
|
73
|
+
requirement: &2156212420 !ruby/object:Gem::Requirement
|
74
74
|
none: false
|
75
75
|
requirements:
|
76
76
|
- - ! '>='
|
@@ -78,10 +78,10 @@ dependencies:
|
|
78
78
|
version: 0.1.0
|
79
79
|
type: :runtime
|
80
80
|
prerelease: false
|
81
|
-
version_requirements: *
|
81
|
+
version_requirements: *2156212420
|
82
82
|
- !ruby/object:Gem::Dependency
|
83
83
|
name: celluloid
|
84
|
-
requirement: &
|
84
|
+
requirement: &2156209840 !ruby/object:Gem::Requirement
|
85
85
|
none: false
|
86
86
|
requirements:
|
87
87
|
- - ! '>='
|
@@ -89,10 +89,10 @@ dependencies:
|
|
89
89
|
version: 0.6.0
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
|
-
version_requirements: *
|
92
|
+
version_requirements: *2156209840
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
94
|
name: ruby_ami
|
95
|
-
requirement: &
|
95
|
+
requirement: &2156188760 !ruby/object:Gem::Requirement
|
96
96
|
none: false
|
97
97
|
requirements:
|
98
98
|
- - ! '>='
|
@@ -100,21 +100,21 @@ dependencies:
|
|
100
100
|
version: 0.1.3
|
101
101
|
type: :runtime
|
102
102
|
prerelease: false
|
103
|
-
version_requirements: *
|
103
|
+
version_requirements: *2156188760
|
104
104
|
- !ruby/object:Gem::Dependency
|
105
105
|
name: ruby_speech
|
106
|
-
requirement: &
|
106
|
+
requirement: &2156167500 !ruby/object:Gem::Requirement
|
107
107
|
none: false
|
108
108
|
requirements:
|
109
109
|
- - ! '>='
|
110
110
|
- !ruby/object:Gem::Version
|
111
|
-
version: 0.
|
111
|
+
version: 0.5.1
|
112
112
|
type: :runtime
|
113
113
|
prerelease: false
|
114
|
-
version_requirements: *
|
114
|
+
version_requirements: *2156167500
|
115
115
|
- !ruby/object:Gem::Dependency
|
116
116
|
name: bundler
|
117
|
-
requirement: &
|
117
|
+
requirement: &2156166720 !ruby/object:Gem::Requirement
|
118
118
|
none: false
|
119
119
|
requirements:
|
120
120
|
- - ~>
|
@@ -122,21 +122,21 @@ dependencies:
|
|
122
122
|
version: 1.0.0
|
123
123
|
type: :development
|
124
124
|
prerelease: false
|
125
|
-
version_requirements: *
|
125
|
+
version_requirements: *2156166720
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
127
|
name: rspec
|
128
|
-
requirement: &
|
128
|
+
requirement: &2156165960 !ruby/object:Gem::Requirement
|
129
129
|
none: false
|
130
130
|
requirements:
|
131
|
-
- -
|
131
|
+
- - ~>
|
132
132
|
- !ruby/object:Gem::Version
|
133
|
-
version: 2.
|
133
|
+
version: 2.7.0
|
134
134
|
type: :development
|
135
135
|
prerelease: false
|
136
|
-
version_requirements: *
|
136
|
+
version_requirements: *2156165960
|
137
137
|
- !ruby/object:Gem::Dependency
|
138
138
|
name: ci_reporter
|
139
|
-
requirement: &
|
139
|
+
requirement: &2156164980 !ruby/object:Gem::Requirement
|
140
140
|
none: false
|
141
141
|
requirements:
|
142
142
|
- - ! '>='
|
@@ -144,10 +144,10 @@ dependencies:
|
|
144
144
|
version: 1.6.3
|
145
145
|
type: :development
|
146
146
|
prerelease: false
|
147
|
-
version_requirements: *
|
147
|
+
version_requirements: *2156164980
|
148
148
|
- !ruby/object:Gem::Dependency
|
149
149
|
name: yard
|
150
|
-
requirement: &
|
150
|
+
requirement: &2156163300 !ruby/object:Gem::Requirement
|
151
151
|
none: false
|
152
152
|
requirements:
|
153
153
|
- - ~>
|
@@ -155,10 +155,10 @@ dependencies:
|
|
155
155
|
version: 0.6.0
|
156
156
|
type: :development
|
157
157
|
prerelease: false
|
158
|
-
version_requirements: *
|
158
|
+
version_requirements: *2156163300
|
159
159
|
- !ruby/object:Gem::Dependency
|
160
160
|
name: rcov
|
161
|
-
requirement: &
|
161
|
+
requirement: &2156162340 !ruby/object:Gem::Requirement
|
162
162
|
none: false
|
163
163
|
requirements:
|
164
164
|
- - ! '>='
|
@@ -166,10 +166,10 @@ dependencies:
|
|
166
166
|
version: '0'
|
167
167
|
type: :development
|
168
168
|
prerelease: false
|
169
|
-
version_requirements: *
|
169
|
+
version_requirements: *2156162340
|
170
170
|
- !ruby/object:Gem::Dependency
|
171
171
|
name: rake
|
172
|
-
requirement: &
|
172
|
+
requirement: &2156161440 !ruby/object:Gem::Requirement
|
173
173
|
none: false
|
174
174
|
requirements:
|
175
175
|
- - ! '>='
|
@@ -177,10 +177,10 @@ dependencies:
|
|
177
177
|
version: '0'
|
178
178
|
type: :development
|
179
179
|
prerelease: false
|
180
|
-
version_requirements: *
|
180
|
+
version_requirements: *2156161440
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: mocha
|
183
|
-
requirement: &
|
183
|
+
requirement: &2156160560 !ruby/object:Gem::Requirement
|
184
184
|
none: false
|
185
185
|
requirements:
|
186
186
|
- - ! '>='
|
@@ -188,10 +188,10 @@ dependencies:
|
|
188
188
|
version: '0'
|
189
189
|
type: :development
|
190
190
|
prerelease: false
|
191
|
-
version_requirements: *
|
191
|
+
version_requirements: *2156160560
|
192
192
|
- !ruby/object:Gem::Dependency
|
193
193
|
name: i18n
|
194
|
-
requirement: &
|
194
|
+
requirement: &2156135140 !ruby/object:Gem::Requirement
|
195
195
|
none: false
|
196
196
|
requirements:
|
197
197
|
- - ! '>='
|
@@ -199,10 +199,10 @@ dependencies:
|
|
199
199
|
version: '0'
|
200
200
|
type: :development
|
201
201
|
prerelease: false
|
202
|
-
version_requirements: *
|
202
|
+
version_requirements: *2156135140
|
203
203
|
- !ruby/object:Gem::Dependency
|
204
204
|
name: countdownlatch
|
205
|
-
requirement: &
|
205
|
+
requirement: &2156134060 !ruby/object:Gem::Requirement
|
206
206
|
none: false
|
207
207
|
requirements:
|
208
208
|
- - ! '>='
|
@@ -210,10 +210,10 @@ dependencies:
|
|
210
210
|
version: '0'
|
211
211
|
type: :development
|
212
212
|
prerelease: false
|
213
|
-
version_requirements: *
|
213
|
+
version_requirements: *2156134060
|
214
214
|
- !ruby/object:Gem::Dependency
|
215
215
|
name: guard-rspec
|
216
|
-
requirement: &
|
216
|
+
requirement: &2156132700 !ruby/object:Gem::Requirement
|
217
217
|
none: false
|
218
218
|
requirements:
|
219
219
|
- - ! '>='
|
@@ -221,7 +221,7 @@ dependencies:
|
|
221
221
|
version: '0'
|
222
222
|
type: :development
|
223
223
|
prerelease: false
|
224
|
-
version_requirements: *
|
224
|
+
version_requirements: *2156132700
|
225
225
|
description: Like Rack is to Rails and Sinatra, Punchblock provides a consistent API
|
226
226
|
on top of several underlying third-party call control protocols.
|
227
227
|
email: punchblock@adhearsion.com
|
@@ -302,6 +302,7 @@ files:
|
|
302
302
|
- lib/punchblock/translator/asterisk/component/asterisk.rb
|
303
303
|
- lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb
|
304
304
|
- lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb
|
305
|
+
- lib/punchblock/translator/asterisk/component/asterisk/input.rb
|
305
306
|
- lib/punchblock/translator/asterisk/component/asterisk/output.rb
|
306
307
|
- lib/punchblock/version.rb
|
307
308
|
- punchblock.gemspec
|
@@ -342,6 +343,7 @@ files:
|
|
342
343
|
- spec/punchblock/translator/asterisk/call_spec.rb
|
343
344
|
- spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb
|
344
345
|
- spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb
|
346
|
+
- spec/punchblock/translator/asterisk/component/asterisk/input_spec.rb
|
345
347
|
- spec/punchblock/translator/asterisk/component/asterisk/output_spec.rb
|
346
348
|
- spec/punchblock/translator/asterisk/component_spec.rb
|
347
349
|
- spec/punchblock/translator/asterisk_spec.rb
|
@@ -361,7 +363,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
361
363
|
version: '0'
|
362
364
|
segments:
|
363
365
|
- 0
|
364
|
-
hash: -
|
366
|
+
hash: -3178520051176557915
|
365
367
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
366
368
|
none: false
|
367
369
|
requirements:
|
@@ -412,6 +414,7 @@ test_files:
|
|
412
414
|
- spec/punchblock/translator/asterisk/call_spec.rb
|
413
415
|
- spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb
|
414
416
|
- spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb
|
417
|
+
- spec/punchblock/translator/asterisk/component/asterisk/input_spec.rb
|
415
418
|
- spec/punchblock/translator/asterisk/component/asterisk/output_spec.rb
|
416
419
|
- spec/punchblock/translator/asterisk/component_spec.rb
|
417
420
|
- spec/punchblock/translator/asterisk_spec.rb
|