savon 0.6.3 → 0.6.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CHANGELOG +31 -7
  2. data/README.textile +0 -0
  3. data/Rakefile +1 -1
  4. data/VERSION +1 -1
  5. data/lib/savon.rb +0 -0
  6. data/lib/savon/client.rb +6 -1
  7. data/lib/savon/core_ext.rb +0 -0
  8. data/lib/savon/core_ext/datetime.rb +0 -0
  9. data/lib/savon/core_ext/hash.rb +0 -0
  10. data/lib/savon/core_ext/object.rb +0 -0
  11. data/lib/savon/core_ext/string.rb +0 -0
  12. data/lib/savon/core_ext/symbol.rb +0 -0
  13. data/lib/savon/core_ext/uri.rb +0 -0
  14. data/lib/savon/request.rb +5 -0
  15. data/lib/savon/response.rb +0 -0
  16. data/lib/savon/soap.rb +11 -9
  17. data/lib/savon/wsdl.rb +67 -31
  18. data/lib/savon/wsse.rb +0 -0
  19. data/spec/fixtures/multiple_user_response.xml +0 -0
  20. data/spec/fixtures/soap_fault.xml +0 -0
  21. data/spec/fixtures/user_fixture.rb +8 -4
  22. data/spec/fixtures/user_response.xml +0 -0
  23. data/spec/fixtures/user_wsdl.xml +0 -0
  24. data/spec/http_stubs.rb +15 -17
  25. data/spec/savon/client_spec.rb +46 -47
  26. data/spec/savon/core_ext/datetime_spec.rb +0 -0
  27. data/spec/savon/core_ext/hash_spec.rb +0 -0
  28. data/spec/savon/core_ext/object_spec.rb +0 -0
  29. data/spec/savon/core_ext/string_spec.rb +0 -0
  30. data/spec/savon/core_ext/symbol_spec.rb +0 -0
  31. data/spec/savon/core_ext/uri_spec.rb +0 -0
  32. data/spec/savon/request_spec.rb +44 -64
  33. data/spec/savon/response_spec.rb +34 -51
  34. data/spec/savon/savon_spec.rb +13 -19
  35. data/spec/savon/soap_spec.rb +61 -92
  36. data/spec/savon/wsdl_spec.rb +19 -34
  37. data/spec/savon/wsse_spec.rb +42 -58
  38. data/spec/spec_helper.rb +1 -1
  39. data/spec/{spec_helper_methods.rb → spec_helper_classes.rb} +32 -4
  40. metadata +15 -15
data/CHANGELOG CHANGED
@@ -1,10 +1,34 @@
1
+ == 0.6.4 (2009-12-13)
2
+ * Refactored specs to be less unit-like.
3
+ * Added a getter for the Savon::Request to Savon::Client and a read_timeout setter for HTTP requests.
4
+ * Replaced WSDL document with stream parsing.
5
+
6
+ Benchmarks (1000 SOAP calls):
7
+
8
+ user system total real
9
+ 0.6.4 72.180000 8.280000 80.460000 (750.799011)
10
+ 0.6.3 192.900000 19.630000 212.530000 (914.031865)
11
+
1
12
  == 0.6.3 (2009-12-11)
2
13
  * Removing 2 ruby deprecation warnings for parenthesized arguments. (Dave Woodward <dave@futuremint.com>)
3
- * Much faster XPath expressions for parsing the WSDL document.
4
14
  * Added global and per request options for disabling Savon::WSDL.
5
15
 
16
+ Benchmarks (1000 SOAP calls):
17
+
18
+ user system total real
19
+ WSDL 192.900000 19.630000 212.530000 (914.031865)
20
+ disabled WSDL 5.680000 1.340000 7.020000 (298.265318)
21
+
22
+ * Improved XPath expressions for parsing the WSDL document.
23
+
24
+ Benchmarks (1000 SOAP calls):
25
+
26
+ user system total real
27
+ 0.6.3 192.900000 19.630000 212.530000 (914.031865)
28
+ 0.6.2 574.720000 78.380000 653.100000 (1387.778539)
29
+
6
30
  == 0.6.2 (2009-12-06)
7
- * Support for changing the name of the SOAP input node.
31
+ * Added support for changing the name of the SOAP input node.
8
32
  * Added a CHANGELOG.
9
33
 
10
34
  == 0.6.1 (2009-12-06)
@@ -12,14 +36,14 @@
12
36
 
13
37
  == 0.6.0 (2009-12-06)
14
38
  * method_missing now yields the SOAP and WSSE objects to a given block.
15
- * The response_process (which previously was a block passed to method_missing) was replaced by the Savon::Response object.
16
- * Improved SOAP action handling (another problem that came up with Issue #1).
39
+ * The response_process (which previously was a block passed to method_missing) was replaced by Savon::Response.
40
+ * Improved SOAP action handling (another problem that came up with issue #1).
17
41
 
18
42
  == 0.5.3 (2009-11-30)
19
- * Fix for Issue #2 (NoMethodError: undefined method `invalid!' for Savon::WSDL)
43
+ * Patch for issue #2 (NoMethodError: undefined method `invalid!' for Savon::WSDL)
20
44
 
21
45
  == 0.5.2 (2009-11-30)
22
- * Patch for Issue #1 (Calls fail if api methods have periods in them)
46
+ * Patch for issue #1 (Calls fail if api methods have periods in them)
23
47
 
24
48
  == 0.5.1 (2009-11-29)
25
49
  * Optimized default response process.
@@ -29,4 +53,4 @@
29
53
  * Added specs
30
54
 
31
55
  == 0.5.0 (2009-11-29)
32
- * Complete rewrite.
56
+ * Complete rewrite.
File without changes
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ task :default => :spec
8
8
  Spec::Rake::SpecTask.new do |spec|
9
9
  spec.spec_files = FileList["spec/**/*_spec.rb"]
10
10
  spec.spec_opts << "--color"
11
- spec.libs << "lib"
11
+ spec.libs += ["lib", "spec"]
12
12
  spec.rcov = true
13
13
  spec.rcov_dir = "rcov"
14
14
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.3
1
+ 0.6.4
File without changes
@@ -23,6 +23,9 @@ module Savon
23
23
  # Accessor for Savon::WSDL.
24
24
  attr_accessor :wsdl
25
25
 
26
+ # Returns the Savon::Request.
27
+ attr_reader :request
28
+
26
29
  # Returns whether to use Savon::WSDL.
27
30
  def wsdl?
28
31
  self.class.wsdl && @wsdl
@@ -47,7 +50,9 @@ module Savon
47
50
  # Expects a SOAP action and sets up Savon::SOAP and Savon::WSSE.
48
51
  # Yields them to a given +block+ in case one was given.
49
52
  def setup(soap_action, &block)
50
- @soap = SOAP.new(wsdl? ? @wsdl.soap_actions[soap_action] : nil)
53
+ @soap = SOAP.new
54
+ @soap.action = @wsdl.operations[soap_action][:action] if wsdl?
55
+ @soap.input = @wsdl.operations[soap_action][:input] if wsdl?
51
56
  @wsse = WSSE.new
52
57
 
53
58
  yield_parameters &block if block
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -45,6 +45,11 @@ module Savon
45
45
  # Returns the endpoint URI.
46
46
  attr_reader :endpoint
47
47
 
48
+ # Sets the read timeout for HTTP requests.
49
+ def read_timeout=(sec)
50
+ http.read_timeout = sec
51
+ end
52
+
48
53
  # Retrieves WSDL document and returns the Net::HTTPResponse.
49
54
  def wsdl
50
55
  log "Retrieving WSDL from: #{@endpoint}"
File without changes
@@ -29,21 +29,23 @@ module Savon
29
29
 
30
30
  end
31
31
 
32
- # Expects a Hash containing the name of the SOAP action and input.
33
- def initialize(action = nil)
34
- @action = action.kind_of?(Hash) ? action[:name] : ""
35
- @input = action.kind_of?(Hash) ? action[:input] : ""
36
- end
37
-
38
32
  # Sets the WSSE options.
39
33
  attr_writer :wsse
40
34
 
41
35
  # Accessor for the SOAP action.
42
- attr_accessor :action
36
+ attr_writer :action
37
+
38
+ def action
39
+ @action ||= ""
40
+ end
43
41
 
44
42
  # Accessor for the SOAP input.
45
43
  attr_writer :input
46
44
 
45
+ def input
46
+ @input ||= ""
47
+ end
48
+
47
49
  # Sets the SOAP header. Expected to be a Hash that can be translated
48
50
  # to XML via Hash.to_soap_xml or any other Object responding to to_s.
49
51
  attr_writer :header
@@ -102,8 +104,8 @@ module Savon
102
104
  # Defaults to use the name of the SOAP action and may be an empty Array
103
105
  # in case the specified SOAP input seems invalid.
104
106
  def input_array
105
- return [@input.to_sym] if @input && !@input.empty?
106
- return [@action.to_sym] if @action && !@action.empty?
107
+ return [input.to_sym] if input && !input.empty?
108
+ return [action.to_sym] if action && !action.empty?
107
109
  []
108
110
  end
109
111
 
@@ -2,68 +2,104 @@ module Savon
2
2
 
3
3
  # Savon::WSDL
4
4
  #
5
- # Represents a WSDL document.
5
+ # Represents the WSDL document.
6
6
  class WSDL
7
7
 
8
- # Expects a Savon::Request object.
8
+ # Initializer, expects a Savon::Request.
9
9
  def initialize(request)
10
10
  @request = request
11
11
  end
12
12
 
13
- # Returns the namespace URI from the WSDL.
13
+ # Returns the namespace URI of the WSDL.
14
14
  def namespace_uri
15
- @namespace_uri ||= document.root.attributes["targetNamespace"] || ""
15
+ @namespace_uri ||= stream.namespace_uri
16
16
  end
17
17
 
18
- # Returns a Hash of available SOAP actions mapped to snake_case (keys)
19
- # and their original names and inputs in another Hash (values).
18
+ # Returns an Array of available SOAP actions.
20
19
  def soap_actions
21
- @soap_actions ||= parse_soap_operations.inject({}) do |hash, (input, action)|
22
- hash.merge input.snakecase.to_sym => { :name => action, :input => input }
23
- end
20
+ @soap_actions ||= stream.operations.keys
21
+ end
22
+
23
+ # Returns a Hash of SOAP operations including their corresponding
24
+ # SOAP actions and inputs.
25
+ def operations
26
+ @operations ||= stream.operations
24
27
  end
25
28
 
26
29
  # Returns +true+ for available methods and SOAP actions.
27
30
  def respond_to?(method)
28
- return true if soap_actions.keys.include? method
31
+ return true if soap_actions.include? method
29
32
  super
30
33
  end
31
34
 
32
- # Returns the WSDL document.
35
+ # Returns the raw WSDL document.
33
36
  def to_s
34
- wsdl_response.body
37
+ @document ||= @request.wsdl.body
35
38
  end
36
39
 
37
40
  private
38
41
 
39
- # Retrieves and returns the WSDL response. Raises an ArgumentError in
40
- # case the WSDL seems to be invalid.
41
- def wsdl_response
42
- unless @wsdl_response
43
- @wsdl_response ||= @request.wsdl
44
- raise ArgumentError, "Invalid WSDL: #{@request.endpoint}" if soap_actions.empty?
42
+ # Returns the Savon::WSDLStream.
43
+ def stream
44
+ unless @stream
45
+ @stream = WSDLStream.new
46
+ REXML::Document.parse_stream to_s, @stream
45
47
  end
46
- @wsdl_response
48
+ @stream
47
49
  end
48
50
 
49
- # Returns a REXML::Document of the WSDL.
50
- def document
51
- @document ||= REXML::Document.new wsdl_response.body
51
+ end
52
+
53
+ # Savon::WSDLStream
54
+ #
55
+ # Stream listener for parsing the WSDL document.
56
+ class WSDLStream
57
+
58
+ # Initializer, sets an empty Hash of operations.
59
+ def initialize
60
+ @operations = {}
52
61
  end
53
62
 
54
- # Parses the WSDL for available SOAP actions and inputs. Returns a Hash
55
- # containing the SOAP action inputs and corresponding SOAP actions.
56
- def parse_soap_operations
57
- wsdl_binding = document.elements["wsdl:definitions/wsdl:binding"]
58
- return {} unless wsdl_binding
63
+ # Returns the namespace URI from the WSDL document.
64
+ attr_reader :namespace_uri
59
65
 
60
- wsdl_binding.elements.inject("wsdl:operation", {}) do |hash, operation|
61
- action = operation.elements["*:operation"].attributes["soapAction"] || ""
62
- action = operation.attributes["name"] if action.empty?
66
+ # Returns the SOAP operations found in the WSDL document.
67
+ attr_reader :operations
68
+
69
+ # Hook method called when the stream parser encounters a tag.
70
+ def tag_start(name, attrs)
71
+ section_from name
72
+ @namespace_uri ||= attrs["targetNamespace"] if @section == :definitions
73
+ operation_from name, attrs if @section == :binding && /.+:operation/ === name
74
+ end
75
+
76
+ # Sets the current section of the WSDL document from a given tag +name+.
77
+ def section_from(name)
78
+ section = case name
79
+ when "wsdl:definitions" then :definitions
80
+ when "wsdl:types" then :types
81
+ when "wsdl:message" then :message
82
+ when "wsdl:portType" then :port_type
83
+ when "wsdl:binding" then :binding
84
+ when "wsdl:service" then :service
85
+ end
86
+ @section = section if section
87
+ end
63
88
 
64
- hash.merge action.split("/").last => action
89
+ # Stores available operations from a given tag +name+ and +attrs+.
90
+ def operation_from(name, attrs)
91
+ if name == "wsdl:operation"
92
+ @action = attrs["name"]
93
+ elsif /.+:operation/ === name
94
+ @action = attrs["soapAction"] if attrs["soapAction"] && !attrs["soapAction"].empty?
95
+ input = @action.split("/").last
96
+ @operations[input.snakecase.to_sym] = { :action => @action, :input => input }
65
97
  end
66
98
  end
67
99
 
100
+ # Catches calls to unimplemented hook methods.
101
+ def method_missing(method, *args)
102
+ end
103
+
68
104
  end
69
105
  end
File without changes
File without changes
File without changes
@@ -1,9 +1,9 @@
1
1
  class UserFixture
2
2
 
3
3
  @namespace_uri = "http://v1_0.ws.user.example.com"
4
- @soap_actions = {
5
- :user_find_by_id => { :name => "User.FindById", :input => "User.FindById" },
6
- :find_user => { :name => "findUser", :input => "findUser" }
4
+ @operations = {
5
+ :user_find_by_id => { :action => "User.FindById", :input => "User.FindById" },
6
+ :find_user => { :action => "findUser", :input => "findUser" }
7
7
  }
8
8
 
9
9
  @datetime_string = "2010-11-22T11:22:33"
@@ -24,9 +24,13 @@ class UserFixture
24
24
 
25
25
  class << self
26
26
 
27
- attr_accessor :namespace_uri, :soap_actions,
27
+ attr_accessor :namespace_uri, :operations,
28
28
  :datetime_string, :datetime_object, :response_hash
29
29
 
30
+ def soap_actions
31
+ @operations.keys
32
+ end
33
+
30
34
  def user_wsdl
31
35
  load_fixture :user_wsdl
32
36
  end
File without changes
File without changes
@@ -2,24 +2,22 @@ require "fakeweb"
2
2
 
3
3
  FakeWeb.allow_net_connect = false
4
4
 
5
- # Register fake WSDL and SOAP request.
6
- FakeWeb.register_uri :get, SpecHelper.some_endpoint, :body => UserFixture.user_wsdl
7
- FakeWeb.register_uri :post, SpecHelper.soap_call_endpoint, :body => UserFixture.user_response
5
+ # Some WSDL and SOAP request.
6
+ FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint, :body => UserFixture.user_wsdl
7
+ FakeWeb.register_uri :post, EndpointHelper.soap_endpoint, :body => UserFixture.user_response
8
8
 
9
- # Register fake WSDL and SOAP request with multiple "//return" nodes.
10
- FakeWeb.register_uri :get, SpecHelper.multiple_endpoint, :body => UserFixture.user_wsdl
11
- FakeWeb.register_uri :post, SpecHelper.soap_multiple_endpoint, :body => UserFixture.multiple_user_response
9
+ # WSDL and SOAP request with multiple "//return" nodes.
10
+ FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:multiple), :body => UserFixture.user_wsdl
11
+ FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:multiple), :body => UserFixture.multiple_user_response
12
12
 
13
- # Register fake WSDL and SOAP request for a Savon::SOAPFault.
14
- FakeWeb.register_uri :get, SpecHelper.soapfault_endpoint, :body => UserFixture.user_wsdl
15
- FakeWeb.register_uri :post, SpecHelper.soap_soapfault_endpoint, :body => UserFixture.soap_fault
13
+ # WSDL and SOAP request with a Savon::SOAPFault.
14
+ FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:soap_fault), :body => UserFixture.user_wsdl
15
+ FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:soap_fault), :body => UserFixture.soap_fault
16
16
 
