savon 0.6.7 → 0.6.8
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +17 -4
- data/README.textile +14 -25
- data/Rakefile +7 -30
- data/lib/savon.rb +2 -1
- data/lib/savon/client.rb +13 -15
- data/lib/savon/core_ext.rb +1 -1
- data/lib/savon/core_ext/hash.rb +3 -6
- data/lib/savon/request.rb +26 -20
- data/lib/savon/soap.rb +33 -17
- data/lib/savon/wsdl.rb +19 -8
- data/spec/endpoint_helper.rb +14 -53
- data/spec/fixtures/response/response_fixture.rb +32 -0
- data/spec/fixtures/response/xml/authentication.xml +14 -0
- data/spec/fixtures/{soap_fault.xml → response/xml/soap_fault.xml} +0 -0
- data/spec/fixtures/{soap_fault12.xml → response/xml/soap_fault12.xml} +0 -0
- data/spec/fixtures/wsdl/wsdl_fixture.rb +37 -0
- data/spec/fixtures/wsdl/xml/authentication.xml +63 -0
- data/spec/fixtures/wsdl/xml/namespaced_actions.xml +307 -0
- data/spec/fixtures/wsdl/xml/no_namespace.xml +115 -0
- data/spec/http_stubs.rb +11 -11
- data/spec/savon/client_spec.rb +46 -41
- data/spec/savon/core_ext/datetime_spec.rb +2 -2
- data/spec/savon/core_ext/hash_spec.rb +10 -10
- data/spec/savon/core_ext/object_spec.rb +2 -2
- data/spec/savon/core_ext/string_spec.rb +2 -2
- data/spec/savon/core_ext/symbol_spec.rb +1 -1
- data/spec/savon/core_ext/uri_spec.rb +1 -1
- data/spec/savon/request_spec.rb +5 -3
- data/spec/savon/response_spec.rb +7 -7
- data/spec/savon/savon_spec.rb +3 -4
- data/spec/savon/soap_spec.rb +13 -5
- data/spec/savon/wsdl_spec.rb +63 -20
- data/spec/spec_helper.rb +3 -2
- metadata +16 -14
- data/VERSION +0 -1
- data/spec/fixtures/multiple_user_response.xml +0 -22
- data/spec/fixtures/user_fixture.rb +0 -62
- data/spec/fixtures/user_response.xml +0 -15
- data/spec/fixtures/user_wsdl.xml +0 -124
data/CHANGELOG
CHANGED
@@ -1,11 +1,24 @@
|
|
1
|
-
== 0.6.
|
2
|
-
*
|
3
|
-
|
4
|
-
|
1
|
+
== 0.6.8 (2010-01-01)
|
2
|
+
* Improved specifications for various kinds of WSDL documents.
|
3
|
+
* Added support for SOAP endpoints which are different than the WSDL endpoint of a service.
|
4
|
+
* Changed how SOAP actions and inputs are retrieved from the WSDL documents. This might break a few existing
|
5
|
+
implementations, but makes Savon work well with even more services. If this change breaks your implementation,
|
6
|
+
please take a look at the +action+ and +input+ methods of the Savon::SOAP object.
|
7
|
+
One specific problem I know of is working with the createsend WSDL and its namespaced actions.
|
8
|
+
To make it work, call the SOAP action without namespace and specify the input manually:
|
9
|
+
client.get_api_key { |soap| soap.input = "User.GetApiKey" }
|
10
|
+
|
11
|
+
== 0.6.7 (2009-12-18)
|
5
12
|
* Implemented support for a proxy server. The proxy URI can be set through an optional Hash of options passed
|
6
13
|
to instantiating Savon::Client (Dave Woodward <dave@futuremint.com>)
|
7
14
|
* Implemented support for SSL client authentication. Settings can be set through an optional Hash of arguments
|
8
15
|
passed to instantiating Savon::Client (colonhyphenp)
|
16
|
+
* Patch for issue #10 (Problem with operation tags without a namespace).
|
17
|
+
|
18
|
+
== 0.6.6 (2009-12-14)
|
19
|
+
* Default to use the name of the SOAP action (the method called in a client) in lowerCamelCase for SOAP action
|
20
|
+
and input when Savon::WSDL is disabled. You still need to specify soap.action and maybe soap.input in case
|
21
|
+
your SOAP actions are named any different.
|
9
22
|
|
10
23
|
== 0.6.5 (2009-12-13)
|
11
24
|
* Added an open_timeout method to Savon::Request.
|
data/README.textile
CHANGED
@@ -2,17 +2,23 @@ h1. Savon
|
|
2
2
|
|
3
3
|
h4. Heavy metal Ruby SOAP client library
|
4
4
|
|
5
|
+
p. "RDoc":http://rdoc.info/projects/rubiii/savon | "Wiki":http://wiki.github.com/rubiii/savon | "ToDo":http://rubiii.tadalist.com/lists/1459816/public | "Metrics":http://getcaliper.com/caliper/project?repo=git://github.com/rubiii/savon.git
|
6
|
+
|
7
|
+
h2. Installation
|
8
|
+
|
5
9
|
bc. $ gem install savon
|
6
10
|
|
7
11
|
p. Savon expects you to be familiar with SOAP, WSDL and tools like soapUI.
|
8
12
|
|
9
|
-
|
13
|
+
h2. Instantiate a client
|
10
14
|
|
11
15
|
p. Instantiate Savon::Client, passing in the WSDL of your service.
|
12
16
|
|
13
17
|
bc. client = Savon::Client.new "http://example.com/UserService?wsdl"
|
14
18
|
|
15
|
-
|
19
|
+
p. More information: "Client":http://wiki.github.com/rubiii/savon/client
|
20
|
+
|
21
|
+
h2. Calling a SOAP action
|
16
22
|
|
17
23
|
p. Assuming your service applies to the "Defaults":http://wiki.github.com/rubiii/savon/defaults, you can now call any available SOAP action.
|
18
24
|
|
@@ -20,7 +26,7 @@ bc. response = client.get_all_users
|
|
20
26
|
|
21
27
|
p. Savon lets you call SOAP actions using snake_case, because even though they will propably be written in lowerCamelCase or CamelCase, it just feels much more natural.
|
22
28
|
|
23
|
-
|
29
|
+
h2. The WSDL object
|
24
30
|
|
25
31
|
p. Savon::WSDL represents the WSDL of your service, including information like the namespace URI and available SOAP actions.
|
26
32
|
|
@@ -29,7 +35,7 @@ bc. client.wsdl.soap_actions
|
|
29
35
|
|
30
36
|
p. More information: "WSDL":http://wiki.github.com/rubiii/savon/wsdl
|
31
37
|
|
32
|
-
|
38
|
+
h2. The SOAP object
|
33
39
|
|
34
40
|
p. Savon::SOAP represents the SOAP request. Pass a block to your SOAP call and the SOAP object is passed to it as the first argument. The object allows setting the SOAP version, header, body and namespaces per request.
|
35
41
|
|
@@ -37,7 +43,7 @@ bc. response = client.get_user_by_id { |soap| soap.body = { :id => 666 } }
|
|
37
43
|
|
38
44
|
p. More information: "SOAP":http://wiki.github.com/rubiii/savon/soap
|
39
45
|
|
40
|
-
|
46
|
+
h2. The WSSE object
|
41
47
|
|
42
48
|
p. Savon::WSSE represents WSSE authentication. Pass a block to your SOAP call and the WSSE object is passed to it as the second argument. The object allows setting the WSSE username, password and whether to use digest authentication.
|
43
49
|
|
@@ -49,34 +55,17 @@ end
|
|
49
55
|
|
50
56
|
p. More information: "WSSE":http://wiki.github.com/rubiii/savon/wsse
|
51
57
|
|
52
|
-
|
53
|
-
|
54
|
-
p. Savon::Client can accept SSL client certificates, as well as verify the validity of a server certificate. Syntax inspired by Adam Wiggin's "Rest-Client":http://github.com/adamwiggins/rest-client
|
55
|
-
|
56
|
-
bc. client = Savon::Client.new(
|
57
|
-
'https://example.org/wsdl',
|
58
|
-
:ssl_client_cert => OpenSSL::X509::Certificate.new(File.read("client_cert.pem")),
|
59
|
-
:ssl_client_key => OpenSSL::PKey::RSA.new(File.read("client_key.pem"), "password if one exists"),
|
60
|
-
:ssl_ca_file => "cacert.pem",
|
61
|
-
:ssl_verify => OpenSSL::SSL::VERIFY_PEER
|
62
|
-
)
|
63
|
-
|
64
|
-
h3. The Response object
|
58
|
+
h2. The Response object
|
65
59
|
|
66
60
|
p. Savon::Response represents the HTTP and SOAP response. It contains and raises errors in case of an HTTP error or SOAP fault (unless disabled). Also you can get the response as XML (for parsing it with an XML library) or translated into a Hash.
|
67
61
|
More information: "Response":http://wiki.github.com/rubiii/savon/response
|
68
62
|
|
69
|
-
|
63
|
+
h2. HTTP errors and SOAP faults
|
70
64
|
|
71
65
|
p. Savon raises a Savon::SOAPFault in case of a SOAP fault and a Savon::HTTPError in case of an HTTP error.
|
72
66
|
More information: "Errors":http://wiki.github.com/rubiii/savon/errors
|
73
67
|
|
74
|
-
|
68
|
+
h2. Logging
|
75
69
|
|
76
70
|
p. Savon logs each request and response to STDOUT. But there are a couple of options to change the default behaviour.
|
77
71
|
More information: "Logging":http://wiki.github.com/rubiii/savon/logging
|
78
|
-
|
79
|
-
h3. Documentation
|
80
|
-
|
81
|
-
p. Wiki: "wiki.github.com/rubiii/savon":http://wiki.github.com/rubiii/savon
|
82
|
-
RDoc: "rdoc.info/projects/rubiii/savon":http://rdoc.info/projects/rubiii/savon
|
data/Rakefile
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "rake"
|
3
3
|
require "spec/rake/spectask"
|
4
|
+
require "spec/rake/verify_rcov"
|
4
5
|
require "rake/rdoctask"
|
5
6
|
|
6
|
-
task :default => :
|
7
|
+
task :default => :spec_verify_rcov
|
7
8
|
|
8
9
|
Spec::Rake::SpecTask.new do |spec|
|
9
10
|
spec.spec_files = FileList["spec/**/*_spec.rb"]
|
@@ -13,38 +14,14 @@ Spec::Rake::SpecTask.new do |spec|
|
|
13
14
|
spec.rcov_dir = "rcov"
|
14
15
|
end
|
15
16
|
|
17
|
+
RCov::VerifyTask.new(:spec_verify_rcov => :spec) do |verify|
|
18
|
+
verify.threshold = 100.0
|
19
|
+
verify.index_html = "rcov/index.html"
|
20
|
+
end
|
21
|
+
|
16
22
|
Rake::RDocTask.new do |rdoc|
|
17
23
|
rdoc.title = "Savon"
|
18
24
|
rdoc.rdoc_dir = "rdoc"
|
19
25
|
rdoc.rdoc_files.include("lib/**/*.rb")
|
20
26
|
rdoc.options = ["--line-numbers", "--inline-source"]
|
21
27
|
end
|
22
|
-
|
23
|
-
begin
|
24
|
-
require "jeweler"
|
25
|
-
Jeweler::Tasks.new do |spec|
|
26
|
-
spec.name = "savon"
|
27
|
-
spec.author = "Daniel Harrington"
|
28
|
-
spec.email = "me@rubiii.com"
|
29
|
-
spec.homepage = "http://github.com/rubiii/savon"
|
30
|
-
spec.summary = "Heavy metal Ruby SOAP client library"
|
31
|
-
spec.description = spec.summary
|
32
|
-
|
33
|
-
spec.files = FileList["[A-Z]*", "{lib,spec}/**/*.{rb,xml}"]
|
34
|
-
|
35
|
-
spec.rdoc_options += [
|
36
|
-
"--title", "Savon",
|
37
|
-
"--line-numbers",
|
38
|
-
"--inline-source"
|
39
|
-
]
|
40
|
-
|
41
|
-
spec.add_runtime_dependency("builder", ">= 2.1.2")
|
42
|
-
spec.add_runtime_dependency("crack", ">= 0.1.4")
|
43
|
-
|
44
|
-
spec.add_development_dependency("rspec", ">= 1.2.8")
|
45
|
-
spec.add_development_dependency("mocha", ">= 0.9.7")
|
46
|
-
spec.add_development_dependency("fakeweb", ">= 1.2.7")
|
47
|
-
end
|
48
|
-
rescue LoadError
|
49
|
-
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
50
|
-
end
|
data/lib/savon.rb
CHANGED
@@ -23,11 +23,12 @@ end
|
|
23
23
|
end
|
24
24
|
|
25
25
|
# gems
|
26
|
+
require "rubygems"
|
26
27
|
%w(builder crack/xml).each do |gem|
|
27
28
|
require gem
|
28
29
|
end
|
29
30
|
|
30
31
|
# core files
|
31
32
|
%w(core_ext wsse soap request response wsdl client).each do |file|
|
32
|
-
require "savon/#{file}"
|
33
|
+
require File.dirname(__FILE__) + "/savon/#{file}"
|
33
34
|
end
|
data/lib/savon/client.rb
CHANGED
@@ -21,7 +21,7 @@ module Savon
|
|
21
21
|
|
22
22
|
# Expects a SOAP +endpoint+ String. Also accepts an optional Hash of
|
23
23
|
# +options+ for specifying a proxy server and SSL client authentication.
|
24
|
-
def initialize(endpoint,options = {})
|
24
|
+
def initialize(endpoint, options = {})
|
25
25
|
@request = Request.new endpoint, options
|
26
26
|
@wsdl = WSDL.new @request
|
27
27
|
end
|
@@ -49,8 +49,8 @@ module Savon
|
|
49
49
|
def method_missing(method, *args, &block) #:doc:
|
50
50
|
super if wsdl? && !@wsdl.respond_to?(method)
|
51
51
|
|
52
|
-
|
53
|
-
|
52
|
+
setup_objects operation_from(method), &block
|
53
|
+
Response.new @request.soap(@soap)
|
54
54
|
end
|
55
55
|
|
56
56
|
# Returns a SOAP operation Hash containing the SOAP action and input
|
@@ -60,32 +60,30 @@ module Savon
|
|
60
60
|
{ :action => method.to_soap_key, :input => method.to_soap_key }
|
61
61
|
end
|
62
62
|
|
63
|
+
# Returns the SOAP endpoint.
|
64
|
+
def soap_endpoint
|
65
|
+
wsdl? ? @wsdl.soap_endpoint : @request.endpoint
|
66
|
+
end
|
67
|
+
|
63
68
|
# Expects a SOAP operation Hash and sets up Savon::SOAP and Savon::WSSE.
|
64
69
|
# Yields them to a given +block+ in case one was given.
|
65
|
-
def
|
66
|
-
@soap = SOAP.new
|
67
|
-
@soap.action, @soap.input = operation[:action], operation[:input]
|
68
|
-
@wsse = WSSE.new
|
70
|
+
def setup_objects(operation, &block)
|
71
|
+
@soap, @wsse = SOAP.new, WSSE.new
|
72
|
+
@soap.action, @soap.input, @soap.endpoint = operation[:action], operation[:input], soap_endpoint
|
69
73
|
|
70
|
-
|
74
|
+
yield_objects &block if block
|
71
75
|
|
72
76
|
@soap.namespaces["xmlns:wsdl"] ||= @wsdl.namespace_uri if wsdl?
|
73
77
|
@soap.wsse = @wsse
|
74
78
|
end
|
75
79
|
|
76
80
|
# Yields Savon::SOAP and Savon::WSSE to a given +block+.
|
77
|
-
def
|
81
|
+
def yield_objects(&block)
|
78
82
|
case block.arity
|
79
83
|
when 1 then yield @soap
|
80
84
|
when 2 then yield @soap, @wsse
|
81
85
|
end
|
82
86
|
end
|
83
87
|
|
84
|
-
# Dispatches a given +soap_action+ and returns a Savon::Response instance.
|
85
|
-
def dispatch(soap_action)
|
86
|
-
response = @request.soap @soap
|
87
|
-
Response.new response
|
88
|
-
end
|
89
|
-
|
90
88
|
end
|
91
89
|
end
|
data/lib/savon/core_ext.rb
CHANGED
data/lib/savon/core_ext/hash.rb
CHANGED
@@ -34,12 +34,9 @@ class Hash
|
|
34
34
|
key = key.strip_namespace.snakecase.to_sym
|
35
35
|
|
36
36
|
value = case value
|
37
|
-
when Hash
|
38
|
-
|
39
|
-
when
|
40
|
-
value.map { |a_value| a_value.map_soap_response rescue a_value }
|
41
|
-
when String
|
42
|
-
value.map_soap_response
|
37
|
+
when Hash then value["xsi:nil"] ? nil : value.map_soap_response
|
38
|
+
when Array then value.map { |a_value| a_value.map_soap_response rescue a_value }
|
39
|
+
when String then value.map_soap_response
|
43
40
|
end
|
44
41
|
hash.merge key => value
|
45
42
|
end
|
data/lib/savon/request.rb
CHANGED
@@ -61,15 +61,11 @@ module Savon
|
|
61
61
|
# Returns the proxy URI.
|
62
62
|
attr_reader :proxy
|
63
63
|
|
64
|
-
#
|
65
|
-
|
66
|
-
http.open_timeout = sec
|
67
|
-
end
|
64
|
+
# Accessor for HTTP open timeout.
|
65
|
+
attr_accessor :open_timeout
|
68
66
|
|
69
|
-
#
|
70
|
-
|
71
|
-
http.read_timeout = sec
|
72
|
-
end
|
67
|
+
# Accessor for HTTP read timeout.
|
68
|
+
attr_accessor :read_timeout
|
73
69
|
|
74
70
|
# Retrieves WSDL document and returns the Net::HTTPResponse.
|
75
71
|
def wsdl
|
@@ -83,7 +79,7 @@ module Savon
|
|
83
79
|
@soap = soap
|
84
80
|
|
85
81
|
log_request
|
86
|
-
@response = http.request_post @endpoint.path, @soap.to_xml, http_header
|
82
|
+
@response = http(@soap.endpoint).request_post @soap.endpoint.path, @soap.to_xml, http_header
|
87
83
|
log_response
|
88
84
|
@response
|
89
85
|
end
|
@@ -92,7 +88,7 @@ module Savon
|
|
92
88
|
|
93
89
|
# Logs the SOAP request.
|
94
90
|
def log_request
|
95
|
-
log "SOAP request: #{@endpoint}"
|
91
|
+
log "SOAP request: #{@soap.endpoint}"
|
96
92
|
log http_header.map { |key, value| "#{key}: #{value}" }.join( ", " )
|
97
93
|
log @soap.to_xml
|
98
94
|
end
|
@@ -103,19 +99,29 @@ module Savon
|
|
103
99
|
log @response.body
|
104
100
|
end
|
105
101
|
|
106
|
-
# Returns a Net::HTTP instance
|
107
|
-
def http
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
add_ssl_authentication if @ssl
|
113
|
-
end
|
102
|
+
# Returns a Net::HTTP instance for a given +endpoint+.
|
103
|
+
def http(endpoint = @endpoint)
|
104
|
+
@http = Net::HTTP::Proxy(@proxy.host, @proxy.port).new endpoint.host, endpoint.port
|
105
|
+
set_http_timeout
|
106
|
+
set_ssl_options endpoint.ssl?
|
107
|
+
set_ssl_authentication if @ssl
|
114
108
|
@http
|
115
109
|
end
|
116
110
|
|
117
|
-
#
|
118
|
-
def
|
111
|
+
# Sets HTTP open and read timeout.
|
112
|
+
def set_http_timeout
|
113
|
+
@http.open_timeout = @open_timeout if @open_timeout
|
114
|
+
@http.read_timeout = @read_timeout if @read_timeout
|
115
|
+
end
|
116
|
+
|
117
|
+
# Sets basic SSL options to the +@http+ instance.
|
118
|
+
def set_ssl_options(use_ssl)
|
119
|
+
@http.use_ssl = use_ssl
|
120
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
121
|
+
end
|
122
|
+
|
123
|
+
# Sets SSL client authentication to the +@http+ instance.
|
124
|
+
def set_ssl_authentication
|
119
125
|
@http.verify_mode = @ssl[:verify] if @ssl[:verify].kind_of? Integer
|
120
126
|
@http.cert = @ssl[:client_cert] if @ssl[:client_cert]
|
121
127
|
@http.key = @ssl[:client_key] if @ssl[:client_key]
|
data/lib/savon/soap.rb
CHANGED
@@ -27,23 +27,32 @@ module Savon
|
|
27
27
|
@@version = version if Savon::SOAPVersions.include? version
|
28
28
|
end
|
29
29
|
|
30
|
+
def initialize
|
31
|
+
@builder = Builder::XmlMarkup.new
|
32
|
+
end
|
33
|
+
|
30
34
|
# Sets the WSSE options.
|
31
35
|
attr_writer :wsse
|
32
36
|
|
33
|
-
#
|
37
|
+
# Sets the SOAP action.
|
34
38
|
attr_writer :action
|
35
39
|
|
40
|
+
# Returns the SOAP action.
|
36
41
|
def action
|
37
42
|
@action ||= ""
|
38
43
|
end
|
39
44
|
|
40
|
-
#
|
45
|
+
# Sets the SOAP input.
|
41
46
|
attr_writer :input
|
42
47
|
|
48
|
+
# Returns the SOAP input.
|
43
49
|
def input
|
44
50
|
@input ||= ""
|
45
51
|
end
|
46
52
|
|
53
|
+
# Accessor for the SOAP endpoint.
|
54
|
+
attr_accessor :endpoint
|
55
|
+
|
47
56
|
# Sets the SOAP header. Expected to be a Hash that can be translated
|
48
57
|
# to XML via Hash.to_soap_xml or any other Object responding to to_s.
|
49
58
|
attr_writer :header
|
@@ -80,17 +89,9 @@ module Savon
|
|
80
89
|
# Returns the SOAP envelope XML.
|
81
90
|
def to_xml
|
82
91
|
unless @xml_body
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
xml.env(:Header) do
|
87
|
-
xml << (header.to_soap_xml rescue header.to_s) + wsse_header
|
88
|
-
end
|
89
|
-
xml.env(:Body) do
|
90
|
-
xml.tag!(:wsdl, *input_array) do
|
91
|
-
xml << (@body.to_soap_xml rescue @body.to_s)
|
92
|
-
end
|
93
|
-
end
|
92
|
+
@xml_body = @builder.env :Envelope, namespaces do |xml|
|
93
|
+
xml_header xml
|
94
|
+
xml_body xml
|
94
95
|
end
|
95
96
|
end
|
96
97
|
@xml_body
|
@@ -98,19 +99,34 @@ module Savon
|
|
98
99
|
|
99
100
|
private
|
100
101
|
|
102
|
+
# Adds a SOAP XML header to a given +xml+ Object.
|
103
|
+
def xml_header(xml)
|
104
|
+
xml.env(:Header) do
|
105
|
+
xml << (header.to_soap_xml rescue header.to_s) + wsse_header
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Adds a SOAP XML body to a given +xml+ Object.
|
110
|
+
def xml_body(xml)
|
111
|
+
xml.env(:Body) do
|
112
|
+
xml.tag!(:wsdl, *input_array) do
|
113
|
+
xml << (@body.to_soap_xml rescue @body.to_s)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
101
118
|
# Returns an Array of SOAP input names to append to the :wsdl namespace.
|
102
119
|
# Defaults to use the name of the SOAP action and may be an empty Array
|
103
120
|
# in case the specified SOAP input seems invalid.
|
104
121
|
def input_array
|
105
|
-
return [input.to_sym]
|
106
|
-
return [action.to_sym]
|
122
|
+
return [input.to_sym] unless input.blank?
|
123
|
+
return [action.to_sym] unless action.blank?
|
107
124
|
[]
|
108
125
|
end
|
109
126
|
|
110
127
|
# Returns the WSSE header or an empty String in case WSSE was not set.
|
111
128
|
def wsse_header
|
112
|
-
|
113
|
-
@wsse.header
|
129
|
+
@wsse.respond_to?(:header) ? @wsse.header : ""
|
114
130
|
end
|
115
131
|
|
116
132
|
end
|