savon 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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