punchblock 1.9.4 → 2.0.0.beta1
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -2
- data/CHANGELOG.md +17 -0
- data/Gemfile +1 -0
- data/Guardfile +4 -0
- data/README.markdown +6 -0
- data/Rakefile +16 -0
- data/benchmarks/ami_event_name_comparison.rb +14 -0
- data/benchmarks/channel.rb +27 -0
- data/lib/punchblock/client.rb +2 -6
- data/lib/punchblock/command/accept.rb +3 -24
- data/lib/punchblock/command/answer.rb +3 -24
- data/lib/punchblock/command/dial.rb +24 -76
- data/lib/punchblock/command/hangup.rb +3 -19
- data/lib/punchblock/command/join.rb +21 -70
- data/lib/punchblock/command/mute.rb +3 -3
- data/lib/punchblock/command/redirect.rb +6 -39
- data/lib/punchblock/command/reject.rb +14 -54
- data/lib/punchblock/command/unjoin.rb +8 -40
- data/lib/punchblock/command/unmute.rb +3 -3
- data/lib/punchblock/command_node.rb +0 -17
- data/lib/punchblock/component/asterisk/agi/command.rb +20 -127
- data/lib/punchblock/component/asterisk/ami/action.rb +30 -117
- data/lib/punchblock/component/component_node.rb +1 -1
- data/lib/punchblock/component/input.rb +89 -268
- data/lib/punchblock/component/output.rb +106 -154
- data/lib/punchblock/component/prompt.rb +51 -0
- data/lib/punchblock/component/record.rb +41 -130
- data/lib/punchblock/component.rb +1 -0
- data/lib/punchblock/connection/asterisk.rb +31 -4
- data/lib/punchblock/connection/xmpp.rb +6 -14
- data/lib/punchblock/core_ext/blather/stanza.rb +1 -1
- data/lib/punchblock/event/active_speaker.rb +2 -10
- data/lib/punchblock/event/answered.rb +3 -3
- data/lib/punchblock/event/asterisk/ami/event.rb +15 -47
- data/lib/punchblock/event/complete.rb +26 -48
- data/lib/punchblock/event/dtmf.rb +3 -13
- data/lib/punchblock/event/end.rb +10 -11
- data/lib/punchblock/event/joined.rb +5 -25
- data/lib/punchblock/event/offer.rb +4 -25
- data/lib/punchblock/event/ringing.rb +3 -3
- data/lib/punchblock/event/unjoined.rb +5 -25
- data/lib/punchblock/event.rb +0 -10
- data/lib/punchblock/has_headers.rb +20 -26
- data/lib/punchblock/rayo_node.rb +46 -23
- data/lib/punchblock/ref.rb +39 -18
- data/lib/punchblock/translator/asterisk/agi_app.rb +15 -0
- data/lib/punchblock/translator/asterisk/agi_command.rb +3 -1
- data/lib/punchblock/translator/asterisk/ami_error_converter.rb +20 -0
- data/lib/punchblock/translator/asterisk/call.rb +60 -39
- data/lib/punchblock/translator/asterisk/channel.rb +41 -0
- data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +4 -1
- data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +4 -4
- data/lib/punchblock/translator/asterisk/component/composed_prompt.rb +62 -0
- data/lib/punchblock/translator/asterisk/component/input.rb +1 -0
- data/lib/punchblock/translator/asterisk/component/mrcp_native_prompt.rb +56 -0
- data/lib/punchblock/translator/asterisk/component/mrcp_prompt.rb +53 -0
- data/lib/punchblock/translator/asterisk/component/mrcp_recog_prompt.rb +99 -0
- data/lib/punchblock/translator/asterisk/component/output.rb +30 -22
- data/lib/punchblock/translator/asterisk/component/record.rb +8 -6
- data/lib/punchblock/translator/asterisk/component.rb +6 -5
- data/lib/punchblock/translator/asterisk/unimrcp_app.rb +26 -0
- data/lib/punchblock/translator/asterisk.rb +24 -28
- data/lib/punchblock/translator/dtmf_recognizer.rb +39 -20
- data/lib/punchblock/translator/freeswitch/call.rb +15 -14
- data/lib/punchblock/translator/freeswitch/component/abstract_output.rb +5 -4
- data/lib/punchblock/translator/freeswitch/component/flite_output.rb +1 -1
- data/lib/punchblock/translator/freeswitch/component/input.rb +5 -0
- data/lib/punchblock/translator/freeswitch/component/output.rb +2 -2
- data/lib/punchblock/translator/freeswitch/component/record.rb +19 -13
- data/lib/punchblock/translator/freeswitch/component/tts_output.rb +2 -2
- data/lib/punchblock/translator/freeswitch/component.rb +2 -5
- data/lib/punchblock/translator/freeswitch.rb +2 -2
- data/lib/punchblock/translator/input_component.rb +33 -13
- data/lib/punchblock/uri_list.rb +21 -0
- data/lib/punchblock/version.rb +1 -1
- data/lib/punchblock.rb +4 -3
- data/punchblock.gemspec +7 -3
- data/spec/punchblock/client/component_registry_spec.rb +1 -1
- data/spec/punchblock/client_spec.rb +10 -26
- data/spec/punchblock/command/accept_spec.rb +41 -7
- data/spec/punchblock/command/answer_spec.rb +51 -7
- data/spec/punchblock/command/dial_spec.rb +56 -14
- data/spec/punchblock/command/hangup_spec.rb +41 -7
- data/spec/punchblock/command/join_spec.rb +53 -11
- data/spec/punchblock/command/mute_spec.rb +19 -4
- data/spec/punchblock/command/redirect_spec.rb +40 -10
- data/spec/punchblock/command/reject_spec.rb +43 -11
- data/spec/punchblock/command/unjoin_spec.rb +40 -9
- data/spec/punchblock/command/unmute_spec.rb +19 -4
- data/spec/punchblock/command_node_spec.rb +0 -4
- data/spec/punchblock/component/asterisk/agi/command_spec.rb +16 -39
- data/spec/punchblock/component/asterisk/ami/action_spec.rb +50 -53
- data/spec/punchblock/component/component_node_spec.rb +3 -5
- data/spec/punchblock/component/input_spec.rb +194 -61
- data/spec/punchblock/component/output_spec.rb +194 -62
- data/spec/punchblock/component/prompt_spec.rb +132 -0
- data/spec/punchblock/component/record_spec.rb +70 -32
- data/spec/punchblock/connection/asterisk_spec.rb +17 -3
- data/spec/punchblock/connection/freeswitch_spec.rb +4 -4
- data/spec/punchblock/connection/xmpp_spec.rb +20 -38
- data/spec/punchblock/event/answered_spec.rb +12 -10
- data/spec/punchblock/event/asterisk/ami/event_spec.rb +27 -22
- data/spec/punchblock/event/complete_spec.rb +15 -19
- data/spec/punchblock/event/dtmf_spec.rb +5 -6
- data/spec/punchblock/event/end_spec.rb +20 -10
- data/spec/punchblock/event/joined_spec.rb +8 -7
- data/spec/punchblock/event/offer_spec.rb +41 -12
- data/spec/punchblock/event/ringing_spec.rb +12 -10
- data/spec/punchblock/event/started_speaking_spec.rb +5 -6
- data/spec/punchblock/event/stopped_speaking_spec.rb +5 -6
- data/spec/punchblock/event/unjoined_spec.rb +7 -7
- data/spec/punchblock/ref_spec.rb +86 -9
- data/spec/punchblock/translator/asterisk/call_spec.rb +317 -154
- data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +28 -5
- data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +15 -13
- data/spec/punchblock/translator/asterisk/component/composed_prompt_spec.rb +237 -0
- data/spec/punchblock/translator/asterisk/component/input_spec.rb +171 -14
- data/spec/punchblock/translator/asterisk/component/mrcp_native_prompt_spec.rb +652 -0
- data/spec/punchblock/translator/asterisk/component/mrcp_prompt_spec.rb +646 -0
- data/spec/punchblock/translator/asterisk/component/output_spec.rb +127 -77
- data/spec/punchblock/translator/asterisk/component/record_spec.rb +17 -8
- data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +2 -2
- data/spec/punchblock/translator/asterisk/component_spec.rb +3 -7
- data/spec/punchblock/translator/asterisk_spec.rb +20 -24
- data/spec/punchblock/translator/freeswitch/call_spec.rb +103 -99
- data/spec/punchblock/translator/freeswitch/component/flite_output_spec.rb +17 -8
- data/spec/punchblock/translator/freeswitch/component/input_spec.rb +26 -14
- data/spec/punchblock/translator/freeswitch/component/output_spec.rb +30 -52
- data/spec/punchblock/translator/freeswitch/component/record_spec.rb +23 -19
- data/spec/punchblock/translator/freeswitch/component/tts_output_spec.rb +18 -8
- data/spec/punchblock/translator/freeswitch/component_spec.rb +4 -8
- data/spec/punchblock/translator/freeswitch_spec.rb +11 -14
- data/spec/punchblock/uri_list_spec.rb +49 -0
- data/spec/punchblock_spec.rb +11 -1
- data/spec/spec_helper.rb +7 -11
- data/spec/support/mock_connection_with_event_handler.rb +1 -1
- metadata +104 -24
- data/lib/punchblock/header.rb +0 -9
- data/lib/punchblock/key_value_pair_node.rb +0 -51
- data/spec/punchblock/header_spec.rb +0 -11
|
@@ -8,7 +8,7 @@ module Punchblock
|
|
|
8
8
|
module AMI
|
|
9
9
|
describe Action do
|
|
10
10
|
it 'registers itself' do
|
|
11
|
-
RayoNode.class_from_registration(:action, 'urn:xmpp:rayo:asterisk:ami:1').should be ==
|
|
11
|
+
RayoNode.class_from_registration(:action, 'urn:xmpp:rayo:asterisk:ami:1').should be == described_class
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
describe "from a stanza" do
|
|
@@ -27,31 +27,21 @@ module Punchblock
|
|
|
27
27
|
MESSAGE
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
subject { RayoNode.
|
|
30
|
+
subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
|
|
31
31
|
|
|
32
|
-
it { should be_instance_of
|
|
32
|
+
it { should be_instance_of described_class }
|
|
33
33
|
|
|
34
34
|
it_should_behave_like 'event'
|
|
35
35
|
|
|
36
36
|
its(:name) { should be == 'Originate' }
|
|
37
|
-
its(:params) { should be ==
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
]}
|
|
46
|
-
|
|
47
|
-
its(:params_hash) { should be == {:channel => 'SIP/101test',
|
|
48
|
-
:context => 'default',
|
|
49
|
-
:exten => '8135551212',
|
|
50
|
-
:priority => '1',
|
|
51
|
-
:callerid => '3125551212',
|
|
52
|
-
:timeout => '30000',
|
|
53
|
-
:variable => 'var1=23|var2=24|var3=25',
|
|
54
|
-
:async => '1'} }
|
|
37
|
+
its(:params) { should be == { 'Channel' => 'SIP/101test',
|
|
38
|
+
'Context' => 'default',
|
|
39
|
+
'Exten' => '8135551212',
|
|
40
|
+
'Priority' => '1',
|
|
41
|
+
'Callerid' => '3125551212',
|
|
42
|
+
'Timeout' => '30000',
|
|
43
|
+
'Variable' => 'var1=23|var2=24|var3=25',
|
|
44
|
+
'Async' => '1'} }
|
|
55
45
|
end
|
|
56
46
|
|
|
57
47
|
describe "testing equality" do
|
|
@@ -76,22 +66,32 @@ module Punchblock
|
|
|
76
66
|
|
|
77
67
|
describe "when setting options in initializer" do
|
|
78
68
|
subject do
|
|
79
|
-
|
|
80
|
-
|
|
69
|
+
described_class.new :name => 'Originate',
|
|
70
|
+
:params => { 'Channel' => 'SIP/101test' }
|
|
81
71
|
end
|
|
82
72
|
|
|
83
|
-
its(:name)
|
|
84
|
-
its(:params)
|
|
85
|
-
|
|
86
|
-
|
|
73
|
+
its(:name) { should be == 'Originate' }
|
|
74
|
+
its(:params) { should be == { 'Channel' => 'SIP/101test' } }
|
|
75
|
+
|
|
76
|
+
describe "exporting to Rayo" do
|
|
77
|
+
it "should export to XML that can be understood by its parser" do
|
|
78
|
+
new_instance = RayoNode.from_xml subject.to_rayo
|
|
79
|
+
new_instance.should be_instance_of described_class
|
|
80
|
+
new_instance.name.should == 'Originate'
|
|
81
|
+
new_instance.params.should == { 'Channel' => 'SIP/101test' }
|
|
82
|
+
end
|
|
87
83
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
84
|
+
it "should render to a parent node if supplied" do
|
|
85
|
+
doc = Nokogiri::XML::Document.new
|
|
86
|
+
parent = Nokogiri::XML::Node.new 'foo', doc
|
|
87
|
+
doc.root = parent
|
|
88
|
+
rayo_doc = subject.to_rayo(parent)
|
|
89
|
+
rayo_doc.should == parent
|
|
90
|
+
end
|
|
93
91
|
end
|
|
92
|
+
end
|
|
94
93
|
|
|
94
|
+
class Action
|
|
95
95
|
class Complete
|
|
96
96
|
describe Success do
|
|
97
97
|
let :stanza do
|
|
@@ -99,6 +99,7 @@ module Punchblock
|
|
|
99
99
|
<complete xmlns="urn:xmpp:rayo:ext:1">
|
|
100
100
|
<success xmlns="urn:xmpp:rayo:asterisk:ami:complete:1">
|
|
101
101
|
<message>Originate successfully queued</message>
|
|
102
|
+
<text-body>Some thing happened</text-body>
|
|
102
103
|
<attribute name="Channel" value="SIP/101-3f3f"/>
|
|
103
104
|
<attribute name="State" value="Ring"/>
|
|
104
105
|
</success>
|
|
@@ -106,35 +107,31 @@ module Punchblock
|
|
|
106
107
|
MESSAGE
|
|
107
108
|
end
|
|
108
109
|
|
|
109
|
-
subject { RayoNode.
|
|
110
|
+
subject { RayoNode.from_xml(parse_stanza(stanza).root).reason }
|
|
110
111
|
|
|
111
|
-
it { should be_instance_of
|
|
112
|
+
it { should be_instance_of described_class }
|
|
112
113
|
|
|
113
|
-
its(:name)
|
|
114
|
-
its(:message)
|
|
115
|
-
its(:
|
|
116
|
-
its(:
|
|
114
|
+
its(:name) { should be == :success }
|
|
115
|
+
its(:message) { should be == "Originate successfully queued" }
|
|
116
|
+
its(:text_body) { should be == 'Some thing happened' }
|
|
117
|
+
its(:headers) { should be == {'Channel' => 'SIP/101-3f3f', 'State' => 'Ring'} }
|
|
118
|
+
its(:attributes) { should be == {'Channel' => 'SIP/101-3f3f', 'State' => 'Ring'} } # For BC
|
|
117
119
|
|
|
118
120
|
describe "when setting options in initializer" do
|
|
119
121
|
subject do
|
|
120
|
-
|
|
122
|
+
described_class.new message: 'Originate successfully queued', text_body: 'Some thing happened', headers: {'Channel' => 'SIP/101-3f3f', 'State' => 'Ring'}
|
|
121
123
|
end
|
|
122
124
|
|
|
123
|
-
its(:message)
|
|
124
|
-
its(:
|
|
125
|
-
its(:
|
|
125
|
+
its(:message) { should be == 'Originate successfully queued' }
|
|
126
|
+
its(:text_body) { should be == 'Some thing happened' }
|
|
127
|
+
its(:headers) { should be == {'Channel' => 'SIP/101-3f3f', 'State' => 'Ring'} }
|
|
128
|
+
its(:attributes) { should be == {'Channel' => 'SIP/101-3f3f', 'State' => 'Ring'} } # For BC
|
|
126
129
|
end
|
|
127
130
|
end
|
|
128
|
-
|
|
129
|
-
describe Attribute do
|
|
130
|
-
let(:class_name) { Attribute }
|
|
131
|
-
let(:element_name) { 'attribute' }
|
|
132
|
-
it_should_behave_like 'key_value_pairs'
|
|
133
|
-
end
|
|
134
131
|
end
|
|
135
132
|
end
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -52,7 +52,7 @@ module Punchblock
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
describe "with an event handler set" do
|
|
55
|
-
let(:handler) {
|
|
55
|
+
let(:handler) { double 'Response' }
|
|
56
56
|
|
|
57
57
|
before do
|
|
58
58
|
handler.should_receive(:call).once.with(event)
|
|
@@ -74,9 +74,7 @@ module Punchblock
|
|
|
74
74
|
let(:component_id) { 'abc123' }
|
|
75
75
|
|
|
76
76
|
let :ref do
|
|
77
|
-
Ref.new
|
|
78
|
-
ref.id = component_id
|
|
79
|
-
end
|
|
77
|
+
Ref.new uri: component_id
|
|
80
78
|
end
|
|
81
79
|
|
|
82
80
|
it "should set the component ID from the ref" do
|
|
@@ -90,7 +88,7 @@ module Punchblock
|
|
|
90
88
|
before do
|
|
91
89
|
subject.request!
|
|
92
90
|
subject.client = Client.new
|
|
93
|
-
subject.response = Ref.new
|
|
91
|
+
subject.response = Ref.new uri: 'abc'
|
|
94
92
|
subject.client.find_component_by_id('abc').should be subject
|
|
95
93
|
end
|
|
96
94
|
|
|
@@ -6,41 +6,101 @@ module Punchblock
|
|
|
6
6
|
module Component
|
|
7
7
|
describe Input do
|
|
8
8
|
it 'registers itself' do
|
|
9
|
-
RayoNode.class_from_registration(:input, 'urn:xmpp:rayo:input:1').should be ==
|
|
9
|
+
RayoNode.class_from_registration(:input, 'urn:xmpp:rayo:input:1').should be == described_class
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
describe "when setting options in initializer" do
|
|
13
13
|
subject do
|
|
14
|
-
|
|
15
|
-
:mode => :
|
|
14
|
+
described_class.new grammar: {value: '[5 DIGITS]', content_type: 'application/grammar+custom'},
|
|
15
|
+
:mode => :voice,
|
|
16
16
|
:terminator => '#',
|
|
17
17
|
:max_silence => 1000,
|
|
18
|
-
:recognizer => '
|
|
18
|
+
:recognizer => 'default',
|
|
19
|
+
:language => 'en-US',
|
|
19
20
|
:initial_timeout => 2000,
|
|
20
21
|
:inter_digit_timeout => 2000,
|
|
21
22
|
:sensitivity => 0.5,
|
|
22
23
|
:min_confidence => 0.5
|
|
23
24
|
end
|
|
24
25
|
|
|
25
|
-
its(:
|
|
26
|
-
its(:mode) { should be == :
|
|
26
|
+
its(:grammars) { should be == [Input::Grammar.new(:value => '[5 DIGITS]', :content_type => 'application/grammar+custom')] }
|
|
27
|
+
its(:mode) { should be == :voice }
|
|
27
28
|
its(:terminator) { should be == '#' }
|
|
28
29
|
its(:max_silence) { should be == 1000 }
|
|
29
|
-
its(:recognizer) { should be == '
|
|
30
|
+
its(:recognizer) { should be == 'default' }
|
|
31
|
+
its(:language) { should be == 'en-US' }
|
|
30
32
|
its(:initial_timeout) { should be == 2000 }
|
|
31
33
|
its(:inter_digit_timeout) { should be == 2000 }
|
|
32
34
|
its(:sensitivity) { should be == 0.5 }
|
|
33
35
|
its(:min_confidence) { should be == 0.5 }
|
|
36
|
+
|
|
37
|
+
context "with multiple grammars" do
|
|
38
|
+
subject do
|
|
39
|
+
Input.new :grammars => [
|
|
40
|
+
{:value => '[5 DIGITS]', :content_type => 'application/grammar+custom'},
|
|
41
|
+
{:value => '[10 DIGITS]', :content_type => 'application/grammar+custom'}
|
|
42
|
+
]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
its(:grammars) { should be == [
|
|
46
|
+
Input::Grammar.new(:value => '[5 DIGITS]', :content_type => 'application/grammar+custom'),
|
|
47
|
+
Input::Grammar.new(:value => '[10 DIGITS]', :content_type => 'application/grammar+custom')
|
|
48
|
+
]}
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context "with a nil grammar" do
|
|
52
|
+
it "removes all grammars" do
|
|
53
|
+
subject.grammar = nil
|
|
54
|
+
subject.grammars.should == []
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context "without any grammars" do
|
|
59
|
+
subject { described_class.new }
|
|
60
|
+
|
|
61
|
+
its(:grammars) { should == [] }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "exporting to Rayo" do
|
|
65
|
+
it "should export to XML that can be understood by its parser" do
|
|
66
|
+
new_instance = RayoNode.from_xml subject.to_rayo
|
|
67
|
+
new_instance.should be_instance_of described_class
|
|
68
|
+
new_instance.grammars.should be == [Input::Grammar.new(value: '[5 DIGITS]', content_type: 'application/grammar+custom')]
|
|
69
|
+
new_instance.mode.should be == :voice
|
|
70
|
+
new_instance.terminator.should be == '#'
|
|
71
|
+
new_instance.max_silence.should be == 1000
|
|
72
|
+
new_instance.recognizer.should be == 'default'
|
|
73
|
+
new_instance.language.should be == 'en-US'
|
|
74
|
+
new_instance.initial_timeout.should be == 2000
|
|
75
|
+
new_instance.inter_digit_timeout.should be == 2000
|
|
76
|
+
new_instance.sensitivity.should be == 0.5
|
|
77
|
+
new_instance.min_confidence.should be == 0.5
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should wrap the grammar value in CDATA" do
|
|
81
|
+
grammar_node = subject.to_rayo.at_xpath('ns:grammar', ns: described_class.registered_ns)
|
|
82
|
+
grammar_node.children.first.should be_a Nokogiri::XML::CDATA
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "should render to a parent node if supplied" do
|
|
86
|
+
doc = Nokogiri::XML::Document.new
|
|
87
|
+
parent = Nokogiri::XML::Node.new 'foo', doc
|
|
88
|
+
doc.root = parent
|
|
89
|
+
rayo_doc = subject.to_rayo(parent)
|
|
90
|
+
rayo_doc.should == parent
|
|
91
|
+
end
|
|
92
|
+
end
|
|
34
93
|
end
|
|
35
94
|
|
|
36
95
|
describe "from a stanza" do
|
|
37
96
|
let :stanza do
|
|
38
97
|
<<-MESSAGE
|
|
39
98
|
<input xmlns="urn:xmpp:rayo:input:1"
|
|
40
|
-
mode="
|
|
99
|
+
mode="voice"
|
|
41
100
|
terminator="#"
|
|
42
101
|
max-silence="1000"
|
|
43
|
-
recognizer="
|
|
102
|
+
recognizer="default"
|
|
103
|
+
language="en-US"
|
|
44
104
|
initial-timeout="2000"
|
|
45
105
|
inter-digit-timeout="2000"
|
|
46
106
|
sensitivity="0.5"
|
|
@@ -48,23 +108,32 @@ module Punchblock
|
|
|
48
108
|
<grammar content-type="application/grammar+custom">
|
|
49
109
|
<![CDATA[ [5 DIGITS] ]]>
|
|
50
110
|
</grammar>
|
|
111
|
+
<grammar content-type="application/grammar+custom">
|
|
112
|
+
<![CDATA[ [10 DIGITS] ]]>
|
|
113
|
+
</grammar>
|
|
51
114
|
</input>
|
|
52
115
|
MESSAGE
|
|
53
116
|
end
|
|
54
117
|
|
|
55
|
-
subject { RayoNode.
|
|
118
|
+
subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
|
|
56
119
|
|
|
57
120
|
it { should be_instance_of Input }
|
|
58
121
|
|
|
59
|
-
its(:
|
|
60
|
-
its(:mode) { should be == :
|
|
122
|
+
its(:grammars) { should be == [Input::Grammar.new(:value => '[5 DIGITS]', :content_type => 'application/grammar+custom'), Input::Grammar.new(:value => '[10 DIGITS]', :content_type => 'application/grammar+custom')] }
|
|
123
|
+
its(:mode) { should be == :voice }
|
|
61
124
|
its(:terminator) { should be == '#' }
|
|
62
125
|
its(:max_silence) { should be == 1000 }
|
|
63
|
-
its(:recognizer) { should be == '
|
|
126
|
+
its(:recognizer) { should be == 'default' }
|
|
127
|
+
its(:language) { should be == 'en-US' }
|
|
64
128
|
its(:initial_timeout) { should be == 2000 }
|
|
65
129
|
its(:inter_digit_timeout) { should be == 2000 }
|
|
66
130
|
its(:sensitivity) { should be == 0.5 }
|
|
67
131
|
its(:min_confidence) { should be == 0.5 }
|
|
132
|
+
|
|
133
|
+
context "without any grammars" do
|
|
134
|
+
let(:stanza) { '<input xmlns="urn:xmpp:rayo:input:1"/>' }
|
|
135
|
+
its(:grammars) { should be == [] }
|
|
136
|
+
end
|
|
68
137
|
end
|
|
69
138
|
|
|
70
139
|
def grxml_doc(mode = :dtmf)
|
|
@@ -83,37 +152,19 @@ module Punchblock
|
|
|
83
152
|
its(:content_type) { should be == 'application/srgs+xml' }
|
|
84
153
|
end
|
|
85
154
|
|
|
86
|
-
describe 'with a simple grammar' do
|
|
87
|
-
subject { Input::Grammar.new :value => '[5 DIGITS]', :content_type => 'application/grammar+custom' }
|
|
88
|
-
|
|
89
|
-
let(:expected_message) { "<![CDATA[ [5 DIGITS] ]]>" }
|
|
90
|
-
|
|
91
|
-
it "should wrap grammar in CDATA" do
|
|
92
|
-
subject.child.to_xml.should be == expected_message.strip
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
155
|
describe 'with a GRXML grammar' do
|
|
97
156
|
subject { Input::Grammar.new :value => grxml_doc, :content_type => 'application/srgs+xml' }
|
|
98
157
|
|
|
99
158
|
its(:content_type) { should be == 'application/srgs+xml' }
|
|
100
159
|
|
|
101
|
-
let(:expected_message) { "<![CDATA[ #{grxml_doc} ]]>" }
|
|
102
|
-
|
|
103
|
-
it "should wrap GRXML in CDATA" do
|
|
104
|
-
subject.child.to_xml.should be == expected_message.strip
|
|
105
|
-
end
|
|
106
|
-
|
|
107
160
|
its(:value) { should be == grxml_doc }
|
|
108
161
|
|
|
109
162
|
describe "comparison" do
|
|
110
|
-
let(:grammar2) { Input::Grammar.new :value =>
|
|
111
|
-
let(:grammar3) { Input::Grammar.new :value => grxml_doc }
|
|
112
|
-
let(:grammar4) { Input::Grammar.new :value => grxml_doc(:speech) }
|
|
163
|
+
let(:grammar2) { Input::Grammar.new :value => grxml_doc }
|
|
164
|
+
let(:grammar3) { Input::Grammar.new :value => grxml_doc(:voice) }
|
|
113
165
|
|
|
114
166
|
it { should be == grammar2 }
|
|
115
|
-
it {
|
|
116
|
-
it { should_not be == grammar4 }
|
|
167
|
+
it { should_not be == grammar3 }
|
|
117
168
|
end
|
|
118
169
|
end
|
|
119
170
|
|
|
@@ -138,8 +189,8 @@ module Punchblock
|
|
|
138
189
|
end
|
|
139
190
|
|
|
140
191
|
describe "actions" do
|
|
141
|
-
let(:mock_client) {
|
|
142
|
-
let(:command) {
|
|
192
|
+
let(:mock_client) { double 'Client' }
|
|
193
|
+
let(:command) { described_class.new grammar: {value: '[5 DIGITS]', content_type: 'application/grammar+custom'} }
|
|
143
194
|
|
|
144
195
|
before do
|
|
145
196
|
command.component_id = 'abc123'
|
|
@@ -176,41 +227,123 @@ module Punchblock
|
|
|
176
227
|
end
|
|
177
228
|
end
|
|
178
229
|
|
|
179
|
-
describe Input::Complete::
|
|
230
|
+
describe Input::Complete::Match do
|
|
231
|
+
let :nlsml_string do
|
|
232
|
+
'''
|
|
233
|
+
<result xmlns="http://www.ietf.org/xml/ns/mrcpv2" grammar="http://flight">
|
|
234
|
+
<interpretation confidence="0.60">
|
|
235
|
+
<input mode="voice">I want to go to Pittsburgh</input>
|
|
236
|
+
<instance>
|
|
237
|
+
<airline>
|
|
238
|
+
<to_city>Pittsburgh</to_city>
|
|
239
|
+
</airline>
|
|
240
|
+
</instance>
|
|
241
|
+
</interpretation>
|
|
242
|
+
<interpretation confidence="0.40">
|
|
243
|
+
<input>I want to go to Stockholm</input>
|
|
244
|
+
<instance>
|
|
245
|
+
<airline>
|
|
246
|
+
<to_city>Stockholm</to_city>
|
|
247
|
+
</airline>
|
|
248
|
+
</instance>
|
|
249
|
+
</interpretation>
|
|
250
|
+
</result>
|
|
251
|
+
'''
|
|
252
|
+
end
|
|
253
|
+
|
|
180
254
|
let :stanza do
|
|
181
255
|
<<-MESSAGE
|
|
182
256
|
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
183
|
-
<
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
</success>
|
|
257
|
+
<match xmlns="urn:xmpp:rayo:input:complete:1" content-type="application/nlsml+xml">
|
|
258
|
+
<![CDATA[#{nlsml_string}]]>
|
|
259
|
+
</match>
|
|
187
260
|
</complete>
|
|
188
261
|
MESSAGE
|
|
189
262
|
end
|
|
190
263
|
|
|
191
|
-
|
|
264
|
+
let :expected_nlsml do
|
|
265
|
+
RubySpeech.parse nlsml_string
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
subject { RayoNode.from_xml(parse_stanza(stanza).root).reason }
|
|
192
269
|
|
|
193
|
-
it { should be_instance_of Input::Complete::
|
|
270
|
+
it { should be_instance_of Input::Complete::Match }
|
|
194
271
|
|
|
195
|
-
its(:name) { should be == :
|
|
196
|
-
its(:
|
|
197
|
-
its(:
|
|
198
|
-
its(:
|
|
199
|
-
its(:
|
|
272
|
+
its(:name) { should be == :match }
|
|
273
|
+
its(:content_type) { should be == 'application/nlsml+xml' }
|
|
274
|
+
its(:nlsml) { should be == expected_nlsml }
|
|
275
|
+
its(:mode) { should be == :voice }
|
|
276
|
+
its(:confidence) { should be == 0.6 }
|
|
277
|
+
its(:interpretation) { should be == { airline: { to_city: 'Pittsburgh' } } }
|
|
278
|
+
its(:utterance) { should be == 'I want to go to Pittsburgh' }
|
|
200
279
|
|
|
201
|
-
describe "when
|
|
280
|
+
describe "when creating from an NLSML document" do
|
|
202
281
|
subject do
|
|
203
|
-
Input::Complete::
|
|
204
|
-
:confidence => 1,
|
|
205
|
-
:utterance => '123',
|
|
206
|
-
:interpretation => 'dtmf-1 dtmf-2 dtmf-3'
|
|
282
|
+
Input::Complete::Match.new :nlsml => expected_nlsml
|
|
207
283
|
end
|
|
208
284
|
|
|
285
|
+
its(:content_type) { should be == 'application/nlsml+xml' }
|
|
286
|
+
its(:nlsml) { should be == expected_nlsml }
|
|
287
|
+
its(:mode) { should be == :voice }
|
|
288
|
+
its(:confidence) { should be == 0.6 }
|
|
289
|
+
its(:interpretation) { should be == { airline: { to_city: 'Pittsburgh' } } }
|
|
290
|
+
its(:utterance) { should be == 'I want to go to Pittsburgh' }
|
|
291
|
+
end
|
|
209
292
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
293
|
+
context "when not enclosed in CDATA, but escaped" do
|
|
294
|
+
let :stanza do
|
|
295
|
+
<<-MESSAGE
|
|
296
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
297
|
+
<match xmlns="urn:xmpp:rayo:input:complete:1" content-type="application/nlsml+xml">
|
|
298
|
+
<result xmlns="http://www.ietf.org/xml/ns/mrcpv2" grammar="http://flight"/>
|
|
299
|
+
</match>
|
|
300
|
+
</complete>
|
|
301
|
+
MESSAGE
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
it "should parse the NLSML correctly" do
|
|
305
|
+
subject.nlsml.grammar.should == "http://flight"
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
context "when nested directly" do
|
|
310
|
+
let :stanza do
|
|
311
|
+
<<-MESSAGE
|
|
312
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
313
|
+
<match xmlns="urn:xmpp:rayo:input:complete:1" content-type="application/nlsml+xml">
|
|
314
|
+
#{nlsml_string}
|
|
315
|
+
</match>
|
|
316
|
+
</complete>
|
|
317
|
+
MESSAGE
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
it "should parse the NLSML correctly" do
|
|
321
|
+
subject.nlsml.grammar.should == "http://flight"
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
describe "comparison" do
|
|
326
|
+
context "with the same nlsml" do
|
|
327
|
+
it "should be equal" do
|
|
328
|
+
subject.should == RayoNode.from_xml(parse_stanza(stanza).root).reason
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
context "with different nlsml" do
|
|
333
|
+
let :other_stanza do
|
|
334
|
+
<<-MESSAGE
|
|
335
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
336
|
+
<match xmlns="urn:xmpp:rayo:input:complete:1">
|
|
337
|
+
<![CDATA[<result xmlns="http://www.ietf.org/xml/ns/mrcpv2" grammar="http://flight"/>]]>
|
|
338
|
+
</match>
|
|
339
|
+
</complete>
|
|
340
|
+
MESSAGE
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
it "should not be equal" do
|
|
344
|
+
subject.should_not == RayoNode.from_xml(parse_stanza(other_stanza).root).reason
|
|
345
|
+
end
|
|
346
|
+
end
|
|
214
347
|
end
|
|
215
348
|
end
|
|
216
349
|
|
|
@@ -218,12 +351,12 @@ module Punchblock
|
|
|
218
351
|
let :stanza do
|
|
219
352
|
<<-MESSAGE
|
|
220
353
|
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
221
|
-
<nomatch xmlns='urn:xmpp:rayo:input:complete:1' />
|
|
354
|
+
<nomatch xmlns='urn:xmpp:rayo:input:complete:1' />
|
|
222
355
|
</complete>
|
|
223
356
|
MESSAGE
|
|
224
357
|
end
|
|
225
358
|
|
|
226
|
-
subject { RayoNode.
|
|
359
|
+
subject { RayoNode.from_xml(parse_stanza(stanza).root).reason }
|
|
227
360
|
|
|
228
361
|
it { should be_instance_of Input::Complete::NoMatch }
|
|
229
362
|
|
|
@@ -234,12 +367,12 @@ module Punchblock
|
|
|
234
367
|
let :stanza do
|
|
235
368
|
<<-MESSAGE
|
|
236
369
|
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
237
|
-
<noinput xmlns='urn:xmpp:rayo:input:complete:1' />
|
|
370
|
+
<noinput xmlns='urn:xmpp:rayo:input:complete:1' />
|
|
238
371
|
</complete>
|
|
239
372
|
MESSAGE
|
|
240
373
|
end
|
|
241
374
|
|
|
242
|
-
subject { RayoNode.
|
|
375
|
+
subject { RayoNode.from_xml(parse_stanza(stanza).root).reason }
|
|
243
376
|
|
|
244
377
|
it { should be_instance_of Input::Complete::NoInput }
|
|
245
378
|
|