savon 0.2.7

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.
@@ -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