Skip to content

Commit e5f9ce6

Browse files
committed
Merge pull request savonrb#559 from apenney/add-attributes
Introduce convert_attributes_to global option.
2 parents ce813d9 + 85850a6 commit e5f9ce6

File tree

5 files changed

+91
-4
lines changed

5 files changed

+91
-4
lines changed

lib/savon/options.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def initialize(options = {})
5454
:raise_errors => true,
5555
:strip_namespaces => true,
5656
:convert_response_tags_to => lambda { |tag| tag.snakecase.to_sym},
57+
:convert_attributes_to => lambda { |k,v| [k,v] },
5758
:multipart => false,
5859
}
5960

@@ -253,6 +254,13 @@ def convert_response_tags_to(converter = nil, &block)
253254
@options[:convert_response_tags_to] = block || converter
254255
end
255256

257+
# Tell Nori how to convert XML attributes on tags from the SOAP response into Hash keys.
258+
# Accepts a lambda or a block which receives an XML tag and returns a Hash key.
259+
# Defaults to doing nothing
260+
def convert_attributes_to(converter = nil, &block)
261+
@options[:convert_attributes_to] = block || converter
262+
end
263+
256264
# Instruct Savon to create a multipart response if available.
257265
def multipart(multipart)
258266
@options[:multipart] = multipart

lib/savon/response.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,11 @@ def nori
9898
return @nori if @nori
9999

100100
nori_options = {
101-
:strip_namespaces => @globals[:strip_namespaces],
102-
:convert_tags_to => @globals[:convert_response_tags_to],
103-
:advanced_typecasting => @locals[:advanced_typecasting],
104-
:parser => @locals[:response_parser]
101+
:strip_namespaces => @globals[:strip_namespaces],
102+
:convert_tags_to => @globals[:convert_response_tags_to],
103+
:convert_attributes_to => @globals[:convert_attributes_to],
104+
:advanced_typecasting => @locals[:advanced_typecasting],
105+
:parser => @locals[:response_parser]
105106
}
106107

107108
non_nil_nori_options = nori_options.reject { |_, value| value.nil? }

spec/fixtures/response/f5.xml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<E:Envelope
2+
xmlns:E="http://schemas.xmlsoap.org/soap/envelope/"
3+
xmlns:A="http://schemas.xmlsoap.org/soap/encoding/"
4+
xmlns:s="http://www.w3.org/2001/XMLSchema-instance"
5+
xmlns:y="http://www.w3.org/2001/XMLSchema"
6+
xmlns:iControl="urn:iControl"
7+
E:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
8+
<E:Body>
9+
<m:get_agent_listen_addressResponse
10+
xmlns:m="urn:iControl:Management/SNMPConfiguration">
11+
<return
12+
s:type="A:Array"
13+
A:arrayType="iControl:Management.SNMPConfiguration.AgentListenAddressPort[2]">
14+
<item>
15+
<transport
16+
s:type="iControl:Management.SNMPConfiguration.TransportType">TRANSPORT_TCP6</transport>
17+
<ipport
18+
s:type="iControl:Common.IPPortDefinition">
19+
<address
20+
s:type="y:string"></address>
21+
<port
22+
s:type="y:long">161</port>
23+
</ipport>
24+
</item>
25+
<item>
26+
<transport
27+
s:type="iControl:Management.SNMPConfiguration.TransportType">TRANSPORT_UDP6</transport>
28+
<ipport
29+
s:type="iControl:Common.IPPortDefinition">
30+
<address
31+
s:type="y:string"></address>
32+
<port
33+
s:type="y:long">161</port>
34+
</ipport>
35+
</item>
36+
</return>
37+
</m:get_agent_listen_addressResponse>
38+
</E:Body>
39+
</E:Envelope>

spec/savon/options_spec.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,35 @@ def to_s
592592
end
593593
end
594594

595+
context "global :convert_attributes_to" do
596+
it "changes how XML tag attributes from the SOAP response are translated into Hash keys" do
597+
client = new_client(:endpoint => @server.url(:repeat), :convert_attributes_to => lambda {|k,v| [k,v]})
598+
response = client.call(:authenticate, :xml => Fixture.response(:f5))
599+
expect(response.body[:get_agent_listen_address_response][:return][:item].first[:ipport][:address]).to eq({:"@s:type"=>"y:string"})
600+
end
601+
602+
it "strips the attributes if an appropriate lambda is set" do
603+
client = new_client(:endpoint => @server.url(:repeat), :convert_attributes_to => lambda {|k,v| []})
604+
response = client.call(:authenticate, :xml => Fixture.response(:f5))
605+
expect(response.body[:get_agent_listen_address_response][:return][:item].first[:ipport][:address]).to eq(nil)
606+
end
607+
608+
it "accepts a block in the block-based interface" do
609+
client = Savon.client do |globals|
610+
globals.log false
611+
globals.wsdl Fixture.wsdl(:authentication)
612+
globals.endpoint @server.url(:repeat)
613+
globals.convert_attributes_to {|k,v| [k,v]}
614+
end
615+
616+
response = client.call(:authenticate) do |locals|
617+
locals.xml Fixture.response(:f5)
618+
end
619+
620+
expect(response.body[:get_agent_listen_address_response][:return][:item].first[:ipport][:address]).to eq({:"@s:type"=>"y:string"})
621+
end
622+
end
623+
595624
context "global and request :soap_header" do
596625
it "merges the headers if both were provided as Hashes" do
597626
global_soap_header = {

spec/savon/response_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@
118118
expect(header.keys).to include('SESSIONNUMBER')
119119
end
120120

121+
it 'respects the global :convert_attributes_to option' do
122+
globals[:convert_attributes_to] = lambda { |k,v| [] }
123+
124+
response_with_header = soap_response(:body => Fixture.response(:header))
125+
header = response_with_header.header
126+
127+
expect(header).to be_a(Hash)
128+
expect(header.keys).to include(:session_number)
129+
end
130+
121131
it "should throw an exception when the response header isn't parsable" do
122132
lambda { invalid_soap_response.header }.should raise_error Savon::InvalidResponseError
123133
end

0 commit comments

Comments
 (0)