smacks-savon 0.0.91 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +40 -16
- data/lib/savon/mash.rb +5 -5
- data/lib/savon/response.rb +11 -38
- data/lib/savon/service.rb +26 -52
- data/lib/savon/wsdl.rb +6 -8
- data/test/fixtures/soap_response.rb +17 -17
- data/test/helper.rb +6 -9
- data/test/savon/mash_test.rb +11 -2
- data/test/savon/service_test.rb +4 -0
- data/test/savon_test.rb +3 -3
- metadata +4 -4
data/README.rdoc
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
= Savon
|
2
2
|
|
3
|
-
|
3
|
+
Ruby SOAP client library to enjoy.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
Communicating with a SOAP webservice can be done in two lines of code.
|
6
|
+
Instantiate a new Savon::Service passing in the URI to the WSDL of the
|
7
|
+
service you would like to use. Then call the SOAP service method on your
|
8
|
+
Savon::Service instance (catched via method_missing) and pass in a Hash
|
9
|
+
of options for the service method to receive.
|
9
10
|
|
10
11
|
== Install
|
11
12
|
|
@@ -14,43 +15,66 @@ service method to receive.
|
|
14
15
|
== Dependencies
|
15
16
|
|
16
17
|
hpricot 0.6.164 (also available for JRuby)
|
17
|
-
smacks-apricoteatsgorilla >= 0.
|
18
|
+
smacks-apricoteatsgorilla >= 0.4.1
|
18
19
|
|
19
20
|
== How to use
|
20
21
|
|
21
|
-
|
22
|
+
Instantiate a new Savon::Service instance passing in the WSDL of your service.
|
22
23
|
|
23
24
|
proxy = Savon::Service.new "http://example.com/ExampleService?wsdl"
|
25
|
+
|
26
|
+
Call the SOAP service method you would like to choose on your Savon::Service
|
27
|
+
instance passing in a Hash of options for the service method to receive.
|
28
|
+
|
24
29
|
response = proxy.findExampleById(:id => 123)
|
25
30
|
|
26
31
|
=== Check for available SOAP service methods
|
27
32
|
|
33
|
+
You can use the service_methods method of the WSDL in your Savon::Service
|
34
|
+
instance to get a list of available SOAP service methods.
|
35
|
+
|
28
36
|
proxy.wsdl.service_methods
|
29
37
|
# => [ "findExampleById", "findExampleByName" ]
|
30
38
|
|
31
|
-
===
|
39
|
+
=== Handle HTTP and SOAP errors
|
40
|
+
|
41
|
+
Check if the SOAP request was successful.
|
32
42
|
|
33
43
|
response.success?
|
34
44
|
response.fault?
|
35
45
|
|
36
|
-
|
46
|
+
Access the fault message and code.
|
37
47
|
|
38
48
|
response.fault
|
39
49
|
response.fault_code
|
40
50
|
|
41
|
-
===
|
51
|
+
=== Different response formats
|
42
52
|
|
43
|
-
|
53
|
+
To work with the response of the service you need to convert the response
|
54
|
+
object using one of the following methods.
|
55
|
+
|
56
|
+
# SOAP response XML:
|
44
57
|
response.to_s
|
45
58
|
|
46
59
|
# response as a Hash
|
47
60
|
response.to_hash
|
48
61
|
|
49
|
-
# response as a Hash starting at a custom root node (via XPath)
|
50
|
-
response.to_hash("//item")
|
51
|
-
|
52
62
|
# response as a Mash
|
53
63
|
response.to_mash
|
54
64
|
|
55
|
-
|
56
|
-
|
65
|
+
The to_hash and to_mash methods accept an XPath expression (Hpricot search)
|
66
|
+
as second parameter to define a custom root node to start translating the
|
67
|
+
response XML at.
|
68
|
+
|
69
|
+
# response as a Hash starting at a custom root node
|
70
|
+
response.to_hash("//item")
|
71
|
+
|
72
|
+
# response as a Mash starting at a custom root node
|
73
|
+
response.to_mash("//user/email")
|
74
|
+
|
75
|
+
=== Logging request and response
|
76
|
+
|
77
|
+
You should specify the logger to use before working with any services.
|
78
|
+
|
79
|
+
# example for Ruby on Rails
|
80
|
+
Savon::Service.logger = RAILS_DEFAULT_LOGGER
|
data/lib/savon/mash.rb
CHANGED
@@ -3,8 +3,8 @@ module Savon
|
|
3
3
|
# Savon::Mash converts a given Hash into an Object.
|
4
4
|
class Mash
|
5
5
|
|
6
|
-
#
|
7
|
-
# and creates getter and setter methods.
|
6
|
+
# Iterates through a given +hash+, stores each value in an instance
|
7
|
+
# variable and creates getter and setter methods.
|
8
8
|
#
|
9
9
|
# === Parameters
|
10
10
|
#
|
@@ -19,9 +19,9 @@ module Savon
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
set_instance_variable
|
23
|
-
define_reader
|
24
|
-
define_writer
|
22
|
+
set_instance_variable(key, value)
|
23
|
+
define_reader(key)
|
24
|
+
define_writer(key)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
data/lib/savon/response.rb
CHANGED
@@ -5,42 +5,15 @@ require "apricoteatsgorilla"
|
|
5
5
|
module Savon
|
6
6
|
|
7
7
|
# Savon::Response represents the HTTP response.
|
8
|
-
#
|
9
|
-
# === Checking for HTTP and SOAP faults
|
10
|
-
#
|
11
|
-
# response.success?
|
12
|
-
# response.fault?
|
13
|
-
#
|
14
|
-
# === Access the fault message and code
|
15
|
-
#
|
16
|
-
# response.fault
|
17
|
-
# response.fault_code
|
18
|
-
#
|
19
|
-
# === Different response formats
|
20
|
-
#
|
21
|
-
# # raw XML response:
|
22
|
-
# response.to_s
|
23
|
-
#
|
24
|
-
# # response as a Hash
|
25
|
-
# response.to_hash
|
26
|
-
#
|
27
|
-
# # response as a Hash starting at a custom root node (via XPath)
|
28
|
-
# response.to_hash("//item")
|
29
|
-
#
|
30
|
-
# # response as a Mash
|
31
|
-
# response.to_mash
|
32
|
-
#
|
33
|
-
# # response as a Mash starting at a custom root node (via XPath)
|
34
|
-
# response.to_mash("//user/email")
|
35
8
|
class Response
|
36
9
|
|
37
|
-
# The HTTP
|
10
|
+
# The HTTP or SOAP fault message.
|
38
11
|
attr_reader :fault
|
39
12
|
|
40
|
-
# The HTTP
|
13
|
+
# The HTTP or SOAP fault code.
|
41
14
|
attr_reader :fault_code
|
42
15
|
|
43
|
-
# Initializer
|
16
|
+
# Initializer expects the HTTP response and checks for HTTP or SOAP faults.
|
44
17
|
#
|
45
18
|
# === Parameters
|
46
19
|
#
|
@@ -55,18 +28,18 @@ module Savon
|
|
55
28
|
@fault_code.nil?
|
56
29
|
end
|
57
30
|
|
58
|
-
# Returns true if
|
31
|
+
# Returns true if there was a HTTP or SOAP fault, false otherwise.
|
59
32
|
def fault?
|
60
33
|
!@fault_code.nil?
|
61
34
|
end
|
62
35
|
|
63
36
|
# Returns the SOAP response message as a Hash. Call with XPath expession
|
64
|
-
# to define a custom +root_node+ to start parsing at.
|
65
|
-
# The root node
|
37
|
+
# (Hpricot search) to define a custom +root_node+ to start parsing at.
|
38
|
+
# Defaults to "//return". The root node will not be included in the Hash.
|
66
39
|
#
|
67
40
|
# === Parameters
|
68
41
|
#
|
69
|
-
# * +root_node+ - Optional. Custom root node to start parsing at.
|
42
|
+
# * +root_node+ - Optional. Custom root node to start parsing at.
|
70
43
|
def to_hash(root_node = "//return")
|
71
44
|
return nil if fault?
|
72
45
|
ApricotEatsGorilla[@response.body, root_node]
|
@@ -74,25 +47,25 @@ module Savon
|
|
74
47
|
|
75
48
|
# Returns the SOAP response message as a Savon::Mash object. Call with
|
76
49
|
# XPath expession to define a custom +root_node+. Defaults to "//return".
|
77
|
-
# The root node
|
50
|
+
# The root node will not be included in the Mash object.
|
78
51
|
#
|
79
52
|
# === Parameters
|
80
53
|
#
|
81
|
-
# * +root_node+ - Optional. Custom root node to start parsing at.
|
54
|
+
# * +root_node+ - Optional. Custom root node to start parsing at.
|
82
55
|
def to_mash(root_node = "//return")
|
83
56
|
return nil if fault?
|
84
57
|
hash = to_hash(root_node)
|
85
58
|
Savon::Mash.new(hash)
|
86
59
|
end
|
87
60
|
|
88
|
-
# Returns the
|
61
|
+
# Returns the SOAP response XML.
|
89
62
|
def to_s
|
90
63
|
@response.body
|
91
64
|
end
|
92
65
|
|
93
66
|
private
|
94
67
|
|
95
|
-
# Checks for
|
68
|
+
# Checks for HTTP and SOAP faults.
|
96
69
|
def validate
|
97
70
|
if @response.code.to_i >= 300
|
98
71
|
@fault, @fault_code = @response.message, @response.code
|
data/lib/savon/service.rb
CHANGED
@@ -5,54 +5,28 @@ require "apricoteatsgorilla"
|
|
5
5
|
|
6
6
|
module Savon
|
7
7
|
|
8
|
-
#
|
8
|
+
# Ruby SOAP client library to enjoy.
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# === Usage example
|
16
|
-
#
|
17
|
-
# proxy = Savon::Service.new "http://example.com/ExampleService?wsdl"
|
18
|
-
# response = proxy.findExampleById(:id => 123)
|
19
|
-
#
|
20
|
-
# === Check for available SOAP service methods
|
21
|
-
#
|
22
|
-
# proxy.wsdl.service_methods
|
23
|
-
# # => [ "findExampleById", "findExampleByName" ]
|
24
|
-
#
|
25
|
-
# === Working with different response formats
|
26
|
-
#
|
27
|
-
# # raw XML response:
|
28
|
-
# response.to_s
|
29
|
-
#
|
30
|
-
# # response as a Hash
|
31
|
-
# response.to_hash
|
32
|
-
#
|
33
|
-
# # response as a Hash starting at a custom root node (via XPath)
|
34
|
-
# response.to_hash("//item")
|
35
|
-
#
|
36
|
-
# # response as a Mash
|
37
|
-
# response.to_mash
|
38
|
-
#
|
39
|
-
# # response as a Mash starting at a custom root node (via XPath)
|
40
|
-
# response.to_mash("//user/email")
|
10
|
+
# Communicating with a SOAP webservice can be done in two lines of code.
|
11
|
+
# Instantiate a new Savon::Service passing in the URI to the WSDL of the
|
12
|
+
# service you would like to use. Then call the SOAP service method on your
|
13
|
+
# Savon::Service instance (catched via method_missing) and pass in a Hash
|
14
|
+
# of options for the service method to receive.
|
41
15
|
class Service
|
42
16
|
|
43
17
|
# The logger to use.
|
44
18
|
@@logger = nil
|
45
19
|
|
46
|
-
#
|
47
|
-
|
48
|
-
|
49
|
-
# Initializer sets the WSDL +endpoint+ URI.
|
20
|
+
# Initializer expects the WSDL +endpoint+ URI to use and sets up
|
21
|
+
# Apricot eats Gorilla.
|
50
22
|
#
|
51
23
|
# ==== Parameters
|
52
24
|
#
|
53
|
-
# * +endpoint+ -
|
25
|
+
# * +endpoint+ - WSDL endpoint URI to use.
|
54
26
|
def initialize(endpoint)
|
55
27
|
@uri = URI(endpoint)
|
28
|
+
ApricotEatsGorilla.nodes_to_namespace = wsdl.choice_elements
|
29
|
+
ApricotEatsGorilla.node_namespace = "wsdl"
|
56
30
|
end
|
57
31
|
|
58
32
|
# Returns an instance of the WSDL.
|
@@ -61,6 +35,11 @@ module Savon
|
|
61
35
|
@wsdl
|
62
36
|
end
|
63
37
|
|
38
|
+
# Sets the Net::HTTP instance to use.
|
39
|
+
def http=(http)
|
40
|
+
@http = http
|
41
|
+
end
|
42
|
+
|
64
43
|
# Sets the logger to use.
|
65
44
|
def self.logger=(logger)
|
66
45
|
@@logger = logger
|
@@ -68,20 +47,16 @@ module Savon
|
|
68
47
|
|
69
48
|
private
|
70
49
|
|
71
|
-
#
|
50
|
+
# Sets up and dispatches the SOAP request. Returns a Savon::Response object.
|
72
51
|
def call_service
|
73
52
|
headers = { "Content-Type" => "text/xml; charset=utf-8", "SOAPAction" => @action }
|
74
53
|
|
75
|
-
ApricotEatsGorilla.setup do |s|
|
76
|
-
s.nodes_to_namespace = wsdl.choice_elements
|
77
|
-
s.node_namespace = "wsdl"
|
78
|
-
end
|
79
54
|
body = ApricotEatsGorilla.soap_envelope("wsdl" => wsdl.namespace_uri) do
|
80
55
|
ApricotEatsGorilla["wsdl:#{@action}" => @options]
|
81
56
|
end
|
82
57
|
|
83
58
|
debug do |logger|
|
84
|
-
logger.info "
|
59
|
+
logger.info "Requesting #{@uri}"
|
85
60
|
logger.info headers.map { |key, value| "#{key}: #{value}" }.join("\n")
|
86
61
|
logger.info body
|
87
62
|
end
|
@@ -110,20 +85,19 @@ module Savon
|
|
110
85
|
end
|
111
86
|
end
|
112
87
|
|
113
|
-
#
|
114
|
-
#
|
88
|
+
# Logs a given +message+ using the @@logger instance or yields the logger
|
89
|
+
# to a given +block+ for logging multiple things at once.
|
115
90
|
def debug(message = nil)
|
116
91
|
if @@logger
|
117
|
-
if message
|
118
|
-
|
119
|
-
end
|
120
|
-
if block_given?
|
121
|
-
yield @@logger
|
122
|
-
end
|
92
|
+
@@logger.info(message) if message
|
93
|
+
yield @@logger if block_given?
|
123
94
|
end
|
124
95
|
end
|
125
96
|
|
126
|
-
#
|
97
|
+
# Method missing catches SOAP service methods called on this object. This
|
98
|
+
# is the default way of calling a SOAP service. The given +method+ will be
|
99
|
+
# validated against the WSDL and dispatched if available. Values supplied
|
100
|
+
# through the optional Hash of +options+ will be send to the service method.
|
127
101
|
#
|
128
102
|
# === Parameters
|
129
103
|
#
|
data/lib/savon/wsdl.rb
CHANGED
@@ -4,7 +4,7 @@ require "hpricot"
|
|
4
4
|
|
5
5
|
module Savon
|
6
6
|
|
7
|
-
# Savon::Wsdl gets, parses and represents the
|
7
|
+
# Savon::Wsdl gets, parses and represents the WSDL.
|
8
8
|
class Wsdl
|
9
9
|
|
10
10
|
# The namespace URI.
|
@@ -21,7 +21,7 @@ module Savon
|
|
21
21
|
#
|
22
22
|
# === Parameters
|
23
23
|
#
|
24
|
-
# * +uri+ - The URI
|
24
|
+
# * +uri+ - The URI of the WSDL.
|
25
25
|
# * +http+ - The Net::HTTP connection instance to use.
|
26
26
|
def initialize(uri, http)
|
27
27
|
@uri, @http = uri, http
|
@@ -49,15 +49,13 @@ module Savon
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
# Parses the WSDL
|
52
|
+
# Parses the WSDL for the namespace URI.
|
53
53
|
def parse_namespace_uri
|
54
54
|
node = @doc.at("//wsdl:definitions")
|
55
|
-
if node
|
56
|
-
@namespace_uri = node.get_attribute("targetNamespace")
|
57
|
-
end
|
55
|
+
@namespace_uri = node.get_attribute("targetNamespace") if node
|
58
56
|
end
|
59
57
|
|
60
|
-
# Parses the WSDL
|
58
|
+
# Parses the WSDL for available SOAP service methods.
|
61
59
|
def parse_service_methods
|
62
60
|
@service_methods, node = [], @doc.search("//soap:operation")
|
63
61
|
if node
|
@@ -67,7 +65,7 @@ module Savon
|
|
67
65
|
end
|
68
66
|
end
|
69
67
|
|
70
|
-
# Parses the WSDL
|
68
|
+
# Parses the WSDL for choice elements.
|
71
69
|
def parse_choice_elements
|
72
70
|
@choice_elements, node = [], @doc.search("//xs:choice//xs:element")
|
73
71
|
if node
|
@@ -1,26 +1,26 @@
|
|
1
1
|
module SoapResponseFixture
|
2
2
|
|
3
3
|
def some_soap_response
|
4
|
-
'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
5
|
-
<soap:Body>
|
6
|
-
<ns2:result xmlns:ns2="http://example.com/">
|
7
|
-
<return>
|
8
|
-
<token>secret</token>
|
9
|
-
</return>
|
10
|
-
</ns2:result>
|
11
|
-
</soap:Body>
|
12
|
-
</soap:Envelope>'
|
4
|
+
'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' <<
|
5
|
+
'<soap:Body>' <<
|
6
|
+
'<ns2:result xmlns:ns2="http://example.com/">' <<
|
7
|
+
'<return>' <<
|
8
|
+
'<token>secret</token>' <<
|
9
|
+
'</return>' <<
|
10
|
+
'</ns2:result>' <<
|
11
|
+
'</soap:Body>' <<
|
12
|
+
'</soap:Envelope>'
|
13
13
|
end
|
14
14
|
|
15
15
|
def soap_fault_response
|
16
|
-
'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
17
|
-
<soap:Body>
|
18
|
-
<soap:Fault>
|
19
|
-
<faultcode>' << soap_fault_code << '</faultcode>
|
20
|
-
<faultstring>' << soap_fault << '</faultstring>
|
21
|
-
</soap:Fault>
|
22
|
-
</soap:Body>
|
23
|
-
</soap:Envelope>'
|
16
|
+
'<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' <<
|
17
|
+
'<soap:Body>' <<
|
18
|
+
'<soap:Fault>' <<
|
19
|
+
'<faultcode>' << soap_fault_code << '</faultcode>' <<
|
20
|
+
'<faultstring>' << soap_fault << '</faultstring>' <<
|
21
|
+
'</soap:Fault>' <<
|
22
|
+
'</soap:Body>' <<
|
23
|
+
'</soap:Envelope>'
|
24
24
|
end
|
25
25
|
|
26
26
|
def soap_fault
|
data/test/helper.rb
CHANGED
@@ -19,15 +19,15 @@ module TestHelper
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def service_http_mock(response_body)
|
22
|
-
http_mock = mock()
|
23
|
-
http_mock.
|
24
|
-
http_mock.
|
22
|
+
http_mock = mock("Net::HTTP")
|
23
|
+
http_mock.stubs(:get).returns(response_mock(WsdlFactory.new.build))
|
24
|
+
http_mock.stubs(:request_post).returns(response_mock(response_body))
|
25
25
|
http_mock
|
26
26
|
end
|
27
27
|
|
28
28
|
def http_mock(response_body)
|
29
|
-
http_mock = mock()
|
30
|
-
http_mock.
|
29
|
+
http_mock = mock("Net::HTTP")
|
30
|
+
http_mock.stubs(:get).returns(response_mock(response_body))
|
31
31
|
http_mock
|
32
32
|
end
|
33
33
|
|
@@ -41,10 +41,7 @@ module TestHelper
|
|
41
41
|
|
42
42
|
def build_response_mock(code, message, body = nil)
|
43
43
|
response_mock = mock("Net::HTTPResponse")
|
44
|
-
response_mock.stubs(
|
45
|
-
:code => code, :message => message, :content_type => "text/html",
|
46
|
-
:body => body
|
47
|
-
)
|
44
|
+
response_mock.stubs(:code => code, :message => message, :body => body)
|
48
45
|
response_mock
|
49
46
|
end
|
50
47
|
|
data/test/savon/mash_test.rb
CHANGED
@@ -2,8 +2,17 @@ require File.join(File.dirname(__FILE__), "..", "helper")
|
|
2
2
|
|
3
3
|
class SavonMashTest < Test::Unit::TestCase
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
context "Creating a new Savon::Mash" do
|
6
|
+
context "with a simple Hash" do
|
7
|
+
should "return a Mash object matching the given Hash" do
|
8
|
+
hash = { :some => { :simple => "test" } }
|
9
|
+
mash = Savon::Mash.new(hash)
|
10
|
+
|
11
|
+
assert_respond_to(mash, :some)
|
12
|
+
assert_respond_to(mash, :simple)
|
13
|
+
assert_equal "test", mash.some.simple
|
14
|
+
end
|
15
|
+
end
|
7
16
|
end
|
8
17
|
|
9
18
|
end
|
data/test/savon/service_test.rb
CHANGED
@@ -7,6 +7,10 @@ class SavonServiceTest < Test::Unit::TestCase
|
|
7
7
|
|
8
8
|
context "Savon::Service" do
|
9
9
|
setup do
|
10
|
+
@some_factory = WsdlFactory.new
|
11
|
+
@some_wsdl = Savon::Wsdl.new(some_uri, http_mock(@some_factory.build))
|
12
|
+
Savon::Wsdl.stubs(:new).returns(@some_wsdl)
|
13
|
+
|
10
14
|
@service = Savon::Service.new(some_url)
|
11
15
|
@service.http = service_http_mock(some_soap_response)
|
12
16
|
@result = @service.findById
|
data/test/savon_test.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smacks-savon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Harrington
|
@@ -30,9 +30,9 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.4.1
|
34
34
|
version:
|
35
|
-
description:
|
35
|
+
description: Ruby SOAP client library to enjoy.
|
36
36
|
email:
|
37
37
|
executables: []
|
38
38
|
|
@@ -73,7 +73,7 @@ rubyforge_project:
|
|
73
73
|
rubygems_version: 1.2.0
|
74
74
|
signing_key:
|
75
75
|
specification_version: 2
|
76
|
-
summary:
|
76
|
+
summary: Ruby SOAP client library to enjoy.
|
77
77
|
test_files:
|
78
78
|
- test/savon_test.rb
|
79
79
|
- test/helper.rb
|