savon 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1e067f76bf98355ac8d45b7794066761b478669e
4
- data.tar.gz: db9c6381959313f8c173b9abfcb24e360e892580
3
+ metadata.gz: 50130e634559c3c2470b09405d608fb86887e1d5
4
+ data.tar.gz: 80f641ad66bf740cd6d90beda49830c544e988b0
5
5
  SHA512:
6
- metadata.gz: bcfab18096e9beaf971fe837bd4af924ce6d04dc7d63458046aad1498f20781606528e8eeeb3f0d6990175cccfdfde3197c719ce34185a5d37a73e47bc84bdcb
7
- data.tar.gz: dbc7b384908c2a1f2bbaac0daf1ba07702aab0fb206a834d7b797e88601b8a264703d8cfbc1273f002e33fa7ddf11ba73a0a97546f9de3505ce1d34de8146602
6
+ metadata.gz: 4a791ac4059d5372ba758b334d066fd18af294ff42776b3f752e0e3ba0ee880d69ccf8cbeb5e9a7a9ce702d22dc45b20f1f34fc32143cc87fd59ca6af0d65e82
7
+ data.tar.gz: a81490063101948bee370664696ef1b61192992ef98477959fd04c2b73e0f7b1ffb5794cade623a0c7e483506a772be3c64175396fb17a8986308ff61da1ef55
@@ -9,3 +9,6 @@ rvm:
9
9
  - rbx
10
10
  notifications:
11
11
  irc: "irc.freenode.org#savon"
