troelskn-handsoap 0.3.8 → 0.4.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/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :minor: 3
3
- :patch: 8
2
+ :minor: 4
3
+ :patch: 0
4
4
  :major: 0
@@ -24,40 +24,6 @@ module Handsoap
24
24
  @xml_query_driver = Handsoap::XmlQueryFront.load_driver!(driver)
25
25
  end
26
26
 
27
- SOAP_NAMESPACE = { 1 => 'http://schemas.xmlsoap.org/soap/envelope/', 2 => 'http://www.w3.org/2003/05/soap-envelope' }
28
-
29
- class Response
30
- def initialize(http_body, soap_namespace)
31
- @http_body = http_body
32
- @soap_namespace = soap_namespace
33
- @document = :lazy
34
- @fault = :lazy
35
- end
36
- def document?
37
- !! document
38
- end
39
- def document
40
- if @document == :lazy
41
- begin
42
- @document = Handsoap::XmlQueryFront.parse_string(@http_body, Handsoap.xml_query_driver)
43
- rescue Handsoap::XmlQueryFront::ParseError => ex
44
- @document = nil
45
- end
46
- end
47
- return @document
48
- end
49
- def fault?
50
- !! fault
51
- end
52
- def fault
53
- if @fault == :lazy
54
- nodes = document? ? document.xpath('/env:Envelope/env:Body/descendant-or-self::env:Fault', { 'env' => @soap_namespace }) : []
55
- @fault = nodes.any? ? Fault.from_xml(nodes.first, :namespace => @soap_namespace) : nil
56
- end
57
- return @fault
58
- end
59
- end
60
-
61
27
  class Fault < Exception
62
28
  attr_reader :code, :reason, :details
63
29
  def initialize(code, reason, details)
@@ -91,18 +57,33 @@ module Handsoap
91
57
  def self.logger=(io)
92
58
  @@logger = io
93
59
  end
60
+ # Sets the endpoint for the service.
61
+ # Arguments:
62
+ # :uri => endpoint uri of the service. Required.
63
+ # :version => 1 | 2
64
+ # :envelope_namespace => Namespace of SOAP-envelope
65
+ # :request_content_type => Content-Type of HTTP request.
66
+ # You must supply either :version or both :envelope_namspace and :request_content_type.
67
+ # :version is simply a shortcut for default values.
94
68
  def self.endpoint(args = {})
95
- @protocol_version = args[:version] || raise("Missing option :version")
96
69
  @uri = args[:uri] || raise("Missing option :uri")
70
+ if args[:version]
71
+ soap_namespace = { 1 => 'http://schemas.xmlsoap.org/soap/envelope/', 2 => 'http://www.w3.org/2003/05/soap-envelope' }
72
+ raise("Unknown protocol version '#{@protocol_version.inspect}'") if soap_namespace[args[:version]].nil?
73
+ @envelope_namespace = soap_namespace[args[:version]]
74
+ @request_content_type = args[:version] == 1 ? "text/xml" : "application/soap+xml"
75
+ end
76
+ @envelope_namespace = args[:envelope_namespace] unless args[:envelope_namespace].nil?
77
+ @request_content_type = args[:request_content_type] unless args[:request_content_type].nil?
78
+ if @envelope_namespace.nil? || @request_content_type.nil?
79
+ raise("Missing option :envelope_namespace, :request_content_type or :version")
80
+ end
97
81
  end
98
82
  def self.envelope_namespace
99
- if SOAP_NAMESPACE[@protocol_version].nil?
100
- raise "Unknown protocol version '#{@protocol_version.inspect}'"
101
- end
102
- SOAP_NAMESPACE[@protocol_version]
83
+ @envelope_namespace
103
84
  end
104
85
  def self.request_content_type
105
- @protocol_version == 1 ? "text/xml" : "application/soap+xml"
86
+ @request_content_type
106
87
  end
107
88
  def self.uri
108
89
  @uri
@@ -158,6 +139,11 @@ module Handsoap
158
139
  # You can override this to provide filtering and logging.
159
140
  def on_before_dispatch
160
141
  end
142
+ # Hook that is called after the http_client is created.
143
+ #
144
+ # You can override this to customize the http_client
145
+ def on_after_create_http_client(http_client)
146
+ end
161
147
  # Hook that is called when there is a response.
162
148
  #
163
149
  # You can override this to register common namespaces, useful for parsing the document.
@@ -172,13 +158,18 @@ module Handsoap
172
158
  # Hook that is called if the dispatch returns a +Fault+.
173
159
  #
174
160
  # Default behaviour is to raise the Fault, but you can override this to provide logging and more fine-grained handling faults.
161
+ #
162
+ # See also: parse_soap_fault
175
163
  def on_fault(fault)
176
164
  raise fault
177
165
  end
178
166
  # Hook that is called if the response does not contain a valid SOAP enevlope.
179
167
  #
180
168
  # Default behaviour is to raise an error
181
- def on_missing_document(soap_response)
169
+ #
170
+ # Note that if your service has operations that are one-way, you shouldn't raise an error here.
171
+ # This is however a fairly exotic case, so that is why the default behaviour is to raise an error.
172
+ def on_missing_document(http_response_body)
182
173
  raise "The response is not a valid SOAP envelope"
