lib/blather/xmpp_node.rb in blather-0.2.1 vs lib/blather/xmpp_node.rb in blather-0.2.2
- old
+ new
@@ -3,25 +3,27 @@
##
# Base XML Node
# All XML classes subclass XMPPNode
# it allows the addition of helpers
class XMPPNode < XML::Node
+ BASE_NAMES = %w[presence message iq].freeze
+
@@registrations = {}
- class_inheritable_accessor :xmlns,
+ class_inheritable_accessor :ns,
:name
##
# Lets a subclass register itself
#
# This registers a namespace that is used when looking
# up the class name of the object to instantiate when a new
# stanza is received
- def self.register(name, xmlns = nil)
+ def self.register(name, ns = nil)
self.name = name.to_s
- self.xmlns = xmlns
- @@registrations[[self.name, self.xmlns]] = self
+ self.ns = ns
+ @@registrations[[self.name, self.ns]] = self
end
##
# Find the class to use given the name and namespace of a stanza
def self.class_from_registration(name, xmlns)
@@ -32,47 +34,116 @@
##
# Looks up the class to use then instantiates an object
# of that class and imports all the <tt>node</tt>'s attributes
# and children into it.
def self.import(node)
- klass = class_from_registration(node.element_name, node.xmlns)
+ klass = class_from_registration(node.element_name, node.namespace)
if klass && klass != self
klass.import(node)
else
new(node.element_name).inherit(node)
end
end
##
+ # Provides an attribute reader helper. Default behavior is to
+ # conver the values of the attribute into a symbol. This can
+ # be turned off by passing <tt>:to_sym => false</tt>
+ #
+ # class Node
+ # attribute_reader :type
+ # attribute_reader :name, :to_sym => false
+ # end
+ #
+ # n = Node.new
+ # n.attributes[:type] = 'foo'
+ # n.type == :foo
+ # n.attributes[:name] = 'bar'
+ # n.name == 'bar'
+ def self.attribute_reader(*syms)
+ opts = syms.last.is_a?(Hash) ? syms.pop : {}
+ syms.flatten.each do |sym|
+ class_eval(<<-END, __FILE__, __LINE__)
+ def #{sym}
+ attributes[:#{sym}]#{".to_sym unless attributes[:#{sym}].blank?" unless opts[:to_sym] == false}
+ end
+ END
+ end
+ end
+
+ ##
+ # Provides an attribute writer helper.
+ #
+ # class Node
+ # attribute_writer :type
+ # end
+ #
+ # n = Node.new
+ # n.type = 'foo'
+ # n.attributes[:type] == 'foo'
+ def self.attribute_writer(*syms)
+ syms.flatten.each do |sym|
+ next if sym.is_a?(Hash)
+ class_eval(<<-END, __FILE__, __LINE__)
+ def #{sym}=(value)
+ attributes[:#{sym}] = value
+ end
+ END
+ end
+ end
+
+ ##
+ # Provides an attribute accessor helper combining
+ # <tt>attribute_reader</tt> and <tt>attribute_writer</tt>
+ #
+ # class Node
+ # attribute_accessor :type
+ # attribute_accessor :name, :to_sym => false
+ # end
+ #
+ # n = Node.new
+ # n.type = 'foo'
+ # n.type == :foo
+ # n.name = 'bar'
+ # n.name == 'bar'
+ def self.attribute_accessor(*syms)
+ attribute_reader *syms
+ attribute_writer *syms
+ end
+
+ ##
# Automatically sets the namespace registered by the subclass
def initialize(name = nil, content = nil)
name ||= self.class.name
content = content.to_s if content
super name.to_s, content
- self.xmlns = self.class.xmlns
+ self.namespace = self.class.ns unless BASE_NAMES.include?(name.to_s)
end
##
# Quickway of turning itself into a proper object
def to_stanza
self.class.import self
end
- def xmlns=(ns)
- attributes['xmlns'] = ns
+ def namespace=(ns)
+ if ns
+ ns = {nil => ns} unless ns.is_a?(Hash)
+ ns.each { |n| XML::Namespace.new self, *n }
+ end
end
- def xmlns
- attributes['xmlns']
+ def namespace(prefix = nil)
+ (ns = namespaces.find_by_prefix(prefix)) ? ns.href : nil
end
##
# Remove a child with the name and (optionally) namespace given
def remove_child(name, ns = nil)
name = name.to_s
- self.each { |n| n.remove! if n.element_name == name && (!ns || n.xmlns == ns) }
+ self.detect { |n| n.remove! if n.element_name == name && (!ns || n.namespace == ns) }
end
##
# Remove all children with a given name
def remove_children(name)
@@ -88,11 +159,13 @@
end
##
# Create a copy
def copy(deep = true)
- self.class.new(self.element_name).inherit(self)
+ copy = self.class.new.inherit(self)
+ copy.element_name = self.element_name
+ copy
end
##
# Inherit all of <tt>stanza</tt>'s attributes and children
def inherit(stanza)
@@ -102,24 +175,25 @@
end
##
# Inherit only <tt>stanza</tt>'s attributes
def inherit_attrs(attrs)
- attrs.each { |a| self[a.name] = a.value }
+ attrs.each { |a| attributes[a.name] = a.value }
self
end
##
- # Turn itself into a string and remove all whitespace between nodes
- def to_s
+ # Turn itself into an XML string and remove all whitespace between nodes
+ def to_xml
# TODO: Fix this for HTML nodes (and any other that might require whitespace)
- super.gsub(">\n<", '><')
+ to_s.gsub(">\n<", '><')
end
##
# Override #find to work when a node isn't attached to a document
def find(what, nslist = nil)
- (self.doc ? super(what, nslist) : select { |i| i.element_name == what})
+ what = what.to_s
+ (self.doc ? super(what, nslist) : select { |i| i.element_name == what })
end
end #XMPPNode
end
\ No newline at end of file