savon 0.9.7 → 0.9.8
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/.travis.yml +2 -1
- data/.yardopts +4 -1
- data/CHANGELOG.md +34 -0
- data/Gemfile +0 -5
- data/README.md +14 -12
- data/Rakefile +2 -6
- data/lib/savon.rb +4 -3
- data/lib/savon/config.rb +103 -0
- data/lib/savon/hooks/group.rb +46 -0
- data/lib/savon/hooks/hook.rb +36 -0
- data/lib/savon/model.rb +103 -0
- data/lib/savon/soap/invalid_response_error.rb +11 -0
- data/lib/savon/soap/request.rb +19 -20
- data/lib/savon/soap/response.rb +7 -0
- data/lib/savon/soap/xml.rb +9 -1
- data/lib/savon/version.rb +1 -1
- data/savon.gemspec +3 -0
- data/spec/savon/model_spec.rb +194 -0
- data/spec/savon/savon_spec.rb +33 -11
- data/spec/savon/soap/request_spec.rb +24 -10
- data/spec/savon/soap/response_spec.rb +15 -0
- data/spec/savon/soap/xml_spec.rb +20 -3
- data/spec/spec_helper.rb +2 -5
- metadata +124 -161
- data/lib/savon/global.rb +0 -109
data/.travis.yml
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# https://github.com/travis-ci/travis-ci/wiki/.travis.yml-options
|
2
|
-
bundler_args: --without developer_happiness
|
3
2
|
script: "bundle exec rake"
|
4
3
|
rvm:
|
5
4
|
- 1.8.7
|
@@ -9,3 +8,5 @@ rvm:
|
|
9
8
|
- rbx
|
10
9
|
- rbx-2.0
|
11
10
|
- jruby
|
11
|
+
notifications:
|
12
|
+
irc: "irc.freenode.org#savon"
|
data/.yardopts
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
## 0.9.8 (2012-02-15)
|
2
|
+
|
3
|
+
* Feature: Savon now ships with [Savon::Model](http://rubygems.org/gems/savon_model).
|
4
|
+
Savon::Model is a lightweight DSL to be used inside your domain models. It's been refactored
|
5
|
+
and is now [even more useful](http://savonrb.com/#how_to_date_a_model) than before.
|
6
|
+
|
7
|
+
* Feature: Merged [pull request 230](https://github.com/rubiii/savon/pull/230) to allow filtering values
|
8
|
+
in logged SOAP request XML messages.
|
9
|
+
|
10
|
+
``` ruby
|
11
|
+
Savon.configure do |config|
|
12
|
+
config.log_filter = ["password"]
|
13
|
+
end
|
14
|
+
```
|
15
|
+
|
16
|
+
* Feature: Added an option to change the default encoding of the XML directive tag (defaults to UTF-8)
|
17
|
+
to fix [issue 234](https://github.com/rubiii/savon/issues/234).
|
18
|
+
|
19
|
+
``` ruby
|
20
|
+
client.request(:find_user) do
|
21
|
+
soap.encoding = "UTF-16"
|
22
|
+
soap.body = { :id => 1 }
|
23
|
+
end
|
24
|
+
```
|
25
|
+
|
26
|
+
* Improvement: Merged [pull request 231](https://github.com/rubiii/savon/pull/231) to gracefully handle
|
27
|
+
invalid response bodies by throwing a `Savon::SOAP::InvalidResponseError`.
|
28
|
+
|
29
|
+
* Fix: [issue 237](https://github.com/rubiii/savon/issues/237) - Set the Content-Type and Content-Length
|
30
|
+
headers for every request.
|
31
|
+
|
32
|
+
* Fix: [pull request 250](https://github.com/rubiii/savon/pull/250) - The Content-Length header should
|
33
|
+
be the size in bytes.
|
34
|
+
|
1
35
|
## 0.9.7 (2011-08-25)
|
2
36
|
|
3
37
|
* Feature: Merged [pull request 210](https://github.com/rubiii/savon/pull/210) by
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
Savon [](http://travis-ci.org/rubiii/savon)
|
2
2
|
=====
|
3
3
|
|
4
4
|
Heavy metal Ruby SOAP client
|
5
5
|
|
6
6
|
[Documentation](http://savonrb.com) | [RDoc](http://rubydoc.info/gems/savon) |
|
7
|
-
[Mailing list](
|
7
|
+
[Mailing list](https://groups.google.com/forum/#!forum/savonrb) | [Twitter](http://twitter.com/savonrb)
|
8
8
|
|
9
9
|
Installation
|
10
10
|
------------
|
@@ -15,26 +15,28 @@ Savon is available through [Rubygems](http://rubygems.org/gems/savon) and can be
|
|
15
15
|
$ gem install savon
|
16
16
|
```
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
Introduction
|
19
|
+
------------
|
20
20
|
|
21
21
|
``` ruby
|
22
|
-
|
23
|
-
|
22
|
+
require "savon"
|
23
|
+
|
24
|
+
# create a client for your SOAP service
|
25
|
+
client = Savon::Client.new("http://service.example.com?wsdl")
|
24
26
|
|
25
27
|
client.wsdl.soap_actions
|
26
28
|
# => [:create_user, :get_user, :get_all_users]
|
27
29
|
|
28
|
-
#
|
29
|
-
response = client.request
|
30
|
+
# execute a SOAP request to call the "getUser" action
|
31
|
+
response = client.request(:get_user) do
|
30
32
|
soap.body = { :id => 1 }
|
31
33
|
end
|
32
34
|
|
33
|
-
response.
|
35
|
+
response.body
|
34
36
|
# => { :get_user_response => { :first_name => "The", :last_name => "Hoff" } }
|
35
37
|
```
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
Documentation
|
40
|
+
-------------
|
39
41
|
|
40
|
-
|
42
|
+
Continue reading at [savonrb.com](http://savonrb.com)
|
data/Rakefile
CHANGED
@@ -1,11 +1,7 @@
|
|
1
|
-
require "bundler"
|
2
|
-
Bundler::GemHelper.install_tasks
|
3
|
-
|
1
|
+
require "bundler/gem_tasks"
|
4
2
|
require "rspec/core/rake_task"
|
5
3
|
|
6
|
-
RSpec::Core::RakeTask.new
|
7
|
-
t.rspec_opts = %w(-c)
|
8
|
-
end
|
4
|
+
RSpec::Core::RakeTask.new
|
9
5
|
|
10
6
|
task :default => :spec
|
11
7
|
task :test => :spec
|
data/lib/savon.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require "savon/version"
|
2
|
-
require "savon/
|
2
|
+
require "savon/config"
|
3
3
|
require "savon/client"
|
4
|
+
require "savon/model"
|
4
5
|
|
5
6
|
module Savon
|
6
|
-
extend
|
7
|
+
extend Config
|
7
8
|
|
8
9
|
# Yields this module to a given +block+. Please refer to the
|
9
|
-
# <tt>Savon::
|
10
|
+
# <tt>Savon::Config</tt> module for configuration options.
|
10
11
|
def self.configure
|
11
12
|
yield self if block_given?
|
12
13
|
end
|
data/lib/savon/config.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
require "logger"
|
2
|
+
require "savon/soap"
|
3
|
+
require "savon/hooks/group"
|
4
|
+
|
5
|
+
module Savon
|
6
|
+
module Config
|
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+. Optionally filtered if +xml+ is truthy.
|
33
|
+
def log(message, xml = false)
|
34
|
+
return unless log?
|
35
|
+
message = filter_xml(message) if xml && !log_filter.empty?
|
36
|
+
logger.send log_level, message
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the log filter. Defaults to an empty Array.
|
40
|
+
def log_filter
|
41
|
+
@log_filter ||= []
|
42
|
+
end
|
43
|
+
|
44
|
+
# Sets the log filter. Expects an Array.
|
45
|
+
attr_writer :log_filter
|
46
|
+
|
47
|
+
# Filters the given +xml+ based on log filter.
|
48
|
+
def filter_xml(xml)
|
49
|
+
doc = Nokogiri::XML(xml)
|
50
|
+
return xml unless doc.errors.empty?
|
51
|
+
|
52
|
+
log_filter.each do |filter|
|
53
|
+
doc.xpath("//*[local-name()='#{filter}']").map { |node| node.content = "***FILTERED***" }
|
54
|
+
end
|
55
|
+
|
56
|
+
doc.root.to_s
|
57
|
+
end
|
58
|
+
|
59
|
+
# Sets whether to raise HTTP errors and SOAP faults.
|
60
|
+
attr_writer :raise_errors
|
61
|
+
|
62
|
+
# Returns whether to raise errors. Defaults to +true+.
|
63
|
+
def raise_errors?
|
64
|
+
@raise_errors != false
|
65
|
+
end
|
66
|
+
|
67
|
+
# Sets the global SOAP version.
|
68
|
+
def soap_version=(version)
|
69
|
+
raise ArgumentError, "Invalid SOAP version: #{version}" if version && !SOAP::Versions.include?(version)
|
70
|
+
@version = version
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns SOAP version. Defaults to +DefaultVersion+.
|
74
|
+
def soap_version
|
75
|
+
@version ||= SOAP::DefaultVersion
|
76
|
+
end
|
77
|
+
|
78
|
+
# Accessor for the global env_namespace.
|
79
|
+
attr_accessor :env_namespace
|
80
|
+
|
81
|
+
# Accessor for the global soap_header.
|
82
|
+
attr_accessor :soap_header
|
83
|
+
|
84
|
+
# Returns the hooks.
|
85
|
+
def hooks
|
86
|
+
@hooks ||= Hooks::Group.new
|
87
|
+
end
|
88
|
+
|
89
|
+
# Reset to default configuration.
|
90
|
+
def reset_config!
|
91
|
+
self.log = nil
|
92
|
+
self.logger = nil
|
93
|
+
self.log_level = nil
|
94
|
+
self.log_filter = nil
|
95
|
+
self.raise_errors = nil
|
96
|
+
self.soap_version = nil
|
97
|
+
self.env_namespace = nil
|
98
|
+
self.soap_header = nil
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
@@ -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
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Savon
|
2
|
+
module Hooks
|
3
|
+
|
4
|
+
# = Savon::Hooks::Hook
|
5
|
+
#
|
6
|
+
# A hook used somewhere in the system.
|
7
|
+
class Hook
|
8
|
+
|
9
|
+
HOOKS = [
|
10
|
+
|
11
|
+
# Replaces the POST request executed to call a service.
|
12
|
+
# See: Savon::SOAP::Request#response
|
13
|
+
#
|
14
|
+
# Receives the <tt>Savon::SOAP::Request</tt> and is expected to return an <tt>HTTPI::Response</tt>.
|
15
|
+
# It can change the request and return something falsy to still execute the POST request.
|
16
|
+
:soap_request
|
17
|
+
|
18
|
+
]
|
19
|
+
|
20
|
+
# Expects an +id+, the name of the +hook+ to use and a +block+ to be called.
|
21
|
+
def initialize(id, hook, &block)
|
22
|
+
self.id = id
|
23
|
+
self.hook = hook
|
24
|
+
self.block = block
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_accessor :id, :hook, :block
|
28
|
+
|
29
|
+
# Calls the +block+ with the given +args+.
|
30
|
+
def call(*args)
|
31
|
+
block.call(*args)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/savon/model.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
module Savon
|
2
|
+
|
3
|
+
# = Savon::Model
|
4
|
+
#
|
5
|
+
# Model for SOAP service oriented applications.
|
6
|
+
module Model
|
7
|
+
|
8
|
+
def self.extended(base)
|
9
|
+
base.setup
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup
|
13
|
+
class_action_module
|
14
|
+
instance_action_module
|
15
|
+
end
|
16
|
+
|
17
|
+
# Accepts one or more SOAP actions and generates both class and instance methods named
|
18
|
+
# after the given actions. Each generated method accepts an optional SOAP body Hash and
|
19
|
+
# a block to be passed to <tt>Savon::Client#request</tt> and executes a SOAP request.
|
20
|
+
def actions(*actions)
|
21
|
+
actions.each do |action|
|
22
|
+
define_class_action(action)
|
23
|
+
define_instance_action(action)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Defines a class-level SOAP action method.
|
30
|
+
def define_class_action(action)
|
31
|
+
class_action_module.module_eval %{
|
32
|
+
def #{action.to_s.snakecase}(body = nil, &block)
|
33
|
+
response = client.request :wsdl, #{action.inspect}, :body => body, &block
|
34
|
+
Savon.hooks.select(:model_soap_response).call(response) || response
|
35
|
+
end
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
# Defines an instance-level SOAP action method.
|
40
|
+
def define_instance_action(action)
|
41
|
+
instance_action_module.module_eval %{
|
42
|
+
def #{action.to_s.snakecase}(body = nil, &block)
|
43
|
+
self.class.#{action.to_s.snakecase} body, &block
|
44
|
+
end
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
# Class methods.
|
49
|
+
def class_action_module
|
50
|
+
@class_action_module ||= Module.new do
|
51
|
+
|
52
|
+
# Returns the memoized <tt>Savon::Client</tt>.
|
53
|
+
def client(&block)
|
54
|
+
@client ||= Savon::Client.new(&block)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Sets the SOAP endpoint to the given +uri+.
|
58
|
+
def endpoint(uri)
|
59
|
+
client.wsdl.endpoint = uri
|
60
|
+
end
|
61
|
+
|
62
|
+
# Sets the target namespace.
|
63
|
+
def namespace(uri)
|
64
|
+
client.wsdl.namespace = uri
|
65
|
+
end
|
66
|
+
|
67
|
+
# Sets the WSDL document to the given +uri+.
|
68
|
+
def document(uri)
|
69
|
+
client.wsdl.document = uri
|
70
|
+
end
|
71
|
+
|
72
|
+
# Sets the HTTP headers.
|
73
|
+
def headers(headers)
|
74
|
+
client.http.headers = headers
|
75
|
+
end
|
76
|
+
|
77
|
+
# Sets basic auth +login+ and +password+.
|
78
|
+
def basic_auth(login, password)
|
79
|
+
client.http.auth.basic(login, password)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Sets WSSE auth credentials.
|
83
|
+
def wsse_auth(*args)
|
84
|
+
client.wsse.credentials(*args)
|
85
|
+
end
|
86
|
+
|
87
|
+
end.tap { |mod| extend(mod) }
|
88
|
+
end
|
89
|
+
|
90
|
+
# Instance methods.
|
91
|
+
def instance_action_module
|
92
|
+
@instance_action_module ||= Module.new do
|
93
|
+
|
94
|
+
# Returns the <tt>Savon::Client</tt> from the class instance.
|
95
|
+
def client(&block)
|
96
|
+
self.class.client(&block)
|
97
|
+
end
|
98
|
+
|
99
|
+
end.tap { |mod| include(mod) }
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|