lolsoap 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.travis.yml +7 -0
- data/.yardopts +1 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.txt +20 -0
- data/README.md +124 -0
- data/Rakefile +29 -0
- data/VERSION +1 -0
- data/lib/lolsoap.rb +11 -0
- data/lib/lolsoap/builder.rb +93 -0
- data/lib/lolsoap/client.rb +25 -0
- data/lib/lolsoap/envelope.rb +94 -0
- data/lib/lolsoap/errors.rb +15 -0
- data/lib/lolsoap/fault.rb +26 -0
- data/lib/lolsoap/hash_builder.rb +48 -0
- data/lib/lolsoap/request.rb +54 -0
- data/lib/lolsoap/response.rb +50 -0
- data/lib/lolsoap/wsdl.rb +98 -0
- data/lib/lolsoap/wsdl/element.rb +28 -0
- data/lib/lolsoap/wsdl/null_element.rb +15 -0
- data/lib/lolsoap/wsdl/null_type.rb +19 -0
- data/lib/lolsoap/wsdl/operation.rb +18 -0
- data/lib/lolsoap/wsdl/type.rb +38 -0
- data/lib/lolsoap/wsdl_parser.rb +121 -0
- data/lolsoap.gemspec +97 -0
- data/test/fixtures/stock_quote.wsdl +74 -0
- data/test/fixtures/stock_quote_fault.xml +16 -0
- data/test/fixtures/stock_quote_response.xml +8 -0
- data/test/helper.rb +14 -0
- data/test/integration/test_client.rb +20 -0
- data/test/integration/test_envelope.rb +45 -0
- data/test/integration/test_request.rb +19 -0
- data/test/integration/test_response.rb +15 -0
- data/test/integration/test_wsdl.rb +28 -0
- data/test/unit/test_builder.rb +95 -0
- data/test/unit/test_client.rb +12 -0
- data/test/unit/test_envelope.rb +112 -0
- data/test/unit/test_fault.rb +33 -0
- data/test/unit/test_hash_builder.rb +127 -0
- data/test/unit/test_request.rb +48 -0
- data/test/unit/test_response.rb +39 -0
- data/test/unit/test_wsdl.rb +143 -0
- data/test/unit/test_wsdl_parser.rb +105 -0
- data/test/unit/wsdl/test_element.rb +31 -0
- data/test/unit/wsdl/test_type.rb +44 -0
- metadata +152 -0
data/.document
ADDED
data/.travis.yml
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--no-private
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.6.4)
|
6
|
+
bundler (~> 1.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
minitest (2.10.0)
|
10
|
+
nokogiri (1.5.0)
|
11
|
+
rake (0.9.2.2)
|
12
|
+
yard (0.7.2)
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
bundler (~> 1.0.0)
|
19
|
+
jeweler (~> 1.6.4)
|
20
|
+
minitest
|
21
|
+
nokogiri
|
22
|
+
yard
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Loco2 Ltd.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# LolSoap #
|
2
|
+
|
3
|
+
A library for dealing with SOAP requests and responses. We tear our hair
|
4
|
+
out so you don't have to.
|
5
|
+
|
6
|
+
https://github.com/loco2/lolsoap
|
7
|
+
|
8
|
+
[![Build Status](https://secure.travis-ci.org/loco2/lolsoap.png)](http://travis-ci.org/loco2/lolsoap)
|
9
|
+
|
10
|
+
## Aims ##
|
11
|
+
|
12
|
+
* A collection of classes to make dealing with SOAP requests and
|
13
|
+
responses, and WSDL documents, easier.
|
14
|
+
* The classes are intended to be loosely coupled and non-prescriptive
|
15
|
+
about how they are used.
|
16
|
+
* LolSoap does not know anything about what HTTP library you want to
|
17
|
+
use, and does not care whether you're doing the IO in a synchronous or
|
18
|
+
asynchronous fashion. This does mean you have to provide a little bit
|
19
|
+
of glue code, but the benefit is flexibility.
|
20
|
+
* No monkey-patching.
|
21
|
+
* Runs without warnings.
|
22
|
+
|
23
|
+
## Synopsis ##
|
24
|
+
|
25
|
+
``` ruby
|
26
|
+
# You will need your own HTTP client
|
27
|
+
http = MyHttpClient.new
|
28
|
+
|
29
|
+
# LolSoap::Client is just a thin wrapper object that handles creating
|
30
|
+
# other objects for you, with a given WSDL file
|
31
|
+
client = LolSoap::Client.new(File.read('lolapi.wsdl'))
|
32
|
+
|
33
|
+
# Create a request object
|
34
|
+
request = client.request('getLols')
|
35
|
+
|
36
|
+
# Populate the request with some data. Namespacing is taken care of
|
37
|
+
# using the type data from the WSDL.
|
38
|
+
request.body do |b|
|
39
|
+
b.lolFactor '11'
|
40
|
+
b.lolDuration 'lolever'
|
41
|
+
...
|
42
|
+
end
|
43
|
+
|
44
|
+
# See the full request XML
|
45
|
+
puts request.content
|
46
|
+
|
47
|
+
# Send that request!
|
48
|
+
raw_response = http.post(request.url, request.headers, request.content)
|
49
|
+
|
50
|
+
# Create a response object
|
51
|
+
response = client.response(request, raw_response)
|
52
|
+
|
53
|
+
# Get access to the XML structure (a Nokogiri::XML::Document)
|
54
|
+
p response.doc
|
55
|
+
|
56
|
+
# Get access to the first node inside the Body
|
57
|
+
p response.body
|
58
|
+
|
59
|
+
# Turn the body into a hash. The WSDL schema is used to work out which
|
60
|
+
# elements are supposed to be collections and which are just singular.
|
61
|
+
p response.body_hash
|
62
|
+
```
|
63
|
+
|
64
|
+
## Bugs/Features ##
|
65
|
+
|
66
|
+
* SOAP 1.1 is not supported. Patches to add support will be considered
|
67
|
+
if they don't add too much extra complexity.
|
68
|
+
* WSSE is not supported.
|
69
|
+
* Assumes that you are able to supply a WSDL document for the service.
|
70
|
+
|
71
|
+
## Overview ##
|
72
|
+
|
73
|
+
These are some of the key classes. If you want, you can require them
|
74
|
+
directly (e.g. `require 'lolsoap/request'` rather than having to
|
75
|
+
`require 'lolsoap'`).
|
76
|
+
|
77
|
+
The main ones:
|
78
|
+
|
79
|
+
* `LolSoap::Request` - A HTTP request to be sent
|
80
|
+
* `LolSoap::Envelope` - The SOAP envelope in the body of a request
|
81
|
+
* `LolSoap::Response` - The API's response
|
82
|
+
* `LolSoap::WSDL` - A WSDL document
|
83
|
+
|
84
|
+
The others:
|
85
|
+
|
86
|
+
* `LolSoap::WSDLParser` - Lower level representation of the WSDL
|
87
|
+
document
|
88
|
+
* `LolSoap::Builder` - XML builder object that knows about types, and
|
89
|
+
therefore how elements should be namespaced.
|
90
|
+
* `LolSoap::Fault` - A SOAP 'fault' (error)
|
91
|
+
* `LolSoap::HashBuilder` - Builds hashes from the API response, using
|
92
|
+
the WSDL type data to determine which elements are collection
|
93
|
+
elements.
|
94
|
+
|
95
|
+
## Authors ##
|
96
|
+
|
97
|
+
* [Jon Leighton](http://jonathanleighton.com/)
|
98
|
+
|
99
|
+
Development sponsored by [Loco2](http://loco2.com/).
|
100
|
+
|
101
|
+
## License ##
|
102
|
+
|
103
|
+
(The MIT License)
|
104
|
+
|
105
|
+
Copyright (c) 2012 Loco2 Ltd.
|
106
|
+
|
107
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
108
|
+
a copy of this software and associated documentation files (the
|
109
|
+
'Software'), to deal in the Software without restriction, including
|
110
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
111
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
112
|
+
permit persons to whom the Software is furnished to do so, subject to
|
113
|
+
the following conditions:
|
114
|
+
|
115
|
+
The above copyright notice and this permission notice shall be
|
116
|
+
included in all copies or substantial portions of the Software.
|
117
|
+
|
118
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
119
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
120
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
121
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
122
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
123
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
124
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'rake'
|
6
|
+
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |gem|
|
9
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
10
|
+
gem.name = "lolsoap"
|
11
|
+
gem.homepage = "http://github.com/jonleighton/lolsoap"
|
12
|
+
gem.license = "MIT"
|
13
|
+
gem.summary = %Q{A library for dealing with SOAP requests and responses.}
|
14
|
+
gem.description = %Q{A library for dealing with SOAP requests and responses. We tear our hair out so you don't have to.}
|
15
|
+
gem.email = "j@jonathanleighton.com"
|
16
|
+
gem.authors = ["Jon Leighton"]
|
17
|
+
# dependencies defined in Gemfile
|
18
|
+
end
|
19
|
+
Jeweler::RubygemsDotOrgTasks.new
|
20
|
+
|
21
|
+
require 'rake/testtask'
|
22
|
+
|
23
|
+
Rake::TestTask.new do |t|
|
24
|
+
t.libs = ["test"]
|
25
|
+
t.pattern = "test/**/test_*.rb"
|
26
|
+
t.ruby_opts = ['-w']
|
27
|
+
end
|
28
|
+
|
29
|
+
task :default => :test
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/lolsoap.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module LolSoap
|
2
|
+
require 'lolsoap/builder'
|
3
|
+
require 'lolsoap/client'
|
4
|
+
require 'lolsoap/envelope'
|
5
|
+
require 'lolsoap/errors'
|
6
|
+
require 'lolsoap/fault'
|
7
|
+
require 'lolsoap/request'
|
8
|
+
require 'lolsoap/response'
|
9
|
+
require 'lolsoap/wsdl'
|
10
|
+
require 'lolsoap/wsdl_parser'
|
11
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'lolsoap/wsdl'
|
2
|
+
|
3
|
+
module LolSoap
|
4
|
+
# Used to build XML, with namespaces automatically added.
|
5
|
+
#
|
6
|
+
# @example General
|
7
|
+
# builder = Builder.new(node, type)
|
8
|
+
# builder.someTag do |t|
|
9
|
+
# t.foo 'bar'
|
10
|
+
# end
|
11
|
+
# # => <ns1:someTag><ns1:foo>bar</ns1:foo></ns1:someTag>
|
12
|
+
#
|
13
|
+
# @example Explicitly specifying a namespace prefix
|
14
|
+
# builder = Builder.new(node, type)
|
15
|
+
# builder['ns2'].someTag
|
16
|
+
# # => <ns2:someTag/>
|
17
|
+
class Builder
|
18
|
+
RESERVED_METHODS = %w(object_id respond_to_missing? inspect === to_s)
|
19
|
+
|
20
|
+
alias :__class__ :class
|
21
|
+
instance_methods.each do |m|
|
22
|
+
undef_method m unless RESERVED_METHODS.include?(m.to_s) || m =~ /^__/
|
23
|
+
end
|
24
|
+
|
25
|
+
# @private
|
26
|
+
class Prefix
|
27
|
+
instance_methods.each do |m|
|
28
|
+
undef_method m unless RESERVED_METHODS.include?(m.to_s) || m =~ /^__/
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(owner, prefix)
|
32
|
+
@owner = owner
|
33
|
+
@prefix = prefix
|
34
|
+
end
|
35
|
+
|
36
|
+
def respond_to?(name)
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def method_missing(*args, &block)
|
43
|
+
@owner.__prefixed_tag__(@prefix, LolSoap::WSDL::NullType.new, *args, &block)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(node, type = WSDL::NullType.new)
|
48
|
+
@node = node
|
49
|
+
@type = type
|
50
|
+
end
|
51
|
+
|
52
|
+
# Add a tag manually, rather than through method_missing. This is so you can still
|
53
|
+
# add tags for the very small number of tags that are also existing methods.
|
54
|
+
def __tag__(name, *args, &block)
|
55
|
+
__prefixed_tag__(@type.prefix, @type.sub_type(name.to_s), name, *args, &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
# @private
|
59
|
+
def __prefixed_tag__(prefix, sub_type, name, *args)
|
60
|
+
sub_node = @node.document.create_element(name.to_s, *args)
|
61
|
+
sub_node.namespace = @node.namespace_scopes.find { |n| n.prefix == prefix }
|
62
|
+
|
63
|
+
@node << sub_node
|
64
|
+
|
65
|
+
builder = __class__.new(sub_node, sub_type)
|
66
|
+
yield builder if block_given?
|
67
|
+
builder
|
68
|
+
end
|
69
|
+
|
70
|
+
# Node accessor. Named to prevent method_missing conflict.
|
71
|
+
def __node__
|
72
|
+
@node
|
73
|
+
end
|
74
|
+
|
75
|
+
# Type accessor. Named to prevent method_missing conflict.
|
76
|
+
def __type__
|
77
|
+
@type
|
78
|
+
end
|
79
|
+
|
80
|
+
# Specify a namespace prefix explicitly
|
81
|
+
def [](prefix)
|
82
|
+
Prefix.new(self, prefix)
|
83
|
+
end
|
84
|
+
|
85
|
+
def respond_to?(name)
|
86
|
+
true
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
alias method_missing __tag__
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'lolsoap/wsdl'
|
2
|
+
require 'lolsoap/request'
|
3
|
+
require 'lolsoap/envelope'
|
4
|
+
require 'lolsoap/response'
|
5
|
+
|
6
|
+
module LolSoap
|
7
|
+
class Client
|
8
|
+
attr_reader :wsdl
|
9
|
+
|
10
|
+
# @param wsdl a WSDL object, or a string that will be parsed into one
|
11
|
+
def initialize(wsdl)
|
12
|
+
@wsdl = wsdl.respond_to?(:to_str) ? WSDL.parse(wsdl.to_str) : wsdl
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [LolSoap::Request] A request for the API action you want to perform
|
16
|
+
def request(name)
|
17
|
+
Request.new(Envelope.new(wsdl, wsdl.operation(name)))
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [LolSoap::Response] A response object for an API action that has been performed
|
21
|
+
def response(request, raw)
|
22
|
+
Response.parse(request, raw)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'lolsoap/builder'
|
3
|
+
|
4
|
+
module LolSoap
|
5
|
+
class Envelope
|
6
|
+
attr_reader :wsdl, :operation, :doc
|
7
|
+
|
8
|
+
# @private
|
9
|
+
SOAP_PREFIX = 'soap'
|
10
|
+
|
11
|
+
# @private
|
12
|
+
SOAP_NAMESPACE = 'http://www.w3.org/2003/05/soap-envelope'
|
13
|
+
|
14
|
+
def initialize(wsdl, operation, doc = Nokogiri::XML::Document.new)
|
15
|
+
@wsdl = wsdl
|
16
|
+
@operation = operation
|
17
|
+
@doc = doc
|
18
|
+
|
19
|
+
initialize_doc
|
20
|
+
end
|
21
|
+
|
22
|
+
# Build the body of the envelope
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# env.body do |b|
|
26
|
+
# b.some 'data'
|
27
|
+
# end
|
28
|
+
def body(klass = Builder)
|
29
|
+
builder = klass.new(input, operation.input)
|
30
|
+
yield builder if block_given?
|
31
|
+
builder
|
32
|
+
end
|
33
|
+
|
34
|
+
# Build the header of the envelope
|
35
|
+
def header(klass = Builder)
|
36
|
+
builder = klass.new(@header)
|
37
|
+
yield builder if block_given?
|
38
|
+
builder
|
39
|
+
end
|
40
|
+
|
41
|
+
def endpoint
|
42
|
+
wsdl.endpoint
|
43
|
+
end
|
44
|
+
|
45
|
+
def action
|
46
|
+
operation.action
|
47
|
+
end
|
48
|
+
|
49
|
+
def input_type
|
50
|
+
operation.input
|
51
|
+
end
|
52
|
+
|
53
|
+
def output_type
|
54
|
+
operation.output
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_xml
|
58
|
+
doc.to_xml
|
59
|
+
end
|
60
|
+
|
61
|
+
def soap_prefix
|
62
|
+
SOAP_PREFIX
|
63
|
+
end
|
64
|
+
|
65
|
+
def soap_namespace
|
66
|
+
SOAP_NAMESPACE
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# @private
|
72
|
+
def input; @input; end
|
73
|
+
|
74
|
+
# @private
|
75
|
+
def initialize_doc
|
76
|
+
doc.root = root = doc.create_element('Envelope')
|
77
|
+
|
78
|
+
namespaces = Hash[wsdl.type_namespaces.map { |prefix, uri| [prefix, root.add_namespace(prefix, uri)] }]
|
79
|
+
namespaces[soap_prefix] = root.add_namespace(soap_prefix, soap_namespace)
|
80
|
+
|
81
|
+
@header = doc.create_element 'Header'
|
82
|
+
|
83
|
+
@body = doc.create_element 'Body'
|
84
|
+
@input = doc.create_element input_type.name
|
85
|
+
|
86
|
+
[root, @header, @body].each { |el| el.namespace = namespaces[soap_prefix] }
|
87
|
+
@input.namespace = namespaces[input_type.prefix]
|
88
|
+
|
89
|
+
@body << @input
|
90
|
+
root << @header
|
91
|
+
root << @body
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|