lib/happymapper.rb in nokogiri-happymapper-0.5.3 vs lib/happymapper.rb in nokogiri-happymapper-0.5.4
- old
+ new
@@ -5,16 +5,19 @@
class Boolean; end
class XmlContent; end
module HappyMapper
+ VERSION = "0.5.4"
+
DEFAULT_NS = "happymapper"
def self.included(base)
base.instance_variable_set("@attributes", {})
base.instance_variable_set("@elements", {})
base.instance_variable_set("@registered_namespaces", {})
+ base.instance_variable_set("@wrapper_anonymous_classes", {})
base.extend ClassMethods
end
module ClassMethods
@@ -194,11 +197,43 @@
# @return [String] the name of the tag as a string, downcased
#
def tag_name
@tag_name ||= to_s.split('::')[-1].downcase
end
+
+ # There is an XML tag that needs to be known for parsing and should be generated
+ # during a to_xml. But it doesn't need to be a class and the contained elements should
+ # be made available on the parent class
+ #
+ # @param [String] name the name of the element that is just a place holder
+ # @param [Proc] blk the element definitions inside the place holder tag
+ #
+ def wrap(name, &blk)
+ # Get an anonymous HappyMapper that has 'name' as its tag and defined
+ # in '&blk'. Then save that to a class instance variable for later use
+ wrapper = AnonymousWrapperClassFactory.get(name, &blk)
+ @wrapper_anonymous_classes[wrapper.inspect] = wrapper
+ # Create getter/setter for each element and attribute defined on the anonymous HappyMapper
+ # onto this class. They get/set the value by passing thru to the anonymous class.
+ passthrus = wrapper.attributes + wrapper.elements
+ passthrus.each do |item|
+ class_eval %{
+ def #{item.method_name}
+ @#{name} ||= self.class.instance_variable_get('@wrapper_anonymous_classes')['#{wrapper.inspect}'].new
+ @#{name}.#{item.method_name}
+ end
+ def #{item.method_name}=(value)
+ @#{name} ||= self.class.instance_variable_get('@wrapper_anonymous_classes')['#{wrapper.inspect}'].new
+ @#{name}.#{item.method_name} = value
+ end
+ }
+ end
+
+ has_one name, wrapper
+ end
+
#
# @param [Nokogiri::XML::Node,Nokogiri:XML::Document,String] xml the XML
# contents to convert into Object.
# @param [Hash] options additional information for parsing. :single => true
# if requesting a single object, otherwise it defaults to retuning an
@@ -387,17 +422,21 @@
#
# @param [Nokogiri::XML::Builder] builder an instance of the XML builder which
# is being used when called recursively.
# @param [String] default_namespace the name of the namespace which is the
# default for the xml being produced; this is specified by the element
- # declaration when calling #to_xml recursively.
+ # declaration when calling #to_xml recursively.
+ # @param [String] tag_from_parent the xml tag to use on the element when being
+ # called recursively. This lets the parent doc define its own structure.
+ # Otherwise the element uses the tag it has defined for itself. Should only
+ # apply when calling a child HappyMapper element.
#
# @return [String,Nokogiri::XML::Builder] return XML representation of the
# HappyMapper object; when called recursively this is going to return
# and Nokogiri::XML::Builder object.
#
- def to_xml(builder = nil,default_namespace = nil)
+ def to_xml(builder = nil,default_namespace = nil,tag_from_parent = nil)
#
# If to_xml has been called without a passed in builder instance that
# means we are going to return xml output. When it has been called with
# a builder instance that means we most likely being called recursively
@@ -452,16 +491,17 @@
end
end.flatten
attributes = Hash[ *attributes ]
-
+
#
- # Create a tag in the builder that matches the class's tag name and append
+ # Create a tag in the builder that matches the class's tag name unless a tag was passed
+ # in a recursive call from the parent doc. Then append
# any attributes to the element that were defined above.
#
- builder.send("#{self.class.tag_name}_",attributes) do |xml|
+ builder.send("#{tag_from_parent || self.class.tag_name}_",attributes) do |xml|
#
# Add all the registered namespaces to the root element.
# When this is called recurisvely by composed classes the namespaces
# are still added to the root element
@@ -573,11 +613,11 @@
#
# Other items are convertable to xml through the xml builder
# process should have their contents retrieved and attached
# to the builder structure
#
- item.to_xml(xml,element.options[:namespace])
+ item.to_xml(xml,element.options[:namespace],element.options[:tag] || nil)
elsif item
item_namespace = element.options[:namespace] || self.class.namespace || default_namespace
@@ -622,13 +662,26 @@
# created for any HappyMapper children of this object.
#
# Params and return are the same as the class parse() method above.
def parse(xml, options = {})
self.class.parse(xml, options.merge!(:update => self))
+ end
+
+ private
+
+ # Factory for creating anonmyous HappyMappers
+ class AnonymousWrapperClassFactory
+ def self.get(name, &blk)
+ Class.new do
+ include HappyMapper
+ tag name
+ instance_eval &blk
+ end
+ end
end
end
-require 'happymapper/item'
-require 'happymapper/attribute'
-require 'happymapper/element'
-require 'happymapper/text_node'
+require File.dirname(__FILE__) + '/happymapper/item'
+require File.dirname(__FILE__) + '/happymapper/attribute'
+require File.dirname(__FILE__) + '/happymapper/element'
+require File.dirname(__FILE__) + '/happymapper/text_node'