183
174
  end
184
175
  def debug(message = nil) #:nodoc:
@@ -195,17 +186,20 @@ module Handsoap
195
186
  def send_http_request(uri, post_body, headers)
196
187
  if Handsoap.http_driver == :curb
197
188
  http_client = Curl::Easy.new(uri)
189
+ on_after_create_http_client(http_client)
198
190
  http_client.headers = headers
199
191
  http_client.http_post post_body
200
192
  return { :status => http_client.response_code, :body => http_client.body_str, :content_type => http_client.content_type }
201
193
  elsif Handsoap.http_driver == :httpclient
202
- response = HTTPClient.new.post(uri, post_body, headers)
194
+ http_client = HTTPClient.new
195
+ on_after_create_http_client(http_client)
196
+ response = http_client.post(uri, post_body, headers)
203
197
  return { :status => response.status, :body => response.content, :content_type => response.contenttype }
204
198
  else
205
199
  raise "Unknown http driver #{Handsoap.http_driver}"
206
200
  end
207
201
  end
208
- # Send document and parses the response into a +Response+
202
+ # Send document and parses the response into a +XmlQueryFront::XmlElement+ (XmlDocument)
209
203
  def dispatch(doc, action)
210
204
  on_before_dispatch
211
205
  headers = {
@@ -229,18 +223,29 @@ module Handsoap
229
223
  logger.puts "---"
230
224
  logger.puts Handsoap.pretty_format_envelope(response[:body])
231
225
  end
232
- soap_response = Response.new(response[:body], self.class.envelope_namespace)
233
- if soap_response.fault?
234
- return on_fault(soap_response.fault)
226
+ # Start the parsing pipe-line.
227
+ # There are various stages and hooks for each, so that you can override those in your service classes.
228
+ xml_document = parse_soap_response_document(response[:body])
229
+ soap_fault = parse_soap_fault(xml_document)
230
+ # Is the response a soap-fault?
231
+ unless soap_fault.nil?
232
+ return on_fault(soap_fault)
235
233
  end
236
- if response[:status] >= 300
234
+ # Does the http-status indicate an error?
235
+ if response[:status] >= 400
237
236
  return on_http_error(response[:status], response[:body])
238
237
  end
239
- unless soap_response.document?
240
- return on_missing_document(soap_response)
238
+ # Does the response contain a valid xml-document?
239
+ if xml_document.nil?
240
+ return on_missing_document(response[:body])
241
+ end
242
+ # Everything seems in order.
243
+ on_response_document(xml_document)
244
+ # BC hack
245
+ def xml_document.document
246
+ self
241
247
  end
242
- on_response_document(soap_response.document)
243
- return soap_response
248
+ return xml_document
244
249
  end
245
250
  # Creates a standard SOAP envelope and yields the +Body+ element.
246
251
  def make_envelope # :yields: Handsoap::XmlMason::Element
@@ -258,6 +263,21 @@ module Handsoap
258
263
  end
259
264
  return doc
260
265
  end
266
+ # String -> [XmlDocument | nil]
267
+ def parse_soap_response_document(http_body)
268
+ begin
269
+ Handsoap::XmlQueryFront.parse_string(http_body, Handsoap.xml_query_driver)
270
+ rescue Handsoap::XmlQueryFront::ParseError => ex
271
+ nil
272
+ end
273
+ end
274
+ # XmlDocument -> [Fault | nil]
275
+ def parse_soap_fault(document)
276
+ unless document.nil?
277
+ node = document.xpath('/env:Envelope/env:Body/descendant-or-self::env:Fault', { 'env' => self.class.envelope_namespace }).first
278
+ Fault.from_xml(node, :namespace => self.class.envelope_namespace) unless node.nil?
279
+ end
280
+ end
261
281
  end
262
282
 
263
283
  def self.pretty_format_envelope(xml_string)
@@ -312,7 +332,7 @@ module Handsoap
312
332
  private
313
333
  # Helper to serialize a node into a ruby string
314
334
  #
315
- # *deprecated*. Use Handsoap::XmlQueryFront::BaseDriver#to_s
335
+ # *deprecated*. Use Handsoap::XmlQueryFront::XmlElement#to_s
316
336
  def xml_to_str(node, xquery = nil)
317
337
  n = xquery ? node.xpath(xquery, ns).first : node
318
338
  return if n.nil?
@@ -321,7 +341,7 @@ module Handsoap
321
341
  alias_method :xml_to_s, :xml_to_str
322
342
  # Helper to serialize a node into a ruby integer
323
343
  #
324
- # *deprecated*. Use Handsoap::XmlQueryFront::BaseDriver#to_i
344
+ # *deprecated*. Use Handsoap::XmlQueryFront::XmlElement#to_i
325
345
  def xml_to_int(node, xquery = nil)
326
346
  n = xquery ? node.xpath(xquery, ns).first : node
327
347
  return if n.nil?
@@ -330,7 +350,7 @@ module Handsoap
330
350
  alias_method :xml_to_i, :xml_to_int
331
351
  # Helper to serialize a node into a ruby float
332
352
  #
333
- # *deprecated*. Use Handsoap::XmlQueryFront::BaseDriver#to_f
353
+ # *deprecated*. Use Handsoap::XmlQueryFront::XmlElement#to_f
334
354
  def xml_to_float(node, xquery = nil)
335
355
  n = xquery ? node.xpath(xquery, ns).first : node
336
356
  return if n.nil?
@@ -339,7 +359,7 @@ module Handsoap
339
359
  alias_method :xml_to_f, :xml_to_float
340
360
  # Helper to serialize a node into a ruby boolean
341
361
  #
342
- # *deprecated*. Use Handsoap::XmlQueryFront::BaseDriver#to_boolean
362
+ # *deprecated*. Use Handsoap::XmlQueryFront::XmlElement#to_boolean
343
363
  def xml_to_bool(node, xquery = nil)
344
364
  n = xquery ? node.xpath(xquery, ns).first : node
345
365
  return if n.nil?
@@ -347,7 +367,7 @@ module Handsoap
347
367
  end
348
368
  # Helper to serialize a node into a ruby Time object
349
369
  #
350
- # *deprecated*. Use Handsoap::XmlQueryFront::BaseDriver#to_date
370
+ # *deprecated*. Use Handsoap::XmlQueryFront::XmlElement#to_date
351
371
  def xml_to_date(node, xquery = nil)
352
372
  n = xquery ? node.xpath(xquery, ns).first : node
353
373
  return if n.nil?
@@ -13,7 +13,7 @@ module Handsoap
13
13
  # :nokogiri
14
14
  # :libxml
15
15
  #
16
- # The resulting object is a wrapper, of the type Handsoap::XmlQueryFront::BaseDriver.
16
+ # The resulting object is a wrapper, of the type Handsoap::XmlQueryFront::XmlElement.
17
17
  #
18
18
  module XmlQueryFront
19
19
 
@@ -65,7 +65,7 @@ module Handsoap
65
65
  end
66
66
  end
67
67
 
68
- # NodeSelection is a wrapper around Array, that implicitly delegates BaseDriver methods to the first element.
68
+ # NodeSelection is a wrapper around Array, that implicitly delegates XmlElement methods to the first element.
69
69
  #
70
70
  # It makes mapping code prettier, since you often need to access the first element of a selection.
71
71
  class NodeSelection < Array
@@ -102,7 +102,7 @@ module Handsoap
102
102
  end
103
103
 
104
104
  # Wraps the underlying (native) xml driver, and provides a uniform interface.
105
- module BaseDriver
105
+ module XmlElement
106
106
  def initialize(element, namespaces = {})
107
107
  @element = element
108
108
  @namespaces = namespaces
@@ -116,7 +116,7 @@ module Handsoap
116
116
  # Checks that an xpath-query doesn't refer to any undefined prefixes in +ns+
117
117
  def assert_prefixes!(expression, ns)
118
118
  expression.scan(/([a-zA-Z_][a-zA-Z0-9_.-]*):[^:]+/).map{|m| m[0] }.each do |prefix|
119
- raise "Undefined prefix '#{prefix}'" if ns[prefix].nil?
119
+ raise "Undefined prefix '#{prefix}' in #{ns.inspect}" if ns[prefix].nil?
120
120
  end
121
121
  end
122
122
  # Returns the value of the element as an integer.
@@ -203,7 +203,7 @@ module Handsoap
203
203
  #
204
204
  # http://libxml.rubyforge.org/
205
205
  class LibXMLDriver
206
- include BaseDriver
206
+ include XmlElement
207
207
  def node_name
208
208
  @element.name
209
209
  end
@@ -236,7 +236,7 @@ module Handsoap
236
236
  #
237
237
  # http://www.germane-software.com/software/rexml/
238
238
  class REXMLDriver
239
- include BaseDriver
239
+ include XmlElement
240
240
  def node_name
241
241
  @element.name
242
242
  end
@@ -274,7 +274,7 @@ module Handsoap
274
274
  #
275
275
  # http://nokogiri.rubyforge.org/nokogiri/
276
276
  class NokogiriDriver
277
- include BaseDriver
277
+ include XmlElement
278
278
  def node_name
279
279
  @element.name
280
280
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: troelskn-handsoap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Troels Knak-Nielsen
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-30 00:00:00 -07:00
12
+ date: 2009-07-31 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -33,7 +33,7 @@ files:
33
33
  - lib/handsoap/service.rb
34
34
  - lib/handsoap/xml_mason.rb
35
35
  - lib/handsoap/xml_query_front.rb
36
- has_rdoc: false
36
+ has_rdoc: true
37
37
  homepage: http://github.com/troelskn/handsoap
38
38
  licenses:
39
39
  post_install_message:
@@ -62,7 +62,7 @@ requirements:
62
62
  rubyforge_project:
63
63
  rubygems_version: 1.3.5
64
64
  signing_key:
65
- specification_version: 3
65
+ specification_version: 2
66
66
  summary: Handsoap is a library for creating SOAP clients in Ruby
67
67
  test_files: []
68
68