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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +1 -2
  4. data/CHANGELOG.md +17 -0
  5. data/Gemfile +1 -0
  6. data/Guardfile +4 -0
  7. data/README.markdown +6 -0
  8. data/Rakefile +16 -0
  9. data/benchmarks/ami_event_name_comparison.rb +14 -0
  10. data/benchmarks/channel.rb +27 -0
  11. data/lib/punchblock/client.rb +2 -6
  12. data/lib/punchblock/command/accept.rb +3 -24
  13. data/lib/punchblock/command/answer.rb +3 -24
  14. data/lib/punchblock/command/dial.rb +24 -76
  15. data/lib/punchblock/command/hangup.rb +3 -19
  16. data/lib/punchblock/command/join.rb +21 -70
  17. data/lib/punchblock/command/mute.rb +3 -3
  18. data/lib/punchblock/command/redirect.rb +6 -39
  19. data/lib/punchblock/command/reject.rb +14 -54
  20. data/lib/punchblock/command/unjoin.rb +8 -40
  21. data/lib/punchblock/command/unmute.rb +3 -3
  22. data/lib/punchblock/command_node.rb +0 -17
  23. data/lib/punchblock/component/asterisk/agi/command.rb +20 -127
  24. data/lib/punchblock/component/asterisk/ami/action.rb +30 -117
  25. data/lib/punchblock/component/component_node.rb +1 -1
  26. data/lib/punchblock/component/input.rb +89 -268
  27. data/lib/punchblock/component/output.rb +106 -154
  28. data/lib/punchblock/component/prompt.rb +51 -0
  29. data/lib/punchblock/component/record.rb +41 -130
  30. data/lib/punchblock/component.rb +1 -0
  31. data/lib/punchblock/connection/asterisk.rb +31 -4
  32. data/lib/punchblock/connection/xmpp.rb +6 -14
  33. data/lib/punchblock/core_ext/blather/stanza.rb +1 -1
  34. data/lib/punchblock/event/active_speaker.rb +2 -10
  35. data/lib/punchblock/event/answered.rb +3 -3
  36. data/lib/punchblock/event/asterisk/ami/event.rb +15 -47
  37. data/lib/punchblock/event/complete.rb +26 -48
  38. data/lib/punchblock/event/dtmf.rb +3 -13
  39. data/lib/punchblock/event/end.rb +10 -11
  40. data/lib/punchblock/event/joined.rb +5 -25
  41. data/lib/punchblock/event/offer.rb +4 -25
  42. data/lib/punchblock/event/ringing.rb +3 -3
  43. data/lib/punchblock/event/unjoined.rb +5 -25
  44. data/lib/punchblock/event.rb +0 -10
  45. data/lib/punchblock/has_headers.rb +20 -26
  46. data/lib/punchblock/rayo_node.rb +46 -23
  47. data/lib/punchblock/ref.rb +39 -18
  48. data/lib/punchblock/translator/asterisk/agi_app.rb +15 -0
  49. data/lib/punchblock/translator/asterisk/agi_command.rb +3 -1
  50. data/lib/punchblock/translator/asterisk/ami_error_converter.rb +20 -0
  51. data/lib/punchblock/translator/asterisk/call.rb +60 -39
  52. data/lib/punchblock/translator/asterisk/channel.rb +41 -0
  53. data/lib/punchblock/translator/asterisk/component/asterisk/agi_command.rb +4 -1
  54. data/lib/punchblock/translator/asterisk/component/asterisk/ami_action.rb +4 -4
  55. data/lib/punchblock/translator/asterisk/component/composed_prompt.rb +62 -0
  56. data/lib/punchblock/translator/asterisk/component/input.rb +1 -0
  57. data/lib/punchblock/translator/asterisk/component/mrcp_native_prompt.rb +56 -0
  58. data/lib/punchblock/translator/asterisk/component/mrcp_prompt.rb +53 -0
  59. data/lib/punchblock/translator/asterisk/component/mrcp_recog_prompt.rb +99 -0
  60. data/lib/punchblock/translator/asterisk/component/output.rb +30 -22
  61. data/lib/punchblock/translator/asterisk/component/record.rb +8 -6
  62. data/lib/punchblock/translator/asterisk/component.rb +6 -5
  63. data/lib/punchblock/translator/asterisk/unimrcp_app.rb +26 -0
  64. data/lib/punchblock/translator/asterisk.rb +24 -28
  65. data/lib/punchblock/translator/dtmf_recognizer.rb +39 -20
  66. data/lib/punchblock/translator/freeswitch/call.rb +15 -14
  67. data/lib/punchblock/translator/freeswitch/component/abstract_output.rb +5 -4
  68. data/lib/punchblock/translator/freeswitch/component/flite_output.rb +1 -1
  69. data/lib/punchblock/translator/freeswitch/component/input.rb +5 -0
  70. data/lib/punchblock/translator/freeswitch/component/output.rb +2 -2
  71. data/lib/punchblock/translator/freeswitch/component/record.rb +19 -13
  72. data/lib/punchblock/translator/freeswitch/component/tts_output.rb +2 -2
  73. data/lib/punchblock/translator/freeswitch/component.rb +2 -5
  74. data/lib/punchblock/translator/freeswitch.rb +2 -2
  75. data/lib/punchblock/translator/input_component.rb +33 -13
  76. data/lib/punchblock/uri_list.rb +21 -0
  77. data/lib/punchblock/version.rb +1 -1
  78. data/lib/punchblock.rb +4 -3
  79. data/punchblock.gemspec +7 -3
  80. data/spec/punchblock/client/component_registry_spec.rb +1 -1
  81. data/spec/punchblock/client_spec.rb +10 -26
  82. data/spec/punchblock/command/accept_spec.rb +41 -7
  83. data/spec/punchblock/command/answer_spec.rb +51 -7
  84. data/spec/punchblock/command/dial_spec.rb +56 -14
  85. data/spec/punchblock/command/hangup_spec.rb +41 -7
  86. data/spec/punchblock/command/join_spec.rb +53 -11
  87. data/spec/punchblock/command/mute_spec.rb +19 -4
  88. data/spec/punchblock/command/redirect_spec.rb +40 -10
  89. data/spec/punchblock/command/reject_spec.rb +43 -11
  90. data/spec/punchblock/command/unjoin_spec.rb +40 -9
  91. data/spec/punchblock/command/unmute_spec.rb +19 -4
  92. data/spec/punchblock/command_node_spec.rb +0 -4
  93. data/spec/punchblock/component/asterisk/agi/command_spec.rb +16 -39
  94. data/spec/punchblock/component/asterisk/ami/action_spec.rb +50 -53
  95. data/spec/punchblock/component/component_node_spec.rb +3 -5
  96. data/spec/punchblock/component/input_spec.rb +194 -61
  97. data/spec/punchblock/component/output_spec.rb +194 -62
  98. data/spec/punchblock/component/prompt_spec.rb +132 -0
  99. data/spec/punchblock/component/record_spec.rb +70 -32
  100. data/spec/punchblock/connection/asterisk_spec.rb +17 -3
  101. data/spec/punchblock/connection/freeswitch_spec.rb +4 -4
  102. data/spec/punchblock/connection/xmpp_spec.rb +20 -38
  103. data/spec/punchblock/event/answered_spec.rb +12 -10
  104. data/spec/punchblock/event/asterisk/ami/event_spec.rb +27 -22
  105. data/spec/punchblock/event/complete_spec.rb +15 -19
  106. data/spec/punchblock/event/dtmf_spec.rb +5 -6
  107. data/spec/punchblock/event/end_spec.rb +20 -10
  108. data/spec/punchblock/event/joined_spec.rb +8 -7
  109. data/spec/punchblock/event/offer_spec.rb +41 -12
  110. data/spec/punchblock/event/ringing_spec.rb +12 -10
  111. data/spec/punchblock/event/started_speaking_spec.rb +5 -6
  112. data/spec/punchblock/event/stopped_speaking_spec.rb +5 -6
  113. data/spec/punchblock/event/unjoined_spec.rb +7 -7
  114. data/spec/punchblock/ref_spec.rb +86 -9
  115. data/spec/punchblock/translator/asterisk/call_spec.rb +317 -154
  116. data/spec/punchblock/translator/asterisk/component/asterisk/agi_command_spec.rb +28 -5
  117. data/spec/punchblock/translator/asterisk/component/asterisk/ami_action_spec.rb +15 -13
  118. data/spec/punchblock/translator/asterisk/component/composed_prompt_spec.rb +237 -0
  119. data/spec/punchblock/translator/asterisk/component/input_spec.rb +171 -14
  120. data/spec/punchblock/translator/asterisk/component/mrcp_native_prompt_spec.rb +652 -0
  121. data/spec/punchblock/translator/asterisk/component/mrcp_prompt_spec.rb +646 -0
  122. data/spec/punchblock/translator/asterisk/component/output_spec.rb +127 -77
  123. data/spec/punchblock/translator/asterisk/component/record_spec.rb +17 -8
  124. data/spec/punchblock/translator/asterisk/component/stop_by_redirect_spec.rb +2 -2
  125. data/spec/punchblock/translator/asterisk/component_spec.rb +3 -7
  126. data/spec/punchblock/translator/asterisk_spec.rb +20 -24
  127. data/spec/punchblock/translator/freeswitch/call_spec.rb +103 -99
  128. data/spec/punchblock/translator/freeswitch/component/flite_output_spec.rb +17 -8
  129. data/spec/punchblock/translator/freeswitch/component/input_spec.rb +26 -14
  130. data/spec/punchblock/translator/freeswitch/component/output_spec.rb +30 -52
  131. data/spec/punchblock/translator/freeswitch/component/record_spec.rb +23 -19
  132. data/spec/punchblock/translator/freeswitch/component/tts_output_spec.rb +18 -8
  133. data/spec/punchblock/translator/freeswitch/component_spec.rb +4 -8
  134. data/spec/punchblock/translator/freeswitch_spec.rb +11 -14
  135. data/spec/punchblock/uri_list_spec.rb +49 -0
  136. data/spec/punchblock_spec.rb +11 -1
  137. data/spec/spec_helper.rb +7 -11
  138. data/spec/support/mock_connection_with_event_handler.rb +1 -1
  139. metadata +104 -24
  140. data/lib/punchblock/header.rb +0 -9
  141. data/lib/punchblock/key_value_pair_node.rb +0 -51
  142. data/spec/punchblock/header_spec.rb +0 -11
