# encoding: utf-8 require 'active_support/core_ext/class/attribute' require 'virtus' module Punchblock class RayoNode include Virtus @@registrations = {} class_attribute :registered_ns, :registered_name attribute :target_call_id attribute :target_mixer_name attribute :component_id attribute :domain attribute :transport attr_accessor :connection, :client, :original_component # Register a new stanza class to a name and/or namespace # # This registers a namespace that is used when looking # up the class name of the object to instantiate when a new # stanza is received # # @param [#to_s] name the name of the node # @param [String, nil] ns the namespace the node belongs to def self.register(name, ns = nil) self.registered_name = name.to_s self.registered_ns = ns.is_a?(Symbol) ? RAYO_NAMESPACES[ns] : ns @@registrations[[self.registered_name, self.registered_ns]] = self end # Find the class to use given the name and namespace of a stanza # # @param [#to_s] name the name to lookup # @param [String, nil] xmlns the namespace the node belongs to # @return [Class, nil] the class appropriate for the name/ns combination def self.class_from_registration(name, ns = nil) @@registrations[[name.to_s, ns]] end # Import an XML::Node to the appropriate class # # Looks up the class the node should be then creates it based on the # elements of the XML::Node # @param [XML::Node] node the node to import # @return the appropriate object based on the node name and namespace def self.from_xml(node, call_id = nil, component_id = nil) ns = (node.namespace.href if node.namespace) klass = class_from_registration(node.name, ns) if klass && klass != self klass.from_xml node, call_id, component_id else new.inherit node end.tap do |event| event.target_call_id = call_id event.component_id = component_id end end def inherit(xml_node) xml_node.attributes.each do |key, attr_node| setter_method = "#{key.gsub('-', '_')}=" send setter_method, xml_node[key] if respond_to?(setter_method) end self end def inspect "#<#{self.class} #{to_hash.map { |k, v| "#{k}=#{v.inspect}" }.compact * ', '}>" end def ==(o) o.is_a?(self.class) && self.to_hash == o.to_hash end def to_hash get_attributes(&:public_reader?) end ## # @return [RayoNode] the original command issued that lead to this event # def source @source ||= client.find_component_by_id component_id if client && component_id @source ||= original_component end def rayo_attributes {} end def rayo_children(root) end def to_rayo(parent = nil) parent = parent.parent if parent.is_a?(Nokogiri::XML::Builder) Nokogiri::XML::Builder.with(parent) do |xml| xml.send(registered_name, {xmlns: registered_ns}.merge(rayo_attributes.delete_if { |k,v| v.nil? })) do |root| rayo_children root end end.doc.root end def to_xml to_rayo.to_xml end alias :to_s :inspect end end