smacks-savon 0.0.91 → 0.1.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.
- 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
|