Skip to content

Instantly share code, notes, and snippets.

@SixArm
Created November 29, 2014 06:39
Show Gist options
  • Save SixArm/6e6915f0d6f356084e71 to your computer and use it in GitHub Desktop.
Save SixArm/6e6915f0d6f356084e71 to your computer and use it in GitHub Desktop.
Exportable module for exporting XML
##
# Exportable module to help create XML from models.
#
# Author: Joel Parker Henderson (joel@joelparkerhenderson.com)
# License: GPL
#
module Exportable
##
# Get this object's export string, such as an XML element string.
#
# Example:
#
# class Item < String
# include Exportable
# end
#
# a = Item.new("Hello")
# a.export
# #=> "<item>Hello</item>"
#
# Example using a given key:
#
# a.export("foo")
# #=> "<foo>Hello</foo>"
#
# Example using a given key and given value:
#
# a.export("foo", "goo")
# #=> "<foo>goo</foo>"
#
def export(key = export_key, value = export_value)
"<#{key}>#{value}</#{key}>"
end
##
# Get this object's export key, such as a XML tag name string.
#
# This default implementation returns the class name, adjusted
# so the first letter is lowercase as per XML convention.
#
# Example:
#
# class Item < String
# include Exportable
# end
#
# a = Item.new
# a.export_key
# #=> "item"
#
def export_key
self.class.name.sub(/^./){$&.downcase}
end
##
# Get this object's export value, such as an XML tag content string.
#
# Example:
#
# class Item < String
# include Exportable
# end
#
# a = Item.new("Hello")
# a.export_value
# #=> "Hello"
#
def export_value
to_s
end
##
# Export an object as an XML string.
#
# This method has cases for four kinds of objects.
#
# * Exportable.
# * Enumerable with items, such as an Array.
# * Enumerable with pairs, such as a Hash.
# * Anything else.
#
# Example:
#
# class Item < String
# include Exportable
# end
#
# class Color < String
# include Exportable
# end
#
# a = Item.new
#
# # Object is Exportable
# obj = Color.new("Red")
# a.export_object(obj)
# #=> "<color>Red</color>"
#
# # Object is Enumerable with items that are Exportable
# obj = [Color.new("Red"), Color.new("Green")]
# a.export_object(obj)
# #=> "<color>Red</color><color>Green</color>"
#
# # Object is Enumerable with pairs and vaules that are Exportable
# obj = {foo: Color.new("Red"), goo: Color.new("Green")}
# a.export_object(obj)
# #=> "<foo><color>Red</color></foo><goo><color>Green</color></goo>"
#
# # Object is anything else, e.g. a String
# obj = "Anything"
# a.export_object(obj)
# #=> "Anything"
#
def export_object(object)
case object
when Exportable
export_object_when_exportable(object)
when Enumerable
export_object_when_enumerable(object)
else
export_object_when_default(object)
end
end
def export_object_when_exportable(object)
object.export
end
def export_object_when_enumerable(object)
if object.respond_to?(:each_pair)
export_object_when_enumerable_with_pairs(object)
else
export_object_when_enumerable_with_items(object)
end
end
def export_object_when_enumerable_with_items(object)
object.map{|x|
export_object(x)
}.join
end
def export_object_when_enumerable_with_pairs(object)
object.keys.map{|key|
export(key, export_object(object[key]))
}.join
end
def export_object_when_default(object)
object.to_s
end
##
# Export an instance variable.
#
# This implementation calls #export_object on the variable.
#
# Example:
#
# class Item
# include Exportable
# attr_accessor :color
# end
#
# a = Item.new
# a.color = "Red"
# a.export_instance_variable(:@color)
# #=> "<color>Red</color>"
#
#
def export_instance_variable(variable)
export(
variable.to_s.sub(/^@/,''),
export_object(instance_variable_get(variable))
)
end
##
# Export all the instance variables.
#
# class Item
# include Exportable
# attr_accessor :color
# attr_accessor :size
# end
#
# This implementation calls #export_instance_variable on each variable.
#
# Example:
#
# a = Item.new
# a.color = "Red"
# a.size = "Large"
# a.export_instance_variables
# #=> "<color>Red</color><size>Large</size>"
#
#
def export_instance_variables
instance_variables.map{|variable|
export_instance_variable(variable)
}.join
end
##
# Export the result of sending a message to this object.
#
# Example:
#
# class Item < String
# include Exportable
# end
#
# a = Item.new("Hello")
# a.export_send("length")
# #=> "<length>5</length>"
#
# Example using a key that is different than the message name:
#
# a.export_send("foo", "length")
# #=> "<foo>5</foo>"
#
def export_send(key, message_name = nil, *args, &block)
export(key, __send__(message_name || key, *args, &block))
end
##
# Export an enumerable.
#
# This implementation calls #export on each element.
#
# class Item < String
# attr_accessor :colors
# end
#
# class Color < String
# include Exportable
# end
#
# a = Item.new
# a.colors = [Color.new("Red"), Color.new("Green")]
# a.export_enumerable("colors")
# #=> "<colors><color>Red</color><color>Green</color></colors>"
#
def export_enumerable(key, enumerable = nil)
export(key, (enumerable || self.__send__(key)).map(&:export).join)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment