savon 0.9.14 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,14 @@
1
+ ## 1.0.0 (2012-06-09)
2
+
3
+ * Fix: `Savon.client` didn't pass the optional block.
4
+
5
+ * Improvement: [#291](https://github.com/rubiii/savon/issues/291) changed the `:soap_request` hook to act
6
+ like an around filter. The hook now receives a callback block to execute the SOAP call and can return
7
+ the result of the callback to continue the request. It can also not call the callback block and return
8
+ some `HTTPI::Response` to mock the SOAP request.
9
+
10
+ As this change affects `savon_spec`, you need to update `savon_spec` to v1.3.0.
11
+
1
12
  ## 0.9.14 (2012-06-07)
2
13
 
3
14
  * Fix: [#292](https://github.com/rubiii/savon/issues/292) again
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Savon [![Build Status](https://secure.travis-ci.org/rubiii/savon.png)](http://travis-ci.org/rubiii/savon)
1
+ Savon [![Build Status](https://secure.travis-ci.org/rubiii/savon.png?branch=master)](http://travis-ci.org/rubiii/savon)
2
2
  =====
3
3
 
4
4
  Heavy metal Ruby SOAP client
@@ -6,8 +6,8 @@ require "savon/model"
6
6
  module Savon
7
7
  extend self
8
8
 
9
- def client(*args)
10
- Client.new(*args)
9
+ def client(*args, &block)
10
+ Client.new(*args, &block)
11
11
  end
12
12
 
13
13
  def configure
@@ -4,17 +4,24 @@ module Savon
4
4
  module CoreExt
5
5
  module String
6
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)
7
+ def self.included(base)
8
+ unless "savon".respond_to?(:snakecase)
9
+ base.send(:include, Extension)
10
+ end
11
+ end
12
+
13
+ module Extension
14
+ def snakecase
15
+ str = dup
16
+ str.gsub! /::/, '/'
17
+ str.gsub! /([A-Z]+)([A-Z][a-z])/, '\1_\2'
18
+ str.gsub! /([a-z\d])([A-Z])/, '\1_\2'
19
+ str.tr! ".", "_"
20
+ str.tr! "-", "_"
21
+ str.downcase!
22
+ str
23
+ end
24
+ end
18
25
 
19
26
  end
20
27
  end
@@ -9,14 +9,18 @@ module Savon
9
9
  class Group
10
10
 
11
11
  # Accepts an Array of +hooks+ to start with.
12
- def initialize(hooks = nil)
13
- self.hooks = hooks
12
+ def initialize(hooks = [])
13
+ @hooks = hooks
14
14
  end
15
15
 
16
- attr_writer :hooks
16
+ # Returns whether this group contains hooks.
17
+ def empty?
18
+ hooks.empty?
19
+ end
17
20
 
18
- def hooks
19
- @hooks ||= []
21
+ # Returns the number of hooks in this group.
22
+ def count
23
+ hooks.count
20
24
  end
21
25
 
22
26
  # Adds a new hook.
@@ -25,14 +29,21 @@ module Savon
25
29
  end
26
30
 
27
31
  # Removes hooks matching the given +ids+.
28
- def reject!(*ids)
32
+ def reject(*ids)
29
33
  ids = ids.flatten
30
34
  hooks.reject! { |hook| ids.include? hook.id }
31
35
  end
32
36
 
33
- # Returns a new group for a given +hook+.
34
- def select(hook)
35
- Group.new hooks.select { |h| h.hook == hook }
37
+ # Fire a given +hook+ with any given +args+.
38
+ def fire(hook, *args, &callback)
39
+ callable = select(hook)
40
+
41
+ if callable.empty?
42
+ callback.call
43
+ else
44
+ args.unshift(callback) if callback
45
+ callable.call(*args)
46
+ end
36
47
  end
37
48
 
38
49
  # Calls the hooks with the given +args+ and returns the
@@ -41,6 +52,17 @@ module Savon
41
52
  hooks.inject(nil) { |memo, hook| hook.call(*args) }
42
53
  end
43
54
 
55
+ private
56
+
57
+ def hooks
58
+ @hooks ||= []
59
+ end
60
+
61
+ # Returns a new group for a given +hook+.
62
+ def select(hook)
63
+ Group.new hooks.select { |h| h.hook == hook }
64
+ end
65
+
44
66
  end
45
67
  end
46
68
  end
@@ -8,17 +8,42 @@ module Savon
8
8
 
9
9
  HOOKS = [
10
10
 
11
- # Replaces the POST request executed to call a service.
11
+ # :soap_request
12
+ #
13
+ # Around filter wrapping the POST request executed to call a SOAP service.
12
14
  # See: Savon::SOAP::Request#response
13
15
  #
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
+ # Arguments
17
+ #
18
+ # [callback] A block to execute the SOAP request
19
+ # [request] The current <tt>Savon::SOAP::Request</tt>
20
+ #
21
+ # Examples
22
+ #
23
+ # Log the time before and after the SOAP call:
24
+ #
25
+ # Savon.config.hooks.define(:my_hook, :soap_request) do |callback, request|
26
+ # Timer.log(:start, Time.now)
27
+ # response = callback.call
28
+ # Timer.log(:end, Time.now)
29
+ # response
30
+ # end
31
+ #
32
+ # Replace the SOAP call and return a custom response:
33
+ #
34
+ # Savon.config.hooks.define(:mock_hook, :soap_request) do |_, request|
35
+ # HTTPI::Response.new(200, {}, "")
36
+ # end
16
37
  :soap_request
17
38
 
18
39
  ]
19
40
 
20
41
  # Expects an +id+, the name of the +hook+ to use and a +block+ to be called.
21
42
  def initialize(id, hook, &block)
43
+ unless HOOKS.include?(hook)
44
+ raise ArgumentError, "No such hook: #{hook}. Expected one of: #{HOOKS.join(', ')}"
45
+ end
46
+
22
47
  self.id = id
23
48
  self.hook = hook
24
49
  self.block = block
@@ -30,8 +30,7 @@ module Savon
30
30
  def define_class_action(action)
31
31
  class_action_module.module_eval %{
32
32
  def #{action.to_s.snakecase}(body = nil, &block)
33
- response = client.request :wsdl, #{action.inspect}, :body => body, &block
34
- config.hooks.select(:model_soap_response).call(response) || response
33
+ client.request :wsdl, #{action.inspect}, :body => body, &block
35
34
  end
36
35
  }
37
36
  end
@@ -49,11 +48,6 @@ module Savon
49
48
  def class_action_module
50
49
  @class_action_module ||= Module.new do
51
50
 
52
- # Returns the memoized <tt>Savon::Config</tt>.
53
- def config
54
- @config ||= Savon.config.clone
55
- end
56
-
57
51
  # Returns the memoized <tt>Savon::Client</tt>.
58
52
  def client(&block)
59
53
  @client ||= Savon::Client.new(&block)
@@ -31,7 +31,7 @@ module Savon
31
31
  # Executes the request and returns the response.
32
32
  def response
33
33
  @response ||= begin
34
- response = config.hooks.select(:soap_request).call(self) || with_logging { HTTPI.post(http) }
34
+ response = config.hooks.fire(:soap_request, self) { with_logging { HTTPI.post(http) } }
35
35
  SOAP::Response.new(config, response)
36
36
  end
37
37
  end
@@ -1,5 +1,5 @@
1
1
  module Savon
2
2
 
3
- VERSION = "0.9.14"
3
+ VERSION = "1.0.0"
4
4
 
5
5
  end
@@ -0,0 +1,71 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::Hooks::Group do
4
+
5
+ let(:group) { subject }
6
+
7
+ describe "#empty?" do
8
+ it "returns true for an empty group" do
9
+ group.should be_empty
10
+ end
11
+
12
+ it "returns false if the group contains hooks" do
13
+ group = Savon::Hooks::Group.new [:some_hook]
14
+ group.should_not be_empty
15
+ end
16
+ end
17
+
18
+ describe "#define" do
19
+ it "lets you define a new hook" do
20
+ group.define(:test_hook, :soap_request)
21
+ group.should_not be_empty
22
+ end
23
+
24
+ it "raises if there is no such hook" do
25
+ expect { group.define(:supposed_to_fail, :no_such_hook) }.to raise_error(ArgumentError)
26
+ end
27
+ end
28
+
29
+ describe "#reject" do
30
+ it "rejects hooks matching any given id" do
31
+ group.define(:remove1, :soap_request)
32
+ group.define(:here_to_stay, :soap_request)
33
+ group.define(:remove2, :soap_request)
34
+ group.count.should == 3
35
+
36
+ group.reject(:remove1, :remove2)
37
+ group.count.should == 1
38
+ end
39
+ end
40
+
41
+ describe "#fire" do
42
+ let(:hook) { lambda {} }
43
+ let(:fallback) { lambda {} }
44
+
45
+ context "with hooks" do
46
+ before do
47
+ group.define(:some_hook, :soap_request, &hook)
48
+ end
49
+
50
+ it "calls the hooks passing any arguments" do
51
+ hook.expects(:call).with(:arg1, :arg2)
52
+ group.fire(:soap_request, :arg1, :arg2)
53
+ end
54
+
55
+ it "calls the hooks passing any arguments and the callback" do
56
+ hook.expects(:call).with(fallback, :arg)
57
+ group.fire(:soap_request, :arg, &fallback)
58
+ end
59
+ end
60
+
61
+ context "without hooks" do
62
+ it "executes the callback" do
63
+ report = :call
64
+ fallback = lambda { report = :back }
65
+ group.fire(:soap_request, &fallback)
66
+ report.should == :back
67
+ end
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+
3
+ describe Savon::Hooks::Hook do
4
+
5
+ let(:hook) { lambda {} }
6
+
7
+ describe "#call" do
8
+ it "calls the hook" do
9
+ hook = Savon::Hooks::Hook.new(:my_hook, :soap_request, &hook)
10
+ hook.expects(:call).with(:arg1, :arg2)
11
+
12
+ hook.call(:arg1, :arg2)
13
+ end
14
+ end
15
+
16
+ end
@@ -26,7 +26,7 @@ describe Savon::Logger do
26
26
  it "logs a given message (pretty and filtered)" do
27
27
  logger.subject.expects(logger.level).with(filtered_message.to_xml(:indent => 2))
28
28
  logger.filter << :hello
29
- warn logger.log(message, :pretty => true, :filter => true)
29
+ logger.log(message, :pretty => true, :filter => true)
30
30
  end
31
31
 
32
32
  it "defaults to wrap the standard Logger" do
@@ -6,38 +6,12 @@ describe Savon::Model do
6
6
  Class.new { extend Savon::Model }
7
7
  end
8
8
 
9
- describe ":model_soap_response hook" do
10
- before(:all) do
11
- model.actions :get_user, "GetAllUsers"
12
- end
13
-
14
- after do
15
- Savon.config.hooks.reject! :test_hook
16
- end
17
-
18
- it "can be used for pre-processing SOAP responses" do
19
- Savon.config.hooks.define(:test_hook, :model_soap_response) do |response|
20
- "hello #{response}"
21
- end
22
-
23
- model.client.stubs(:request).returns("world") #
24
- model.get_user.should == "hello world"
25
- end
26
- end
27
-
28
9
  describe ".client" do
29
10
  it "memoizes the Savon::Client" do
30
11
  model.client.should equal(model.client)
31
12
  end
32
13
  end
33
14
 
34
- describe ".config" do
35
- it "memoizes a clone of the global config" do
36
- model.config.should be_a(Savon::Config)
37
- model.config.should_not equal(Savon.config)
38
- end
39
- end
40
-
41
15
  describe ".endpoint" do
42
16
  it "sets the SOAP endpoint" do
43
17
  model.endpoint "http://example.com"
@@ -2,9 +2,15 @@ require "spec_helper"
2
2
 
3
3
  describe Savon::SOAP::Request do
4
4
 
5
- let(:soap_request) { Savon::SOAP::Request.new(config, http_request, soap_xml) }
6
- let(:http_request) { HTTPI::Request.new }
7
- let(:config) { Savon::Config.default }
5
+ let(:soap_request) { Savon::SOAP::Request.new(config, http_request, soap_xml) }
6
+ let(:http_request) { HTTPI::Request.new }
7
+ let(:http_response) { HTTPI::Response.new 200, {}, Fixture.response(:authentication) }
8
+
9
+ let(:config) {
10
+ config = Savon::Config.default
11
+ config.log = false
12
+ config
13
+ }
8
14
 
9
15
  def soap_xml(*args)
10
16
  @soap_xml ||= soap_xml!(*args)
@@ -26,7 +32,7 @@ describe Savon::SOAP::Request do
26
32
 
27
33
  describe ".execute" do
28
34
  it "executes a SOAP request and returns the response" do
29
- HTTPI.expects(:post).returns(HTTPI::Response.new 200, {}, Fixture.response(:authentication))
35
+ HTTPI.expects(:post).returns(http_response)
30
36
  response = Savon::SOAP::Request.execute config, http_request, soap_xml
31
37
  response.should be_a(Savon::SOAP::Response)
32
38
  end
@@ -67,9 +73,40 @@ describe Savon::SOAP::Request do
67
73
 
68
74
  describe "#response" do
69
75
  it "executes an HTTP POST request and returns a Savon::SOAP::Response" do
70
- HTTPI.expects(:post).returns(HTTPI::Response.new 200, {}, Fixture.response(:authentication))
76
+ HTTPI.expects(:post).returns(http_response)
71
77
  soap_request.response.should be_a(Savon::SOAP::Response)
72
78
  end
79
+
80
+ context "with a :soap_request hook" do
81
+ it "lets you replace the HTTP request and return your own response" do
82
+ config.hooks.define(:test, :soap_request) do |_, request|
83
+ request.should be_a(Savon::SOAP::Request)
84
+ http_response
85
+ end
86
+
87
+ response = soap_request.response
88
+ response.http.should equal(http_response)
89
+ end
90
+
91
+ it "works as an around filter for the SOAP request" do
92
+ HTTPI.expects(:post).returns(http_response)
93
+ state = []
94
+
95
+ config.hooks.define(:test, :soap_request) do |callback, request|
96
+ state << :before
97
+ response = callback.call
98
+ state << response
99
+ state << :after
100
+ response
101
+ end
102
+
103
+ response = soap_request.response
104
+
105
+ state[0].should == :before
106
+ state[1].should be_a(HTTPI::Response)
107
+ state[2].should == :after
108
+ end
109
+ end
73
110
  end
74
111
 
75
112
  end
@@ -6,7 +6,7 @@ RSpec.configure do |config|
6
6
  end
7
7
 
8
8
  # Silence log output
9
- $stdout = StringIO.new
9
+ Savon.config.log = false
10
10
  HTTPI.log = false
11
11
 
12
12
  require "support/endpoint"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: savon
3
3
  version: !ruby/object:Gem::Version
4
- hash: 39
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
+ - 1
7
8
  - 0
8
- - 9
9
- - 14
10
- version: 0.9.14
9
+ - 0
10
+ version: 1.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Daniel Harrington
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-06-07 00:00:00 Z
18
+ date: 2012-06-09 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  version_requirements: &id001 !ruby/object:Gem::Requirement
@@ -242,6 +242,8 @@ files:
242
242
  - spec/savon/client_spec.rb
243
243
  - spec/savon/config_spec.rb
244
244
  - spec/savon/core_ext/string_spec.rb
245
+ - spec/savon/hooks/group_spec.rb
246
+ - spec/savon/hooks/hook_spec.rb
245
247
  - spec/savon/http/error_spec.rb
246
248
  - spec/savon/logger_spec.rb
247
249
  - spec/savon/model_spec.rb