17
- # Register fake WSDL and SOAP request for a Savon::HTTPError.
18
- FakeWeb.register_uri :get, SpecHelper.httperror_endpoint, :body => UserFixture.user_wsdl
19
- FakeWeb.register_uri :post, SpecHelper.soap_httperror_endpoint, :body => "",
20
- :status => ["404", "Not Found"]
17
+ # WSDL and SOAP request with a Savon::HTTPError.
18
+ FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:http_error), :body => UserFixture.user_wsdl
19
+ FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:http_error), :body => "", :status => ["404", "Not Found"]
21
20
 
22
- # Register fake WSDL and SOAP request for an invalid endpoint.
23
- FakeWeb.register_uri :get, SpecHelper.invalid_endpoint, :body => ""
24
- FakeWeb.register_uri :post, SpecHelper.soap_invalid_endpoint, :body => "",
25
- :status => ["404", "Not Found"]
21
+ # WSDL and SOAP request with an invalid endpoint.
22
+ FakeWeb.register_uri :get, EndpointHelper.wsdl_endpoint(:invalid), :body => ""
23
+ FakeWeb.register_uri :post, EndpointHelper.soap_endpoint(:invalid), :body => "", :status => ["404", "Not Found"]
@@ -1,69 +1,68 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Savon::Client do
4
- before { @client = some_client_instance }
4
+ before { @client = Savon::Client.new EndpointHelper.wsdl_endpoint }
5
5
 
