julianmorrison-savon 0.6.8
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +92 -0
- data/README.textile +71 -0
- data/Rakefile +27 -0
- data/lib/savon.rb +34 -0
- data/lib/savon/client.rb +84 -0
- data/lib/savon/core_ext.rb +3 -0
- data/lib/savon/core_ext/datetime.rb +8 -0
- data/lib/savon/core_ext/hash.rb +78 -0
- data/lib/savon/core_ext/object.rb +21 -0
- data/lib/savon/core_ext/string.rb +47 -0
- data/lib/savon/core_ext/symbol.rb +8 -0
- data/lib/savon/core_ext/uri.rb +10 -0
- data/lib/savon/request.rb +159 -0
- data/lib/savon/response.rb +108 -0
- data/lib/savon/soap.rb +138 -0
- data/lib/savon/wsdl.rb +122 -0
- data/lib/savon/wsse.rb +122 -0
- data/spec/endpoint_helper.rb +22 -0
- data/spec/fixtures/response/response_fixture.rb +32 -0
- data/spec/fixtures/response/xml/authentication.xml +14 -0
- data/spec/fixtures/response/xml/soap_fault.xml +8 -0
- data/spec/fixtures/response/xml/soap_fault12.xml +18 -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 +23 -0
- data/spec/savon/client_spec.rb +83 -0
- data/spec/savon/core_ext/datetime_spec.rb +12 -0
- data/spec/savon/core_ext/hash_spec.rb +134 -0
- data/spec/savon/core_ext/object_spec.rb +40 -0
- data/spec/savon/core_ext/string_spec.rb +68 -0
- data/spec/savon/core_ext/symbol_spec.rb +11 -0
- data/spec/savon/core_ext/uri_spec.rb +15 -0
- data/spec/savon/request_spec.rb +124 -0
- data/spec/savon/response_spec.rb +122 -0
- data/spec/savon/savon_spec.rb +23 -0
- data/spec/savon/soap_spec.rb +131 -0
- data/spec/savon/wsdl_spec.rb +84 -0
- data/spec/savon/wsse_spec.rb +132 -0
- data/spec/spec_helper.rb +16 -0
- metadata +166 -0
@@ -0,0 +1,159 @@
|
|
1
|
+
module Savon
|
2
|
+
|
3
|
+
# == Savon::Request
|
4
|
+
#
|
5
|
+
# Handles both WSDL and SOAP HTTP requests.
|
6
|
+
class Request
|
7
|
+
|
8
|
+
# Content-Types by SOAP version.
|
9
|
+
ContentType = { 1 => "text/xml", 2 => "application/soap+xml" }
|
10
|
+
|
11
|
+
# Whether to log HTTP requests.
|
12
|
+
@@log = true
|
13
|
+
|
14
|
+
# The default logger.
|
15
|
+
@@logger = Logger.new STDOUT
|
16
|
+
|
17
|
+
# The default log level.
|
18
|
+
@@log_level = :debug
|
19
|
+
|
20
|
+
# Sets whether to log HTTP requests.
|
21
|
+
def self.log=(log)
|
22
|
+
@@log = log
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns whether to log HTTP requests.
|
26
|
+
def self.log?
|
27
|
+
@@log
|
28
|
+
end
|
29
|
+
|
30
|
+
# Sets the logger.
|
31
|
+
def self.logger=(logger)
|
32
|
+
@@logger = logger
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the logger.
|
36
|
+
def self.logger
|
37
|
+
@@logger
|
38
|
+
end
|
39
|
+
|
40
|
+
# Sets the log level.
|
41
|
+
def self.log_level=(log_level)
|
42
|
+
@@log_level = log_level
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the log level.
|
46
|
+
def self.log_level
|
47
|
+
@@log_level
|
48
|
+
end
|
49
|
+
|
50
|
+
# Expects a SOAP +endpoint+ String. Also accepts an optional Hash of
|
51
|
+
# +options+ for specifying a proxy server and SSL client authentication.
|
52
|
+
def initialize(endpoint, options = {})
|
53
|
+
@endpoint = URI endpoint
|
54
|
+
@proxy = options[:proxy] ? URI(options[:proxy]) : URI("")
|
55
|
+
@ssl = options[:ssl] if options[:ssl]
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns the endpoint URI.
|
59
|
+
attr_reader :endpoint
|
60
|
+
|
61
|
+
# Returns the proxy URI.
|
62
|
+
attr_reader :proxy
|
63
|
+
|
64
|
+
# Accessor for HTTP open timeout.
|
65
|
+
attr_accessor :open_timeout
|
66
|
+
|
67
|
+
# Accessor for HTTP read timeout.
|
68
|
+
attr_accessor :read_timeout
|
69
|
+
|
70
|
+
# Retrieves WSDL document and returns the Net::HTTPResponse.
|
71
|
+
def wsdl
|
72
|
+
log "Retrieving WSDL from: #{@endpoint}"
|
73
|
+
|
74
|
+
query = @endpoint.path
|
75
|
+
query += ('?' + @endpoint.query) if @endpoint.query
|
76
|
+
req = Net::HTTP::Get.new query
|
77
|
+
req.basic_auth(@endpoint.user, @endpoint.password) if @endpoint.user
|
78
|
+
|
79
|
+
http.start {|h| h.request(req) }
|
80
|
+
end
|
81
|
+
|
82
|
+
# Executes a SOAP request using a given Savon::SOAP instance and
|
83
|
+
# returns the Net::HTTPResponse.
|
84
|
+
def soap(soap)
|
85
|
+
@soap = soap
|
86
|
+
|
87
|
+
log_request
|
88
|
+
|
89
|
+
req = Net::HTTP::Post.new @soap.endpoint.path, http_header
|
90
|
+
req.body = @soap.to_xml
|
91
|
+
req.basic_auth(@soap.endpoint.user, @soap.endpoint.password) if @soap.endpoint.user
|
92
|
+
|
93
|
+
@response = http(@soap.endpoint).start {|h| h.request(req) }
|
94
|
+
|
95
|
+
log_response
|
96
|
+
@response
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# Logs the SOAP request.
|
102
|
+
def log_request
|
103
|
+
log "SOAP request: #{@soap.endpoint}"
|
104
|
+
log http_header.map { |key, value| "#{key}: #{value}" }.join( ", " )
|
105
|
+
log @soap.to_xml
|
106
|
+
end
|
107
|
+
|
108
|
+
# Logs the SOAP response.
|
109
|
+
def log_response
|
110
|
+
log "SOAP response (status #{@response.code}):"
|
111
|
+
log @response.body
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns a Net::HTTP instance for a given +endpoint+.
|
115
|
+
def http(endpoint = @endpoint)
|
116
|
+
@http = Net::HTTP::Proxy(@proxy.host, @proxy.port).new endpoint.host, endpoint.port
|
117
|
+
set_http_timeout
|
118
|
+
set_ssl_options endpoint.ssl?
|
119
|
+
set_ssl_authentication if @ssl
|
120
|
+
@http
|
121
|
+
end
|
122
|
+
|
123
|
+
# Sets HTTP open and read timeout.
|
124
|
+
def set_http_timeout
|
125
|
+
@http.open_timeout = @open_timeout if @open_timeout
|
126
|
+
@http.read_timeout = @read_timeout if @read_timeout
|
127
|
+
end
|
128
|
+
|
129
|
+
# Sets basic SSL options to the +@http+ instance.
|
130
|
+
def set_ssl_options(use_ssl)
|
131
|
+
@http.use_ssl = use_ssl
|
132
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
133
|
+
end
|
134
|
+
|
135
|
+
# Sets SSL client authentication to the +@http+ instance.
|
136
|
+
def set_ssl_authentication
|
137
|
+
@http.verify_mode = @ssl[:verify] if @ssl[:verify].kind_of? Integer
|
138
|
+
@http.cert = @ssl[:client_cert] if @ssl[:client_cert]
|
139
|
+
@http.key = @ssl[:client_key] if @ssl[:client_key]
|
140
|
+
@http.ca_file = @ssl[:ca_file] if @ssl[:ca_file]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Returns a Hash containing the header for an HTTP request.
|
144
|
+
def http_header
|
145
|
+
{ "Content-Type" => ContentType[@soap.version], "SOAPAction" => @soap.action }
|
146
|
+
end
|
147
|
+
|
148
|
+
# Logs a given +message+.
|
149
|
+
def log(message)
|
150
|
+
self.class.logger.send self.class.log_level, message if log?
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns whether logging is possible.
|
154
|
+
def log?
|
155
|
+
self.class.log? && self.class.logger.respond_to?(self.class.log_level)
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Savon
|
2
|
+
|
3
|
+
# == Savon::Response
|
4
|
+
#
|
5
|
+
# Represents the HTTP and SOAP response.
|
6
|
+
class Response
|
7
|
+
|
8
|
+
# The global setting of whether to raise errors.
|
9
|
+
@@raise_errors = true
|
10
|
+
|
11
|
+
# Sets the global setting of whether to raise errors.
|
12
|
+
def self.raise_errors=(raise_errors)
|
13
|
+
@@raise_errors = raise_errors
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the global setting of whether to raise errors.
|
17
|
+
def self.raise_errors?
|
18
|
+
@@raise_errors
|
19
|
+
end
|
20
|
+
|
21
|
+
# Expects a Net::HTTPResponse and handles errors.
|
22
|
+
def initialize(response)
|
23
|
+
@response = response
|
24
|
+
|
25
|
+
handle_soap_fault
|
26
|
+
handle_http_error
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns whether there was a SOAP fault.
|
30
|
+
def soap_fault?
|
31
|
+
@soap_fault
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns the SOAP fault message.
|
35
|
+
attr_reader :soap_fault
|
36
|
+
|
37
|
+
# Returns whether there was an HTTP error.
|
38
|
+
def http_error?
|
39
|
+
@http_error
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the HTTP error message.
|
43
|
+
attr_reader :http_error
|
44
|
+
|
45
|
+
# Returns the SOAP response as a Hash.
|
46
|
+
def to_hash
|
47
|
+
@body.find_regexp(/.+/).map_soap_response
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the SOAP response XML.
|
51
|
+
def to_xml
|
52
|
+
@response.body
|
53
|
+
end
|
54
|
+
|
55
|
+
alias :to_s :to_xml
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Returns the SOAP response body as a Hash.
|
60
|
+
def body
|
61
|
+
unless @body
|
62
|
+
body = Crack::XML.parse @response.body
|
63
|
+
@body = body.find_regexp [/.+:Envelope/, /.+:Body/]
|
64
|
+
end
|
65
|
+
@body
|
66
|
+
end
|
67
|
+
|
68
|
+
# Handles SOAP faults. Raises a Savon::SOAPFault unless the default
|
69
|
+
# behavior of raising errors was turned off.
|
70
|
+
def handle_soap_fault
|
71
|
+
if soap_fault_message
|
72
|
+
@soap_fault = soap_fault_message
|
73
|
+
raise Savon::SOAPFault, soap_fault_message if self.class.raise_errors?
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns a SOAP fault message in case a SOAP fault was found.
|
78
|
+
def soap_fault_message
|
79
|
+
unless @soap_fault_message
|
80
|
+
soap_fault = body.find_regexp [/.+:Fault/]
|
81
|
+
@soap_fault_message = soap_fault_message_by_version(soap_fault)
|
82
|
+
end
|
83
|
+
@soap_fault_message
|
84
|
+
end
|
85
|
+
|
86
|
+
# Expects a Hash that might contain information about a SOAP fault.
|
87
|
+
# Returns the SOAP fault message in case one was found.
|
88
|
+
def soap_fault_message_by_version(soap_fault)
|
89
|
+
if soap_fault.keys.include? "faultcode"
|
90
|
+
"(#{soap_fault['faultcode']}) #{soap_fault['faultstring']}"
|
91
|
+
elsif soap_fault.keys.include? "Code"
|
92
|
+
# SOAP 1.2 error code element is capitalized, see: http://www.w3.org/TR/soap12-part1/#faultcodeelement
|
93
|
+
"(#{soap_fault['Code']['Value']}) #{soap_fault['Reason']['Text']}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Handles HTTP errors. Raises a Savon::HTTPError unless the default
|
98
|
+
# behavior of raising errors was turned off.
|
99
|
+
def handle_http_error
|
100
|
+
if @response.code.to_i >= 300
|
101
|
+
@http_error = "#{@response.message} (#{@response.code})"
|
102
|
+
@http_error << ": #{@response.body}" unless @response.body.empty?
|
103
|
+
raise Savon::HTTPError, http_error if self.class.raise_errors?
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
data/lib/savon/soap.rb
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
module Savon
|
2
|
+
|
3
|
+
# == Savon::SOAP
|
4
|
+
#
|
5
|
+
# Represents the SOAP parameters and envelope.
|
6
|
+
class SOAP
|
7
|
+
|
8
|
+
# SOAP namespaces by SOAP version.
|
9
|
+
SOAPNamespace = {
|
10
|
+
1 => "http://schemas.xmlsoap.org/soap/envelope/",
|
11
|
+
2 => "http://www.w3.org/2003/05/soap-envelope"
|
12
|
+
}
|
13
|
+
|
14
|
+
# Content-Types by SOAP version.
|
15
|
+
ContentType = { 1 => "text/xml", 2 => "application/soap+xml" }
|
16
|
+
|
17
|
+
# The global SOAP version.
|
18
|
+
@@version = 1
|
19
|
+
|
20
|
+
# Returns the global SOAP version.
|
21
|
+
def self.version
|
22
|
+
@@version
|
23
|
+
end
|
24
|
+
|
25
|
+
# Sets the global SOAP version.
|
26
|
+
def self.version=(version)
|
27
|
+
@@version = version if Savon::SOAPVersions.include? version
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
@builder = Builder::XmlMarkup.new
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sets the WSSE options.
|
35
|
+
attr_writer :wsse
|
36
|
+
|
37
|
+
# Sets the SOAP action.
|
38
|
+
attr_writer :action
|
39
|
+
|
40
|
+
# Returns the SOAP action.
|
41
|
+
def action
|
42
|
+
@action ||= ""
|
43
|
+
end
|
44
|
+
|
45
|
+
# Sets the SOAP input.
|
46
|
+
attr_writer :input
|
47
|
+
|
48
|
+
# Returns the SOAP input.
|
49
|
+
def input
|
50
|
+
@input ||= ""
|
51
|
+
end
|
52
|
+
|
53
|
+
# Accessor for the SOAP endpoint.
|
54
|
+
attr_accessor :endpoint
|
55
|
+
|
56
|
+
# Sets the SOAP header. Expected to be a Hash that can be translated
|
57
|
+
# to XML via Hash.to_soap_xml or any other Object responding to to_s.
|
58
|
+
attr_writer :header
|
59
|
+
|
60
|
+
# Returns the SOAP header. Defaults to an empty Hash.
|
61
|
+
def header
|
62
|
+
@header ||= {}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Sets the SOAP body. Expected to be a Hash that can be translated to
|
66
|
+
# XML via Hash.to_soap_xml or any other Object responding to to_s.
|
67
|
+
attr_writer :body
|
68
|
+
|
69
|
+
# Sets the namespaces. Expected to be a Hash containing the namespaces
|
70
|
+
# (keys) and the corresponding URI's (values).
|
71
|
+
attr_writer :namespaces
|
72
|
+
|
73
|
+
# Returns the namespaces. A Hash containing the namespaces (keys) and
|
74
|
+
# the corresponding URI's (values).
|
75
|
+
def namespaces
|
76
|
+
@namespaces ||= { "xmlns:env" => SOAPNamespace[version] }
|
77
|
+
end
|
78
|
+
|
79
|
+
# Convenience method for setting the "xmlns:wsdl" namespace.
|
80
|
+
def namespace=(namespace)
|
81
|
+
namespaces["xmlns:wsdl"] = namespace
|
82
|
+
end
|
83
|
+
|
84
|
+
# Sets the SOAP version.
|
85
|
+
def version=(version)
|
86
|
+
@version = version if Savon::SOAPVersions.include? version
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns the SOAP version. Defaults to the global default.
|
90
|
+
def version
|
91
|
+
@version ||= self.class.version
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns the SOAP envelope XML.
|
95
|
+
def to_xml
|
96
|
+
unless @xml_body
|
97
|
+
@xml_body = @builder.env :Envelope, namespaces do |xml|
|
98
|
+
xml_header xml
|
99
|
+
xml_body xml
|
100
|
+
end
|
101
|
+
end
|
102
|
+
@xml_body
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# Adds a SOAP XML header to a given +xml+ Object.
|
108
|
+
def xml_header(xml)
|
109
|
+
xml.env(:Header) do
|
110
|
+
xml << (header.to_soap_xml rescue header.to_s) + wsse_header
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Adds a SOAP XML body to a given +xml+ Object.
|
115
|
+
def xml_body(xml)
|
116
|
+
xml.env(:Body) do
|
117
|
+
xml.tag!(:wsdl, *input_array) do
|
118
|
+
xml << (@body.to_soap_xml rescue @body.to_s)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns an Array of SOAP input names to append to the :wsdl namespace.
|
124
|
+
# Defaults to use the name of the SOAP action and may be an empty Array
|
125
|
+
# in case the specified SOAP input seems invalid.
|
126
|
+
def input_array
|
127
|
+
return [input.to_sym] unless input.blank?
|
128
|
+
return [action.to_sym] unless action.blank?
|
129
|
+
[]
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns the WSSE header or an empty String in case WSSE was not set.
|
133
|
+
def wsse_header
|
134
|
+
@wsse.respond_to?(:header) ? @wsse.header : ""
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
data/lib/savon/wsdl.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
module Savon
|
2
|
+
|
3
|
+
# Savon::WSDL
|
4
|
+
#
|
5
|
+
# Represents the WSDL document.
|
6
|
+
class WSDL
|
7
|
+
|
8
|
+
# Initializer, expects a Savon::Request.
|
9
|
+
def initialize(request)
|
10
|
+
@request = request
|
11
|
+
end
|
12
|
+
|
13
|
+
# Sets whether to use the WSDL.
|
14
|
+
attr_writer :enabled
|
15
|
+
|
16
|
+
# Returns whether to use the WSDL. Defaults to +true+.
|
17
|
+
def enabled?
|
18
|
+
@enabled.nil? ? true : @enabled
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the namespace URI of the WSDL.
|
22
|
+
def namespace_uri
|
23
|
+
@namespace_uri ||= stream.namespace_uri
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns an Array of available SOAP actions.
|
27
|
+
def soap_actions
|
28
|
+
@soap_actions ||= stream.operations.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns a Hash of SOAP operations including their corresponding
|
32
|
+
# SOAP actions and inputs.
|
33
|
+
def operations
|
34
|
+
@operations ||= stream.operations
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the SOAP endpoint.
|
38
|
+
def soap_endpoint
|
39
|
+
@soap_endpoint ||= stream.soap_endpoint
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns +true+ for available methods and SOAP actions.
|
43
|
+
def respond_to?(method)
|
44
|
+
return true if soap_actions.include? method
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the raw WSDL document.
|
49
|
+
def to_s
|
50
|
+
@document ||= @request.wsdl.body
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# Returns the Savon::WSDLStream.
|
56
|
+
def stream
|
57
|
+
unless @stream
|
58
|
+
@stream = WSDLStream.new
|
59
|
+
REXML::Document.parse_stream to_s, @stream
|
60
|
+
end
|
61
|
+
@stream
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
# Savon::WSDLStream
|
67
|
+
#
|
68
|
+
# Stream listener for parsing the WSDL document.
|
69
|
+
class WSDLStream
|
70
|
+
|
71
|
+
# The main sections of a WSDL document.
|
72
|
+
Sections = %w(definitions types message portType binding service)
|
73
|
+
|
74
|
+
def initialize
|
75
|
+
@depth, @operations = 0, {}
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns the namespace URI.
|
79
|
+
attr_reader :namespace_uri
|
80
|
+
|
81
|
+
# Returns the SOAP operations.
|
82
|
+
attr_reader :operations
|
83
|
+
|
84
|
+
# Returns the SOAP endpoint.
|
85
|
+
attr_reader :soap_endpoint
|
86
|
+
|
87
|
+
# Hook method called when the stream parser encounters a starting tag.
|
88
|
+
def tag_start(tag, attrs)
|
89
|
+
@depth += 1
|
90
|
+
tag = tag.strip_namespace
|
91
|
+
|
92
|
+
@section = tag.to_sym if @depth <= 2 && Sections.include?(tag)
|
93
|
+
@namespace_uri ||= attrs["targetNamespace"] if @section == :definitions
|
94
|
+
@soap_endpoint ||= URI(attrs["location"]) if @section == :service && tag == "address"
|
95
|
+
|
96
|
+
operation_from tag, attrs if @section == :binding && tag == "operation"
|
97
|
+
end
|
98
|
+
|
99
|
+
# Hook method called when the stream parser encounters a closing tag.
|
100
|
+
def tag_end(tag)
|
101
|
+
@depth -= 1
|
102
|
+
end
|
103
|
+
|
104
|
+
# Stores available operations from a given tag +name+ and +attrs+.
|
105
|
+
def operation_from(tag, attrs)
|
106
|
+
@input = attrs["name"] if attrs["name"]
|
107
|
+
|
108
|
+
if attrs["soapAction"]
|
109
|
+
@action = !attrs["soapAction"].blank? ? attrs["soapAction"] : @input
|
110
|
+
@input = @action.split("/").last if !@input || @input.empty?
|
111
|
+
|
112
|
+
@operations[@input.snakecase.to_sym] = { :action => @action, :input => @input }
|
113
|
+
@input, @action = nil, nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Catches calls to unimplemented hook methods.
|
118
|
+
def method_missing(method, *args)
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|