12
+ matrix:
13
+ allow_failures:
14
+ - rvm: jruby-19mode
@@ -1,10 +1,18 @@
1
+ # 2.5.0 (2014-05-03)
2
+
3
+ * Feature: [#566](https://github.com/savonrb/savon/pull/566) Allow specifying HTTPI adapter per client.
4
+
5
+ ```ruby
6
+ curb_client = Savon.client(wsdl: "http://example.com/service.wsdl", adapter: :curb)
7
+ http_client = Savon.client(wsdl: "http://example.com/service.wsdl", adapter: :httpclient)
8
+ ```
9
+
1
10
  ## 2.4.0 (2014-03-31)
2
11
 
3
12
  * Logging is off by default. To enable this behavior, set the :log option to true
4
13
 
5
14
  ``` ruby
6
- client = Savon.client(wsdl: "http://example.com/service.wsdl")
7
- client.options[:log] = true
15
+ client = Savon.client(wsdl: "http://example.com/service.wsdl", log: true)
8
16
  ```
9
17
 
10
18
  ### 2.3.2 (2013-12-09)
data/README.md CHANGED
@@ -25,22 +25,6 @@ or add it to your Gemfile like this:
25
25
  gem 'savon', '~> 2.3.0'
26
26
  ```
27
27
 
28
-
29
- ## Maintainer needed
30
-
31
- So I've been maintaining Savon and its dependant projects for the last four years and it's become quite
32
- apparent now with my schedule I do not have the time to keep this project going single-handed.
33
-
34
- Luckily there are numerous people helping out from time to time, but maintaining this project is pretty
35
- much a full-time job and it keeps me from working on the next major version.
36
-
37
- I'll be able to contribute on a small scale going forward, and will do my best in the meantime to catch
38
- up with everything I am behind on.
39
-
40
- If you are interested, please email me at [me at rubiii dot com].
41
- I'll do everything I can to help you get started.
42
-
43
-
44
28
  ## Usage example
45
29
 
46
30
  ``` ruby
@@ -66,16 +50,16 @@ For more examples, you should check out the
66
50
  ## Give back
67
51
 
68
52
  If you're using Savon and you or your company is making money from it, then please consider
69
- donating via [Gittip](https://www.gittip.com/rubiii/) so that I can continue to improve it.
53
+ donating via [Gittip](https://www.gittip.com/tjarratt/) so that I can continue to improve it.
70
54
 
71
- [![donate](donate.png)](https://www.gittip.com/rubiii/)
55
+ [![donate](donate.png)](https://www.gittip.com/tjarratt/)
72
56
 
73
57
 
74
58
  ## Documentation
75
59
 
76
60
  Please make sure to [read the documentation](http://savonrb.com/version2/).
77
61
 
78
- And if you find any problems with it or if you think something's missing,
62
+ And if you find any problems with it or if you think something's missing,
79
63
  feel free to [help out and improve the documentation](https://github.com/savonrb/savonrb.com).
80
64
 
81
65
  Donate icon from the [Noun Project](http://thenounproject.com/noun/donate/#icon-No285).
@@ -57,6 +57,7 @@ module Savon
57
57
  @wsdl.endpoint = @globals[:endpoint] if @globals.include? :endpoint
58
58
  @wsdl.namespace = @globals[:namespace] if @globals.include? :namespace
59
59
  @wsdl.servicename = @globals[:servicename] if @globals.include? :servicename
60
+ @wsdl.adapter = @globals[:adapter] if @globals.include? :adapter
60
61
 
61
62
  @wsdl.request = WSDLRequest.new(@globals).build
62
63
  end
@@ -83,7 +83,7 @@ module Savon
83
83
  end
84
84
 
85
85
  def call_with_logging(request)
86
- @logger.log(request) { HTTPI.post(request) }
86
+ @logger.log(request) { HTTPI.post(request, @globals[:adapter]) }
87
87
  end
88
88
 
89
89
  def build_request(builder)
@@ -54,7 +54,9 @@ module Savon
54
54
  :raise_errors => true,
55
55
  :strip_namespaces => true,
56
56
  :convert_response_tags_to => lambda { |tag| tag.snakecase.to_sym},
57
+ :convert_attributes_to => lambda { |k,v| [k,v] },
57
58
  :multipart => false,
59
+ :adapter => nil,
58
60
  }
59
61
 
60
62
  options = defaults.merge(options)
@@ -253,10 +255,22 @@ module Savon
253
255
  @options[:convert_response_tags_to] = block || converter
254
256
  end
255
257
 
258
+ # Tell Nori how to convert XML attributes on tags from the SOAP response into Hash keys.
259
+ # Accepts a lambda or a block which receives an XML tag and returns a Hash key.
260
+ # Defaults to doing nothing
261
+ def convert_attributes_to(converter = nil, &block)
262
+ @options[:convert_attributes_to] = block || converter
263
+ end
264
+
256
265
  # Instruct Savon to create a multipart response if available.
257
266
  def multipart(multipart)
258
267
  @options[:multipart] = multipart
259
268
  end
269
+
270
+ # Instruct Savon what HTTPI adapter it should use instead of default
271
+ def adapter(adapter)
272
+ @options[:adapter] = adapter
273
+ end
260
274
  end
261
275
 
262
276
  class LocalOptions < Options
@@ -98,10 +98,11 @@ module Savon
98
98
  return @nori if @nori
99
99
 
100
100
  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]
105
106
  }
106
107
 
107
108
  non_nil_nori_options = nori_options.reject { |_, value| value.nil? }
@@ -1,3 +1,3 @@
1
1
  module Savon
2
- VERSION = '2.4.0'
2
+ VERSION = '2.5.0'
3
3
  end
@@ -16,9 +16,9 @@ Gem::Specification.new do |s|
16
16
  s.rubyforge_project = s.name
17
17
  s.license = 'MIT'
18
18
 
19
- s.add_dependency "nori", "~> 2.3.0"
19
+ s.add_dependency "nori", "~> 2.4.0"
20
20
  s.add_dependency "httpi", "~> 2.1.0"
21
- s.add_dependency "wasabi", "~> 3.2.2"
21
+ s.add_dependency "wasabi", "~> 3.3.0"
22
22
  s.add_dependency "akami", "~> 1.2.0"
23
23
  s.add_dependency "gyoku", "~> 1.1.0"
24
24
 
@@ -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>
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ module LogInterceptor
4
+ @@intercepted_request = ""
5
+ def self.debug(message)
6
+ # save only the first XMLly message
7
+ if message.include? "xml version"
8
+ @@intercepted_request = message if @@intercepted_request == ""
9
+ end
10
+ end
11
+
12
+ def self.info(message)
13
+ end
14
+
15
+ def self.get_intercepted_request
16
+ @@intercepted_request
17
+ end
18
+
19
+ def self.reset_intercepted_request
20
+ @@intercepted_request = ""
21
+ end
22
+ end
23
+
24
+ describe 'Correct translation of attributes to XML' do
25
+ it "new :@attr syntax: correctly maps a Ruby Hash to XML attributes" do
26
+ LogInterceptor.reset_intercepted_request
27
+
28
+ client = Savon.client(
29
+ :wsdl => "http://mt205.sabameeting.com/CWS/CWS.asmx?WSDL",
30
+ :logger => LogInterceptor
31
+ )
32
+
33
+ response = nil
34
+ begin
35
+ response = call_and_fail_gracefully(client, :add_new_user, :message => { :user => { :@userID => "test" } })
36
+ rescue
37
+ end
38
+
39
+ xml_doc = Nokogiri::XML(LogInterceptor.get_intercepted_request)
40
+ xml_doc.remove_namespaces!
41
+
42
+ attributes_element_not_present = xml_doc.xpath("//AddNewUser/attributes").blank?
43
+
44
+ puts "new syntax: attributes element not present: " + attributes_element_not_present.to_s
45
+
46
+ expect(attributes_element_not_present).to eq true
47
+ end
48
+
49
+ it "old :attributes! syntax: correctly maps a Ruby Hash to XML attributes" do
50
+ LogInterceptor.reset_intercepted_request
51
+
52
+ client = Savon.client(
53
+ :wsdl => "http://mt205.sabameeting.com/CWS/CWS.asmx?WSDL",
54
+ :logger => LogInterceptor
55
+ )
56
+
57
+ response = nil
58
+ begin
59
+ response = call_and_fail_gracefully(client, :add_new_user, :message => { :user => {}, :attributes! => { :user => { :userID => "test" } } })
60
+ rescue
61
+ end
62
+
63
+ xml_doc = Nokogiri::XML(LogInterceptor.get_intercepted_request)
64
+ xml_doc.remove_namespaces!
65
+
66
+ attributes_element_not_present = xml_doc.xpath("//AddNewUser/attributes").blank?
67
+
68
+ puts "new syntax: attributes element not present: " + attributes_element_not_present.to_s
69
+
70
+ expect(attributes_element_not_present).to eq true
71
+ end
72
+ end
@@ -84,7 +84,9 @@ describe "Options" do
84
84
  client = new_client(:endpoint => non_routable_ip, :open_timeout => 0.1)
85
85
 
86
86
  expect { client.call(:authenticate) }.to raise_error { |error|
87
- if error.kind_of? Errno::EHOSTUNREACH
87
+ host_unreachable = error.kind_of? Errno::EHOSTUNREACH
88
+ net_unreachable = error.kind_of? Errno::ENETUNREACH
89
+ if host_unreachable || net_unreachable
88
90
  warn "Warning: looks like your network may be down?!\n" +
89
91
  "-> skipping spec at #{__FILE__}:#{__LINE__}"
90
92
  else
@@ -495,7 +497,7 @@ describe "Options" do
495
497
  expect(request).to include("<wsse:Username>lea</wsse:Username>")
496
498
 
497
499
  # the nonce node
498
- expect(request).to match(/<wsse:Nonce>.+<\/wsse:Nonce>/)
500
+ expect(request).to match(/<wsse:Nonce.*>.+\n<\/wsse:Nonce>/)
499
501
 
500
502
  # the created node with a timestamp
501
503
  expect(request).to match(/<wsu:Created>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.*<\/wsu:Created>/)
@@ -590,6 +592,68 @@ describe "Options" do
590
592
  end
591
593
  end
592
594
 
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
+
624
+ context 'global: :adapter' do
625
+ it 'passes option to Wasabi initializer for WSDL fetching' do
626
+ ## I want to use there something similar to the next mock expectation, but I can't
627
+ ## as due to how Savon sets up Wasabi::Document and Wasabi::Document initialize itself
628
+ ## adapter= method is called first time with nil and second time with adapter. [Envek, 2014-05-03]
629
+ # Wasabi::Document.any_instance.expects(:adapter=).with(:fake_adapter_for_test)
630
+ client = Savon.client(
631
+ :log => false,
632
+ :wsdl => @server.url(:authentication),
633
+ :adapter => :fake_adapter_for_test,
634
+ )
635
+ operations = client.operations
636
+ expect(operations).to eq([:authenticate])
637
+ expect(FakeAdapterForTest.class_variable_get(:@@requests).size).to eq(1)
638
+ expect(FakeAdapterForTest.class_variable_get(:@@requests).first.url).to eq(URI.parse(@server.url(:authentication)))
639
+ expect(FakeAdapterForTest.class_variable_get(:@@methods)).to eq([:get])
640
+ end
641
+
642
+ it 'instructs HTTPI to use provided adapter for performing SOAP requests' do
643
+ client = new_client_without_wsdl(
644
+ :endpoint => @server.url(:repeat),
645
+ :namespace => "http://v1.example.com",
646
+ :adapter => :adapter_for_test,
647
+ )
648
+ response = client.call(:authenticate)
649
+ expect(response.http.body).to include('xmlns:wsdl="http://v1.example.com"')
650
+ expect(response.http.body).to include('<wsdl:authenticate>')
651
+ expect(AdapterForTest.class_variable_get(:@@requests).size).to eq(1)
652
+ expect(AdapterForTest.class_variable_get(:@@requests).first.url).to eq(URI.parse(@server.url(:repeat)))
653
+ expect(AdapterForTest.class_variable_get(:@@methods)).to eq([:post])
654
+ end
655
+ end
656
+
593
657
  context "global and request :soap_header" do
594
658
  it "merges the headers if both were provided as Hashes" do
595
659
  global_soap_header = {
@@ -118,6 +118,16 @@ describe Savon::Response do
118
118
  expect(header.keys).to include('SESSIONNUMBER')
119
119
  end
120
120
 
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
+
121
131
  it "should throw an exception when the response header isn't parsable" do
122
132
  lambda { invalid_soap_response.header }.should raise_error Savon::InvalidResponseError
123
133
  end
@@ -0,0 +1,48 @@
1
+ require 'httpi/adapter/httpclient'
2
+
3
+ # Proxy adapter. Records all requests and passes them to HTTPClient
4
+ class AdapterForTest < HTTPI::Adapter::Base
5
+
6
+ register :adapter_for_test
7
+
8
+ def initialize(request)
9
+ @@requests ||= []
10
+ @@requests.push request
11
+ @request = request
12
+ @worker = HTTPI::Adapter::HTTPClient.new(request)
13
+ end
14
+
15
+ def client
16
+ @worker.client
17
+ end
18
+
19
+ def request(method)
20
+ @@methods ||= []
21
+ @@methods.push method
22
+ @worker.request(method)
23
+ end
24
+
25
+ end
26
+
27
+ # Fake adapter with request recording.
28
+ # Takes path from url and returns fixture WSDL with that name.
29
+ class FakeAdapterForTest < HTTPI::Adapter::Base
30
+
31
+ register :fake_adapter_for_test
32
+
33
+ def initialize(request)
34
+ @@requests ||= []
35
+ @@requests.push request
36
+ @request = request
37
+ end
38
+
39
+ attr_reader :client
40
+
41
+ def request(method)
42
+ @@methods ||= []
43
+ @@methods.push method
44
+ target = @request.url.path.to_sym
45
+ HTTPI::Response.new(200, {}, Fixture.wsdl(target))
46
+ end
47
+
48
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: savon
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Harrington
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-01 00:00:00.000000000 Z
11
+ date: 2014-05-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nori
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ~>
18
18
  - !ruby/object:Gem::Version
19
- version: 2.3.0
19
+ version: 2.4.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ~>
25
25
  - !ruby/object:Gem::Version
26
- version: 2.3.0
26
+ version: 2.4.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: httpi
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
- version: 3.2.2
47
+ version: 3.3.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
- version: 3.2.2
54
+ version: 3.3.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: akami
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -233,6 +233,7 @@ files:
233
233
  - spec/fixtures/gzip/message.gz
234
234
  - spec/fixtures/response/another_soap_fault.xml
235
235
  - spec/fixtures/response/authentication.xml
236
+ - spec/fixtures/response/f5.xml
236
237
  - spec/fixtures/response/header.xml
237
238
  - spec/fixtures/response/list.xml
238
239
  - spec/fixtures/response/multi_ref.xml
@@ -254,6 +255,7 @@ files:
254
255
  - spec/fixtures/wsdl/team_software.xml
255
256
  - spec/fixtures/wsdl/vies.xml
256
257
  - spec/fixtures/wsdl/wasmuth.xml
258
+ - spec/integration/centra_spec.rb
257
259
  - spec/integration/email_example_spec.rb
258
260
  - spec/integration/random_quote_spec.rb
259
261
  - spec/integration/ratp_example_spec.rb
@@ -278,6 +280,7 @@ files:
278
280
  - spec/savon/response_spec.rb
279
281
  - spec/savon/soap_fault_spec.rb
280
282
  - spec/spec_helper.rb
283
+ - spec/support/adapters.rb
281
284
  - spec/support/endpoint.rb
282
285
  - spec/support/fixture.rb
283
286
  - spec/support/integration.rb