lib/happymapper.rb in nokogiri-happymapper-0.5.9 vs lib/happymapper.rb in nokogiri-happymapper-0.6.0
- old
+ new
@@ -107,12 +107,12 @@
# the object will be converted upon parsing
# @param [Hash] options additional parameters to send to the relationship
#
def element(name, type, options={})
element = Element.new(name, type, options)
+ attr_accessor element.method_name.intern unless @elements[name]
@elements[name] = element
- attr_accessor element.method_name.intern
end
#
# The elements defined through {#element}, {#has_one}, and {#has_many}.
#
@@ -183,20 +183,36 @@
def has_many(name, type, options={})
element name, type, {:single => false}.merge(options)
end
#
+ # The list of registered after_parse callbacks.
+ #
+ def after_parse_callbacks
+ @after_parse_callbacks ||= []
+ end
+
+ #
+ # Register a new after_parse callback, given as a block.
+ #
+ # @yield [object] Yields the newly-parsed object to the block after parsing.
+ # Sub-objects will be already populated.
+ def after_parse(&block)
+ after_parse_callbacks.push(block)
+ end
+
+ #
# Specify a namespace if a node and all its children are all namespaced
# elements. This is simpler than passing the :namespace option to each
# defined element.
#
# @param [String] namespace the namespace to set as default for the class
# element.
#
def namespace(namespace = nil)
@namespace = namespace if namespace
- @namespace
+ @namespace if defined? @namespace
end
#
# @param [String] new_tag_name the name for the tag
#
@@ -247,13 +263,11 @@
# The callback defined through {.with_nokogiri_config}.
#
# @return [Proc] the proc to pass to Nokogiri to setup parse options. nil if empty.
#
- def nokogiri_config_callback
- @nokogiri_config_callback
- end
+ attr_reader :nokogiri_config_callback
# Register a config callback according to the block Nokogori expects when calling Nokogiri::XML::Document.parse().
# See http://nokogiri.org/Nokogiri/XML/Document.html#method-c-parse
#
# @param [Proc] the proc to pass to Nokogiri to setup parse options
@@ -271,11 +285,11 @@
# :namespace is the namespace to use for additional information.
#
def parse(xml, options = {})
# create a local copy of the objects namespace value for this parse execution
- namespace = @namespace
+ namespace = (@namespace if defined? @namespace)
# If the XML specified is an Node then we have what we need.
if xml.is_a?(Nokogiri::XML::Node) && !xml.is_a?(Nokogiri::XML::Document)
node = xml
else
@@ -408,32 +422,36 @@
elements.each do |elem|
obj.send("#{elem.method_name}=",elem.from_xml_node(n, namespace, namespaces))
end
- if @content
+ if (defined? @content) && @content
obj.send("#{@content.method_name}=",@content.from_xml_node(n, namespace, namespaces))
end
# If the HappyMapper class has the method #xml_value=,
# attr_writer :xml_value, or attr_accessor :xml_value then we want to
# assign the current xml that we just parsed to the xml_value
if obj.respond_to?('xml_value=')
n.namespaces.each {|name,path| n[name] = path }
- obj.xml_value = n.to_xml
+ obj.xml_value = n.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML)
end
# If the HappyMapper class has the method #xml_content=,
# attr_write :xml_content, or attr_accessor :xml_content then we want to
# assign the child xml that we just parsed to the xml_content
if obj.respond_to?('xml_content=')
n = n.children if n.respond_to?(:children)
- obj.xml_content = n.to_xml
+ obj.xml_content = n.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML)
end
+ # Call any registered after_parse callbacks for the object's class
+
+ obj.class.after_parse_callbacks.each { |callback| callback.call(obj) }
+
# collect the object that we have created
obj
end
@@ -478,23 +496,27 @@
# that it can be called recursively by classes that are also HappyMapper
# classes, allowg for the composition of classes.
#
# @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.
- # @param [String] tag_from_parent the xml tag to use on the element when being
+ # @param [String] default_namespace The name of the namespace which is the
+ # default for the xml being produced; this is the namespace of the
+ # parent
+ # @param [String] namespace_override The namespace specified with the element
+ # declaration in the parent. Overrides the namespace declaration in the
+ # element class itself 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,tag_from_parent = nil)
+ def to_xml(builder = nil, default_namespace = nil, namespace_override = 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
@@ -537,11 +559,11 @@
#
# Attributes that have a nil value should be ignored unless they explicitly
# state that they should be expressed in the output.
#
if not value.nil? || attribute.options[:state_when_nil]
- attribute_namespace = attribute.options[:namespace] || default_namespace
+ attribute_namespace = attribute.options[:namespace]
[ "#{attribute_namespace ? "#{attribute_namespace}:" : ""}#{attribute.tag}", value ]
else
[]
end
@@ -574,43 +596,48 @@
builder.doc.root.add_namespace(name,href)
end
end
#
- # If the object we are persisting has a namespace declaration we will want
+ # If the object we are serializing has a namespace declaration we will want
# to use that namespace or we will use the default namespace.
# When neither are specifed we are simply using whatever is default to the
# builder
#
+ namespace_for_parent = namespace_override
if self.class.respond_to?(:namespace) && self.class.namespace
- xml.parent.namespace = builder.doc.root.namespace_definitions.find { |x| x.prefix == self.class.namespace }
- elsif default_namespace
- xml.parent.namespace = builder.doc.root.namespace_definitions.find { |x| x.prefix == default_namespace }
+ namespace_for_parent ||= self.class.namespace
end
+ namespace_for_parent ||= default_namespace
+ xml.parent.namespace =
+ builder.doc.root.namespace_definitions.find { |x| x.prefix == namespace_for_parent }
+
#
# When a content has been defined we add the resulting value
# the output xml
#
- if content = self.class.instance_variable_get('@content')
+ if self.class.instance_variable_defined?('@content')
+ if content = self.class.instance_variable_get('@content')
- unless content.options[:read_only]
- text_accessor = content.tag || content.name
- value = send(text_accessor)
+ unless content.options[:read_only]
+ text_accessor = content.tag || content.name
+ value = send(text_accessor)
- if on_save_action = content.options[:on_save]
- if on_save_action.is_a?(Proc)
- value = on_save_action.call(value)
- elsif respond_to?(on_save_action)
- value = send(on_save_action,value)
+ if on_save_action = content.options[:on_save]
+ if on_save_action.is_a?(Proc)
+ value = on_save_action.call(value)
+ elsif respond_to?(on_save_action)
+ value = send(on_save_action,value)
+ end
end
+
+ builder.text(value)
end
- builder.text(value)
end
-
end
#
# for every define element (i.e. has_one, has_many, element) we are
# going to persist each one
@@ -672,11 +699,13 @@
#
# 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],element.options[:tag] || nil)
+ item.to_xml(xml, self.class.namespace || default_namespace,
+ element.options[:namespace],
+ element.options[:tag] || nil)
elsif !item.nil?
item_namespace = element.options[:namespace] || self.class.namespace || default_namespace
@@ -731,10 +760,10 @@
class AnonymousWrapperClassFactory
def self.get(name, &blk)
Class.new do
include HappyMapper
tag name
- instance_eval &blk
+ instance_eval(&blk)
end
end
end
end