@@ -11,7 +11,7 @@ module Punchblock
11
11
  module Connection
12
12
  class XMPP < GenericConnection
13
13
  include Blather::DSL
14
- attr_accessor :event_handler, :root_domain, :calls_domain, :mixers_domain
14
+ attr_accessor :event_handler, :root_domain
15
15
 
16
16
  ##
17
17
  # Initialize the required connection attributes
@@ -29,11 +29,8 @@ module Punchblock
29
29
 
30
30
  setup(*[:username, :password, :host, :port, :certs, :connection_timeout].map { |key| options.delete key })
31
31
 
32
- @root_domain = Blather::JID.new(options[:root_domain] || options[:rayo_domain] || @username).domain
33
- @calls_domain = options[:calls_domain] || "calls.#{@root_domain}"
34
- @mixers_domain = options[:mixers_domain] || "mixers.#{@root_domain}"
32
+ @root_domain = Blather::JID.new(options[:root_domain] || options[:rayo_domain] || @username).domain
35
33
 
36
- @callmap = {} # This hash maps call IDs to their XMPP domain.
37
34
  @joined_mixers = []
38
35
 
39
36
  @ping_period = options.has_key?(:ping_period) ? options[:ping_period] : 60
@@ -62,12 +59,13 @@ module Punchblock
62
59
  command.connection = self
63
60
  command.target_call_id ||= options[:call_id]
64
61
  command.target_mixer_name ||= options[:mixer_name]
62
+ command.domain ||= options[:domain]
65
63
  command.component_id ||= options[:component_id]
66
64
  if command.is_a?(Command::Join) && command.mixer_name
67
65
  @joined_mixers << command.mixer_name
68
66
  end
69
67
  create_iq(jid_for_command(command)).tap do |iq|
70
- iq << command
68
+ command.to_rayo(iq)
71
69
  end
72
70
  end
73
71
 
@@ -111,15 +109,11 @@ module Punchblock
111
109
 
112
110
  if command.target_call_id
113
111
  node = command.target_call_id
114
- domain = @callmap[command.target_call_id] || calls_domain
115
112
  elsif command.target_mixer_name
116
113
  node = command.target_mixer_name
117
- domain = @callmap[command.target_mixer_name] || mixers_domain
118
- else
119
- domain = calls_domain
120
114
  end
121
115
 
122
- Blather::JID.new(node, domain, command.component_id).to_s
116
+ Blather::JID.new(node, command.domain || root_domain, command.component_id).to_s
123
117
  end
124
118
 
125
119
  def send_presence(presence)
@@ -130,10 +124,10 @@ module Punchblock
130
124
 
