troelskn-handsoap 0.2.9 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -5,7 +5,7 @@ Install
5
5
  ---
6
6
 
7
7
  gem sources -a http://gems.github.com
8
- sudo gem install troelskn-handsoap curb
8
+ sudo gem install troelskn-handsoap curb nokogiri
9
9
 
10
10
  What
11
11
  ---
@@ -13,6 +13,8 @@ Handsoap is a library for creating SOAP clients in Ruby.
13
13
 
14
14
  [Watch a tutorial](http://www.vimeo.com/4813848), showing how to use Handsoap. The final application can be found at: [http://github.com/troelskn/handsoap-example/tree/master](http://github.com/troelskn/handsoap-example/tree/master)
15
15
 
16
+ API docs are at [http://rdoc.info/projects/troelskn/handsoap](http://rdoc.info/projects/troelskn/handsoap)
17
+
16
18
  ![Handsoap](http://ny-image0.etsy.com/il_430xN.68558416.jpg)
17
19
 
18
20
  Why
@@ -68,6 +70,11 @@ The protocol also contains a large and unwieldy specification of how to do the (
68
70
 
69
71
  Handsoap only supports RPC-style SOAP. This seems to be the most common style. It's probably possible to add support for Document-style with little effort, but until I see the need I'm not going there.
70
72
 
73
+ API documnetation
74
+ ---
75
+
76
+ In addition to this guide, there's autogenerated API documentation available at [http://rdoc.info/projects/troelskn/handsoap](http://rdoc.info/projects/troelskn/handsoap)
77
+
71
78
  The toolbox
72
79
  ---
73
80
 
@@ -75,7 +82,7 @@ The Handsoap toolbox consists of the following components.
75
82
 
76
83
  Handsoap can use either [curb](http://curb.rubyforge.org/) or [httpclient](http://dev.ctor.org/http-access2) for HTTP-connectivity. The former is recommended, and default, but for portability you might choose the latter. You usually don't need to interact at the HTTP-level, but if you do (for example, if you have to use SSL), you can.
77
84
 
78
- For parsing XML, Handsoap uses [Nokogiri](http://github.com/tenderlove/nokogiri/tree/master). While this may become optional in the future, the dependency is a bit tighter. The XML-parser is used internally in Handsoap, as well as by the code that maps from SOAP to Ruby (The code you're writing). Nokogiri is very fast (being based om libxml) and has a polished and stable api.
85
+ For parsing XML, Handsoap defaults to use [Nokogiri](http://github.com/tenderlove/nokogiri/tree/master). Handsoap has an abstraction layer, so that you can switch between REXML, Nokogiri and ruby-libxml. Besides providing portability between these parsers, Handsop also gives some helper functions that are meaningful when parsing SOAP envelopes.
79
86
 
80
87
  There is also a library for generating XML, which you'll use when mapping from Ruby to SOAP. It's quite similar to [Builder](http://builder.rubyforge.org/), but is tailored towards being used for writing SOAP-messages. The name of this library is `XmlMason` and it is included/part of Handsoap.
81
88
 
@@ -101,7 +108,7 @@ Recommendations
101
108
 
102
109
  7. Write Ruby-code (using XmlMason) to generate a request that is similar to the example from soapUI. (In your copy+paste buffer)
103
110
 
104
- 8. Write Ruby-code to parse the response (a Nokogiri XML-document) into Ruby data types.
111
+ 8. Write Ruby-code to parse the response (an XML-document) into Ruby data types.
105
112
 
106
113
  9. Write an integration test to verify that your method works as expected. You can use soapUI to [generate a mock-service](http://www.soapui.org/userguide/mock/getting_started.html).
107
114
 
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
+ :minor: 3
3
+ :patch: 0
2
4
  :major: 0
3
- :minor: 2
4
- :patch: 9
@@ -1,41 +1,43 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  module Handsoap
3
- class CodeWriter
3
+ # Used internally to generate Ruby source code
4
+ class CodeWriter #:nodoc: all
4
5
 
5
- def initialize
6
- @buffer = ""
7
- @indentation = 0
8
- end
6
+ def initialize
7
+ @buffer = ""
8
+ @indentation = 0
9
+ end
9
10
 
10
- def begin(text)
11
- puts(text)
12
- indent
13
- end
11
+ def begin(text)
12
+ puts(text)
13
+ indent
14
+ end
14
15
 
15
- def end(str = "end")
16
- unindent
17
- puts(str)
18
- end
16
+ def end(str = "end")
17
+ unindent
18
+ puts(str)
19
+ end
19
20
 
20
- def puts(text = "")
21
- @buffer << text.gsub(/^(.*)$/, (" " * @indentation) + "\\1")
22
- @buffer << "\n" # unless @buffer.match(/\n$/)
23
- end
21
+ def puts(text = "")
22
+ @buffer << text.gsub(/^(.*)$/, (" " * @indentation) + "\\1")
23
+ @buffer << "\n" # unless @buffer.match(/\n$/)
24
+ end
24
25
 
25
- def indent
26
- @indentation = @indentation + 1
27
- end
26
+ def indent
27
+ @indentation = @indentation + 1
28
+ end
28
29
 
29
- def unindent
30
- @indentation = @indentation - 1
31
- end
30
+ def unindent
31
+ @indentation = @indentation - 1
32
+ end
32
33
 
33
- def to_s
34
- @buffer
35
- end
34
+ def to_s
35
+ @buffer
36
36
  end
37
+ end
37
38
 
38
- class Compiler
39
+ # Used internally by the generator to generate a Service stub.
40
+ class Compiler #:nodoc: all
39
41
 
40
42
  def initialize(wsdl, basename = nil)
41
43
  @wsdl = wsdl
@@ -5,7 +5,10 @@ require 'uri'
5
5
  require 'nokogiri'
6
6
 
7
7
  module Handsoap
8
- module Parser
8
+ # Classes for parsing a WSDL.
9
+ #
10
+ # Used internally by the generator.
11
+ module Parser #:nodoc: all
9
12
  class Interface
10
13
  attr_accessor :name, :operations
11
14
 
@@ -1,35 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
- require 'rubygems'
3
- require 'nokogiri'
4
2
  require 'time'
5
3
  require 'handsoap/xml_mason'
6
-
7
- # Nokogiri doesn't have a way of getting plain strings out,
8
- # so this monkeypatch adds that capability ..
9
- module Utf8StringPatch
10
- def to_utf8
11
- # HTMLEntities.decode_entities(self.serialize(:encoding => 'UTF-8'))
12
- if Gem.loaded_specs['nokogiri'].version >= Gem::Version.new('1.3.0')
13
- self.serialize(:encoding => 'UTF-8').gsub('&lt;', '<').gsub('&gt;', '>').gsub('&quot;', '"').gsub('&apos;', "'").gsub('&amp;', '&')
14
- else
15
- self.serialize('UTF-8').gsub('&lt;', '<').gsub('&gt;', '>').gsub('&quot;', '"').gsub('&apos;', "'").gsub('&amp;', '&')
16
- end
17
- end
18
- end
19
-
20
- module Nokogiri
21
- module XML
22
- class Text
23
- include Utf8StringPatch
24
- end
25
- class Nodeset
26
- include Utf8StringPatch
27
- end
28
- class Attr
29
- include Utf8StringPatch
30
- end
31
- end
32
- end
4
+ require 'handsoap/xml_query_front'
33
5
 
34
6
  module Handsoap
35
7
 
@@ -44,6 +16,14 @@ module Handsoap
44
16
  return driver
45
17
  end
46
18
 
19
+ def self.xml_query_driver
20
+ @xml_query_driver || (self.xml_query_driver = :nokogiri)
21
+ end
22
+
23
+ def self.xml_query_driver=(driver)
24
+ @xml_query_driver = Handsoap::XmlQueryFront.load_driver!(driver)
25
+ end
26
+
47
27
  SOAP_NAMESPACE = { 1 => 'http://schemas.xmlsoap.org/soap/envelope/', 2 => 'http://www.w3.org/2001/12/soap-encoding' }
48
28
 
49
29
  class Response
@@ -58,8 +38,11 @@ module Handsoap
58
38
  end
59
39
  def document
60
40
  if @document == :lazy
61
- doc = Nokogiri::XML(@http_body)
62
- @document = (doc && doc.root && doc.errors.empty?) ? doc : nil
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
63
46
  end
64
47
  return @document
65
48
  end
@@ -160,7 +143,18 @@ module Handsoap
160
143
  super
161
144
  end
162
145
  end
163
- def invoke(action, options = { :soap_action => :auto }, &block)
146
+ # Creates an XML document and sends it over HTTP.
147
+ #
148
+ # +action+ is the QName of the rootnode of the envelope.
149
+ #
150
+ # +options+ currently takes one option +:soap_action+, which can be one of:
151
+ #
152
+ # :auto sends a SOAPAction http header, deduced from the action name. (This is the default)
153
+ #
154
+ # +String+ sends a SOAPAction http header.
155
+ #
156
+ # +nil+ sends no SOAPAction http header.
157
+ def invoke(action, options = { :soap_action => :auto }, &block) # :yields: Handsoap::XmlMason::Element
164
158
  if action
165
159
  if options.kind_of? String
166
160
  options = { :soap_action => options }
@@ -179,13 +173,21 @@ module Handsoap
179
173
  dispatch(doc, options[:soap_action])
180
174
  end
181
175
  end
176
+ # Hook that is called before the message is dispatched.
177
+ #
178
+ # You can override this to provide filtering and logging.
182
179
  def on_before_dispatch
183
180
  end
181
+ # Hook that is called if the dispatch returns a +Fault+.
182
+ #
183
+ # Default behaviour is to raise the Fault, but you can override this to provide logging and more fine-grained handling faults.
184
184
  def on_fault(fault)
185
185
  raise fault
186
186
  end
187
187
  private
188
188
  # Helper to serialize a node into a ruby string
189
+ #
190
+ # *deprecated*. Use Handsoap::XmlQueryFront::BaseDriver#to_s
189
191
  def xml_to_str(node, xquery = nil)
190
192
  n = xquery ? node.xpath(xquery, ns).first : node
191
193
  return if n.nil?
@@ -193,6 +195,8 @@ module Handsoap
193
195
  end
194
196
  alias_method :xml_to_s, :xml_to_str
195
197
  # Helper to serialize a node into a ruby integer
198
+ #
199
+ # *deprecated*. Use Handsoap::XmlQueryFront::BaseDriver#to_i
196
200
  def xml_to_int(node, xquery = nil)
197
201
  n = xquery ? node.xpath(xquery, ns).first : node
198
202
  return if n.nil?
@@ -200,6 +204,8 @@ module Handsoap
200
204
  end
201
205
  alias_method :xml_to_i, :xml_to_int
202
206
  # Helper to serialize a node into a ruby float
207
+ #
208
+ # *deprecated*. Use Handsoap::XmlQueryFront::BaseDriver#to_f
203
209
  def xml_to_float(node, xquery = nil)
204
210
  n = xquery ? node.xpath(xquery, ns).first : node
205
211
  return if n.nil?
@@ -207,18 +213,22 @@ module Handsoap
207
213
  end
208
214
  alias_method :xml_to_f, :xml_to_float
209
215
  # Helper to serialize a node into a ruby boolean
216
+ #
217
+ # *deprecated*. Use Handsoap::XmlQueryFront::BaseDriver#to_boolean
210
218
  def xml_to_bool(node, xquery = nil)
211
219
  n = xquery ? node.xpath(xquery, ns).first : node
212
220
  return if n.nil?
213
221
  n.to_s == "true"
214
222
  end
215
223
  # Helper to serialize a node into a ruby Time object
224
+ #
225
+ # *deprecated*. Use Handsoap::XmlQueryFront::BaseDriver#to_date
216
226
  def xml_to_date(node, xquery = nil)
217
227
  n = xquery ? node.xpath(xquery, ns).first : node
218
228
  return if n.nil?
219
229
  Time.iso8601(n.to_s)
220
230
  end
221
- def debug(message = nil)
231
+ def debug(message = nil) #:nodoc:
222
232
  if @@logger
223
233
  if message
224
234
  @@logger.puts(message)
@@ -228,8 +238,9 @@ module Handsoap
228
238
  end
229
239
  end
230
240
  end
241
+ # Takes care of the HTTP level dispatch.
231
242
  def dispatch(doc, action)
232
- on_before_dispatch()
243
+ on_before_dispatch
233
244
  headers = {
234
245
  "Content-Type" => "#{self.class.request_content_type};charset=UTF-8"
235
246
  }
@@ -273,7 +284,8 @@ module Handsoap
273
284
  end
274
285
  return soap_response
275
286
  end
276
- def make_envelope
287
+ # Creates a standard SOAP envelope and yields the +Body+ element.
288
+ def make_envelope # :yields: Handsoap::XmlMason::Element
277
289
  doc = XmlMason::Document.new do |doc|
278
290
  doc.alias 'env', self.class.envelope_namespace
279
291
  doc.add "env:Envelope" do |env|
@@ -292,11 +304,11 @@ module Handsoap
292
304
  def self.pretty_format_envelope(xml_string)
293
305
  if /^<.*:Envelope/.match(xml_string)
294
306
  begin
295
- doc = Nokogiri::XML(xml_string)
307
+ doc = Handsoap::XmlQueryFront.parse_string(xml_string, Handsoap.xml_query_driver)
296
308
  rescue Exception => ex
297
309
  return "Formatting failed: " + ex.to_s
298
310
  end
299
- return doc.to_s
311
+ return doc.to_xml
300
312
  # return "\n\e[1;33m" + doc.to_s + "\e[0m"
301
313
  end
302
314
  return xml_string
@@ -2,28 +2,44 @@
2
2
 
3
3
  module Handsoap
4
4
 
5
+ # XmlMason is a simple XML builder.
5
6
  module XmlMason
6
7
 
7
- HTML_ESCAPE = { '&' => '&amp;', '"' => '&quot;', '>' => '&gt;', '<' => '&lt;' }
8
+ XML_ESCAPE = { '&' => '&amp;', '"' => '&quot;', '>' => '&gt;', '<' => '&lt;' }
8
9
 
9
- def self.html_escape(s)
10
- s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
10
+ def self.xml_escape(s)
11
+ s.to_s.gsub(/[&"><]/) { |special| XML_ESCAPE[special] }
11
12
  end
12
13
 
13
14
  class Node
14
15
  def initialize
15
16
  @namespaces = {}
16
17
  end
17
- def add(node_name, value = nil, *flags)
18
+ def add(node_name, value = nil, *flags) # :yields: Handsoap::XmlMason::Element
18
19
  prefix, name = parse_ns(node_name)
19
20
  node = append_child Element.new(self, prefix, name, value, flags)
20
21
  if block_given?
21
22
  yield node
22
23
  end
23
24
  end
25
+ # Registers a prefix for a namespace.
26
+ #
27
+ # You must register a namespace, before you can refer it.
24
28
  def alias(prefix, namespaces)
25
29
  @namespaces[prefix] = namespaces
26
30
  end
31
+ # Finds the first element whos +node_name+ equals +name+
32
+ #
33
+ # Doesn't regard namespaces/prefixes.
34
+ def find(name)
35
+ raise NotImplementedError.new
36
+ end
37
+ # Finds all elements whos +node_name+ equals +name+
38
+ #
39
+ # Doesn't regard namespaces/prefixes.
40
+ def find_all(name)
41
+ raise NotImplementedError.new
42
+ end
27
43
  def parse_ns(name)
28
44
  matches = name.match /^([^:]+):(.*)$/
29
45
  if matches
@@ -36,7 +52,7 @@ module Handsoap
36
52
  end
37
53
 
38
54
  class Document < Node
39
- def initialize
55
+ def initialize # :yields: Document
40
56
  super
41
57
  @document_element = nil
42
58
  if block_given?
@@ -74,7 +90,7 @@ module Handsoap
74
90
  @text = text
75
91
  end
76
92
  def to_s(indentation = '')
77
- XmlMason.html_escape(@text)
93
+ XmlMason.xml_escape(@text)
78
94
  end
79
95
  end
80
96
 
@@ -85,7 +101,7 @@ module Handsoap
85
101
  end
86
102
 
87
103
  class Element < Node
88
- def initialize(parent, prefix, node_name, value = nil, flags = [])
104
+ def initialize(parent, prefix, node_name, value = nil, flags = []) # :yields: Handsoap::XmlMason::Element
89
105
  super()
90
106
  # if prefix.to_s == ""
91
107
  # raise "missing prefix"
@@ -102,12 +118,17 @@ module Handsoap
102
118
  yield self
103
119
  end
104
120
  end
121
+ # Returns the document that this element belongs to, or self if this is the document.
105
122
  def document
106
123
  @parent.respond_to?(:document) ? @parent.document : @parent
107
124
  end
125
+ # Returns the qname (prefix:nodename)
108
126
  def full_name
109
127
  @prefix.nil? ? @node_name : (@prefix + ":" + @node_name)
110
128
  end
129
+ # Adds a child node.
130
+ #
131
+ # You usually won't need to call this method, but will rather use +add+
111
132
  def append_child(node)
112
133
  if value_node?
113
134
  raise "Element already has a text value. Can't add nodes"
@@ -115,6 +136,11 @@ module Handsoap
115
136
  @children << node
116
137
  return node
117
138
  end
139
+ # Sets the inner text of this element.
140
+ #
141
+ # By default the string is escaped, but you can pass the flag :raw to inject XML.
142
+ #
143
+ # You usually won't need to call this method, but will rather use +add+
118
144
  def set_value(value, *flags)
119
145
  if @children.length > 0
120
146
  raise "Element already has children. Can't set value"
@@ -125,6 +151,7 @@ module Handsoap
125
151
  @children = [TextNode.new(value)]
126
152
  end
127
153
  end
154
+ # Sets the value of an attribute.
128
155
  def set_attr(name, value)
129
156
  full_name = parse_ns(name).join(":")
130
157
  @attributes[name] = value
@@ -171,8 +198,8 @@ module Handsoap
171
198
  if @prefix && (not defines_namespace?(@prefix))
172
199
  set_attr "xmlns:#{@prefix}", get_namespace(@prefix)
173
200
  end
174
- name = XmlMason.html_escape(full_name)
175
- attr = (@attributes.any? ? (" " + @attributes.map { |key, value| XmlMason.html_escape(key) + '="' + XmlMason.html_escape(value) + '"' }.join(" ")) : "")
201
+ name = XmlMason.xml_escape(full_name)
202
+ attr = (@attributes.any? ? (" " + @attributes.map { |key, value| XmlMason.xml_escape(key) + '="' + XmlMason.xml_escape(value) + '"' }.join(" ")) : "")
176
203
  if @children.any?
177
204
  if value_node?
178
205
  children = @children[0].to_s(indentation + " ")
@@ -0,0 +1,249 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Handsoap
3
+ #
4
+ # A simple frontend for parsing XML document with Xpath.
5
+ #
6
+ # This provides a unified interface for multiple xpath-capable dom-parsers,
7
+ # allowing seamless switching between the underlying implementations.
8
+ #
9
+ # A document is loaded using the function Handsoap::XmlQueryFront.parse_string, passing
10
+ # the xml source string and a driver, which can (currently) be one of:
11
+ #
12
+ # :rexml
13
+ # :nokogiri
14
+ # :libxml
15
+ #
16
+ # The resulting object is a wrapper, of the type Handsoap::XmlQueryFront::BaseDriver.
17
+ #
18
+ module XmlQueryFront
19
+
20
+ # This error is raised if the document didn't parse
21
+ class ParseError < RuntimeError; end
22
+
23
+ # Loads requirements for a driver.
24
+ #
25
+ # This function is implicitly called by +parse_string+.
26
+ def self.load_driver!(driver)
27
+ if driver == :rexml
28
+ require 'rexml/document'
29
+ elsif driver == :nokogiri
30
+ require 'nokogiri'
31
+ elsif driver == :libxml
32
+ require 'libxml'
33
+ else
34
+ raise "Unknown driver #{driver}"
35
+ end
36
+ return driver
37
+ end
38
+
39
+ # Returns a wrapped XML parser, using the requested driver.
40
+ #
41
+ # +driver+ can be one of the following:
42
+ # :rexml
43
+ # :nokogiri
44
+ # :libxml
45
+ def self.parse_string(xml_string, driver)
46
+ load_driver!(driver)
47
+ if driver == :rexml
48
+ doc = REXML::Document.new(xml_string)
49
+ raise ParseError.new if doc.root.nil?
50
+ XmlQueryFront::REXMLDriver.new(doc)
51
+ elsif driver == :nokogiri
52
+ doc = Nokogiri::XML(xml_string)
53
+ raise ParseError.new unless (doc && doc.root && doc.errors.empty?)
54
+ XmlQueryFront::NokogiriDriver.new(doc)
55
+ elsif driver == :libxml
56
+ begin
57
+ LibXML::XML::Error.set_handler &LibXML::XML::Error::QUIET_HANDLER
58
+ doc = XmlQueryFront::LibXMLDriver.new(LibXML::XML::Parser.string(xml_string).parse)
59
+ rescue ArgumentError, LibXML::XML::Error => ex
60
+ raise ParseError.new
61
+ end
62
+ end
63
+ end
64
+
65
+ # Wraps the underlying (native) xml driver, and provides a uniform interface.
66
+ module BaseDriver
67
+ def initialize(element, namespaces = {})
68
+ @element = element
69
+ @namespaces = namespaces
70
+ end
71
+ # Registers a prefix to refer to a namespace.
72
+ #
73
+ # You can either register a nemspace with this function or pass it explicitly to the +xpath+ method.
74
+ def add_namespace(prefix, uri)
75
+ @namespaces[prefix] = uri
76
+ end
77
+ # Checks that an xpath-query doesn't refer to any undefined prefixes in +ns+
78
+ def assert_prefixes!(expression, ns)
79
+ expression.scan(/([a-zA-Z_][a-zA-Z0-9_.-]*):[^:]+/).map{|m| m[0] }.each do |prefix|
80
+ raise "Undefined prefix '#{prefix}'" if ns[prefix].nil?
81
+ end
82
+ end
83
+ # Returns the value of the element as an integer.
84
+ #
85
+ # See +to_s+
86
+ def to_i
87
+ t = self.to_s
88
+ return if t.nil?
89
+ t.to_i
90
+ end
91
+ # Returns the value of the element as a float.
92
+ #
93
+ # See +to_s+
94
+ def to_f
95
+ t = self.to_s
96
+ return if t.nil?
97
+ t.to_f
98
+ end
99
+ # Returns the value of the element as an boolean.
100
+ #
101
+ # See +to_s+
102
+ def to_boolean
103
+ t = self.to_s
104
+ return if t.nil?
105
+ t.downcase == 'true'
106
+ end
107
+ # Returns the value of the element as a ruby Time object.
108
+ #
109
+ # See +to_s+
110
+ def to_date
111
+ t = self.to_s
112
+ return if t.nil?
113
+ Time.iso8601(t)
114
+ end
115
+ # Returns the underlying native element.
116
+ #
117
+ # You shouldn't need to use this, since doing so would void portability.
118
+ def native_element
119
+ @element
120
+ end
121
+ # Returns the node name of the current element.
122
+ def node_name
123
+ raise NotImplementedError.new
124
+ end
125
+ # Queries the document with XPath, relative to the current element.
126
+ #
127
+ # +ns+ Should be a Hash of prefix => namespace
128
+ #
129
+ # Returns an Array of wrapped elements.
130
+ #
131
+ # See add_namespace
132
+ def xpath(expression, ns = nil)
133
+ raise NotImplementedError.new
134
+ end
135
+ # Returns the inner text content of this element, or the value (if it's an attr or textnode).
136
+ #
137
+ # The output is a UTF-8 encoded string, without xml-entities.
138
+ def to_s
139
+ raise NotImplementedError.new
140
+ end
141
+ # Returns the outer XML for this element.
142
+ def to_xml
143
+ raise NotImplementedError.new
144
+ end
145
+ # Alias for +xpath+
146
+ def /(expression)
147
+ self.xpath(expression)
148
+ end
149
+ end
150
+
151
+ # Driver for +libxml+.
152
+ #
153
+ # http://libxml.rubyforge.org/
154
+ class LibXMLDriver
155
+ include BaseDriver
156
+ def node_name
157
+ @element.name
158
+ end
159
+ def xpath(expression, ns = nil)
160
+ ns = {} if ns.nil?
161
+ ns = @namespaces.merge(ns)
162
+ assert_prefixes!(expression, ns)
163
+ @element.find(expression, ns.map{|k,v| "#{k}:#{v}" }).to_a.map{|node| LibXMLDriver.new(node, ns) }
164
+ end
165
+ def to_xml
166
+ @element.to_s
167
+ end
168
+ def to_s
169
+ if @element.kind_of? LibXML::XML::Attr
170
+ @element.value
171
+ else
172
+ @element.content
173
+ end
174
+ end
175
+ end
176
+
177
+ # Driver for +REXML+
178
+ #
179
+ # http://www.germane-software.com/software/rexml/
180
+ class REXMLDriver
181
+ include BaseDriver
182
+ def node_name
183
+ @element.name
184
+ end
185
+ def xpath(expression, ns = nil)
186
+ ns = {} if ns.nil?
187
+ ns = @namespaces.merge(ns)
188
+ assert_prefixes!(expression, ns)
189
+ REXML::XPath.match(@element, expression, ns).map{|node| REXMLDriver.new(node, ns) }
190
+ end
191
+ def to_xml
192
+ require 'rexml/formatters/pretty'
193
+ formatter = REXML::Formatters::Pretty.new
194
+ out = String.new
195
+ formatter.write(@element, out)
196
+ out
197
+ end
198
+ def to_s
199
+ if @element.kind_of? REXML::Attribute
200
+ @element.value
201
+ else
202
+ @element.text
203
+ end
204
+ end
205
+ end
206
+
207
+ # Driver for +Nokogiri+
208
+ #
209
+ # http://nokogiri.rubyforge.org/nokogiri/
210
+ class NokogiriDriver
211
+ include BaseDriver
212
+ def node_name
213
+ @element.name
214
+ end
215
+ def self.serialize_args #:nodoc:
216
+ @serialize_args ||= if Gem.loaded_specs['nokogiri'].version >= Gem::Version.new('1.3.0')
217
+ { :encoding => 'UTF-8' }
218
+ else
219
+ 'UTF-8'
220
+ end
221
+ end
222
+ def xpath(expression, ns = nil)
223
+ ns = {} if ns.nil?
224
+ ns = @namespaces.merge(ns)
225
+ assert_prefixes!(expression, ns)
226
+ @element.xpath(expression, ns).map{|node| NokogiriDriver.new(node, ns) }
227
+ end
228
+ def to_xml
229
+ @element.serialize(NokogiriDriver.serialize_args)
230
+ end
231
+ def to_s
232
+ if @element.kind_of?(Nokogiri::XML::Text) || @element.kind_of?(Nokogiri::XML::CDATA)
233
+ element = @element
234
+ elsif @element.kind_of?(Nokogiri::XML::Attr)
235
+ return @element.value
236
+ else
237
+ element = @element.children.first
238
+ end
239
+ return if element.nil?
240
+ # This looks messy because it is .. Nokogiri's interface is in a flux
241
+ if element.kind_of?(Nokogiri::XML::CDATA)
242
+ element.serialize(NokogiriDriver.serialize_args).gsub(/^<!\[CDATA\[/, "").gsub(/\]\]>$/, "")
243
+ else
244
+ element.serialize(NokogiriDriver.serialize_args).gsub('&lt;', '<').gsub('&gt;', '>').gsub('&quot;', '"').gsub('&apos;', "'").gsub('&amp;', '&')
245
+ end
246
+ end
247
+ end
248
+ end
249
+ end
data/lib/handsoap.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  require 'handsoap/xml_mason'
3
+ require 'handsoap/xml_query_front'
3
4
  require 'handsoap/service'
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.2.9
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Troels Knak-Nielsen
@@ -9,19 +9,10 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-17 00:00:00 -07:00
12
+ date: 2009-06-23 00:00:00 -07:00
13
13
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: nokogiri
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 1.2.3
24
- version:
14
+ dependencies: []
15
+
25
16
  description: Handsoap is a library for creating SOAP clients in Ruby
26
17
  email: troelskn@gmail.com
27
18
  executables: []
@@ -41,6 +32,7 @@ files:
41
32
  - lib/handsoap/parser.rb
42
33
  - lib/handsoap/service.rb
43
34
  - lib/handsoap/xml_mason.rb
35
+ - lib/handsoap/xml_query_front.rb
44
36
  has_rdoc: true
45
37
  homepage: http://github.com/troelskn/handsoap
46
38
  post_install_message:
@@ -60,8 +52,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
52
  - !ruby/object:Gem::Version
61
53
  version: "0"
62
54
  version:
63
- requirements: []
64
-
55
+ requirements:
56
+ - |-
57
+ You need to install either "curb" or "httpclient", using one of:
58
+ gem install curb
59
+ gem install httpclient
60
+ - It is recommended that you install either "nokogiri" or "libxml-ruby"
65
61
  rubyforge_project:
66
62
  rubygems_version: 1.2.0
67
63
  signing_key: