savon 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,58 @@
1
+ = Savon
2
+
3
+ Savon::Service is a SOAP client library to enjoy. The goal is to minimize
4
+ the overhead of working with SOAP services and provide a lightweight
5
+ alternative to other libraries.
6
+
7
+ == Install
8
+
9
+ $ gem install rubiii-savon -s http://gems.github.com
10
+
11
+ == Dependencies
12
+
13
+ rubiii-apricoteatsgorilla >= 0.5.2
14
+ hpricot 0.8.241 (the latest JRuby-compatible version)
15
+
16
+ Hpricot 0.8.241 is also available at: {Apricot eats Gorilla Downloads}[http://github.com/rubiii/apricoteatsgorilla/downloads]
17
+
18
+ == How to use
19
+
20
+ Instantiate a new Savon::Service instance passing in the WSDL of your service.
21
+
22
+ proxy = Savon::Service.new("http://example.com/ExampleService?wsdl")
23
+
24
+ Call the SOAP service method of your choice on your Savon::Service instance.
25
+
26
+ response = proxy.get_all_users
27
+
28
+ Or pass in a Hash of options for the SOAP service to receive.
29
+
30
+ response = proxy.find_user_by_id(:id => 123)
31
+
32
+ Or specify a custom XPath-Expression to start translating the SOAP response at.
33
+ By default the response is translated starting at "//return".
34
+
35
+ response = proxy.find_user_by_id(nil, "//user/email")
36
+
37
+ === Check for available SOAP actions
38
+
39
+ Access the WSDL to get an Array of SOAP actions found in the WSDL document.
40
+
41
+ proxy.wsdl.soap_actions
42
+ # => [ "getAllUsers", "findUserById" ]
43
+
44
+ === Handle HTTP error and SOAP faults
45
+
46
+ Savon::Service raises a Savon::SOAPFault in case of a SOAP fault and a
47
+ Savon::HTTPError in case of an HTTP error.
48
+
49
+ === Logging request and response
50
+
51
+ You should specify the logger to use before working with any service.
52
+
53
+ # example for Ruby on Rails
54
+ Savon.logger = RAILS_DEFAULT_LOGGER
55
+
56
+ Of course you can also specify the log level if needed. By default it's set to :debug.
57
+
58
+ Savon.log_level = :info
@@ -0,0 +1,48 @@
1
+ require "rubygems"
2
+ require "rake"
3
+ require "spec/rake/spectask"
4
+ require "rake/rdoctask"
5
+
6
+ task :default => :spec
7
+
8
+ Spec::Rake::SpecTask.new do |spec|
9
+ spec.spec_files = FileList["spec/**/*_spec.rb"]
10
+ spec.spec_opts << "--color"
11
+ end
12
+
13
+ Rake::RDocTask.new do |rdoc|
14
+ rdoc.title = "Savon"
15
+ rdoc.rdoc_dir = "rdoc"
16
+ rdoc.main = "README.rdoc"
17
+ rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb")
18
+ rdoc.options = ["--line-numbers", "--inline-source"]
19
+ end
20
+
21
+ begin
22
+ require "jeweler"
23
+ Jeweler::Tasks.new do |spec|
24
+ spec.name = "savon"
25
+ spec.author = "Daniel Harrington"
26
+ spec.email = "me@rubiii.com"
27
+ spec.homepage = "http://github.com/rubiii/savon"
28
+ spec.summary = "SOAP client library to enjoy"
29
+ spec.description = spec.summary
30
+
31
+ spec.files = FileList["[A-Z]*", "{lib,spec}/**/*.{rb,xml}"]
32
+
33
+ spec.rdoc_options += [
34
+ "--title", "Savon",
35
+ "--main", "README.rdoc",
36
+ "--line-numbers",
37
+ "--inline-source"
38
+ ]
39
+
40
+ spec.add_runtime_dependency("hpricot", "0.8.241")
41
+ spec.add_runtime_dependency("rubiii-apricoteatsgorilla", "0.5.9")
42
+
43
+ spec.add_development_dependency("rspec", ">= 1.2.8")
44
+ spec.add_development_dependency("rr", ">= 0.10.0")
45
+ end
46
+ rescue LoadError
47
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
48
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.7
@@ -0,0 +1,44 @@
1
+ module Savon
2
+
3
+ # Raised by the <tt>on_http_error</tt> method in case of an HTTP error.
4
+ # <tt>on_http_error</tt> may be overwritten to customize error handling.
5
+ class HTTPError < StandardError; end
6
+
7
+ # Raised by the <tt>on_soap_fault</tt> method in case of a SOAP fault.
8
+ # <tt>on_soap_fault</tt> may be overwritten to customize error handling.
9
+ class SOAPFault < StandardError; end
10
+
11
+ # The logger to use.
12
+ @@logger = nil
13
+
14
+ # The log level to use.
15
+ @@log_level = :debug
16
+
17
+ # Sets the logger to use.
18
+ def self.logger=(logger)
19
+ @@logger = logger
20
+ end
21
+
22
+ # Sets the log level to use.
23
+ def self.log_level=(log_level)
24
+ @@log_level = log_level
25
+ end
26
+
27
+ # Logs a given +message+ using the +@@logger+ instance or yields the logger
28
+ # to a given +block+ for logging multiple messages at once.
29
+ def self.log(message = nil)
30
+ if @@logger
31
+ @@logger.send(@@log_level, message) if message
32
+ yield @@logger if block_given?
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ %w(net/http uri rubygems hpricot apricoteatsgorilla).each do |gem|
39
+ require gem
40
+ end
41
+
42
+ %w(service wsdl).each do |file|
43
+ require File.join(File.dirname(__FILE__), "savon", file)
44
+ end
@@ -0,0 +1,135 @@
1
+ module Savon
2
+
3
+ # == Savon::Service
4
+ #
5
+ # Savon::Service is a SOAP client library to enjoy. The goal is to minimize
6
+ # the overhead of working with SOAP services and provide a lightweight
7
+ # alternative to other libraries.
8
+ #
9
+ # ==== Example
10
+ #
11
+ # proxy = Savon::Service.new("http://example.com/ExampleService?wsdl")
12
+ # response = proxy.find_user_by_id(:id => 123)
13
+ class Service
14
+
15
+ # Supported SOAP versions.
16
+ SOAPVersions = [1, 2]
17
+
18
+ # Content-Types by SOAP version.
19
+ ContentType = { 1 => "text/xml", 2 => "application/soap+xml" }
20
+
21
+ # Accessor for the WSSE username.
22
+ attr_accessor :wsse_username
23
+
24
+ # Accessor for the WSSE password.
25
+ attr_accessor :wsse_password
26
+
27
+ # Sets whether the WSSE password should be encrypted.
28
+ attr_writer :wsse_password_digest
29
+
30
+ # Initializer expects an +endpoint+ URI and takes an optional SOAP +version+.
31
+ def initialize(endpoint, version = 1)
32
+ raise ArgumentError, "Invalid endpoint: #{endpoint}" unless /^http.+/ === endpoint
33
+ raise ArgumentError, "Invalid version: #{version}" unless SOAPVersions.include? version
34
+ @endpoint = URI(endpoint)
35
+ @version = version
36
+ end
37
+
38
+ # Returns an instance of Savon::WSDL.
39
+ def wsdl
40
+ @wsdl ||= WSDL.new(@endpoint, http)
41
+ end
42
+
43
+ # Returns whether the WSSE password should be encrypted. Defaults to +false+.
44
+ def wsse_password_digest?
45
+ @wsse_password_digest == true
46
+ end
47
+
48
+ private
49
+
50
+ # Dispatches a SOAP request, handles any HTTP errors and SOAP faults
51
+ # and returns the SOAP response.
52
+ def dispatch(soap_action, soap_body, response_xpath)
53
+ ApricotEatsGorilla.nodes_to_namespace = { :wsdl => wsdl.choice_elements }
54
+ headers, body = build_request_parameters(soap_action, soap_body)
55
+
56
+ Savon.log("SOAP request: #{@endpoint}")
57
+ Savon.log(headers.map { |k, v| "#{k}: #{v}" }.join(", "))
58
+ Savon.log(body)
59
+
60
+ response = http.request_post(@endpoint.path, body, headers)
61
+
62
+ Savon.log("SOAP response (status #{response.code}):")
63
+ Savon.log(response.body)
64
+
65
+ soap_fault = ApricotEatsGorilla[response.body, "//soap:Fault"]
66
+ raise_soap_fault(soap_fault) if soap_fault && !soap_fault.empty?
67
+ raise_http_error(response) if response.code.to_i >= 300
68
+
69
+ ApricotEatsGorilla[response.body, response_xpath]
70
+ end
71
+
72
+ # Expects the requested +soap_action+ and +soap_body+ and builds and
73
+ # returns the request header and body to dispatch a SOAP request.
74
+ def build_request_parameters(soap_action, soap_body)
75
+ headers = { "Content-Type" => ContentType[@version], "SOAPAction" => soap_action }
76
+ namespaces = { :wsdl => wsdl.namespace_uri }
77
+
78
+ body = ApricotEatsGorilla.soap_envelope(namespaces, wsse, @version) do
79
+ ApricotEatsGorilla["wsdl:#{soap_action}" => soap_body]
80
+ end
81
+ [headers, body]
82
+ end
83
+
84
+ # Returns the WSSE arguments if :wsse_username and :wsse_password are set.
85
+ def wsse
86
+ if @wsse_username && @wsse_password
87
+ { :username => @wsse_username, :password => @wsse_password,
88
+ :password_digest => wsse_password_digest? }
89
+ else
90
+ nil
91
+ end
92
+ end
93
+
94
+ # Expects a Hash containing information about a SOAP fault and raises
95
+ # a Savon::SOAPFault.
96
+ def raise_soap_fault(soap_fault)
97
+ message = case @version
98
+ when 1
99
+ "#{soap_fault[:faultcode]}: #{soap_fault[:faultstring]}"
100
+ else
101
+ "#{soap_fault[:code][:value]}: #{soap_fault[:reason][:text]}"
102
+ end
103
+ raise SOAPFault, message
104
+ end
105
+
106
+ # Expects a Net::HTTPResponse and raises a Savon::HTTPError.
107
+ def raise_http_error(response)
108
+ raise HTTPError, "#{response.message} (#{response.code}): #{response.body}"
109
+ end
110
+
111
+ # Returns a Net::HTTP instance.
112
+ def http
113
+ @http ||= Net::HTTP.new(@endpoint.host, @endpoint.port)
114
+ end
115
+
116
+ # Catches calls to SOAP actions, checks if the method called was found in
117
+ # the WSDL and dispatches the SOAP action if it's valid. Takes an optional
118
+ # Hash of options to be passed to the SOAP action and an optional XPath-
119
+ # Expression to define a custom XML root node to start parsing the SOAP
120
+ # response at.
121
+ def method_missing(method, *args)
122
+ soap_action = camelize(method)
123
+ super unless wsdl.soap_actions.include? soap_action
124
+ soap_body = args[0] || {}
125
+ response_xpath = args[1] || "//return"
126
+ dispatch(soap_action, soap_body, response_xpath)
127
+ end
128
+
129
+ # Converts a given +string+ from snake_case to lowerCamelCase.
130
+ def camelize(string)
131
+ string.to_s.gsub(/_(.)/) { $1.upcase } if string
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,70 @@
1
+ module Savon
2
+
3
+ # Savon::WSDL represents the WSDL document.
4
+ class WSDL
5
+
6
+ # Returns the namespace URI.
7
+ def namespace_uri
8
+ @namespace ||= parse_namespace_uri
9
+ end
10
+
11
+ # Returns an Array of available SOAP actions.
12
+ def soap_actions
13
+ @soap_actions ||= parse_soap_actions
14
+ end
15
+
16
+ # Returns an Array of choice elements.
17
+ def choice_elements
18
+ @choice_elements ||= parse_choice_elements
19
+ end
20
+
21
+ # Initializer expects the endpoint +uri+ and a Net::HTTP instance (+http+).
22
+ def initialize(uri, http)
23
+ @uri, @http = uri, http
24
+ end
25
+
26
+ # Returns the body of the Net::HTTPResponse from the WSDL request.
27
+ def to_s
28
+ @response ? @response.body : nil
29
+ end
30
+
31
+ private
32
+
33
+ # Returns an Hpricot::Document of the WSDL. Retrieves the WSDL from the
34
+ # endpoint URI in case it wasn't retrieved already.
35
+ def document
36
+ unless @document
37
+ @response = @http.get("#{@uri.path}?#{@uri.query}")
38
+ @document = Hpricot.XML(@response.body)
39
+ raise ArgumentError, "Unable to find WSDL at: #{@uri}" if
40
+ !soap_actions || soap_actions.empty?
41
+ end
42
+ @document
43
+ end
44
+
45
+ # Parses the WSDL for the namespace URI.
46
+ def parse_namespace_uri
47
+ definitions = document.at("//wsdl:definitions")
48
+ definitions.get_attribute("targetNamespace") if definitions
49
+ end
50
+
51
+ # Parses the WSDL for available SOAP actions.
52
+ def parse_soap_actions
53
+ soap_actions = document.search("[@soapAction]")
54
+
55
+ soap_actions.collect do |soap_action|
56
+ soap_action.parent.get_attribute("name")
57
+ end if soap_actions
58
+ end
59
+
60
+ # Parses the WSDL for choice elements.
61
+ def parse_choice_elements
62
+ choice_elements = document.search("//xs:choice//xs:element")
63
+
64
+ choice_elements.collect do |choice_element|
65
+ choice_element.get_attribute("ref").sub(/(.+):/, "")
66
+ end if choice_elements
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,8 @@
1
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
2
+ <soap:Body>
3
+ <soap:Fault>
4
+ <faultcode>soap:Server</faultcode>
5
+ <faultstring>Fault occurred while processing.</faultstring>
6
+ </soap:Fault>
7
+ </soap:Body>
8
+ </soap:Envelope>
@@ -0,0 +1,13 @@
1
+ <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
2
+ <soap:Body>
3
+ <ns2:findUserResponse xmlns:ns2="http://v1_0.ws.user.example.com">
4
+ <return>
5
+ <id>123</id>
6
+ <email>thedude@example.com</email>
7
+ <username>thedude</username>
8
+ <firstname>The</firstname>
9
+ <lastname>Dude</lastname>
10
+ </return>
11
+ </ns2:findUserResponse>
12
+ </soap:Body>
13
+ </soap:Envelope>
@@ -0,0 +1,106 @@
1
+ <wsdl:definitions
2
+ name="UserWebService"
3
+ targetNamespace="http://v1_0.ws.user.example.com"
4
+ xmlns:ns1="http://cxf.apache.org/bindings/xformat"
5
+ xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
6
+ xmlns:tns="http://v1_0.ws.user.example.com"
7
+ xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
8
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema">
9
+
10
+ <wsdl:types>
11
+ <xs:schema
12
+ attributeFormDefault="unqualified"
13
+ elementFormDefault="unqualified"
14
+ targetNamespace="http://v1_0.ws.user.example.com"
15
+ xmlns:tns="http://v1_0.ws.user.example.com"
16
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
17
+ <xs:element name="findUser" type="tns:findUser" />
18
+ <xs:element name="findUserRequest" type="tns:findUserRequest" />
19
+ <xs:element name="baseFindUserRequest" type="tns:baseFindUserRequest" />
20
+ <xs:element name="idCredential" type="tns:idCredential" />
21
+ <xs:element name="emailCredential" type="tns:emailCredential" />
22
+ <xs:element name="findUserResponse" type="tns:findUserResponse" />
23
+ <xs:element name="userResponse" type="tns:userResponse" />
24
+
25
+ <xs:complexType name="findUser">
26
+ <xs:sequence>
27
+ <xs:element minOccurs="1" name="requestData" type="tns:findUserRequest" />
28
+ </xs:sequence>
29
+ </xs:complexType>
30
+ <xs:complexType name="findUserRequest">
31
+ <xs:complexContent>
32
+ <xs:extension base="tns:baseFindUserRequest">
33
+ <xs:sequence>
34
+ <xs:element minOccurs="0" name="mandant" type="tns:mandant" />
35
+ </xs:sequence>
36
+ </xs:extension>
37
+ </xs:complexContent>
38
+ </xs:complexType>
39
+ <xs:complexType name="baseFindUserRequest">
40
+ <xs:choice>
41
+ <xs:element ref="tns:idCredential" />
42
+ <xs:element ref="tns:emailCredential" />
43
+ </xs:choice>
44
+ </xs:complexType>
45
+ <xs:complexType name="idCredential">
46
+ <xs:sequence>
47
+ <xs:element name="id" type="xs:string" />
48
+ <xs:element name="token" type="xs:string" />
49
+ </xs:sequence>
50
+ </xs:complexType>
51
+ <xs:complexType name="emailCredential">
52
+ <xs:sequence>
53
+ <xs:element name="email" type="xs:string" />
54
+ <xs:element name="token" type="xs:string" />
55
+ </xs:sequence>
56
+ </xs:complexType>
57
+ <xs:complexType name="findUserResponse">
58
+ <xs:sequence>
59
+ <xs:element minOccurs="0" name="return" type="tns:userResponse" />
60
+ </xs:sequence>
61
+ </xs:complexType>
62
+ <xs:complexType name="userResponse">
63
+ <xs:sequence>
64
+ <xs:element minOccurs="0" name="id" type="xs:string" />
65
+ <xs:element minOccurs="0" name="email" type="xs:string" />
66
+ <xs:element minOccurs="0" name="username" type="xs:string" />
67
+ <xs:element minOccurs="0" name="firstname" type="xs:string" />
68
+ <xs:element minOccurs="0" name="lastname" type="xs:string" />
69
+ </xs:sequence>
70
+ </xs:complexType>
71
+ </xs:schema>
72
+ </wsdl:types>
73
+
74
+ <wsdl:message name="findUser">
75
+ <wsdl:part element="tns:findUser" name="parameters"></wsdl:part>
76
+ </wsdl:message>
77
+ <wsdl:message name="findUserResponse">
78
+ <wsdl:part element="tns:findUserResponse" name="parameters"></wsdl:part>
79
+ </wsdl:message>
80
+
81
+ <wsdl:portType name="UserWebService">
82
+ <wsdl:operation name="findUser">
83
+ <wsdl:input message="tns:findUser" name="findUser"></wsdl:input>
84
+ <wsdl:output message="tns:findUserResponse" name="findUserResponse"></wsdl:output>
85
+ </wsdl:operation>
86
+ </wsdl:portType>
87
+
88
+ <wsdl:binding name="UserWebServiceSoapBinding" type="tns:UserWebService">
89
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
90
+ <wsdl:operation name="findUser">
91
+ <soap:operation soapAction="" style="document" />
92
+ <wsdl:input name="findUser">
93
+ <soap:body use="literal" />
94
+ </wsdl:input>
95
+ <wsdl:output name="findUserResponse">
96
+ <soap:body use="literal" />
97
+ </wsdl:output>
98
+ </wsdl:operation>
99
+ </wsdl:binding>
100
+
101
+ <wsdl:service name="UserWebService">
102
+ <wsdl:port binding="tns:UserWebServiceSoapBinding" name="UserWebServicePort">
103
+ <soap:address location="http://example.com/user/1.0/UserService" />
104
+ </wsdl:port>
105
+ </wsdl:service>
106
+ </wsdl:definitions>
@@ -0,0 +1,71 @@
1
+ require File.join(File.dirname(__FILE__), "..", "spec_helper")
2
+
3
+ describe Savon::Service do
4
+ include SpecHelper
5
+
6
+ # initialize
7
+ describe "initialize" do
8
+ it "raises an ArgumentError when called with an invalid endpoint" do
9
+ ["", nil, "invalid", 123].each do |argument|
10
+ lambda { Savon::Service.new(argument) }.should raise_error(ArgumentError)
11
+ end
12
+ end
13
+
14
+ it "raises an ArgumentError when called with an invalid version" do
15
+ ["", nil, "invalid", 123].each do |argument|
16
+ lambda { Savon::Service.new("http://example.com", argument) }.
17
+ should raise_error(ArgumentError)
18
+ end
19
+ end
20
+ end
21
+
22
+ # wsdl
23
+ describe "wsdl" do
24
+ before { @service = new_service_instance }
25
+
26
+ it "returns an instance of Savon::WSDL" do
27
+ @service.wsdl.should be_a(Savon::WSDL)
28
+ end
29
+
30
+ it "returns the exact same Savon::WSDL instance every time" do
31
+ @service.wsdl.should equal(@service.wsdl)
32
+ end
33
+ end
34
+
35
+ # method_missing
36
+ describe "method_missing" do
37
+ before { @service = new_service_instance }
38
+
39
+ it "raises a NoMethodError when called with an invalid soap_action" do
40
+ lambda { @service.invalid_action }.should raise_error(NoMethodError)
41
+ end
42
+
43
+ it "by default returns content from the response using the '//return' XPath" do
44
+ @service.find_user.should == { :firstname => "The", :lastname => "Dude",
45
+ :email => "thedude@example.com", :username => "thedude", :id => "123" }
46
+ end
47
+
48
+ it "returns the content of the response starting at a custom XPath" do
49
+ @service.find_user(nil, "//email").should == "thedude@example.com"
50
+ end
51
+
52
+ it "returns nil if a given XPath does not match anything from the SOAP response" do
53
+ @service.find_user(nil, "//doesNotMatchAnything").should be_nil
54
+ end
55
+
56
+ it "raises a Savon::SOAPFault in case of a SOAP fault" do
57
+ @service = new_service_instance(:soap_fault => true)
58
+ lambda { @service.find_user }.should raise_error(Savon::SOAPFault)
59
+ end
60
+
61
+ it "raises a Savon::HTTPError in case the server returned an error code and no SOAP fault" do
62
+ @service = new_service_instance(:http_error => true)
63
+ lambda { @service.find_user }.should raise_error(Savon::HTTPError)
64
+ end
65
+
66
+ it "raises a Savon::SOAPFault in case the server returned an error code and a SOAP fault" do
67
+ @service = new_service_instance(:soap_fault => true, :http_error => true)
68
+ lambda { @service.find_user }.should raise_error(Savon::SOAPFault)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,65 @@
1
+ require File.join(File.dirname(__FILE__), "..", "spec_helper")
2
+
3
+ describe Savon::WSDL do
4
+ include SpecHelper
5
+
6
+ #namespace_uri
7
+ describe "namespace_uri" do
8
+ before { @wsdl = new_wsdl }
9
+
10
+ it "returns the namespace URI from the WSDL" do
11
+ @wsdl.namespace_uri == UserFixture.namespace_uri
12
+ end
13
+
14
+ it "returns the same object every time" do
15
+ @wsdl.namespace_uri.should equal(@wsdl.namespace_uri)
16
+ end
17
+ end
18
+
19
+ # soap_actions
20
+ describe "soap_actions" do
21
+ before { @wsdl = new_wsdl }
22
+
23
+ it "returns the SOAP actions from the WSDL" do
24
+ @wsdl.soap_actions == UserFixture.soap_actions
25
+ end
26
+
27
+ it "returns the same object every time" do
28
+ @wsdl.soap_actions.should equal(@wsdl.soap_actions)
29
+ end
30
+ end
31
+
32
+ # choice_elements
33
+ describe "choice_elements" do
34
+ before { @wsdl = new_wsdl }
35
+
36
+ it "returns the choice elements from the WSDL" do
37
+ @wsdl.choice_elements == UserFixture.choice_elements
38
+ end
39
+
40
+ it "returns the same object every time" do
41
+ @wsdl.choice_elements.should equal(@wsdl.choice_elements)
42
+ end
43
+ end
44
+
45
+ # initialize
46
+ describe "initialize" do
47
+ it "expects an endpoint URI and a Net::HTTP instance" do
48
+ @wsdl = Savon::WSDL.new(some_uri, some_http)
49
+ end
50
+ end
51
+
52
+ # to_s
53
+ describe "to_s" do
54
+ before { @wsdl = new_wsdl }
55
+
56
+ it "returns nil before the WSDL document was retrieved" do
57
+ @wsdl.to_s.should be_nil
58
+ end
59
+
60
+ it "returns the response body when available" do
61
+ @wsdl.soap_actions # trigger http request
62
+ @wsdl.to_s.should == UserFixture.user_wsdl
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,100 @@
1
+ require "rubygems"
2
+ gem "rspec", ">= 1.2.8"
3
+ require "spec"
4
+ require "rr"
5
+ require File.join(File.dirname(__FILE__), "..", "lib", "savon")
6
+
7
+ Spec::Runner.configure do |config|
8
+ config.mock_with :rr
9
+ end
10
+
11
+ module SpecHelper
12
+ def some_url
13
+ "http://example.com"
14
+ end
15
+
16
+ def some_uri
17
+ URI(some_url)
18
+ end
19
+
20
+ def some_http
21
+ Net::HTTP.new(some_uri.host, some_uri.port)
22
+ end
23
+
24
+ def new_wsdl
25
+ Savon::WSDL.new(some_uri, UserFixture.http_mock)
26
+ end
27
+
28
+ def new_service_instance(options = {})
29
+ service = Savon::Service.new(some_url)
30
+ service.instance_variable_set("@http", UserFixture.http_mock(options))
31
+ service
32
+ end
33
+ end
34
+
35
+ class UserFixture
36
+ extend RR::Adapters::RRMethods
37
+
38
+ class << self
39
+ include SpecHelper
40
+
41
+ def namespace_uri
42
+ "http://v1_0.ws.user.example.com"
43
+ end
44
+
45
+ def soap_actions
46
+ %w(findUser)
47
+ end
48
+
49
+ def choice_elements
50
+ %w(idCredential emailCredential)
51
+ end
52
+
53
+ def user_wsdl
54
+ load_fixture("user_wsdl.xml")
55
+ end
56
+
57
+ def user_response
58
+ load_fixture("user_response.xml")
59
+ end
60
+
61
+ def soap_fault
62
+ load_fixture("soap_fault.xml")
63
+ end
64
+
65
+ def http_mock(options = {})
66
+ response_body = options[:soap_fault] ? soap_fault : user_response
67
+ response_code = options[:http_error] ? 500 : 200
68
+ response_body = "" if options[:http_error] && !options[:soap_fault]
69
+ generate_http_mock(soap_response_mock(response_body, response_code))
70
+ end
71
+
72
+ private
73
+
74
+ def load_fixture(file)
75
+ file_path = File.join(File.dirname(__FILE__), "fixtures", file)
76
+ IO.readlines(file_path, "").to_s
77
+ end
78
+
79
+ def generate_http_mock(soap_response)
80
+ mock = some_http
81
+ stub(mock).get(anything) { wsdl_response_mock(user_wsdl) }
82
+ stub(mock).request_post(anything, anything, anything) { soap_response }
83
+ mock
84
+ end
85
+
86
+ def wsdl_response_mock(response_body)
87
+ mock = mock()
88
+ stub(mock).body { response_body }
89
+ mock
90
+ end
91
+
92
+ def soap_response_mock(response_body, response_code)
93
+ mock = mock()
94
+ stub(mock).body { response_body }
95
+ stub(mock).code { response_code }
96
+ stub(mock).message { "whatever" }
97
+ mock
98
+ end
99
+ end
100
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: savon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.7
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Harrington
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-06 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hpricot
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.8.241
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rubiii-apricoteatsgorilla
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.5.9
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.2.8
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: rr
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.10.0
54
+ version:
55
+ description: SOAP client library to enjoy
56
+ email: me@rubiii.com
57
+ executables: []
58
+
59
+ extensions: []
60
+
61
+ extra_rdoc_files:
62
+ - README.rdoc
63
+ files:
64
+ - README.rdoc
65
+ - Rakefile
66
+ - VERSION
67
+ - lib/savon.rb
68
+ - lib/savon/service.rb
69
+ - lib/savon/wsdl.rb
70
+ - spec/fixtures/soap_fault.xml
71
+ - spec/fixtures/user_response.xml
72
+ - spec/fixtures/user_wsdl.xml
73
+ - spec/savon/service_spec.rb
74
+ - spec/savon/wsdl_spec.rb
75
+ - spec/spec_helper.rb
76
+ has_rdoc: true
77
+ homepage: http://github.com/rubiii/savon
78
+ licenses: []
79
+
80
+ post_install_message:
81
+ rdoc_options:
82
+ - --charset=UTF-8
83
+ - --title
84
+ - Savon
85
+ - --main
86
+ - README.rdoc
87
+ - --line-numbers
88
+ - --inline-source
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: "0"
96
+ version:
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: "0"
102
+ version:
103
+ requirements: []
104
+
105
+ rubyforge_project:
106
+ rubygems_version: 1.3.5
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: SOAP client library to enjoy
110
+ test_files:
111
+ - spec/savon/service_spec.rb
112
+ - spec/savon/wsdl_spec.rb
113
+ - spec/spec_helper.rb