savon 0.9.7 → 0.9.8
Sign up to get free protection for your applications and to get access to all the features.
- 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 [![Build Status](
|
1
|
+
Savon [![Build Status](https://secure.travis-ci.org/rubiii/savon.png)](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
|