6
- def some_client_instance
7
- Savon::Client.new SpecHelper.some_endpoint
6
+ it "is initialized with a SOAP endpoint String" do
7
+ Savon::Client.new EndpointHelper.wsdl_endpoint
8
8
  end
9
9
 
10
- describe "initialize" do
11
- it "expects a SOAP endpoint String" do
12
- some_client_instance
13
- end
10
+ it "raises an ArgumentError when initialized with an invalid endpoint" do
11
+ lambda { Savon::Client.new "invalid" }.should raise_error ArgumentError
12
+ end
14
13
 
15
- it "raises an ArgumentError in case of an invalid endpoint" do
16
- lambda { Savon::Client.new "invalid" }.should raise_error ArgumentError
17
- end
14
+ it "has a getter for accessing the Savon::WSDL" do
15
+ @client.wsdl.should be_a Savon::WSDL
18
16
  end
19
17
 
20
- describe "wsdl" do
21
- it "returns the Savon::WSDL" do
22
- @client.wsdl.should be_a Savon::WSDL
23
- end
18
+ it "has a getter for accessing the Savon::Request" do
19
+ @client.request.should be_a Savon::Request
24
20
  end
25
21
 
26
- describe "respond_to?" do
27
- it "returns true for available SOAP actions" do
28
- @client.respond_to?(UserFixture.soap_actions.keys.first).
29
- should be_true
30
- end
22
+ it "has a getter for returning whether to use the Savon::WSDL (global setting)" do
23
+ @client.wsdl?.should be_true
31
24
 
