Skip to content

Commit

Permalink
Extract XmlMini. Namespace FileLike extension.
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremy committed Nov 26, 2008
1 parent d1213fa commit b7fef26
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 128 deletions.
142 changes: 14 additions & 128 deletions activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -1,137 +1,23 @@
require 'date' require 'date'

require 'active_support/xml_mini'
# = XmlMini
# This is a derivitive work of XmlSimple 1.0.11
# Author:: Joseph Holsten <joseph@josephholsten.com>
# Copyright:: Copyright (c) 2008 Joseph Holsten
# Copyright:: Copyright (c) 2003-2006 Maik Schmidt <contact@maik-schmidt.de>
# License:: Distributes under the same terms as Ruby.
class XmlMini
require 'rexml/document'
include REXML

CONTENT_KEY = '__content__'

# Parse an XML Document string into a simple hash
#
# Same as XmlSimple::xml_in but doesn't shoot itself in the foot,
# and uses the defaults from ActiveSupport
#
# string::
# XML Document string to parse
#
def self.parse(string)
doc = REXML::Document.new(string)
merge_element!({}, doc.root)
end

private
# Convert an XML element and merge into the hash
#
# hash::
# Hash to merge the converted element into.
# element::
# XML element to merge into hash
def self.merge_element!(hash, element)
merge!(hash, element.name, collapse(element))
end

# Actually converts an XML document element into a data structure.
#
# element::
# The document element to be collapsed.
def self.collapse(element)
hash = get_attributes(element)

if element.has_elements?
element.each_element {|child| merge_element!(hash, child) }
merge_texts!(hash, element) unless empty_content?(element)
else
return merge_texts!(hash, element)
end
hash
end

# Merge all the texts of an element into the hash
#
# hash::
# Hash to add the converted emement to.
# element::
# XML element whose texts are to me merged into the hash
def self.merge_texts!(hash, element)
unless element.has_text?
hash
else
# must use value to prevent double-escaping
text_values = element.texts.map {|t| t.value }
merge!(hash, CONTENT_KEY, text_values.join)
end
end

# Adds a new key/value pair to an existing Hash. If the key to be added
# already exists and the existing value associated with key is not
# an Array, it will be wrapped in an Array. Then the new value is
# appended to that Array.
#
# hash::
# Hash to add key/value pair to.
# key::
# Key to be added.
# value::
# Value to be associated with key.
def self.merge!(hash, key, value)
if hash.has_key?(key)
if hash[key].instance_of?(Array)
hash[key] << value
else
hash[key] = [ hash[key], value ]
end
elsif value.instance_of?(Array)
hash[key] = [ value ]
else
hash[key] = value
end
hash
end

# Converts the attributes array of an XML element into a hash.
# Returns an empty Hash if node has no attributes.
#
# element::
# XML element to extract attributes from.
def self.get_attributes(element)
attributes = {}
element.attributes.each { |n,v| attributes[n] = v }
attributes
end

# Determines if a document element has text content
#
# element::
# XML element to be checked.
def self.empty_content?(element)
element.texts.join.strip.empty?
end
end

# This module exists to decorate files deserialized using Hash.from_xml with
# the <tt>original_filename</tt> and <tt>content_type</tt> methods.
module FileLike #:nodoc:
attr_writer :original_filename, :content_type

def original_filename
@original_filename || 'untitled'
end

def content_type
@content_type || 'application/octet-stream'
end
end


module ActiveSupport #:nodoc: module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc: module CoreExtensions #:nodoc:
module Hash #:nodoc: module Hash #:nodoc:
module Conversions module Conversions
# This module exists to decorate files deserialized using Hash.from_xml with
# the <tt>original_filename</tt> and <tt>content_type</tt> methods.
module FileLike #:nodoc:
attr_writer :original_filename, :content_type

def original_filename
@original_filename || 'untitled'
end

def content_type
@content_type || 'application/octet-stream'
end
end


XML_TYPE_NAMES = { XML_TYPE_NAMES = {
"Symbol" => "symbol", "Symbol" => "symbol",
Expand Down
111 changes: 111 additions & 0 deletions activesupport/lib/active_support/xml_mini.rb
@@ -0,0 +1,111 @@
# = XmlMini
# This is a derivitive work of XmlSimple 1.0.11
# Author:: Joseph Holsten <joseph@josephholsten.com>
# Copyright:: Copyright (c) 2008 Joseph Holsten
# Copyright:: Copyright (c) 2003-2006 Maik Schmidt <contact@maik-schmidt.de>
# License:: Distributes under the same terms as Ruby.
module XmlMini
extend self

CONTENT_KEY = '__content__'.freeze

# Parse an XML Document string into a simple hash
#
# Same as XmlSimple::xml_in but doesn't shoot itself in the foot,
# and uses the defaults from ActiveSupport
#
# string::
# XML Document string to parse
def parse(string)
require 'rexml/document'
doc = REXML::Document.new(string)
merge_element!({}, doc.root)
end

private
# Convert an XML element and merge into the hash
#
# hash::
# Hash to merge the converted element into.
# element::
# XML element to merge into hash
def merge_element!(hash, element)
merge!(hash, element.name, collapse(element))
end

# Actually converts an XML document element into a data structure.
#
# element::
# The document element to be collapsed.
def collapse(element)
hash = get_attributes(element)

if element.has_elements?
element.each_element {|child| merge_element!(hash, child) }
merge_texts!(hash, element) unless empty_content?(element)
hash
else
merge_texts!(hash, element)
end
end

# Merge all the texts of an element into the hash
#
# hash::
# Hash to add the converted emement to.
# element::
# XML element whose texts are to me merged into the hash
def merge_texts!(hash, element)
unless element.has_text?
hash
else
# must use value to prevent double-escaping
merge!(hash, CONTENT_KEY, element.texts.sum(&:value))
end
end

# Adds a new key/value pair to an existing Hash. If the key to be added
# already exists and the existing value associated with key is not
# an Array, it will be wrapped in an Array. Then the new value is
# appended to that Array.
#
# hash::
# Hash to add key/value pair to.
# key::
# Key to be added.
# value::
# Value to be associated with key.
def merge!(hash, key, value)
if hash.has_key?(key)
if hash[key].instance_of?(Array)
hash[key] << value
else
hash[key] = [hash[key], value]
end
elsif value.instance_of?(Array)
hash[key] = [value]
else
hash[key] = value
end
hash
end

# Converts the attributes array of an XML element into a hash.
# Returns an empty Hash if node has no attributes.
#
# element::
# XML element to extract attributes from.
def get_attributes(element)
attributes = {}
element.attributes.each { |n,v| attributes[n] = v }
attributes
end

# Determines if a document element has text content
#
# element::
# XML element to be checked.
def empty_content?(element)
element.texts.join.blank?
end
end

0 comments on commit b7fef26

Please sign in to comment.