131
125
  def handle_presence(p)
132
126
  throw :pass unless p.rayo_event?
133
- @callmap[p.call_id] = p.from.domain
134
127
  event = p.event
135
128
  event.connection = self
136
129
  event.domain = p.from.domain
130
+ event.transport = "xmpp"
137
131
  if @joined_mixers.include?(p.call_id)
138
132
  event.target_mixer_name = p.call_id
139
133
  else
@@ -143,8 +137,6 @@ module Punchblock
143
137
  end
144
138
 
145
139
  def handle_iq_result(iq, command)
146
- # FIXME: Do we need to raise a warning if the domain changes?
147
- @callmap[iq.from.node] = iq.from.domain
148
140
  command.response = iq.rayo_node.is_a?(Ref) ? iq.rayo_node : true
149
141
  end
150
142
 
@@ -8,7 +8,7 @@ module Blather
8
8
  #
9
9
  def rayo_node
10
10
  first_child = at_xpath '*'
11
- Punchblock::RayoNode.import first_child, nil, component_id if first_child
11
+ Punchblock::RayoNode.from_xml first_child, nil, component_id if first_child
12
12
  rescue Punchblock::RayoNode::InvalidNodeError
13
13
  nil
14
14
  end
@@ -3,16 +3,8 @@
3
3
  module Punchblock
4
4
  class Event
5
5
  module ActiveSpeaker
6
- def call_id
7
- read_attr :'call-id'
8
- end
9
-
10
- def call_id=(other)
11
- write_attr :'call-id', other
12
- end
13
-
14
- def inspect_attributes # :nodoc:
15
- [:call_id] + super
6
+ def self.included(klass)
7
+ klass.attribute :call_id
16
8
  end
17
9
  end
18
10
  end
@@ -6,6 +6,6 @@ module Punchblock
6
6
  register :answered, :core
7
7
 
8
8
  include HasHeaders
9
- end # End
10
- end # Event
11
- end # Punchblock
9
+ end
10
+ end
11
+ end
@@ -1,7 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'punchblock/key_value_pair_node'
4
-
5
3
  module Punchblock
6
4
  class Event
7
5
  module Asterisk
@@ -9,60 +7,30 @@ module Punchblock
9
7
  class Event < Punchblock::Event
10
8
  register :event, :ami
11
9
 
12
- def self.new(options = {})
13
- super().tap do |new_node|
14
- options.each_pair { |k,v| new_node.send :"#{k}=", v }
15
- end
16
- end
17
-
18
- def name
19
- read_attr :name
20
- end
10
+ attribute :name
11
+ attribute :headers, Hash, default: {}
21
12
 
22
- def name=(other)
23
- write_attr :name, other
24
- end
13
+ alias :attributes :headers
25
14
 
