Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #8537: parse_xml_arrays_to_ruby_arrays.diff

File parse_xml_arrays_to_ruby_arrays.diff, 12.1 kB (added by hasmanyjosh, 2 years ago)

new and improved patch, parse xml arrays, and have ARes use them the right way

  • activeresource/test/connection_test.rb

    old new  
    115115   
    116116  def test_get_collection_empty 
    117117    people = @conn.get("/people_empty_elements.xml") 
    118     assert_nil people 
     118    assert_equal [], people 
    119119  end 
    120120 
    121121  def test_post 
  • activeresource/test/base/custom_methods_test.rb

    old new  
    66  def setup 
    77    @matz  = { :id => 1, :name => 'Matz' }.to_xml(:root => 'person') 
    88    @matz_deep  = { :id => 1, :name => 'Matz', :other => 'other' }.to_xml(:root => 'person') 
     9    @matz_array = [{ :id => 1, :name => 'Matz' }].to_xml(:root => 'people') 
    910    @ryan  = { :name => 'Ryan' }.to_xml(:root => 'person') 
    1011    @addy  = { :id => 1, :street => '12345 Street' }.to_xml(:root => 'address') 
    1112    @addy_deep  = { :id => 1, :street => '12345 Street', :zip => "27519" }.to_xml(:root => 'address') 
     
    1516      mock.get    "/people/1.xml",             {}, @matz 
    1617      mock.get    "/people/1/shallow.xml", {}, @matz 
    1718      mock.get    "/people/1/deep.xml", {}, @matz_deep 
    18       mock.get    "/people/retrieve.xml?name=Matz", {}, "<people>#{@matz}</people>" 
    19       mock.get    "/people/managers.xml", {}, "<people>#{@matz}</people>" 
     19      mock.get    "/people/retrieve.xml?name=Matz", {}, @matz_array 
     20      mock.get    "/people/managers.xml", {}, @matz_array 
    2021      mock.put    "/people/1/promote.xml?position=Manager", {}, nil, 204 
    2122      mock.put    "/people/promote.xml?name=Matz", {}, nil, 204, {} 
    2223      mock.put    "/people/sort.xml?by=name", {}, nil, 204 
  • activeresource/test/base_test.rb

    old new  
    99    @david = { :id => 2, :name => 'David' }.to_xml(:root => 'person') 
    1010    @addy  = { :id => 1, :street => '12345 Street' }.to_xml(:root => 'address') 
    1111    @default_request_headers = { 'Content-Type' => 'application/xml' } 
     12    @rick = { :name => "Rick", :age => 25 }.to_xml(:root => "person") 
     13    @people = [{ :id => 1, :name => 'Matz' }, { :id => 2, :name => 'David' }].to_xml(:root => 'people') 
     14    @people_david = [{ :id => 2, :name => 'David' }].to_xml(:root => 'people') 
     15    @addresses = [{ :id => 1, :street => '12345 Street' }].to_xml(:root => 'addresses') 
    1216     
    1317    ActiveResource::HttpMock.respond_to do |mock| 
    1418      mock.get    "/people/1.xml",             {}, @matz 
     
    1822      mock.delete "/people/1.xml",             {}, nil, 200 
    1923      mock.delete "/people/2.xml",             {}, nil, 400 
    2024      mock.get    "/people/99.xml",            {}, nil, 404 
    21       mock.post   "/people.xml",               {}, "<person><name>Rick</name><age type='integer'>25</age></person>", 201, 'Location' => '/people/5.xml' 
    22       mock.get    "/people.xml",               {}, "<people>#{@matz}#{@david}</people>" 
    23       mock.get    "/people/1/addresses.xml",   {}, "<addresses>#{@addy}</addresses>" 
     25      mock.post   "/people.xml",               {}, @rick, 201, 'Location' => '/people/5.xml' 
     26      mock.get    "/people.xml",               {}, @people 
     27      mock.get    "/people/1/addresses.xml",   {}, @addresses 
    2428      mock.get    "/people/1/addresses/1.xml", {}, @addy 
    2529      mock.get    "/people/1/addresses/2.xml", {}, nil, 404 
    2630      mock.get    "/people/2/addresses/1.xml", {}, nil, 404 
     
    225229  end 
    226230 
    227231  def test_find_all_by_from 
    228     ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/people.xml", {}, "<people>#{@david}</people>"
     232    ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/people.xml", {}, @people_david
    229233   
    230234    people = Person.find(:all, :from => "/companies/1/people.xml") 
    231235    assert_equal 1, people.size 
     
    233237  end 
    234238 
    235239  def test_find_all_by_from_with_options 
    236     ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/people.xml", {}, "<people>#{@david}</people>"
     240    ActiveResource::HttpMock.respond_to { |m| m.get "/companies/1/people.xml", {}, @people_david
    237241   
    238242    people = Person.find(:all, :from => "/companies/1/people.xml") 
    239243    assert_equal 1, people.size 
     
    241245  end 
    242246 
    243247  def test_find_all_by_symbol_from 
    244     ActiveResource::HttpMock.respond_to { |m| m.get "/people/managers.xml", {}, "<people>#{@david}</people>"
     248    ActiveResource::HttpMock.respond_to { |m| m.get "/people/managers.xml", {}, @people_david
    245249   
    246250    people = Person.find(:all, :from => :managers) 
    247251    assert_equal 1, people.size 
  • activeresource/lib/active_resource/connection.rb

    old new  
    8181    end 
    8282 
    8383    def xml_from_response(response) 
    84       if response = from_xml_data(Hash.from_xml(response.body)) 
    85         response.first 
    86       else 
    87         nil 
    88       end 
     84      from_xml_data(Hash.from_xml(response.body)) 
    8985    end 
    9086 
    9187 
     
    150146      # Manipulate from_xml Hash, because xml_simple is not exactly what we 
    151147      # want for ActiveResource. 
    152148      def from_xml_data(data) 
    153         case data 
    154           when Hash 
    155             if data.keys.size == 1 
    156               case data.values.first 
    157                 when Hash  then [ from_xml_data(data.values.first) ] 
    158                 when Array then from_xml_data(data.values.first) 
    159                 else       data.values.first 
    160               end 
    161             else 
    162               data.each_key { |key| data[key] = from_xml_data(data[key]) } 
    163               data 
    164             end 
    165           when Array then data.collect { |val| from_xml_data(val) } 
    166           else data 
     149        if data.is_a?(Hash) && data.keys.size == 1 
     150          data.values.first 
     151        else 
     152          data 
    167153        end 
    168154      end 
     155       
    169156  end 
    170157end 
  • activesupport/test/core_ext/array_ext_test.rb

    old new  
    121121      { :name => "Jason", :age => 31, :age_in_millis => BigDecimal.new('1.0') } 
    122122    ].to_xml(:skip_instruct => true, :indent => 0) 
    123123 
    124     assert_equal "<records><record>", xml.first(17), xml 
     124    assert_equal '<records type="array"><record>', xml.first(30) 
    125125    assert xml.include?(%(<age type="integer">26</age>)), xml 
    126126    assert xml.include?(%(<age-in-millis type="integer">820497600000</age-in-millis>)), xml 
    127127    assert xml.include?(%(<name>David</name>)), xml 
     
    135135      { :name => "David", :age => 26, :age_in_millis => 820497600000 }, { :name => "Jason", :age => 31 } 
    136136    ].to_xml(:skip_instruct => true, :indent => 0, :root => "people") 
    137137 
    138     assert_equal "<people><person>", xml.first(16
     138    assert_equal '<people type="array"><person>', xml.first(29
    139139  end 
    140140 
    141141  def test_to_xml_with_options 
  • activesupport/test/core_ext/hash_ext_test.rb

    old new  
    370370  def test_two_levels_with_array 
    371371    xml = { :name => "David", :addresses => [{ :street => "Paulina" }, { :street => "Evergreen" }] }.to_xml(@xml_options) 
    372372    assert_equal "<person>", xml.first(8) 
    373     assert xml.include?(%(<addresses><address>)) 
     373    assert xml.include?(%(<addresses type="array"><address>)) 
    374374    assert xml.include?(%(<address><street>Paulina</street></address>)) 
    375375    assert xml.include?(%(<address><street>Evergreen</street></address>)) 
    376376    assert xml.include?(%(<name>David</name>)) 
     
    378378 
    379379  def test_three_levels_with_array 
    380380    xml = { :name => "David", :addresses => [{ :streets => [ { :name => "Paulina" }, { :name => "Paulina" } ] } ] }.to_xml(@xml_options) 
    381     assert xml.include?(%(<addresses><address><streets><street><name>)) 
     381    assert xml.include?(%(<addresses type="array"><address><streets type="array"><street><name>)) 
    382382  end 
    383383 
    384384  def test_single_record_from_xml 
     
    447447 
    448448  def test_multiple_records_from_xml 
    449449    topics_xml = <<-EOT 
    450       <topics
     450      <topics type="array"
    451451        <topic> 
    452452          <title>The First Topic</title> 
    453453          <author-name>David</author-name> 
     
    491491      :parent_id => nil 
    492492    }.stringify_keys 
    493493 
    494     assert_equal expected_topic_hash, Hash.from_xml(topics_xml)["topics"]["topic"].first 
     494    assert_equal expected_topic_hash, Hash.from_xml(topics_xml)["topics"].first 
    495495  end 
    496496 
    497497  def test_single_record_from_xml_with_attributes_other_than_type 
     
    516516 
    517517    assert_equal expected_topic_hash, Hash.from_xml(topic_xml)["rsp"]["photos"]["photo"] 
    518518  end 
     519   
     520  def test_empty_array_from_xml 
     521    blog_xml = <<-XML 
     522      <blog> 
     523        <posts type="array"></posts> 
     524      </blog> 
     525    XML 
     526    expected_blog_hash = {"blog" => {"posts" => []}} 
     527    assert_equal expected_blog_hash, Hash.from_xml(blog_xml) 
     528  end 
    519529 
     530  def test_array_with_one_entry_from_xml 
     531    blog_xml = <<-XML 
     532      <blog> 
     533        <posts type="array"> 
     534          <post>a post</post> 
     535        </posts> 
     536      </blog> 
     537    XML 
     538    expected_blog_hash = {"blog" => {"posts" => ["a post"]}} 
     539    assert_equal expected_blog_hash, Hash.from_xml(blog_xml) 
     540  end 
     541 
     542  def test_array_with_multiple_entries_from_xml 
     543    blog_xml = <<-XML 
     544      <blog> 
     545        <posts type="array"> 
     546          <post>a post</post> 
     547          <post>another post</post> 
     548        </posts> 
     549      </blog> 
     550    XML 
     551    expected_blog_hash = {"blog" => {"posts" => ["a post", "another post"]}} 
     552    assert_equal expected_blog_hash, Hash.from_xml(blog_xml) 
     553  end 
     554 
    520555  def test_xsd_like_types_from_xml 
    521556    bacon_xml = <<-EOT 
    522557    <bacon> 
  • activesupport/lib/active_support/core_ext/hash/conversions.rb

    old new  
    163163                    else 
    164164                      content 
    165165                    end 
     166                  elsif value['type'] == 'array' 
     167                    child_key, entries = value.detect { |k,v| k != 'type' }   # child_key is throwaway 
     168                    if entries.nil? 
     169                      [] 
     170                    else 
     171                      case entries.class.to_s   # something weird with classes not matching here.  maybe singleton methods breaking is_a? 
     172                      when "Array" 
     173                        entries.collect { |v| typecast_xml_value(v) } 
     174                      when "Hash" 
     175                        [typecast_xml_value(entries)] 
     176                      else 
     177                        raise "can't typecast #{entries.inspect}" 
     178                      end 
     179                    end 
    166180                  elsif value['type'] == 'string' && value['nil'] != 'true' 
    167181                    "" 
    168182                  else 
  • activesupport/lib/active_support/core_ext/array/conversions.rb

    old new  
    6363 
    6464          opts = options.merge({ :root => children }) 
    6565 
    66           options[:builder].tag!(root) { 
    67             yield options[:builder] if block_given? 
    68             each { |e| e.to_xml(opts.merge!({ :skip_instruct => true })) } 
    69           } 
     66          xml = options[:builder] 
     67          if empty? 
     68            xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) 
     69          else 
     70            xml.tag!(root, options[:skip_types] ? {} : {:type => "array"}) { 
     71              yield xml if block_given? 
     72              each { |e| e.to_xml(opts.merge!({ :skip_instruct => true })) } 
     73            } 
     74          end 
    7075        end 
    7176 
    7277      end