regenersis-savon 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/.rspec +1 -0
- data/.travis.yml +12 -0
- data/CHANGELOG.md +639 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +42 -0
- data/Rakefile +7 -0
- data/lib/regenersis-savon.rb +1 -0
- data/lib/savon.rb +15 -0
- data/lib/savon/client.rb +168 -0
- data/lib/savon/core_ext/object.rb +14 -0
- data/lib/savon/core_ext/string.rb +23 -0
- data/lib/savon/error.rb +6 -0
- data/lib/savon/global.rb +115 -0
- data/lib/savon/hooks/group.rb +46 -0
- data/lib/savon/hooks/hook.rb +36 -0
- data/lib/savon/http/error.rb +42 -0
- data/lib/savon/model.rb +103 -0
- data/lib/savon/soap.rb +21 -0
- data/lib/savon/soap/fault.rb +59 -0
- data/lib/savon/soap/request.rb +71 -0
- data/lib/savon/soap/response.rb +109 -0
- data/lib/savon/soap/xml.rb +227 -0
- data/lib/savon/version.rb +5 -0
- data/lib/savon/wasabi/document.rb +41 -0
- data/regenersis-savon.gemspec +35 -0
- data/spec/fixtures/gzip/message.gz +0 -0
- data/spec/fixtures/response/another_soap_fault.xml +14 -0
- data/spec/fixtures/response/authentication.xml +14 -0
- data/spec/fixtures/response/header.xml +13 -0
- data/spec/fixtures/response/list.xml +18 -0
- data/spec/fixtures/response/multi_ref.xml +39 -0
- data/spec/fixtures/response/soap_fault.xml +8 -0
- data/spec/fixtures/response/soap_fault12.xml +18 -0
- data/spec/fixtures/response/taxcloud.xml +1 -0
- data/spec/fixtures/wsdl/authentication.xml +63 -0
- data/spec/fixtures/wsdl/lower_camel.xml +52 -0
- data/spec/fixtures/wsdl/multiple_namespaces.xml +61 -0
- data/spec/fixtures/wsdl/multiple_types.xml +60 -0
- data/spec/fixtures/wsdl/taxcloud.xml +934 -0
- data/spec/savon/client_spec.rb +461 -0
- data/spec/savon/core_ext/object_spec.rb +19 -0
- data/spec/savon/core_ext/string_spec.rb +37 -0
- data/spec/savon/http/error_spec.rb +52 -0
- data/spec/savon/model_spec.rb +194 -0
- data/spec/savon/savon_spec.rb +85 -0
- data/spec/savon/soap/fault_spec.rb +89 -0
- data/spec/savon/soap/request_spec.rb +57 -0
- data/spec/savon/soap/response_spec.rb +224 -0
- data/spec/savon/soap/xml_spec.rb +309 -0
- data/spec/savon/soap_spec.rb +16 -0
- data/spec/savon/wasabi/document_spec.rb +45 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/endpoint.rb +25 -0
- data/spec/support/fixture.rb +35 -0
- metadata +323 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Daniel Harrington
|
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,42 @@
|
|
1
|
+
Savon [![Build Status](https://secure.travis-ci.org/rubiii/savon.png)](http://travis-ci.org/rubiii/savon)
|
2
|
+
=====
|
3
|
+
|
4
|
+
Heavy metal Ruby SOAP client
|
5
|
+
|
6
|
+
[Documentation](http://savonrb.com) | [RDoc](http://rubydoc.info/gems/savon) |
|
7
|
+
[Mailing list](https://groups.google.com/forum/#!forum/savonrb) | [Twitter](http://twitter.com/savonrb)
|
8
|
+
|
9
|
+
Installation
|
10
|
+
------------
|
11
|
+
|
12
|
+
Savon is available through [Rubygems](http://rubygems.org/gems/savon) and can be installed via:
|
13
|
+
|
14
|
+
```
|
15
|
+
$ gem install savon
|
16
|
+
```
|
17
|
+
|
18
|
+
Introduction
|
19
|
+
------------
|
20
|
+
|
21
|
+
``` ruby
|
22
|
+
require "savon"
|
23
|
+
|
24
|
+
# create a client for your SOAP service
|
25
|
+
client = Savon::Client.new("http://service.example.com?wsdl")
|
26
|
+
|
27
|
+
client.wsdl.soap_actions
|
28
|
+
# => [:create_user, :get_user, :get_all_users]
|
29
|
+
|
30
|
+
# execute a SOAP request to call the "getUser" action
|
31
|
+
response = client.request(:get_user) do
|
32
|
+
soap.body = { :id => 1 }
|
33
|
+
end
|
34
|
+
|
35
|
+
response.body
|
36
|
+
# => { :get_user_response => { :first_name => "The", :last_name => "Hoff" } }
|
37
|
+
```
|
38
|
+
|
39
|
+
Documentation
|
40
|
+
-------------
|
41
|
+
|
42
|
+
Continue reading at [savonrb.com](http://savonrb.com)
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "savon"
|
data/lib/savon.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "savon/version"
|
2
|
+
require "savon/global"
|
3
|
+
require "savon/client"
|
4
|
+
require "savon/model"
|
5
|
+
|
6
|
+
module Savon
|
7
|
+
extend Global
|
8
|
+
|
9
|
+
# Yields this module to a given +block+. Please refer to the
|
10
|
+
# <tt>Savon::Global</tt> module for configuration options.
|
11
|
+
def self.configure
|
12
|
+
yield self if block_given?
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/lib/savon/client.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
require "httpi/request"
|
2
|
+
require "akami"
|
3
|
+
|
4
|
+
require "savon/wasabi/document"
|
5
|
+
require "savon/soap/xml"
|
6
|
+
require "savon/soap/request"
|
7
|
+
require "savon/soap/response"
|
8
|
+
|
9
|
+
module Savon
|
10
|
+
|
11
|
+
# = Savon::Client
|
12
|
+
#
|
13
|
+
# Savon::Client is the main object for connecting to a SOAP service.
|
14
|
+
class Client
|
15
|
+
|
16
|
+
# Initializes the Savon::Client for a SOAP service. Accepts a +block+ which is evaluated in the
|
17
|
+
# context of this object to let you access the +wsdl+, +http+, and +wsse+ methods.
|
18
|
+
#
|
19
|
+
# == Examples
|
20
|
+
#
|
21
|
+
# # Using a remote WSDL
|
22
|
+
# client = Savon::Client.new("http://example.com/UserService?wsdl")
|
23
|
+
#
|
24
|
+
# # Using a local WSDL
|
25
|
+
# client = Savon::Client.new File.expand_path("../wsdl/service.xml", __FILE__)
|
26
|
+
#
|
27
|
+
# # Directly accessing a SOAP endpoint
|
28
|
+
# client = Savon::Client.new do
|
29
|
+
# wsdl.endpoint = "http://example.com/UserService"
|
30
|
+
# wsdl.namespace = "http://users.example.com"
|
31
|
+
# end
|
32
|
+
def initialize(wsdl_document = nil, &block)
|
33
|
+
wsdl.document = wsdl_document if wsdl_document
|
34
|
+
process 1, &block if block
|
35
|
+
wsdl.request = http
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the <tt>Savon::Wasabi::Document</tt>.
|
39
|
+
def wsdl
|
40
|
+
@wsdl ||= Wasabi::Document.new
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the <tt>HTTPI::Request</tt>.
|
44
|
+
def http
|
45
|
+
@http ||= HTTPI::Request.new
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the <tt>Akami::WSSE</tt> object.
|
49
|
+
def wsse
|
50
|
+
@wsse ||= Akami.wsse
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the <tt>Savon::SOAP::XML</tt> object. Please notice, that this object is only available
|
54
|
+
# in a block given to <tt>Savon::Client#request</tt>. A new instance of this object is created
|
55
|
+
# per SOAP request.
|
56
|
+
attr_reader :soap
|
57
|
+
|
58
|
+
# Executes a SOAP request for a given SOAP action. Accepts a +block+ which is evaluated in the
|
59
|
+
# context of this object to let you access the +soap+, +wsdl+, +http+ and +wsse+ methods.
|
60
|
+
#
|
61
|
+
# == Examples
|
62
|
+
#
|
63
|
+
# # Calls a "getUser" SOAP action with the payload of "<userId>123</userId>"
|
64
|
+
# client.request(:get_user) { soap.body = { :user_id => 123 } }
|
65
|
+
#
|
66
|
+
# # Prefixes the SOAP input tag with a given namespace: "<wsdl:GetUser>...</wsdl:GetUser>"
|
67
|
+
# client.request(:wsdl, "GetUser") { soap.body = { :user_id => 123 } }
|
68
|
+
#
|
69
|
+
# # SOAP input tag with attributes: <getUser xmlns:wsdl="http://example.com">...</getUser>"
|
70
|
+
# client.request(:get_user, "xmlns:wsdl" => "http://example.com")
|
71
|
+
def request(*args, &block)
|
72
|
+
raise ArgumentError, "Savon::Client#request requires at least one argument" if args.empty?
|
73
|
+
|
74
|
+
self.soap = SOAP::XML.new
|
75
|
+
preconfigure extract_options(args)
|
76
|
+
process &block if block
|
77
|
+
soap.wsse = wsse
|
78
|
+
|
79
|
+
response = SOAP::Request.new(http, soap).response
|
80
|
+
set_cookie response.http.headers
|
81
|
+
response
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Writer for the <tt>Savon::SOAP::XML</tt> object.
|
87
|
+
attr_writer :soap
|
88
|
+
|
89
|
+
# Accessor for the original self of a given block.
|
90
|
+
attr_accessor :original_self
|
91
|
+
|
92
|
+
# Passes a cookie from the last request +headers+ to the next one.
|
93
|
+
def set_cookie(headers)
|
94
|
+
http.headers["Cookie"] = headers["Set-Cookie"] if headers["Set-Cookie"]
|
95
|
+
end
|
96
|
+
|
97
|
+
# Expects an Array of +args+ and returns an Array containing the namespace (might be +nil+),
|
98
|
+
# the SOAP input and a Hash of attributes for the input tag (which might be empty).
|
99
|
+
def extract_options(args)
|
100
|
+
attributes = Hash === args.last ? args.pop : {}
|
101
|
+
namespace = args.size > 1 ? args.shift.to_sym : nil
|
102
|
+
input = args.first
|
103
|
+
|
104
|
+
[namespace, input, attributes]
|
105
|
+
end
|
106
|
+
|
107
|
+
# Expects an Array of +args+ to preconfigure the system.
|
108
|
+
def preconfigure(args)
|
109
|
+
soap.endpoint = wsdl.endpoint
|
110
|
+
soap.namespace_identifier = args[0]
|
111
|
+
soap.namespace = wsdl.namespace
|
112
|
+
soap.element_form_default = wsdl.element_form_default if wsdl.document?
|
113
|
+
|
114
|
+
body = args[2].delete(:body)
|
115
|
+
soap.body = body if body
|
116
|
+
|
117
|
+
wsdl.type_namespaces.each do |path, uri|
|
118
|
+
soap.use_namespace(path, uri)
|
119
|
+
end
|
120
|
+
|
121
|
+
wsdl.type_definitions.each do |path, type|
|
122
|
+
soap.types[path] = type
|
123
|
+
end
|
124
|
+
|
125
|
+
set_soap_action args[1]
|
126
|
+
set_soap_input *args
|
127
|
+
end
|
128
|
+
|
129
|
+
# Expects an +input+ and sets the +SOAPAction+ HTTP headers.
|
130
|
+
def set_soap_action(input_tag)
|
131
|
+
soap_action = wsdl.soap_action(input_tag.to_sym) if wsdl.document?
|
132
|
+
soap_action ||= Gyoku::XMLKey.create(input_tag).to_sym
|
133
|
+
http.headers["SOAPAction"] = %{"#{soap_action}"}
|
134
|
+
end
|
135
|
+
|
136
|
+
# Expects a +namespace+, +input+ and +attributes+ and sets the SOAP input.
|
137
|
+
def set_soap_input(namespace, input, attributes)
|
138
|
+
new_input_tag = wsdl.soap_input(input.to_sym) if wsdl.document?
|
139
|
+
new_input_tag ||= Gyoku::XMLKey.create(input)
|
140
|
+
soap.input = [namespace, new_input_tag.to_sym, attributes]
|
141
|
+
end
|
142
|
+
|
143
|
+
# Processes a given +block+. Yields objects if the block expects any arguments.
|
144
|
+
# Otherwise evaluates the block in the context of this object.
|
145
|
+
def process(offset = 0, &block)
|
146
|
+
block.arity > 0 ? yield_objects(offset, &block) : evaluate(&block)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Yields a number of objects to a given +block+ depending on how many arguments
|
150
|
+
# the block is expecting.
|
151
|
+
def yield_objects(offset, &block)
|
152
|
+
yield *[soap, wsdl, http, wsse][offset, block.arity]
|
153
|
+
end
|
154
|
+
|
155
|
+
# Evaluates a given +block+ inside this object. Stores the original block binding.
|
156
|
+
def evaluate(&block)
|
157
|
+
self.original_self = eval "self", block.binding
|
158
|
+
instance_eval &block
|
159
|
+
end
|
160
|
+
|
161
|
+
# Handles calls to undefined methods by delegating to the original block binding.
|
162
|
+
def method_missing(method, *args, &block)
|
163
|
+
super unless original_self
|
164
|
+
original_self.send method, *args, &block
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Savon
|
2
|
+
module CoreExt
|
3
|
+
module Object
|
4
|
+
|
5
|
+
# Returns +true+ if the Object is nil, false or empty. Implementation from ActiveSupport.
|
6
|
+
def blank?
|
7
|
+
respond_to?(:empty?) ? empty? : !self
|
8
|
+
end unless method_defined?(:blank?)
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
Object.send :include, Savon::CoreExt::Object
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "savon/soap"
|
2
|
+
|
3
|
+
module Savon
|
4
|
+
module CoreExt
|
5
|
+
module String
|
6
|
+
|
7
|
+
# Returns the String in snake_case.
|
8
|
+
def snakecase
|
9
|
+
str = dup
|
10
|
+
str.gsub! /::/, '/'
|
11
|
+
str.gsub! /([A-Z]+)([A-Z][a-z])/, '\1_\2'
|
12
|
+
str.gsub! /([a-z\d])([A-Z])/, '\1_\2'
|
13
|
+
str.tr! ".", "_"
|
14
|
+
str.tr! "-", "_"
|
15
|
+
str.downcase!
|
16
|
+
str
|
17
|
+
end unless method_defined?(:snakecase)
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
String.send :include, Savon::CoreExt::String
|
data/lib/savon/error.rb
ADDED
data/lib/savon/global.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require "logger"
|
2
|
+
require "savon/soap"
|
3
|
+
require "savon/hooks/group"
|
4
|
+
|
5
|
+
module Savon
|
6
|
+
module Global
|
7
|
+
|
8
|
+
# Sets whether to log HTTP requests.
|
9
|
+
attr_writer :log
|
10
|
+
|
11
|
+
# Returns whether to log HTTP requests. Defaults to +true+.
|
12
|
+
def log?
|
13
|
+
@log != false
|
14
|
+
end
|
15
|
+
|
16
|
+
# Sets the logger to use.
|
17
|
+
attr_writer :logger
|
18
|
+
|
19
|
+
# Returns the logger. Defaults to an instance of +Logger+ writing to STDOUT.
|
20
|
+
def logger
|
21
|
+
@logger ||= ::Logger.new STDOUT
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sets the log level.
|
25
|
+
attr_writer :log_level
|
26
|
+
|
27
|
+
# Returns the log level. Defaults to :debug.
|
28
|
+
def log_level
|
29
|
+
@log_level ||= :debug
|
30
|
+
end
|
31
|
+
|
32
|
+
# Logs a given +message+.
|
33
|
+
def log(message)
|
34
|
+
logger.send log_level, message if log?
|
35
|
+
end
|
36
|
+
|
37
|
+
# Sets whether to raise HTTP errors and SOAP faults.
|
38
|
+
attr_writer :raise_errors
|
39
|
+
|
40
|
+
# Returns whether to raise errors. Defaults to +true+.
|
41
|
+
def raise_errors?
|
42
|
+
@raise_errors != false
|
43
|
+
end
|
44
|
+
|
45
|
+
# Sets the global SOAP version.
|
46
|
+
def soap_version=(version)
|
47
|
+
raise ArgumentError, "Invalid SOAP version: #{version}" unless SOAP::Versions.include? version
|
48
|
+
@version = version
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns SOAP version. Defaults to +DefaultVersion+.
|
52
|
+
def soap_version
|
53
|
+
@version ||= SOAP::DefaultVersion
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns whether to strip namespaces in a SOAP response Hash.
|
57
|
+
# Defaults to +true+.
|
58
|
+
def strip_namespaces?
|
59
|
+
Savon.deprecate("use Nori.strip_namespaces? instead of Savon.strip_namespaces?")
|
60
|
+
Nori.strip_namespaces?
|
61
|
+
end
|
62
|
+
|
63
|
+
# Sets whether to strip namespaces in a SOAP response Hash.
|
64
|
+
def strip_namespaces=(strip)
|
65
|
+
Savon.deprecate("use Nori.strip_namespaces= instead of Savon.strip_namespaces=")
|
66
|
+
Nori.strip_namespaces = strip
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the global env_namespace.
|
70
|
+
attr_reader :env_namespace
|
71
|
+
|
72
|
+
# Sets the global env_namespace.
|
73
|
+
attr_writer :env_namespace
|
74
|
+
|
75
|
+
# Returns the global soap_header.
|
76
|
+
attr_reader :soap_header
|
77
|
+
|
78
|
+
# Sets the global soap_header.
|
79
|
+
attr_writer :soap_header
|
80
|
+
|
81
|
+
# Expects a +message+ and raises a warning if configured.
|
82
|
+
def deprecate(message)
|
83
|
+
warn("Deprecation: #{message}") if deprecate?
|
84
|
+
end
|
85
|
+
|
86
|
+
# Sets whether to warn about deprecations.
|
87
|
+
def deprecate=(deprecate)
|
88
|
+
@deprecate = deprecate
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns whether to warn about deprecation.
|
92
|
+
def deprecate?
|
93
|
+
@deprecate != false
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns the hooks.
|
97
|
+
def hooks
|
98
|
+
@hooks ||= Hooks::Group.new
|
99
|
+
end
|
100
|
+
|
101
|
+
# Reset to default configuration.
|
102
|
+
def reset_config!
|
103
|
+
self.log = true
|
104
|
+
self.logger = ::Logger.new STDOUT
|
105
|
+
self.log_level = :debug
|
106
|
+
self.raise_errors = true
|
107
|
+
self.soap_version = SOAP::DefaultVersion
|
108
|
+
self.strip_namespaces = true
|
109
|
+
self.env_namespace = nil
|
110
|
+
self.soap_header = {}
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "savon/hooks/hook"
|
2
|
+
|
3
|
+
module Savon
|
4
|
+
module Hooks
|
5
|
+
|
6
|
+
# = Savon::Hooks::Group
|
7
|
+
#
|
8
|
+
# Manages a list of hooks.
|
9
|
+
class Group
|
10
|
+
|
11
|
+
# Accepts an Array of +hooks+ to start with.
|
12
|
+
def initialize(hooks = nil)
|
13
|
+
self.hooks = hooks
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_writer :hooks
|
17
|
+
|
18
|
+
def hooks
|
19
|
+
@hooks ||= []
|
20
|
+
end
|
21
|
+
|
22
|
+
# Adds a new hook.
|
23
|
+
def define(id, hook, &block)
|
24
|
+
hooks << Hook.new(id, hook, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Removes hooks matching the given +ids+.
|
28
|
+
def reject!(*ids)
|
29
|
+
ids = ids.flatten
|
30
|
+
hooks.reject! { |hook| ids.include? hook.id }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns a new group for a given +hook+.
|
34
|
+
def select(hook)
|
35
|
+
Group.new hooks.select { |h| h.hook == hook }
|
36
|
+
end
|
37
|
+
|
38
|
+
# Calls the hooks with the given +args+ and returns the
|
39
|
+
# value of the last hooks.
|
40
|
+
def call(*args)
|
41
|
+
hooks.inject(nil) { |memo, hook| hook.call(*args) }
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|