Skip to content

Instantly share code, notes, and snippets.

@larrylv
Last active October 7, 2015 07:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save larrylv/a67e11a7e9ec6b0b7697 to your computer and use it in GitHub Desktop.
Save larrylv/a67e11a7e9ec6b0b7697 to your computer and use it in GitHub Desktop.
Convert Hash to XML
require "minitest/autorun"
require "builder"
class Converter
XML_DECLARATION = %q(<?xml version="1.0" encoding="UTF-8"?>)
def self.to_xml(h)
raise unless h.kind_of? Hash
h.inject("") { |s, (k, v)| s += node_with(k, v) }
end
private
def self.node_with(k, v)
case v
when Hash then node_with_hash(k, v)
when Array then node_with_array(k, v)
else node_with_string(k, v)
end
end
def self.node_with_hash(k, v)
node_with_string(k, to_xml(v))
end
def self.node_with_array(k, v)
v.map { |elt| node_with(k, elt) }.join("")
end
def self.node_with_string(k, v)
"<#{k}>#{v}</#{k}>"
end
end
class TestConverter < Minitest::Test
def setup
@profile = {:name => "Larry", :twitter => "@larrylv", :github => "@larrylv"}
end
def test_string_values
expected_value = <<-XML
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
XML
assert_equal format_xml_string(expected_value), Converter.to_xml(@profile)
end
def test_hash_values
@profile[:blog] = {
:tech => "blog.larrylv.com",
:journey => "journey.larrylv.com",
:homepage => "larrylv.com"
}
expected_value = <<-XML
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
<blog>
<tech>blog.larrylv.com</tech>
<journey>journey.larrylv.com</journey>
<homepage>larrylv.com</homepage>
</blog>
XML
assert_equal format_xml_string(expected_value), Converter.to_xml(@profile)
end
def test_array_values
@profile[:blogs] = {:blog => %w(blog.larrylv.com journey.larrylv.com larrylv.com)}
expected_value = <<-XML
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
<blogs>
<blog>blog.larrylv.com</blog>
<blog>journey.larrylv.com</blog>
<blog>larrylv.com</blog>
</blogs>
XML
assert_equal format_xml_string(expected_value), Converter.to_xml(@profile)
end
private
def format_xml_string(s)
s.split("\n").map(&:strip).join("")
end
end
require "minitest/autorun"
require "active_support/core_ext/string/strip"
require "builder"
class Converter
def self.hash_to_xml(hash, options = {})
raise unless hash.kind_of? Hash
if options[:builder]
builder = options[:builder]
else
builder = Builder::XmlMarkup.new(indent: 2)
builder.instruct!
end
hash.each do |k, v|
node_with(builder, k, v)
end
builder.target!
end
def self.array_to_xml(array, key, attributes = {}, options = {})
raise unless array.kind_of? Array
builder = options[:builder] || Builder::XmlMarkup.new(indent: 2)
array.each do |elt|
node_with(builder, key, elt, attributes)
end
builder.target!
end
private
def self.node_with(builder, k, v, attributes = {})
case v
when Hash
if v.keys.include? :content!
attributes = v.inject({}) do |attrs, (kk, vv)|
next attrs unless kk.to_s =~ /^@/
attrs[kk.to_s[1..-1]] = vv
attrs
end
node_with(builder, k, v[:content!], attributes)
else
builder.tag!(k, attributes) { hash_to_xml(v, :builder => builder) }
end
when Array
array_to_xml(v, k, attributes, :builder => builder)
else
builder.tag!(k, v, attributes)
end
end
end
class TestConverter < Minitest::Test
def setup
@profile = {:name => "Larry", :twitter => "@larrylv", :github => "@larrylv"}
end
def test_string_values
expected_value = <<-XML.strip_heredoc
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
XML
assert_equal expected_value, Converter.hash_to_xml(@profile)
end
def test_hash_values
@profile[:blog] = {
:tech => "blog.larrylv.com",
:journey => "journey.larrylv.com",
:homepage => "larrylv.com"
}
expected_value = <<-XML.strip_heredoc
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
<blog>
<tech>blog.larrylv.com</tech>
<journey>journey.larrylv.com</journey>
<homepage>larrylv.com</homepage>
</blog>
XML
assert_equal expected_value, Converter.hash_to_xml(@profile)
end
def test_array_values
@profile[:blogs] = {:blog => %w(blog.larrylv.com journey.larrylv.com larrylv.com)}
expected_value = <<-XML.strip_heredoc
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
<blogs>
<blog>blog.larrylv.com</blog>
<blog>journey.larrylv.com</blog>
<blog>larrylv.com</blog>
</blogs>
XML
assert_equal expected_value, Converter.hash_to_xml(@profile)
end
def test_attributes
@profile[:blog] = {
:content! => {
:tech => "blog.larrylv.com",
:journey => "journey.larrylv.com",
:homepage => "larrylv.com"
},
:@count => 3,
:@readers => "few"
}
expected_value = <<-XML.strip_heredoc
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
<blog count="3" readers="few">
<tech>blog.larrylv.com</tech>
<journey>journey.larrylv.com</journey>
<homepage>larrylv.com</homepage>
</blog>
XML
assert_equal expected_value, Converter.hash_to_xml(@profile)
end
def test_array_with_attributes
@profile[:blogs] = {
:blog => {
:content! => %w(blog.larrylv.com journey.larrylv.com larrylv.com),
:@count => 3,
:@readers => "few"
}
}
expected_value = <<-XML.strip_heredoc
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
<blogs>
<blog count="3" readers="few">blog.larrylv.com</blog>
<blog count="3" readers="few">journey.larrylv.com</blog>
<blog count="3" readers="few">larrylv.com</blog>
</blogs>
XML
assert_equal expected_value, Converter.hash_to_xml(@profile)
end
end
require "minitest/autorun"
require "active_support/core_ext/string/strip"
require "builder"
class Converter
def self.hash_to_xml(hash, options = {})
raise unless hash.kind_of? Hash
if options[:builder]
builder = options[:builder]
else
builder = Builder::XmlMarkup.new(indent: 2)
builder.instruct!
end
hash.each do |k, v|
node_with(builder, k, v)
end
builder.target!
end
def self.array_to_xml(array, key, options = {})
raise unless array.kind_of? Array
builder = options[:builder] || Builder::XmlMarkup.new(indent: 2)
array.each do |elt|
node_with(builder, key, elt)
end
builder.target!
end
private
def self.node_with(builder, k, v)
case v
when Hash
builder.tag!(k) { hash_to_xml(v, :builder => builder) }
when Array
array_to_xml(v, k, :builder => builder)
else
builder.tag!(k, v)
end
end
end
class TestConverter < Minitest::Test
def setup
@profile = {:name => "Larry", :twitter => "@larrylv", :github => "@larrylv"}
end
def test_string_values
expected_value = <<-XML.strip_heredoc
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
XML
assert_equal expected_value, Converter.hash_to_xml(@profile)
end
def test_hash_values
@profile[:blog] = {
:tech => "blog.larrylv.com",
:journey => "journey.larrylv.com",
:homepage => "larrylv.com"
}
expected_value = <<-XML.strip_heredoc
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
<blog>
<tech>blog.larrylv.com</tech>
<journey>journey.larrylv.com</journey>
<homepage>larrylv.com</homepage>
</blog>
XML
assert_equal expected_value, Converter.hash_to_xml(@profile)
end
def test_array_values
@profile[:blogs] = {:blog => %w(blog.larrylv.com journey.larrylv.com larrylv.com)}
expected_value = <<-XML.strip_heredoc
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<name>Larry</name>
<twitter>@larrylv</twitter>
<github>@larrylv</github>
<blogs>
<blog>blog.larrylv.com</blog>
<blog>journey.larrylv.com</blog>
<blog>larrylv.com</blog>
</blogs>
XML
assert_equal expected_value, Converter.hash_to_xml(@profile)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment