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
|
@@ -6,7 +6,7 @@ module Punchblock
|
|
|
6
6
|
module Component
|
|
7
7
|
describe Output do
|
|
8
8
|
it 'registers itself' do
|
|
9
|
-
RayoNode.class_from_registration(:output, 'urn:xmpp:rayo:output:1').should be ==
|
|
9
|
+
RayoNode.class_from_registration(:output, 'urn:xmpp:rayo:output:1').should be == described_class
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
describe 'default values' do
|
|
@@ -18,21 +18,29 @@ module Punchblock
|
|
|
18
18
|
its(:max_time) { should be nil }
|
|
19
19
|
its(:voice) { should be nil }
|
|
20
20
|
its(:renderer) { should be nil }
|
|
21
|
+
its(:render_documents) { should be == [] }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def ssml_doc(mode = :ordinal)
|
|
25
|
+
RubySpeech::SSML.draw do
|
|
26
|
+
say_as(:interpret_as => mode) { string '100' }
|
|
27
|
+
end
|
|
21
28
|
end
|
|
22
29
|
|
|
23
30
|
describe "when setting options in initializer" do
|
|
24
31
|
subject do
|
|
25
|
-
Output.new :interrupt_on => :
|
|
32
|
+
Output.new :interrupt_on => :voice,
|
|
26
33
|
:start_offset => 2000,
|
|
27
34
|
:start_paused => false,
|
|
28
35
|
:repeat_interval => 2000,
|
|
29
36
|
:repeat_times => 10,
|
|
30
37
|
:max_time => 30000,
|
|
31
38
|
:voice => 'allison',
|
|
32
|
-
:renderer => 'swift'
|
|
39
|
+
:renderer => 'swift',
|
|
40
|
+
:render_document => {:value => ssml_doc}
|
|
33
41
|
end
|
|
34
42
|
|
|
35
|
-
its(:interrupt_on) { should be == :
|
|
43
|
+
its(:interrupt_on) { should be == :voice }
|
|
36
44
|
its(:start_offset) { should be == 2000 }
|
|
37
45
|
its(:start_paused) { should be == false }
|
|
38
46
|
its(:repeat_interval) { should be == 2000 }
|
|
@@ -40,28 +48,131 @@ module Punchblock
|
|
|
40
48
|
its(:max_time) { should be == 30000 }
|
|
41
49
|
its(:voice) { should be == 'allison' }
|
|
42
50
|
its(:renderer) { should be == 'swift' }
|
|
51
|
+
its(:render_documents) { should be == [Output::Document.new(:value => ssml_doc)] }
|
|
52
|
+
|
|
53
|
+
context "using #ssml=" do
|
|
54
|
+
subject do
|
|
55
|
+
Output.new :ssml => ssml_doc
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
its(:render_documents) { should be == [Output::Document.new(:value => ssml_doc)] }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context "with multiple documents" do
|
|
62
|
+
subject do
|
|
63
|
+
Output.new :render_documents => [
|
|
64
|
+
{:value => ssml_doc},
|
|
65
|
+
{:value => ssml_doc(:cardinal)}
|
|
66
|
+
]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
its(:render_documents) { should be == [
|
|
70
|
+
Output::Document.new(:value => ssml_doc),
|
|
71
|
+
Output::Document.new(:value => ssml_doc(:cardinal))
|
|
72
|
+
]}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context "with a urilist" do
|
|
76
|
+
subject do
|
|
77
|
+
Output.new render_document: {
|
|
78
|
+
content_type: 'text/uri-list',
|
|
79
|
+
value: Punchblock::URIList.new('http://example.com/hello.mp3')
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
its(:render_documents) { should be == [Output::Document.new(content_type: 'text/uri-list', value: ['http://example.com/hello.mp3'])] }
|
|
84
|
+
|
|
85
|
+
describe "exporting to Rayo" do
|
|
86
|
+
it "should export to XML that can be understood by its parser" do
|
|
87
|
+
puts subject.to_rayo.to_xml
|
|
88
|
+
new_instance = RayoNode.from_xml Nokogiri::XML(subject.to_rayo.to_xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root
|
|
89
|
+
new_instance.render_documents.should be == [Output::Document.new(content_type: 'text/uri-list', value: ['http://example.com/hello.mp3'])]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context "with a nil document" do
|
|
95
|
+
it "removes all documents" do
|
|
96
|
+
subject.render_document = nil
|
|
97
|
+
subject.render_documents.should == []
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context "without any documents" do
|
|
102
|
+
subject { described_class.new }
|
|
103
|
+
|
|
104
|
+
its(:render_documents) { should == [] }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe "exporting to Rayo" do
|
|
108
|
+
it "should export to XML that can be understood by its parser" do
|
|
109
|
+
new_instance = RayoNode.from_xml Nokogiri::XML(subject.to_rayo.to_xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root
|
|
110
|
+
new_instance.should be_instance_of described_class
|
|
111
|
+
new_instance.interrupt_on.should be == :voice
|
|
112
|
+
new_instance.start_offset.should be == 2000
|
|
113
|
+
new_instance.start_paused.should be == false
|
|
114
|
+
new_instance.repeat_interval.should be == 2000
|
|
115
|
+
new_instance.repeat_times.should be == 10
|
|
116
|
+
new_instance.max_time.should be == 30000
|
|
117
|
+
new_instance.voice.should be == 'allison'
|
|
118
|
+
new_instance.renderer.should be == 'swift'
|
|
119
|
+
new_instance.render_documents.should be == [Output::Document.new(:value => ssml_doc)]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "should wrap the document value in CDATA" do
|
|
123
|
+
grammar_node = subject.to_rayo.at_xpath('ns:document', ns: described_class.registered_ns)
|
|
124
|
+
grammar_node.children.first.should be_a Nokogiri::XML::CDATA
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "should render to a parent node if supplied" do
|
|
128
|
+
doc = Nokogiri::XML::Document.new
|
|
129
|
+
parent = Nokogiri::XML::Node.new 'foo', doc
|
|
130
|
+
doc.root = parent
|
|
131
|
+
rayo_doc = subject.to_rayo(parent)
|
|
132
|
+
rayo_doc.should == parent
|
|
133
|
+
end
|
|
134
|
+
end
|
|
43
135
|
end
|
|
44
136
|
|
|
45
137
|
describe "from a stanza" do
|
|
46
138
|
let :stanza do
|
|
47
139
|
<<-MESSAGE
|
|
48
140
|
<output xmlns='urn:xmpp:rayo:output:1'
|
|
49
|
-
interrupt-on='
|
|
141
|
+
interrupt-on='voice'
|
|
50
142
|
start-offset='2000'
|
|
51
143
|
start-paused='false'
|
|
52
144
|
repeat-interval='2000'
|
|
53
145
|
repeat-times='10'
|
|
54
146
|
max-time='30000'
|
|
55
147
|
voice='allison'
|
|
56
|
-
renderer='swift'>
|
|
148
|
+
renderer='swift'>
|
|
149
|
+
<document content-type="application/ssml+xml">
|
|
150
|
+
<![CDATA[
|
|
151
|
+
<speak version="1.0"
|
|
152
|
+
xmlns="http://www.w3.org/2001/10/synthesis"
|
|
153
|
+
xml:lang="en-US">
|
|
154
|
+
<say-as interpret-as="ordinal">100</say-as>
|
|
155
|
+
</speak>
|
|
156
|
+
]]>
|
|
157
|
+
</document>
|
|
158
|
+
<document content-type="application/ssml+xml">
|
|
159
|
+
<![CDATA[
|
|
160
|
+
<speak version="1.0"
|
|
161
|
+
xmlns="http://www.w3.org/2001/10/synthesis"
|
|
162
|
+
xml:lang="en-US">
|
|
163
|
+
<say-as interpret-as="ordinal">100</say-as>
|
|
164
|
+
</speak>
|
|
165
|
+
]]>
|
|
166
|
+
</document>
|
|
167
|
+
</output>
|
|
57
168
|
MESSAGE
|
|
58
169
|
end
|
|
59
170
|
|
|
60
|
-
subject { RayoNode.
|
|
171
|
+
subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
|
|
61
172
|
|
|
62
173
|
it { should be_instance_of Output }
|
|
63
174
|
|
|
64
|
-
its(:interrupt_on) { should be == :
|
|
175
|
+
its(:interrupt_on) { should be == :voice }
|
|
65
176
|
its(:start_offset) { should be == 2000 }
|
|
66
177
|
its(:start_paused) { should be == false }
|
|
67
178
|
its(:repeat_interval) { should be == 2000 }
|
|
@@ -69,73 +180,89 @@ module Punchblock
|
|
|
69
180
|
its(:max_time) { should be == 30000 }
|
|
70
181
|
its(:voice) { should be == 'allison' }
|
|
71
182
|
its(:renderer) { should be == 'swift' }
|
|
72
|
-
its(:
|
|
183
|
+
its(:render_documents) { should be == [Output::Document.new(:value => ssml_doc), Output::Document.new(:value => ssml_doc)] }
|
|
73
184
|
|
|
74
|
-
context "with
|
|
185
|
+
context "with a urilist" do
|
|
75
186
|
let :stanza do
|
|
76
187
|
<<-MESSAGE
|
|
77
|
-
<output xmlns='urn:xmpp:rayo:output:1'
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
voice='allison'
|
|
85
|
-
renderer='swift'>
|
|
86
|
-
<speak version="1.0"
|
|
87
|
-
xmlns="http://www.w3.org/2001/10/synthesis"
|
|
88
|
-
xml:lang="en-US">
|
|
89
|
-
<say-as interpret-as="ordinal">100</say-as>
|
|
90
|
-
</speak>
|
|
188
|
+
<output xmlns='urn:xmpp:rayo:output:1'>
|
|
189
|
+
<document content-type="text/uri-list">
|
|
190
|
+
<![CDATA[
|
|
191
|
+
http://example.com/hello.mp3
|
|
192
|
+
http://example.com/goodbye.mp3
|
|
193
|
+
]]>
|
|
194
|
+
</document>
|
|
91
195
|
</output>
|
|
92
196
|
MESSAGE
|
|
93
197
|
end
|
|
94
198
|
|
|
95
|
-
|
|
96
|
-
RubySpeech::SSML.draw do
|
|
97
|
-
say_as(:interpret_as => mode) { string '100' }
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
its(:ssml) { should be == ssml_doc }
|
|
199
|
+
its(:render_documents) { should be == [Output::Document.new(content_type: 'text/uri-list', value: ['http://example.com/hello.mp3', 'http://example.com/goodbye.mp3'])] }
|
|
102
200
|
end
|
|
103
201
|
end
|
|
104
202
|
|
|
105
|
-
describe
|
|
106
|
-
|
|
203
|
+
describe Output::Document do
|
|
204
|
+
describe "when not passing a content type" do
|
|
205
|
+
subject { Output::Document.new :value => ssml_doc }
|
|
206
|
+
its(:content_type) { should be == 'application/ssml+xml' }
|
|
207
|
+
end
|
|
107
208
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
209
|
+
describe 'with an SSML document' do
|
|
210
|
+
subject { Output::Document.new :value => ssml_doc, :content_type => 'application/ssml+xml' }
|
|
211
|
+
|
|
212
|
+
its(:content_type) { should be == 'application/ssml+xml' }
|
|
213
|
+
|
|
214
|
+
its(:value) { should be == ssml_doc }
|
|
111
215
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
216
|
+
describe "comparison" do
|
|
217
|
+
let(:document2) { Output::Document.new :value => ssml_doc }
|
|
218
|
+
let(:document3) { Output::Document.new :value => ssml_doc(:normal) }
|
|
219
|
+
|
|
220
|
+
it { should be == document2 }
|
|
221
|
+
it { should_not be == document3 }
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
describe 'with a urilist' do
|
|
226
|
+
subject { Output::Document.new content_type: 'text/uri-list', value: Punchblock::URIList.new('http://example.com/hello.mp3', 'http://example.com/goodbye.mp3') }
|
|
227
|
+
|
|
228
|
+
its(:value) { should be == Punchblock::URIList.new('http://example.com/hello.mp3', 'http://example.com/goodbye.mp3') }
|
|
229
|
+
|
|
230
|
+
describe "comparison" do
|
|
231
|
+
let(:document2) { Output::Document.new content_type: 'text/uri-list', value: Punchblock::URIList.new('http://example.com/hello.mp3', 'http://example.com/goodbye.mp3') }
|
|
232
|
+
let(:document3) { Output::Document.new value: '<speak xmlns="http://www.w3.org/2001/10/synthesis" version="1.0" xml:lang="en-US"><say-as interpret-as="ordinal">100</say-as></speak>' }
|
|
233
|
+
let(:document4) { Output::Document.new content_type: 'text/uri-list', value: Punchblock::URIList.new('http://example.com/hello.mp3') }
|
|
234
|
+
let(:document5) { Output::Document.new content_type: 'text/uri-list', value: Punchblock::URIList.new('http://example.com/goodbye.mp3', 'http://example.com/hello.mp3') }
|
|
235
|
+
|
|
236
|
+
it { should be == document2 }
|
|
237
|
+
it { should_not be == document3 }
|
|
238
|
+
it { should_not be == document4 }
|
|
239
|
+
it { should_not be == document5 }
|
|
116
240
|
end
|
|
117
241
|
end
|
|
118
242
|
|
|
119
|
-
|
|
243
|
+
describe 'with a document reference by URL' do
|
|
244
|
+
let(:url) { 'http://foo.com/bar.grxml' }
|
|
120
245
|
|
|
121
|
-
|
|
246
|
+
subject { Output::Document.new :url => url }
|
|
122
247
|
|
|
123
|
-
|
|
248
|
+
its(:url) { should be == url }
|
|
249
|
+
its(:content_type) { should be nil}
|
|
124
250
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
251
|
+
describe "comparison" do
|
|
252
|
+
it "should be the same with the same url" do
|
|
253
|
+
Output::Document.new(:url => url).should be == Output::Document.new(:url => url)
|
|
254
|
+
end
|
|
129
255
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
256
|
+
it "should be different with a different url" do
|
|
257
|
+
Output::Document.new(:url => url).should_not be == Output::Document.new(:url => 'http://doo.com/dah')
|
|
258
|
+
end
|
|
259
|
+
end
|
|
133
260
|
end
|
|
134
261
|
end
|
|
135
262
|
|
|
136
263
|
describe "actions" do
|
|
137
|
-
let(:mock_client) {
|
|
138
|
-
let(:command) {
|
|
264
|
+
let(:mock_client) { double 'Client' }
|
|
265
|
+
let(:command) { described_class.new }
|
|
139
266
|
|
|
140
267
|
before do
|
|
141
268
|
command.component_id = 'abc123'
|
|
@@ -596,20 +723,25 @@ module Punchblock
|
|
|
596
723
|
end
|
|
597
724
|
end
|
|
598
725
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
726
|
+
{
|
|
727
|
+
Output::Complete::Finish => :finish,
|
|
728
|
+
Output::Complete::MaxTime => :'max-time',
|
|
729
|
+
}.each do |klass, element_name|
|
|
730
|
+
describe klass do
|
|
731
|
+
let :stanza do
|
|
732
|
+
<<-MESSAGE
|
|
602
733
|
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
603
|
-
|
|
734
|
+
<#{element_name} xmlns='urn:xmpp:rayo:output:complete:1' />
|
|
604
735
|
</complete>
|
|
605
|
-
|
|
606
|
-
|
|
736
|
+
MESSAGE
|
|
737
|
+
end
|
|
607
738
|
|
|
608
|
-
|
|
739
|
+
subject { RayoNode.from_xml(parse_stanza(stanza).root).reason }
|
|
609
740
|
|
|
610
|
-
|
|
741
|
+
it { should be_instance_of klass }
|
|
611
742
|
|
|
612
|
-
|
|
743
|
+
its(:name) { should be == element_name }
|
|
744
|
+
end
|
|
613
745
|
end
|
|
614
746
|
end
|
|
615
|
-
end
|
|
747
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'spec_helper'
|
|
4
|
+
|
|
5
|
+
module Punchblock
|
|
6
|
+
module Component
|
|
7
|
+
describe Prompt do
|
|
8
|
+
it 'registers itself' do
|
|
9
|
+
RayoNode.class_from_registration(:prompt, 'urn:xmpp:rayo:prompt:1').should be == described_class
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe "when setting options in initializer" do
|
|
13
|
+
let(:output) { Output.new :render_document => {content_type: 'text/uri-list', value: Punchblock::URIList.new('http://example.com/hello.mp3')} }
|
|
14
|
+
let(:input) { Input.new :mode => :voice }
|
|
15
|
+
subject { described_class.new output, input, :barge_in => true }
|
|
16
|
+
|
|
17
|
+
its(:output) { should be == output }
|
|
18
|
+
its(:input) { should be == input }
|
|
19
|
+
its(:barge_in) { should be_true }
|
|
20
|
+
|
|
21
|
+
context "with barge-in unset" do
|
|
22
|
+
subject { described_class.new output, input }
|
|
23
|
+
|
|
24
|
+
its(:barge_in) { should be_nil }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context "with options for sub-components" do
|
|
28
|
+
subject { described_class.new({renderer: :foo}, {recognizer: :bar}) }
|
|
29
|
+
|
|
30
|
+
its(:output) { should be == Output.new(renderer: :foo) }
|
|
31
|
+
its(:input) { should be == Input.new(recognizer: :bar) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "exporting to Rayo" do
|
|
35
|
+
it "should export to XML that can be understood by its parser" do
|
|
36
|
+
new_instance = RayoNode.from_xml subject.to_rayo
|
|
37
|
+
new_instance.should be_instance_of described_class
|
|
38
|
+
new_instance.output.should be == output
|
|
39
|
+
new_instance.input.should be == input
|
|
40
|
+
new_instance.barge_in.should be_true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should render to a parent node if supplied" do
|
|
44
|
+
doc = Nokogiri::XML::Document.new
|
|
45
|
+
parent = Nokogiri::XML::Node.new 'foo', doc
|
|
46
|
+
doc.root = parent
|
|
47
|
+
rayo_doc = subject.to_rayo(parent)
|
|
48
|
+
rayo_doc.should == parent
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "from a stanza" do
|
|
54
|
+
let :ssml do
|
|
55
|
+
RubySpeech::SSML.draw do
|
|
56
|
+
audio :src => 'http://foo.com/bar.mp3'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
let :stanza do
|
|
61
|
+
<<-MESSAGE
|
|
62
|
+
<prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
|
|
63
|
+
<output xmlns="urn:xmpp:rayo:output:1" voice="allison">
|
|
64
|
+
<document content-type="application/ssml+xml">
|
|
65
|
+
<![CDATA[
|
|
66
|
+
<speak version="1.0"
|
|
67
|
+
xmlns="http://www.w3.org/2001/10/synthesis"
|
|
68
|
+
xml:lang="en-US">
|
|
69
|
+
<audio src="http://foo.com/bar.mp3"/>
|
|
70
|
+
</speak>
|
|
71
|
+
]]>
|
|
72
|
+
</document>
|
|
73
|
+
</output>
|
|
74
|
+
<input xmlns="urn:xmpp:rayo:input:1" mode="voice">
|
|
75
|
+
<grammar content-type="application/grammar+custom">
|
|
76
|
+
<![CDATA[ [5 DIGITS] ]]>
|
|
77
|
+
</grammar>
|
|
78
|
+
</input>
|
|
79
|
+
</prompt>
|
|
80
|
+
MESSAGE
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
subject { RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
|
|
84
|
+
|
|
85
|
+
it { should be_instance_of described_class }
|
|
86
|
+
|
|
87
|
+
its(:barge_in) { should be_true }
|
|
88
|
+
its(:output) { should be == Output.new(:voice => 'allison', :render_document => {:value => ssml}) }
|
|
89
|
+
its(:input) { should be == Input.new(:mode => :voice, :grammar => {:value => '[5 DIGITS]', :content_type => 'application/grammar+custom'}) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe "actions" do
|
|
93
|
+
let(:mock_client) { double 'Client' }
|
|
94
|
+
let(:command) { described_class.new }
|
|
95
|
+
|
|
96
|
+
before do
|
|
97
|
+
command.component_id = 'abc123'
|
|
98
|
+
command.target_call_id = '123abc'
|
|
99
|
+
command.client = mock_client
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe '#stop_action' do
|
|
103
|
+
subject { command.stop_action }
|
|
104
|
+
|
|
105
|
+
its(:to_xml) { should be == '<stop xmlns="urn:xmpp:rayo:ext:1"/>' }
|
|
106
|
+
its(:component_id) { should be == 'abc123' }
|
|
107
|
+
its(:target_call_id) { should be == '123abc' }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe '#stop!' do
|
|
111
|
+
describe "when the command is executing" do
|
|
112
|
+
before do
|
|
113
|
+
command.request!
|
|
114
|
+
command.execute!
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "should send its command properly" do
|
|
118
|
+
mock_client.should_receive(:execute_command).with(command.stop_action, :target_call_id => '123abc', :component_id => 'abc123')
|
|
119
|
+
command.stop!
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
describe "when the command is not executing" do
|
|
124
|
+
it "should raise an error" do
|
|
125
|
+
lambda { command.stop! }.should raise_error(InvalidActionError, "Cannot stop a Prompt that is new")
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end # Punchblock
|