32
- it "still behaves like usual otherwise" do
33
- @client.respond_to?(:object_id).should be_true
34
- @client.respond_to?(:some_undefined_method).should be_false
35
- end
25
+ Savon::Client.wsdl = false
26
+ @client.wsdl?.should be_false
27
+ Savon::Client.wsdl = true
28
+
29
+ @client.wsdl = false
30
+ @client.wsdl?.should be_false
36
31
  end
37
32
 
38
- describe "method_missing" do
39
- it "dispatches SOAP requests for available SOAP actions" do
40
- @client.find_user.should be_a Savon::Response
41
- end
33
+ it "responds to SOAP actions while still behaving as usual otherwise" do
34
+ @client.respond_to?(UserFixture.soap_actions.first).should be_true
35
+ @client.respond_to?(:object_id).should be_true
36
+ @client.respond_to?(:some_undefined_method).should be_false
37
+ end
42
38
 
43
- it "raises a Savon::SOAPFault in case of a SOAP fault" do
44
- client = Savon::Client.new SpecHelper.soapfault_endpoint
45
- lambda { client.find_user }.should raise_error Savon::SOAPFault
46
- end
39
+ it "dispatches SOAP calls via method_missing and returns the Savon::Response" do
40
+ @client.find_user.should be_a Savon::Response
41
+ end
47
42
 
