Skip to content

Commit 79b4553

Browse files
Add BXML Verbs (#75)
* Add Root Classes for BXML Verbs * remove unfinished verbs from sdk requires * add unit tests for Bxml and Response * add ffi to install libxml2 for windows * use 3.2.2 of libxml * switch to libxml require * Try Using Ox (#78) * ox dump instead of to_s * use attribute map in verb * standardize expected bxml var * typos * Add Terminal Verbs (#76) * Add Terminal Verbs * update bridge and add unit test * add unit test for root verb module * bridge test * bridge comment * update conference * add terminal verb unit test * verb test * all attributes in bridge test * add conference and test * add conference to sdk * remove backslash escaping * test number * use real booleans for conference * add comment to bridge * add pause and test * conference timeout is a Number * add forward and test * add explicit empty hash to tag * add hangup and test * add pause_recording and test * add phone_number and test * add play_audio and test * comments for params * add record and test * add redirect and test * add resume_recording and test * add ring and test * add send_dtmf and test * add sip_uri and test * add speak_sentence and test * add start_gather and test * add start_recording and test * add stop_gather and test * add stop_recording and test * add stop_stream and test * _name for stop_stream * add stream_param and test * add test for tag verb * turn ssml regex into constants * test decimals in ring verb * test decimals in conference * comment clean up * Add Non-Terminal Verbs (#77) * Add Non-Terminal Verbs * merge SWI-1730 * update gather and add tests * period in gather comment * add start_stream and test * add transfer and test * remove add_verb method * update response and bxml class tests * update non-terminal verbs and tests * refactor base verb classes (#80) * use call id for bridge test * update gem ox dependency * Apply suggestions from code review Co-authored-by: Matthew Martin <[email protected]> --------- Co-authored-by: Matthew Martin <[email protected]>
1 parent c65595b commit 79b4553

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1810
-505
lines changed

Gemfile.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ PATH
44
bandwidth-sdk (11.0.0)
55
faraday (>= 1.0.1, < 3.0)
66
faraday-multipart
7+
ox (~> 2.4)
78

89
GEM
910
remote: https://rubygems.org/
@@ -21,6 +22,7 @@ GEM
2122
jaro_winkler (1.5.4)
2223
method_source (1.0.0)
2324
multipart-post (2.3.0)
25+
ox (2.14.14)
2426
parallel (1.22.1)
2527
parser (3.2.0.0)
2628
ast (~> 2.4.1)
@@ -65,6 +67,7 @@ PLATFORMS
6567

6668
DEPENDENCIES
6769
bandwidth-sdk!
70+
ox (~> 2.4, >= 2.4.1)
6871
pry-byebug
6972
rake (~> 13.0.1)
7073
rspec (~> 3.6, >= 3.6.0)

bandwidth-sdk.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
2929

3030
s.add_runtime_dependency 'faraday', '>= 1.0.1', '< 3.0'
3131
s.add_runtime_dependency 'faraday-multipart'
32+
s.add_runtime_dependency 'ox', '~> 2.4'
3233

3334
s.add_development_dependency 'rspec', '~> 3.6', '>= 3.6.0'
3435

lib/bandwidth-sdk.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,38 @@
105105
require 'bandwidth-sdk/models/voice_api_error'
106106
require 'bandwidth-sdk/models/voice_code_response'
107107

108+
# BXML
109+
require 'bandwidth-sdk/models/bxml/root'
110+
require 'bandwidth-sdk/models/bxml/bxml'
111+
require 'bandwidth-sdk/models/bxml/response'
112+
require 'bandwidth-sdk/models/bxml/verb'
113+
require 'bandwidth-sdk/models/bxml/nestable_verb'
114+
require 'bandwidth-sdk/models/bxml/verbs/bridge'
115+
require 'bandwidth-sdk/models/bxml/verbs/conference'
116+
require 'bandwidth-sdk/models/bxml/verbs/forward'
117+
require 'bandwidth-sdk/models/bxml/verbs/gather'
118+
require 'bandwidth-sdk/models/bxml/verbs/hangup'
119+
require 'bandwidth-sdk/models/bxml/verbs/pause_recording'
120+
require 'bandwidth-sdk/models/bxml/verbs/pause'
121+
require 'bandwidth-sdk/models/bxml/verbs/phone_number'
122+
require 'bandwidth-sdk/models/bxml/verbs/play_audio'
123+
require 'bandwidth-sdk/models/bxml/verbs/record'
124+
require 'bandwidth-sdk/models/bxml/verbs/redirect'
125+
require 'bandwidth-sdk/models/bxml/verbs/resume_recording'
126+
require 'bandwidth-sdk/models/bxml/verbs/ring'
127+
require 'bandwidth-sdk/models/bxml/verbs/send_dtmf'
128+
require 'bandwidth-sdk/models/bxml/verbs/sip_uri'
129+
require 'bandwidth-sdk/models/bxml/verbs/speak_sentence'
130+
require 'bandwidth-sdk/models/bxml/verbs/start_gather'
131+
require 'bandwidth-sdk/models/bxml/verbs/start_recording'
132+
require 'bandwidth-sdk/models/bxml/verbs/start_stream'
133+
require 'bandwidth-sdk/models/bxml/verbs/stop_gather'
134+
require 'bandwidth-sdk/models/bxml/verbs/stop_recording'
135+
require 'bandwidth-sdk/models/bxml/verbs/stop_stream'
136+
require 'bandwidth-sdk/models/bxml/verbs/stream_param'
137+
require 'bandwidth-sdk/models/bxml/verbs/tag'
138+
require 'bandwidth-sdk/models/bxml/verbs/transfer'
139+
108140
# APIs
109141
require 'bandwidth-sdk/api/calls_api'
110142
require 'bandwidth-sdk/api/conferences_api'

lib/bandwidth-sdk/models/bxml/bxml.rb

Lines changed: 7 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,12 @@
1-
require 'builder'
2-
Dir[File.dirname(__FILE__) + '/verbs/*'].each {|file|
3-
require_relative file
4-
}
5-
6-
module Bandwidth
7-
module Voice
1+
module Bandwidth
2+
module Bxml
83
class Bxml
9-
# Initializer
10-
# @param verbs [Array] optional list of verbs to include in the bxml tag
11-
def initialize(verbs = nil)
12-
@verbs = verbs || []
13-
end
14-
15-
# Return BXML representaion of this response
16-
def to_bxml()
17-
xml = Builder::XmlMarkup.new()
18-
xml.instruct!(:xml, :version=>'1.0', :encoding=>'UTF-8')
19-
xml.Bxml do
20-
@verbs.each {|verb| verb.to_bxml(xml)}
21-
end
22-
xml.target!().gsub(SPEAK_SENTENCE_REGEX){|s|s.gsub(SSML_REGEX, '<\1>')}
23-
end
24-
25-
# Add one or more verbs to this response
26-
def push(*verbs)
27-
@verbs.push(*verbs)
28-
end
4+
include Bandwidth::Bxml::Root
295

30-
# Add a verb to this response
31-
def <<(verb)
32-
@verbs << verb
6+
# Initializer
7+
# @param nested_verbs [Array<Verb>] XML element children. Defaults to an empty array.
8+
def initialize(nested_verbs = [])
9+
super(tag='Bxml', nested_verbs)
3310
end
3411
end
3512
end
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
require 'ox'
2+
3+
module Bandwidth
4+
module Bxml
5+
module NestableVerb
6+
include Bandwidth::Bxml::Verb
7+
8+
# Initializer
9+
# @param tag [String] Name of the XML element.
10+
# @param content [String] XML element content. Defaults to nil.
11+
# @param nested_verbs [Array] XML element children. Defaults to an empty array.
12+
# @param attributes [Hash] The attributes to add to the element. Defaults to an empty hash.
13+
def initialize(tag, content = nil, nested_verbs = [], attributes = {})
14+
@tag = tag
15+
@content = content
16+
@nested_verbs = nested_verbs
17+
@attributes = attributes
18+
@attribute_map = []
19+
end
20+
21+
# Generate an XML element for the verb
22+
# @return [Node] The XML element.
23+
def generate_xml
24+
root = Ox::Element.new(@tag)
25+
if @content
26+
root << @content
27+
end
28+
29+
if @nested_verbs.length > 0
30+
@nested_verbs.each do |verb|
31+
root << verb.generate_xml
32+
end
33+
end
34+
35+
if !@attributes.empty?
36+
@attributes.each do |key, value|
37+
if @attribute_map.include? key.to_sym
38+
root[@attribute_map[key.to_sym]] = value
39+
else
40+
raise NoMethodError.new("attribute '#{key}' is not a valid attribute for this verb")
41+
end
42+
end
43+
end
44+
45+
return root
46+
end
47+
48+
end
49+
end
50+
end

lib/bandwidth-sdk/models/bxml/response.rb

Lines changed: 7 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,12 @@
1-
require 'builder'
2-
Dir[File.dirname(__FILE__) + '/verbs/*'].each {|file|
3-
require_relative file
4-
}
5-
6-
SSML_REGEX = /&lt;([a-zA-Z\/\/].*?)&gt;/
7-
SPEAK_SENTENCE_REGEX = /<SpeakSentence.*?>.*?<\/SpeakSentence>/
8-
9-
module Bandwidth
10-
module Voice
1+
module Bandwidth
2+
module Bxml
113
class Response
12-
# Initializer
13-
# @param verbs [Array] optional list of verbs to include into response
14-
def initialize(verbs = nil)
15-
@verbs = verbs || []
16-
end
4+
include Bandwidth::Bxml::Root
175

18-
# Return BXML representaion of this response
19-
def to_bxml()
20-
xml = Builder::XmlMarkup.new()
21-
xml.instruct!(:xml, :version=>'1.0', :encoding=>'UTF-8')
22-
xml.Response do
23-
@verbs.each {|verb| verb.to_bxml(xml)}
24-
end
25-
xml.target!().gsub(SPEAK_SENTENCE_REGEX){|s|s.gsub(SSML_REGEX, '<\1>')}
26-
end
27-
28-
# Add one or more verbs to this response
29-
def push(*verbs)
30-
@verbs.push(*verbs)
31-
end
32-
33-
# Add a verb to this response
34-
def <<(verb)
35-
@verbs << verb
6+
# Initializer
7+
# @param nested_verbs [Array<Verb>] XML element children. Defaults to an empty array.
8+
def initialize(nested_verbs = [])
9+
super(tag='Response', nested_verbs)
3610
end
3711
end
3812
end
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
require 'ox'
2+
3+
module Bandwidth
4+
module Bxml
5+
SPEAK_SENTENCE_REGEX = /<SpeakSentence.*?>(.*?)<\/SpeakSentence>/
6+
SSML_REGEX = /&lt;([a-zA-Z\/\/].*?)&gt;/
7+
8+
module Root
9+
# Initializer
10+
# @param tag [String] Name of the XML element.
11+
# @param nested_verbs [Array<Verb>] XML element children. Defaults to an empty array.
12+
def initialize(tag, nested_verbs = [])
13+
@tag = tag
14+
@nested_verbs = nested_verbs
15+
end
16+
17+
# Generate an XML element for the BXML response
18+
# @return [Document] The XML element.
19+
def generate_xml
20+
xml = Ox::Document.new
21+
instruct = Ox::Instruct.new(:xml)
22+
instruct[:version] = '1.0'
23+
instruct[:encoding] = 'UTF-8'
24+
xml << instruct
25+
root = Ox::Element.new(@tag)
26+
@nested_verbs.each do |verb|
27+
root << verb.generate_xml
28+
end
29+
xml << root
30+
return xml
31+
end
32+
33+
# Add a verb to the nested verbs array
34+
# @param *nested_verbs [Verb] or [Array<Verb>] Verb or verbs to add to the array.
35+
def add_verb(nested_verbs)
36+
@nested_verbs.push(*nested_verbs)
37+
end
38+
39+
# Return BXML representaion of this response
40+
# @return [String] The XML response in string format.
41+
def to_bxml
42+
bxml = Ox.dump(generate_xml)
43+
return bxml.gsub(SPEAK_SENTENCE_REGEX) { |text| text.gsub(SSML_REGEX, '<\1>')}
44+
end
45+
end
46+
end
47+
end
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
require 'ox'
2+
3+
module Bandwidth
4+
module Bxml
5+
module Verb
6+
# Initializer
7+
# @param tag [String] Name of the XML element.
8+
# @param content [String] XML element content. Defaults to nil.
9+
# @param attributes [Hash] The attributes to add to the element. Defaults to an empty hash.
10+
def initialize(tag, content = nil, attributes = {})
11+
@tag = tag
12+
@content = content
13+
@attributes = attributes
14+
@attribute_map = []
15+
end
16+
17+
# Set XML attributes for the verb
18+
# @param attributes [Hash] The attributes to add to the element.
19+
def set_attributes(attributes)
20+
@attributes = attributes
21+
end
22+
23+
# Generate an XML element for the verb
24+
# @return [Node] The XML element.
25+
def generate_xml
26+
root = Ox::Element.new(@tag)
27+
if @content
28+
root << @content
29+
end
30+
31+
if !@attributes.empty?
32+
@attributes.each do |key, value|
33+
if @attribute_map.include? key.to_sym
34+
root[@attribute_map[key.to_sym]] = value
35+
else
36+
raise NoMethodError.new("attribute '#{key}' is not a valid attribute for this verb")
37+
end
38+
end
39+
end
40+
41+
return root
42+
end
43+
44+
# Return BXML representaion of this element
45+
# @return [String] The XML element in string format.
46+
def to_bxml
47+
return Ox.dump(generate_xml)
48+
end
49+
end
50+
end
51+
end

lib/bandwidth-sdk/models/bxml/verbs/bridge.rb

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,29 @@
1-
require_relative 'xml_verb'
2-
3-
module Bandwidth
4-
module Voice
5-
# The Bridge verb allows you to connect 2 calls
1+
module Bandwidth
2+
module Bxml
63
class Bridge
7-
include XmlVerb
4+
include Bandwidth::Bxml::Verb
85

9-
def to_bxml(xml)
10-
xml.Bridge(call_id, compact_hash({
11-
'bridgeCompleteUrl' => bridge_complete_url,
12-
'bridgeCompleteMethod' => bridge_complete_method,
13-
'bridgeTargetCompleteUrl' => bridge_target_complete_url,
14-
'bridgeTargetCompleteMethod' => bridge_target_complete_method,
15-
'username' => username,
16-
'password' => password,
17-
'tag' => tag,
18-
'bridgeCompleteFallbackUrl' => bridge_complete_fallback_url,
19-
'bridgeCompleteFallbackMethod' => bridge_complete_fallback_method,
20-
'bridgeTargetCompleteFallbackUrl' => bridge_target_complete_fallback_url,
21-
'bridgeTargetCompleteFallbackMethod' => bridge_target_complete_fallback_method,
22-
'fallbackUsername' => fallback_username,
23-
'fallbackPassword' => fallback_password
24-
}))
6+
# Initializer
7+
# @param target_call [String] The callId of the call to be bridged.
8+
# @param attributes [Hash] The attributes to add to the element. Defaults to an empty hash.
9+
def initialize(target_call, attributes = {})
10+
super("Bridge", target_call, attributes)
11+
12+
@attribute_map = {
13+
bridge_complete_url: 'bridgeCompleteUrl', # Optional [String]: URL to send the Bridge Complete event to and request new BXML. If this attribute is specified, then Verbs following the <Bridge> verb will be ignored and the BXML returned in this webhook is executed on the call. If this attribute is not specified then no webhook will be sent, and execution of the verbs following the <Bridge> verb continues. May be a relative URL. Defaults to None.
14+
bridge_complete_method: 'bridgeCompleteMethod', # Optional [String]: The HTTP method to use for the request to bridgeCompleteUrl. GET or POST. Default value is POST.
15+
bridge_complete_fallback_url: 'bridgeCompleteFallbackUrl', # Optional [String]: A fallback url which, if provided, will be used to retry the Bridge Complete webhook delivery in case bridgeCompleteUrl fails to respond. Defaults to None.
16+
bridge_complete_fallback_method: 'bridgeCompleteFallbackMethod', # Optional [String]: The HTTP method to use to deliver the Bridge Complete webhook to bridgeCompleteFallbackUrl. GET or POST. Default value is POST.
17+
bridge_target_complete_url: 'bridgeTargetCompleteUrl', # Optional [String]: URL to send the Bridge Target Complete event to and request new BXML. If this attribute is specified, then the BXML returned in this webhook is executed on the target call. If this attribute is not specified then no webhook will be sent, and the target call will be hung up. May be a relative URL. Defaults to None.
18+
bridge_target_complete_method: 'bridgeTargetCompleteMethod', # Optional [String]: The HTTP method to use for the request to bridgeTargetCompleteUrl. GET or POST. Default value is POST.
19+
bridge_target_complete_fallback_url: 'bridgeTargetCompleteFallbackUrl', # Optional [String]: A fallback url which, if provided, will be used to retry the Bridge Target Complete webhook delivery in case bridgeTargetCompleteUrl fails to respond. Defaults to None.
20+
bridge_target_complete_fallback_method: 'bridgeTargetCompleteFallbackMethod', # Optional [String]: The HTTP method to use to deliver the Bridge Target Complete webhook to bridgeTargetCompleteFallbackUrl. GET or POST. Default value is POST.
21+
username: 'username', # Optional [String]: The username to send in the HTTP request to bridgeCompleteUrl and to bridgeTargetCompleteUrl. Defaults to None.
22+
password: 'password', # Optional [String]: The password to send in the HTTP request to bridgeCompleteUrl and to bridgeTargetCompleteUrl. Defaults to None.
23+
fallback_username: 'fallbackUsername', # Optional [String]: The username to send in the HTTP request to bridgeCompleteFallbackUrl and to bridgeTargetCompleteFallbackUrl. Defaults to None.
24+
fallback_password: 'fallbackPassword', # Optional [String]: The password to send in the HTTP request to bridgeCompleteFallbackUrl and to bridgeTargetCompleteFallbackUrl. Defaults to None.
25+
tag: 'tag', # Optional [String]: A custom string that will be sent with the bridgeComplete webhook and all future webhooks of the call unless overwritten by a future tag attribute or <Tag> verb, or cleared. May be cleared by setting tag="". Max length 256 characters. Defaults to None.
26+
}
2527
end
2628
end
2729
end

0 commit comments

Comments
 (0)