Skip to content

Commit

Permalink
added hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
rubiii committed Sep 28, 2011
1 parent f3bb6e5 commit d5b7e8c
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 25 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,7 @@
## 1.0.0 (UPCOMING)

* Feature: Added [hooks](http://savonrb.com/#hook_into_the_system).

## 0.9.7 (2011-08-25)

* Feature: Merged [pull request 210](https://github.com/rubiii/savon/pull/210) by
Expand Down
6 changes: 6 additions & 0 deletions lib/savon/global.rb
@@ -1,5 +1,6 @@
require "logger"
require "savon/soap"
require "savon/hooks/group"

module Savon
module Global
Expand Down Expand Up @@ -92,6 +93,11 @@ def deprecate?
@deprecate != false
end

# Returns the hooks.
def hooks
@hooks ||= Hooks::Group.new
end

# Reset to default configuration.
def reset_config!
self.log = true
Expand Down
46 changes: 46 additions & 0 deletions lib/savon/hooks/group.rb
@@ -0,0 +1,46 @@
require "savon/hooks/hook"

module Savon
module Hooks

# = Savon::Hooks::Group
#
# Manages a list of hooks.
class Group

# Accepts an Array of +hooks+ to start with.
def initialize(hooks = nil)
self.hooks = hooks
end

attr_writer :hooks

def hooks
@hooks ||= []
end

# Adds a new hook.
def define(id, hook, &block)
hooks << Hook.new(id, hook, &block)
end

# Removes hooks matching the given +ids+.
def reject!(*ids)
ids = ids.flatten
hooks.reject! { |hook| ids.include? hook.id }
end

# Returns a new group for a given +hook+.
def select(hook)
Group.new hooks.select { |h| h.hook == hook }
end

# Calls the hooks with the given +args+ and returns the
# value of the last hooks.
def call(*args)
hooks.inject(nil) { |memo, hook| hook.call(*args) }
end

end
end
end
36 changes: 36 additions & 0 deletions lib/savon/hooks/hook.rb
@@ -0,0 +1,36 @@
module Savon
module Hooks

# = Savon::Hooks::Hook
#
# A hook used somewhere in the system.
class Hook

HOOKS = [

# Replaces the POST request executed to call a service.
# See: Savon::SOAP::Request#response
#
# Receives the <tt>Savon::SOAP::Request</tt> and is expected to return an <tt>HTTPI::Response</tt>.
# It can change the request and return something falsy to still execute the POST request.
:soap_request

]

# Expects an +id+, the name of the +hook+ to use and a +block+ to be called.
def initialize(id, hook, &block)
self.id = id
self.hook = hook
self.block = block
end

attr_accessor :id, :hook, :block

# Calls the +block+ with the given +args+.
def call(*args)
block.call(*args)
end

end
end
end
36 changes: 18 additions & 18 deletions lib/savon/soap/request.rb
Expand Up @@ -14,43 +14,43 @@ class Request

# Expects an <tt>HTTPI::Request</tt> and a <tt>Savon::SOAP::XML</tt> object
# to execute a SOAP request and returns the response.
def self.execute(request, soap)
new(request, soap).response
def self.execute(http, soap)
new(http, soap).response
end

# Expects an <tt>HTTPI::Request</tt> and a <tt>Savon::SOAP::XML</tt> object.
def initialize(request, soap)
self.request = setup(request, soap)
def initialize(http, soap)
self.soap = soap
self.http = configure(http)
end

# Accessor for the <tt>HTTPI::Request</tt>.
attr_accessor :request
attr_accessor :soap, :http

# Executes the request and returns the response.
def response
@response ||= with_logging { HTTPI.post request }
@response ||= SOAP::Response.new(
Savon.hooks.select(:soap_request).call(self) || with_logging { HTTPI.post(http) }
)
end

private

# Sets up the +request+ using a given +soap+ object.
def setup(request, soap)
url, body = soap.endpoint, soap.to_xml
# Configures a given +http+ from the +soap+ object.
def configure(http)
http.url = soap.endpoint
http.body = soap.to_xml
http.headers["Content-Type"] ||= ContentType[soap.version]
http.headers["Content-Length"] ||= soap.to_xml.length.to_s

request.url = url
request.body = body
request.headers["Content-Type"] ||= ContentType[soap.version]
request.headers["Content-Length"] ||= body.length.to_s

request
http
end

# Logs the HTTP request, yields to a given +block+ and returns a <tt>Savon::SOAP::Response</tt>.
def with_logging
log_request request.url, request.headers, request.body
log_request http.url, http.headers, http.body
response = yield
log_response response.code, response.body
SOAP::Response.new response
response
end

# Logs the SOAP request +url+, +headers+ and +body+.
Expand Down
2 changes: 1 addition & 1 deletion lib/savon/version.rb
@@ -1,5 +1,5 @@
module Savon

Version = "0.9.7"
Version = "1.0.0"

end
12 changes: 6 additions & 6 deletions spec/savon/soap/request_spec.rb
Expand Up @@ -20,30 +20,30 @@

describe ".new" do
it "uses the SOAP endpoint for the request" do
soap_request.request.url.should == URI(soap.endpoint)
soap_request.http.url.should == URI(soap.endpoint)
end

it "sets the SOAP body for the request" do
soap_request.request.body.should == soap.to_xml
soap_request.http.body.should == soap.to_xml
end

it "sets the Content-Type header for SOAP 1.1" do
soap_request.request.headers["Content-Type"].should == Savon::SOAP::Request::ContentType[1]
soap_request.http.headers["Content-Type"].should == Savon::SOAP::Request::ContentType[1]
end

it "sets the Content-Type header for SOAP 1.2" do
soap.version = 2
soap_request.request.headers["Content-Type"].should == Savon::SOAP::Request::ContentType[2]
soap_request.http.headers["Content-Type"].should == Savon::SOAP::Request::ContentType[2]
end

it "does not set the Content-Type header if it's already specified" do
headers = { "Content-Type" => "text/plain" }
soap_request = Savon::SOAP::Request.new HTTPI::Request.new(:headers => headers), soap
soap_request.request.headers["Content-Type"].should == headers["Content-Type"]
soap_request.http.headers["Content-Type"].should == headers["Content-Type"]
end

it "sets the Content-Length header" do
soap_request.request.headers["Content-Length"].should == soap.to_xml.length.to_s
soap_request.http.headers["Content-Length"].should == soap.to_xml.length.to_s
end
end

Expand Down

0 comments on commit d5b7e8c

Please sign in to comment.