punchblock 0.8.0 → 0.8.1

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 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
- find_first('//ns:interpretation', :ns => self.registered_ns).text
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
- find_first('//ns:utterance', :ns => self.registered_ns).text
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
@@ -7,6 +7,7 @@ module Punchblock
7
7
 
8
8
  autoload :AGICommand
9
9
  autoload :AMIAction
10
+ autoload :Input
10
11
  autoload :Output
11
12
  end
12
13
  end
@@ -9,7 +9,7 @@ module Punchblock
9
9
  class Component
10
10
  include Celluloid
11
11
 
12
- attr_reader :id
12
+ attr_reader :id, :call
13
13
 
14
14
  def initialize(component_node, call = nil)
15
15
  @component_node, @call = component_node, call
@@ -1,3 +1,3 @@
1
1
  module Punchblock
2
- VERSION = "0.8.0"
2
+ VERSION = "0.8.1"
3
3
  end
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.3.4"]
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>, [">= 2.5.0"]
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.0
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-06 00:00:00.000000000 Z
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: &2152641860 !ruby/object:Gem::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: *2152641860
26
+ version_requirements: *2156232960
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: blather
29
- requirement: &2152641280 !ruby/object:Gem::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: *2152641280
37
+ version_requirements: *2156230140
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: activesupport
40
- requirement: &2152640660 !ruby/object:Gem::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: *2152640660
48
+ version_requirements: *2156227040
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: state_machine
51
- requirement: &2152639980 !ruby/object:Gem::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: *2152639980
59
+ version_requirements: *2156223280
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: future-resource
62
- requirement: &2152639220 !ruby/object:Gem::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: *2152639220
70
+ version_requirements: *2156218340
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: has-guarded-handlers
73
- requirement: &2152638480 !ruby/object:Gem::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: *2152638480
81
+ version_requirements: *2156212420
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: celluloid
84
- requirement: &2152637500 !ruby/object:Gem::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: *2152637500
92
+ version_requirements: *2156209840
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: ruby_ami
95
- requirement: &2152636520 !ruby/object:Gem::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: *2152636520
103
+ version_requirements: *2156188760
104
104
  - !ruby/object:Gem::Dependency
105
105
  name: ruby_speech
106
- requirement: &2152635380 !ruby/object:Gem::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.3.4
111
+ version: 0.5.1
112
112
  type: :runtime
113
113
  prerelease: false
114
- version_requirements: *2152635380
114
+ version_requirements: *2156167500
115
115
  - !ruby/object:Gem::Dependency
116
116
  name: bundler
117
- requirement: &2152634520 !ruby/object:Gem::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: *2152634520
125
+ version_requirements: *2156166720
126
126
  - !ruby/object:Gem::Dependency
127
127
  name: rspec
128
- requirement: &2152633440 !ruby/object:Gem::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.5.0
133
+ version: 2.7.0
134
134
  type: :development
135
135
  prerelease: false
136
- version_requirements: *2152633440
136
+ version_requirements: *2156165960
137
137
  - !ruby/object:Gem::Dependency
138
138
  name: ci_reporter
139
- requirement: &2152632400 !ruby/object:Gem::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: *2152632400
147
+ version_requirements: *2156164980
148
148
  - !ruby/object:Gem::Dependency
149
149
  name: yard
150
- requirement: &2152631620 !ruby/object:Gem::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: *2152631620
158
+ version_requirements: *2156163300
159
159
  - !ruby/object:Gem::Dependency
160
160
  name: rcov
161
- requirement: &2152630600 !ruby/object:Gem::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: *2152630600
169
+ version_requirements: *2156162340
170
170
  - !ruby/object:Gem::Dependency
171
171
  name: rake
172
- requirement: &2152629520 !ruby/object:Gem::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: *2152629520
180
+ version_requirements: *2156161440
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: mocha
183
- requirement: &2152622020 !ruby/object:Gem::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: *2152622020
191
+ version_requirements: *2156160560
192
192
  - !ruby/object:Gem::Dependency
193
193
  name: i18n
194
- requirement: &2152620880 !ruby/object:Gem::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: *2152620880
202
+ version_requirements: *2156135140
203
203
  - !ruby/object:Gem::Dependency
204
204
  name: countdownlatch
205
- requirement: &2152619940 !ruby/object:Gem::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: *2152619940
213
+ version_requirements: *2156134060
214
214
  - !ruby/object:Gem::Dependency
215
215
  name: guard-rspec
216
- requirement: &2152619460 !ruby/object:Gem::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: *2152619460
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: -4143902595723607278
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