26
- ##
27
- # @return [Hash] hash of key-value pairs of attributes
28
- #
29
- def attributes_hash
30
- attributes.inject({}) do |hash, attribute|
31
- hash[attribute.name.downcase.gsub('-', '_').to_sym] = attribute.value
32
- hash
15
+ def inherit(xml_node)
16
+ xml_node.xpath('//ns:attribute', ns: self.class.registered_ns).to_a.each do |attribute|
17
+ headers[attribute[:name]] = attribute[:value]
33
18
  end
19
+ super
34
20
  end
35
21
 
36
- ##
37
- # @return [Array[Attribute]] attributes
38
- #
39
- def attributes
40
- find('//ns:attribute', :ns => self.class.registered_ns).map do |i|
41
- Attribute.new i
42
- end
22
+ def rayo_attributes
23
+ {'name' => name}
43
24
  end
44
25
 
45
- ##
46
- # @param [Hash, Array] attributes A hash of key-value attribute pairs, or an array of Attribute objects
47
- #
48
- def attributes=(attributes)
49
- find('//ns:attribute', :ns => self.class.registered_ns).each(&:remove)
50
- if attributes.is_a? Hash
51
- attributes.each_pair { |k,v| self << Attribute.new(k, v) }
52
- elsif attributes.is_a? Array
53
- [attributes].flatten.each { |i| self << Attribute.new(i) }
26
+ def rayo_children(root)
27
+ super
28
+ headers.each do |name, value|
29
+ root.attribute name: name, value: value
54
30
  end
55
31
  end
56
-
57
- def inspect_attributes # :nodoc:
58
- [:name, :attributes_hash] + super
59
- end
60
-
61
- class Attribute < RayoNode
62
- include KeyValuePairNode
63
- end
64
32
  end
65
33
  end
66
34
  end
67
- end # Command
68
- end # Punchblock
35
+ end
36
+ end
@@ -5,51 +5,34 @@ module Punchblock
5
5
  class Complete < Event
6
6
  register :complete, :ext
7
7
 
8
- def reason
9
- element = find_first '*'
10
- return unless element
11
- RayoNode.import(element).tap do |reason|
12
- reason.target_call_id = target_call_id
13
- reason.component_id = component_id
14
- end
15
- end
8
+ attribute :reason
16
9
 
17
- def reason=(other)
18
- children.map(&:remove)
19
- self << other
20
- end
10
+ attribute :recording
21
11
 
22
- def recording
23
- element = find_first('//ns:recording', :ns => RAYO_NAMESPACES[:record_complete])
24
- return unless element
25
- RayoNode.import(element).tap do |recording|
26
- recording.target_call_id = target_call_id
27
- recording.component_id = component_id
12
+ def inherit(xml_node)
13
+ if reason_node = xml_node.at_xpath('*')
14
+ self.reason = RayoNode.from_xml(reason_node).tap do |reason|
15
+ reason.target_call_id = target_call_id
16
+ reason.component_id = component_id
17
+ end
28
18
  end
29
- end
30
-
31
- def inspect_attributes # :nodoc:
32
- [:reason, :recording] + super
33
- end
34
19
 
35
- class Reason < RayoNode
36
- def self.new(options = {})
37
- super().tap do |new_node|
38
- case options
39
- when Nokogiri::XML::Node
40
- new_node.inherit options
41
- when Hash
42
- options.each_pair { |k,v| new_node.send :"#{k}=", v }
43
- end
20
+ if recording_node = xml_node.at_xpath('//ns:recording', ns: RAYO_NAMESPACES[:record_complete])
21
+ self.recording = RayoNode.from_xml(recording_node).tap do |recording|
22
+ recording.target_call_id = target_call_id
23
+ recording.component_id = component_id
44
24
  end
45
25
  end
46
26
 
47
- def name
48
- super.to_sym
49
- end
27
+ super
28
+ end
29
+
30
+ class Reason < RayoNode
31
+ attribute :name
50
32
 
51
- def inspect_attributes # :nodoc:
52
- [:name] + super
33
+ def inherit(xml_node)
34
+ self.name = xml_node.name.to_sym
35
+ super
53
36
  end
54
37
  end
55
38
 