48
- it "raises a Savon::HTTPError in case of an HTTP error" do
49
- client = Savon::Client.new SpecHelper.httperror_endpoint
50
- lambda { client.find_user }.should raise_error Savon::HTTPError
51
- end
43
+ it "raises a Savon::SOAPFault in case of a SOAP fault" do
44
+ client = Savon::Client.new EndpointHelper.wsdl_endpoint(:soap_fault)
45
+ lambda { client.find_user }.should raise_error Savon::SOAPFault
46
+ end
52
47
 
53
- it "yields the SOAP object to a block that expects one argument" do
54
- @client.find_user { |soap| soap.should be_a Savon::SOAP }
55
- end
48
+ it "raises a Savon::HTTPError in case of an HTTP error" do
49
+ client = Savon::Client.new EndpointHelper.wsdl_endpoint(:http_error)
50
+ lambda { client.find_user }.should raise_error Savon::HTTPError
51
+ end
56
52
 
57
- it "yields the SOAP and WSSE object to a block that expects two argument" do
58
- @client.find_user do |soap, wsse|
59
- soap.should be_a Savon::SOAP
60
- wsse.should be_a Savon::WSSE
61
- end
62
- end
53
+ it "yields the SOAP object to a block when it expects one argument" do
54
+ @client.find_user { |soap| soap.should be_a Savon::SOAP }
55
+ end
63
56
 
64
- it "still raises a NoMethodError for undefined methods" do
65
- lambda { @client.some_undefined_method }.should raise_error NoMethodError
57
+ it "yields the SOAP and WSSE object to a block when it expects two argument" do
58
+ @client.find_user do |soap, wsse|
59
+ soap.should be_a Savon::SOAP
60
+ wsse.should be_a Savon::WSSE
66
61
  end
67
62
  end
68
63
 
69
- end
64
+ it "still raises a NoMethodError for undefined methods" do
65
+ lambda { @client.some_undefined_method }.should raise_error NoMethodError
66
+ end
67
+
68
+ end