mirror of
https://github.com/github/rails.git
synced 2026-02-01 17:54:59 -05:00
Use XSD-compatible type names for Hash#to_xml and make the converters extendable #8047 [Tim Pope]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@6546 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
*SVN*
|
||||
|
||||
* Use XSD-compatible type names for Hash#to_xml and make the converters extendable #8047 [Tim Pope]
|
||||
|
||||
* Added yielding of builder in Hash#to_xml [DHH]
|
||||
|
||||
* Hash#with_indifferent_access now also converts hashes kept in arrays to indifferent access (makes it easier to treat HTML and XML parameters the same) [DHH]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
require 'date'
|
||||
require 'xml_simple'
|
||||
require 'cgi'
|
||||
require 'base64'
|
||||
|
||||
# Extensions needed for Hash#to_query
|
||||
class Object
|
||||
@@ -26,21 +27,40 @@ module ActiveSupport #:nodoc:
|
||||
XML_TYPE_NAMES = {
|
||||
"Fixnum" => "integer",
|
||||
"Bignum" => "integer",
|
||||
"BigDecimal" => "numeric",
|
||||
"BigDecimal" => "decimal",
|
||||
"Float" => "float",
|
||||
"Date" => "date",
|
||||
"DateTime" => "datetime",
|
||||
"Time" => "datetime",
|
||||
"TrueClass" => "boolean",
|
||||
"FalseClass" => "boolean"
|
||||
} unless defined? XML_TYPE_NAMES
|
||||
} unless defined?(XML_TYPE_NAMES)
|
||||
|
||||
XML_FORMATTING = {
|
||||
"date" => Proc.new { |date| date.to_s(:db) },
|
||||
"datetime" => Proc.new { |time| time.xmlschema },
|
||||
"binary" => Proc.new { |binary| Base64.encode64(binary) },
|
||||
"yaml" => Proc.new { |yaml| yaml.to_yaml }
|
||||
} unless defined? XML_FORMATTING
|
||||
} unless defined?(XML_FORMATTING)
|
||||
|
||||
unless defined?(XML_PARSING)
|
||||
XML_PARSING = {
|
||||
"date" => Proc.new { |date| ::Date.parse(date) },
|
||||
"datetime" => Proc.new { |time| ::Time.parse(time).utc },
|
||||
"integer" => Proc.new { |integer| integer.to_i },
|
||||
"float" => Proc.new { |float| float.to_f },
|
||||
"decimal" => Proc.new { |number| BigDecimal(number) },
|
||||
"boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) },
|
||||
"string" => Proc.new { |string| string.to_s },
|
||||
"yaml" => Proc.new { |yaml| YAML::load(yaml) rescue yaml },
|
||||
"base64Binary" => Proc.new { |bin| Base64.decode64(bin) }
|
||||
}
|
||||
|
||||
XML_PARSING.update(
|
||||
"double" => XML_PARSING["float"],
|
||||
"dateTime" => XML_PARSING["datetime"]
|
||||
)
|
||||
end
|
||||
|
||||
def self.included(klass)
|
||||
klass.extend(ClassMethods)
|
||||
@@ -127,14 +147,13 @@ module ActiveSupport #:nodoc:
|
||||
when "Hash"
|
||||
if value.has_key?("__content__")
|
||||
content = translate_xml_entities(value["__content__"])
|
||||
case value["type"]
|
||||
when "integer" then content.to_i
|
||||
when "boolean" then content.strip == "true"
|
||||
when "datetime" then ::Time.parse(content).utc
|
||||
when "date" then ::Date.parse(content)
|
||||
when "yaml" then YAML::load(content) rescue content
|
||||
else content
|
||||
if XML_PARSING[value["type"]]
|
||||
XML_PARSING[value["type"]].call(content)
|
||||
else
|
||||
content
|
||||
end
|
||||
elsif value['type'] == 'string' && value['nil'] != 'true'
|
||||
""
|
||||
else
|
||||
(value.blank? || value['type'] || value['nil'] == 'true') ? nil : value.inject({}) do |h,(k,v)|
|
||||
h[k] = typecast_xml_value(v)
|
||||
@@ -180,4 +199,4 @@ module ActiveSupport #:nodoc:
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -126,7 +126,7 @@ class ArrayToXmlTests < Test::Unit::TestCase
|
||||
assert xml.include?(%(<age-in-millis type="integer">820497600000</age-in-millis>)), xml
|
||||
assert xml.include?(%(<name>David</name>)), xml
|
||||
assert xml.include?(%(<age type="integer">31</age>)), xml
|
||||
assert xml.include?(%(<age-in-millis type="numeric">1.0</age-in-millis>)), xml
|
||||
assert xml.include?(%(<age-in-millis type="decimal">1.0</age-in-millis>)), xml
|
||||
assert xml.include?(%(<name>Jason</name>)), xml
|
||||
end
|
||||
|
||||
|
||||
@@ -395,6 +395,8 @@ class HashToXmlTest < Test::Unit::TestCase
|
||||
<content type="yaml">--- \n1: should be an integer\n:message: Have a nice day\narray: \n- should-have-dashes: true\n should_have_underscores: true\n</content>
|
||||
<author-email-address>david@loudthinking.com</author-email-address>
|
||||
<parent-id></parent-id>
|
||||
<ad-revenue type="decimal">1.5</ad-revenue>
|
||||
<optimum-viewing-angle type="float">135</optimum-viewing-angle>
|
||||
</topic>
|
||||
EOT
|
||||
|
||||
@@ -409,7 +411,9 @@ class HashToXmlTest < Test::Unit::TestCase
|
||||
:viewed_at => Time.utc(2003, 7, 16, 9, 28),
|
||||
:content => { :message => "Have a nice day", 1 => "should be an integer", "array" => [{ "should-have-dashes" => true, "should_have_underscores" => true }] },
|
||||
:author_email_address => "david@loudthinking.com",
|
||||
:parent_id => nil
|
||||
:parent_id => nil,
|
||||
:ad_revenue => BigDecimal("1.50"),
|
||||
:optimum_viewing_angle => 135.0
|
||||
}.stringify_keys
|
||||
|
||||
assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["topic"]
|
||||
@@ -513,6 +517,30 @@ class HashToXmlTest < Test::Unit::TestCase
|
||||
assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["rsp"]["photos"]["photo"]
|
||||
end
|
||||
|
||||
def test_xsd_like_types_from_xml
|
||||
bacon_xml = <<-EOT
|
||||
<bacon>
|
||||
<weight type="double">0.5</weight>
|
||||
<price type="decimal">12.50</price>
|
||||
<chunky type="boolean"> 1 </chunky>
|
||||
<expires-at type="dateTime">2007-12-25T12:34:56+0000</expires-at>
|
||||
<notes type="string"></notes>
|
||||
<illustration type="base64Binary">YmFiZS5wbmc=</illustration>
|
||||
</bacon>
|
||||
EOT
|
||||
|
||||
expected_bacon_hash = {
|
||||
:weight => 0.5,
|
||||
:chunky => true,
|
||||
:price => BigDecimal("12.50"),
|
||||
:expires_at => Time.utc(2007,12,25,12,34,56),
|
||||
:notes => "",
|
||||
:illustration => "babe.png"
|
||||
}.stringify_keys
|
||||
|
||||
assert_equal expected_bacon_hash, Hash.from_xml(bacon_xml)["bacon"]
|
||||
end
|
||||
|
||||
def test_should_use_default_value_for_unknown_key
|
||||
hash_wia = HashWithIndifferentAccess.new(3)
|
||||
assert_equal 3, hash_wia[:new_key]
|
||||
|
||||
Reference in New Issue
Block a user