@@ -64,18 +47,13 @@ module Punchblock
64
47
  class Error < Reason
65
48
  register :error, :ext_complete
66
49
 
67
- def details
68
- text.strip
69
- end
70
-
71
- def details=(other)
72
- self << other
73
- end
50
+ attribute :details
74
51
 
75
- def inspect_attributes # :nodoc:
76
- [:details] + super
52
+ def inherit(xml_node)
53
+ self.details = xml_node.text.strip
54
+ super
77
55
  end
78
56
  end
79
- end # Complete
57
+ end
80
58
  end
81
- end # Punchblock
59
+ end
@@ -5,17 +5,7 @@ module Punchblock
5
5
  class DTMF < Event
6
6
  register :dtmf, :core
7
7
 
8
- def signal
9
- read_attr :signal
10
- end
11
-
12
- def signal=(other)
13
- write_attr :signal, other
14
- end
15
-
16
- def inspect_attributes # :nodoc:
17
- [:signal] + super
18
- end
19
- end # End
8
+ attribute :signal
9
+ end
20
10
  end
21
- end # Punchblock
11
+ end
@@ -7,17 +7,16 @@ module Punchblock
7
7
 
8
8
  include HasHeaders
9
9
 
10
- def reason
11
- children.select { |c| c.is_a? Nokogiri::XML::Element }.first.name.to_sym
12
- end
13
-
14
- def reason=(other)
15
- self << Nokogiri::XML::Element.new(other.to_s, self.document)
16
- end
10
+ attribute :reason, Symbol
11
+ attribute :platform_code, String
17
12
 
18
- def inspect_attributes # :nodoc:
19
- [:reason] + super
13
+ def inherit(xml_node)
14
+ if reason_node = xml_node.at_xpath('*')
15
+ self.reason = reason_node.name
16
+ self.platform_code = reason_node['platform-code']
17
+ end
18
+ super
20
19
  end
21
- end # End
20
+ end
22
21
  end
23
- end # Punchblock
22
+ end
@@ -5,33 +5,13 @@ module Punchblock
5
5
  class Joined < Event
6
6
  register :joined, :core
7
7
 
8
- ##
9
8
  # @return [String] the call ID that was joined
10
- def call_id
11
- read_attr :'call-id'
12
- end
9
+ attribute :call_uri
13
10
 
14
- ##
15
- # @param [String] other the call ID that was joined
16
- def call_id=(other)
17
- write_attr :'call-id', other
18
- end
19
-
20
- ##
21
11
  # @return [String] the mixer name that was joined
22
- def mixer_name
23
- read_attr :'mixer-name'
24
- end
25
-
26
- ##
27
- # @param [String] other the mixer name that was joined
28
- def mixer_name=(other)
29
- write_attr :'mixer-name', other
30
- end
12
+ attribute :mixer_name
31
13
 
32
- def inspect_attributes # :nodoc:
33
- [:call_id, :mixer_name] + super
34
- end
35
- end # Joined
14
+ alias :call_id :call_uri
15
+ end
36
16
  end
37
- end # Punchblock
17
+ end
@@ -7,29 +7,8 @@ module Punchblock
7
7
 
8
8
  include HasHeaders
9
9
 
10
- def to
11
- read_attr :to
12
- end
13
-
14
- def to=(offer_to)
15
- write_attr :to, offer_to
16
- end
17
-
18
- def from
19
- read_attr :from
20
- end
21
-
22
- def from=(offer_from)
23
- write_attr :from, offer_from
24
- end
25
-
26
- def inspect_attributes # :nodoc:
27
- [:to, :from] + super
28
- end
29
-
30
- def inspect
31
- "#<Punchblock::Event::Offer to=\"#{to}\", from=\"#{from}\", headers=#{headers_hash.inspect}, call_id=\"#{target_call_id}\""
32
- end
33
- end # Offer
10
+ attribute :to
11
+ attribute :from
12
+ end
34
13
  end
35
- end # Punchblock
14
+ end
@@ -6,6 +6,6 @@ module Punchblock
6
6
  register :ringing, :core
7
7
 
8
8
  include HasHeaders
9
- end # End
10
- end # Event
11
- end # Punchblock
9
+ end
10
+ end
11
+ end
@@ -5,33 +5,13 @@ module Punchblock
5
5
  class Unjoined < Event
6
6
  register :unjoined, :core
7
7
 
8
- ##
9
8
  # @return [String] the call ID that was unjoined
10
- def call_id
11
- read_attr :'call-id'
12
- end
9
+ attribute :call_uri
13
10
 
14
- ##
15
- # @param [String] other the call ID that was unjoined
16
- def call_id=(other)
17
- write_attr :'call-id', other
18
- end
19
-
20
- ##
21
11
  # @return [String] the mixer name that was unjoined
22
- def mixer_name
23
- read_attr :'mixer-name'
24
- end
25
-
26
- ##
27
- # @param [String] other the mixer name that was unjoined
28
- def mixer_name=(other)
29
- write_attr :'mixer-name', other
30
- end
12
+ attribute :mixer_name
31
13
 
32
- def inspect_attributes # :nodoc:
33
- [:call_id, :mixer_name] + super
34
- end
35
- end # Unjoined
14
+ alias :call_id :call_uri
15
+ end
36
16
  end
37
- end # Punchblock
17
+ end
@@ -2,16 +2,6 @@
2
2
 
3
3
  module Punchblock
4
4
  class Event < RayoNode
5
- def self.new(options = {})
6
- super().tap do |new_node|
7
- case options
8
- when Nokogiri::XML::Node
9
- new_node.inherit options
10
- when Hash
11
- options.each_pair { |k,v| new_node.send :"#{k}=", v }
12
- end
13
- end
14
- end
15
5
  end
16
6
  end
17
7
 
@@ -2,39 +2,33 @@
2
2
 
3
3
  module Punchblock
4
4
  module HasHeaders
5
- ##
6
- # @return [Hash] hash of key-value pairs of headers
7
- #
8
- def headers_hash
9
- headers.inject({}) do |hash, header|
10
- hash[header.name.downcase.gsub('-', '_').to_sym] = header.value
11
- hash
12
- end
5
+ def self.included(klass)
6
+ klass.attribute :headers, Hash, default: {}
13
7
  end
14
8
 
15
- ##
16
- # @return [Array[Header]] headers
17
- #
18
- def headers
19
- find('//ns:header', :ns => self.class.registered_ns).map do |i|
20
- Header.new i
21
- end
9
+ def headers=(other)
10
+ super(other || {})
22
11
  end
23
12
 
24
- ##
25
- # @param [Hash, Array] headers A hash of key-value header pairs, or an array of Header objects
26
- #
27
- def headers=(headers)
28
- find('//ns:header', :ns => self.class.registered_ns).each(&:remove)
29
- if headers.is_a? Hash
30
- headers.each_pair { |k,v| self << Header.new(k, v) }
31
- elsif headers.is_a? Array
32
- [headers].flatten.each { |i| self << Header.new(i) }
13
+ def inherit(xml_node)
14
+ xml_node.xpath('//ns:header', ns: self.class.registered_ns).to_a.each do |header|
15
+ if headers.has_key?(header[:name])
16
+ headers[header[:name]] = [headers[header[:name]]]
17
+ headers[header[:name]] << header[:value]
18
+ else
19
+ headers[header[:name]] = header[:value]
20
+ end
33
21
  end
22
+ super
34
23
  end
35
24
 
36
- def inspect_attributes # :nodoc:
37
- [:headers_hash] + super
25
+ def rayo_children(root)
26
+ super
27
+ headers.each do |name, value|
28
+ Array(value).each do |v|
29
+ root.header name: name, value: v
30
+ end
31
+ end
38
32
  end
39
33
  end
40
34
  end
@@ -1,17 +1,25 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'active_support/core_ext/class/attribute'
4
- require 'niceogiri'
4
+ require 'virtus'
5
5
 
6
6
  module Punchblock
7
- class RayoNode < Niceogiri::XML::Node
7
+ class RayoNode
8
+ include Virtus
9
+
8
10
  InvalidNodeError = Class.new Punchblock::Error
9
11
 
10
12
  @@registrations = {}
11
13
 
12
14
  class_attribute :registered_ns, :registered_name
13
15
 
14
- attr_accessor :target_call_id, :target_mixer_name, :component_id, :domain, :connection, :client, :original_component
16
+ attribute :target_call_id
17
+ attribute :target_mixer_name
18
+ attribute :component_id
19
+ attribute :domain
20
+ attribute :transport
21
+
22
+ attr_accessor :connection, :client, :original_component
15
23
 
16
24
  # Register a new stanza class to a name and/or namespace
17
25
  #
@@ -42,12 +50,11 @@ module Punchblock
42
50
  # elements of the XML::Node
43
51
  # @param [XML::Node] node the node to import
44
52
  # @return the appropriate object based on the node name and namespace
45
- def self.import(node, call_id = nil, component_id = nil)
46
- node = Nokogiri::XML(node.to_xml).root if Punchblock.jruby?
53
+ def self.from_xml(node, call_id = nil, component_id = nil)
47
54
  ns = (node.namespace.href if node.namespace)
48
- klass = class_from_registration(node.element_name, ns)
55
+ klass = class_from_registration(node.name, ns)
49
56
  if klass && klass != self
50
- klass.import node, call_id, component_id
57
+ klass.from_xml node, call_id, component_id
51
58
  else
52
59
  new.inherit node
53
60
  end.tap do |event|
@@ -56,27 +63,23 @@ module Punchblock
56
63
  end
57
64
  end
58
65
 
59
- # Create a new Node object
60
- #
61
- # @param [String, nil] name the element name
62
- # @param [XML::Document, nil] doc the document to attach the node to. If
63
- # not provided one will be created
64
- # @return a new object with the registered name and namespace
65
- def self.new(name = registered_name, doc = nil)
66
- raise InvalidNodeError, "Trying to create a new #{self} with no name" unless name
67
- super name, doc, registered_ns
66
+ def inherit(xml_node)
67
+ xml_node.attributes.each do |key, attr_node|
68
+ send "#{key.gsub('-', '_')}=", xml_node[key]
69
+ end
70
+ self
68
71
  end
69
72
 
70
- def inspect_attributes # :nodoc:
71
- [:target_call_id, :component_id, :target_mixer_name]
73
+ def inspect
74
+ "#<#{self.class} #{to_hash.map { |k, v| "#{k}=#{v.inspect}" }.compact * ', '}>"
72
75
  end
73
76
 
74
- def inspect
75
- "#<#{self.class} #{inspect_attributes.map { |c| "#{c}=#{self.__send__(c).inspect rescue nil}" }.compact * ', '}>"
77
+ def ==(o)
78
+ o.is_a?(self.class) && self.to_hash == o.to_hash
76
79
  end
77
80
 
78
- def eql?(o, *fields)
79
- super o, *(fields + inspect_attributes)
81
+ def to_hash
82
+ get_attributes(&:public_reader?)
80
83
  end
81
84
 
82
85
  ##
@@ -87,7 +90,27 @@ module Punchblock
87
90
  @source ||= original_component
88
91
  end
89
92
 
93
+ def rayo_attributes
94
+ {}
95
+ end
96
+
97
+ def rayo_children(root)
98
+ end
99
+
100
+ def to_rayo(parent = nil)
101
+ parent = parent.parent if parent.is_a?(Nokogiri::XML::Builder)
102
+ Nokogiri::XML::Builder.with(parent) do |xml|
103
+ xml.send(registered_name,
104
+ {xmlns: registered_ns}.merge(rayo_attributes.delete_if { |k,v| v.nil? })) do |root|
105
+ rayo_children root
106
+ end
107
+ end.doc.root
108
+ end
109
+
110
+ def to_xml
111
+ to_rayo.to_xml
112
+ end
113
+
90
114
  alias :to_s :inspect
91
- alias :xmlns :namespace_href
92
115
  end
93
116
  end