1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Support for non heterogeneous arrays when serializing to xml. Unless guessable from array name the type name will be included as attribute

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@7173 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
Tobias Lütke 2007-07-09 22:07:39 +00:00
parent cb23816960
commit 187e1f85d0
5 changed files with 65 additions and 13 deletions

View file

@ -364,4 +364,11 @@ class AssetTagHelperNonVhostTest < Test::Unit::TestCase
ensure ensure
ActionController::Base.asset_host = nil ActionController::Base.asset_host = nil
end end
def test_asset_host_without_protocol_should_use_request_protocol_even_if_path_present
ActionController::Base.asset_host = 'a.example.com/files/go/here'
assert_equal 'gopher://a.example.com/files/go/here/collaboration/hieraki/images/xml.png', image_path('xml.png')
ensure
ActionController::Base.asset_host = nil
end
end end

View file

@ -211,7 +211,13 @@ module ActiveRecord #:nodoc:
builder.tag!(tag, :type => :array) builder.tag!(tag, :type => :array)
else else
builder.tag!(tag, :type => :array) do builder.tag!(tag, :type => :array) do
records.each { |r| r.to_xml(opts.merge(:root=>r.class.to_s.underscore)) } association_name = association.to_s.singularize
records.each do |record|
record.to_xml opts.merge(
:root => association_name,
:type => (record.class.to_s.underscore == association_name ? nil : record.class.name)
)
end
end end
end end
when :has_one, :belongs_to when :has_one, :belongs_to
@ -248,6 +254,10 @@ module ActiveRecord #:nodoc:
args << {:xmlns=>options[:namespace]} args << {:xmlns=>options[:namespace]}
end end
if options[:type]
args << {:type=>options[:type]}
end
builder.tag!(*args) do builder.tag!(*args) do
add_attributes add_attributes
add_includes add_includes

View file

@ -2,6 +2,7 @@ require 'abstract_unit'
require 'fixtures/post' require 'fixtures/post'
require 'fixtures/author' require 'fixtures/author'
require 'fixtures/tagging' require 'fixtures/tagging'
require 'fixtures/comment'
class Contact < ActiveRecord::Base class Contact < ActiveRecord::Base
# mock out self.columns so no pesky db is needed for these tests # mock out self.columns so no pesky db is needed for these tests
@ -147,8 +148,8 @@ class DatabaseConnectedXmlSerializationTest < Test::Unit::TestCase
def test_include_uses_association_name def test_include_uses_association_name
xml = authors(:david).to_xml :include=>:hello_posts, :indent => 0 xml = authors(:david).to_xml :include=>:hello_posts, :indent => 0
assert_match %r{<hello-posts type="array">}, xml assert_match %r{<hello-posts type="array">}, xml
assert_match %r{<post>}, xml assert_match %r{<hello-post type="Post">}, xml
assert_match %r{<sti-post>}, xml assert_match %r{<hello-post type="StiPost">}, xml
end end
def test_methods_are_called_on_object def test_methods_are_called_on_object
@ -171,4 +172,18 @@ class DatabaseConnectedXmlSerializationTest < Test::Unit::TestCase
assert_match %r{^ <posts type="array"/>}, xml assert_match %r{^ <posts type="array"/>}, xml
end end
def test_should_has_many_array_elements_should_include_type_when_different_from_guessed_value
xml = authors(:david).to_xml :include=>:posts_with_comments, :indent => 2
assert Hash.from_xml(xml)
assert_match %r{^ <posts-with-comments type="array">}, xml
assert_match %r{^ <posts-with-comment type="Post">}, xml
assert_match %r{^ <posts-with-comment type="StiPost">}, xml
types = Hash.from_xml(xml)['author']['posts_with_comments'].collect {|t| t['type'] }
assert types.include?('SpecialPost')
assert types.include?('Post')
assert types.include?('StiPost')
end
end end

View file

@ -167,7 +167,7 @@ module ActiveSupport #:nodoc:
private private
def typecast_xml_value(value) def typecast_xml_value(value)
case value.class.to_s case value.class.to_s
when "Hash" when 'Hash'
if value.has_key?("__content__") if value.has_key?("__content__")
content = translate_xml_entities(value["__content__"]) content = translate_xml_entities(value["__content__"])
if parser = XML_PARSING[value["type"]] if parser = XML_PARSING[value["type"]]
@ -195,31 +195,34 @@ module ActiveSupport #:nodoc:
end end
elsif value['type'] == 'string' && value['nil'] != 'true' elsif value['type'] == 'string' && value['nil'] != 'true'
"" ""
# blank or nil parsed values are represented by nil
elsif value.blank? || value['nil'] == 'true'
nil
# If the type is the only element which makes it then
# this still makes the value nil
elsif value['type'] && value.size == 1
nil
else else
xml_value = (value.blank? || value['type'] || value['nil'] == 'true') ? nil : value.inject({}) do |h,(k,v)| xml_value = value.inject({}) do |h,(k,v)|
h[k] = typecast_xml_value(v) h[k] = typecast_xml_value(v)
h h
end end
# Turn { :files => { :file => #<StringIO> } into { :files => #<StringIO> } so it is compatible with # Turn { :files => { :file => #<StringIO> } into { :files => #<StringIO> } so it is compatible with
# how multipart uploaded files from HTML appear # how multipart uploaded files from HTML appear
if xml_value.is_a?(Hash) && xml_value["file"].is_a?(StringIO) xml_value["file"].is_a?(StringIO) ? xml_value["file"] : xml_value
xml_value["file"]
else
xml_value
end end
end when 'Array'
when "Array"
value.map! { |i| typecast_xml_value(i) } value.map! { |i| typecast_xml_value(i) }
case value.length case value.length
when 0 then nil when 0 then nil
when 1 then value.first when 1 then value.first
else value else value
end end
when "String" when 'String'
value value
else else
raise "can't typecast #{value.inspect}" raise "can't typecast #{value.class.name} - #{value.inspect}"
end end
end end

View file

@ -589,6 +589,23 @@ class HashToXmlTest < Test::Unit::TestCase
assert_equal expected_bacon_hash, Hash.from_xml(bacon_xml)["bacon"] assert_equal expected_bacon_hash, Hash.from_xml(bacon_xml)["bacon"]
end end
def test_type_trickles_through_when_unknown
product_xml = <<-EOT
<product>
<weight type="double">0.5</weight>
<image type="ProductImage"><filename>image.gif</filename></image>
</product>
EOT
expected_product_hash = {
:weight => 0.5,
:image => {'type' => 'ProductImage', 'filename' => 'image.gif' },
}.stringify_keys
assert_equal expected_product_hash, Hash.from_xml(product_xml)["product"]
end
def test_should_use_default_value_for_unknown_key def test_should_use_default_value_for_unknown_key
hash_wia = HashWithIndifferentAccess.new(3) hash_wia = HashWithIndifferentAccess.new(3)
assert_equal 3, hash_wia[:new_key] assert_equal 3, hash_wia[:new_key]