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:
parent
cb23816960
commit
187e1f85d0
5 changed files with 65 additions and 13 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
|
|
Loading…
Reference in a new issue