savon 2.1.0 → 2.2.0

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/.gitignore CHANGED
@@ -8,4 +8,5 @@ tmp
8
8
  *~
9
9
  *.gem
10
10
  .bundle
11
+ .rspec
11
12
  Gemfile.lock
@@ -1,10 +1,11 @@
1
1
  # https://github.com/travis-ci/travis-ci/wiki/.travis.yml-options
2
2
  language: "ruby"
3
- script: "bundle exec rake"
3
+ script: "bundle exec rake --trace"
4
4
  rvm:
5
5
  - 1.8.7
6
6
  - 1.9.2
7
7
  - 1.9.3
8
+ - 2.0
8
9
  - jruby-18mode
9
10
  - jruby-19mode
10
11
  - rbx-18mode
@@ -1,3 +1,41 @@
1
+ ### 2.2.0 (2013-04-21)
2
+
3
+ * Feature: [#416](https://github.com/savonrb/savon/pull/416) The global `namespace_identifier`
4
+ option can now be set to `nil` to not add a namespace identifier to the message tag.
5
+
6
+ * Feature: [#408](https://github.com/savonrb/savon/pull/408) Added `Savon::Client#service_name`
7
+ to return the name of the SOAP service.
8
+
9
+ * Improvement: When mistyping an option name, Savon used to raise a simple `NoMethodError`.
10
+ This is because regardless of whether you're using the Hash or block syntax to pass global
11
+ or local options, both are just method calls on some options object.
12
+
13
+ ```
14
+ NoMethodError: undefined method 'wsdk' for #<Savon::GlobalOptions:0x007fed95a55228>
15
+ ```
16
+
17
+ As of this change, Savon now catches those errors and raise a `Savon::UnknownOptionError`
18
+ with a slightly more helpful error message instead.
19
+
20
+ ```
21
+ Savon::UnknownOptionError:
22
+ Unknown global option: :wsdk
23
+ ```
24
+
25
+ * Improvement: [#385](https://github.com/savonrb/savon/issues/385) Instead of raising an
26
+ `ArgumentError` when Wasabi can't find any operations in the WSDL. Savon now raises a
27
+ `Savon::UnknownOperationError`. This might happen when Wasabi fails to parse the WSDL
28
+ because of imports for example.
29
+
30
+ * Fix: [#430](https://github.com/savonrb/savon/pull/430) allows you to rescue and ignore
31
+ `Savon::Error` errors in production while still having mocks trigger test failures.
32
+
33
+ * Fix: [#393](https://github.com/savonrb/savon/pull/393) changed `Savon::SOAPFault` to work
34
+ with generic response Hash keys.
35
+
36
+ * Fix: [#423](https://github.com/savonrb/savon/issues/423) fixes a problem where Wasabi was
37
+ not able to find extension base elements defined in imports it didn't follow.
38
+
1
39
  ### 2.1.0 (2013-02-03)
2
40
 
3
41
  * Feature: [#372](https://github.com/savonrb/savon/pull/372) added global `ssl_cert_key_password` option.
@@ -0,0 +1,46 @@
1
+ # Contribution Guide
2
+
3
+ This page describes how to contribute changes to Savon.
4
+
5
+ Please do not create a pull request without reading this guide first.
6
+ Make sure to read the documentation for your version at [savonrb.com](http://savonrb.com/)
7
+ and post questions to the [mailing list](https://groups.google.com/forum/#!forum/savonrb).
8
+
9
+ **Bug fixes**
10
+
11
+ If you really think you found a bug, please make sure to add as many information as possible
12
+ to the ticket. You're a developer, we are developers and you know we need tests to reproduce
13
+ problems and make sure they don't come back.
14
+
15
+ So if you can reproduce your problem in a spec, that would be awesome! If you can't, please
16
+ let us know how we could make this easier for you. Also, provide code and the WSDL of the
17
+ service your working with so others can try to come up with a spec for your problem.
18
+
19
+ After we have a failing spec, it obviously needs to be fixed. Make sure your new spec is the
20
+ only failing one under the `spec` directory. Travis only runs the "unit tests" at `spec/savon`,
21
+ but Savon actually has with some additional "integration/example specs" at `spec/integration`,
22
+ which you need to run locally to make sure the integration with real world services still works.
23
+
24
+ Notice that these specs are not run by Travis, because the service's are not guaranteed to work
25
+ all the time and the specs will timeout after a few seconds when the service is currently down.
26
+
27
+ Please follow this basic workflow for pull requests:
28
+
29
+ * [Fork the project](https://help.github.com/articles/fork-a-repo)
30
+ * Create a feature branch and make your bug fix
31
+ * Add tests for it!
32
+ * Update the [Changelog](https://github.com/savonrb/savon/blob/master/CHANGELOG.md)
33
+ * [Send a pull request](https://help.github.com/articles/using-pull-requests)
34
+ * [Check that your pull request passes the build](https://travis-ci.org/savonrb/savon/pull_requests)
35
+
36
+
37
+ **Improvements and feature requests**
38
+
39
+ If you have an idea for an improvement or a new feature, please feel free to
40
+ [create a new issue](https://github.com/savonrb/savon/issues/new) and describe your idea
41
+ so that other people can give their insights and opinions. This is also important to avoid
42
+ duplicate work.
43
+
44
+ Pull requests and issues on GitHub are meant to be used to discuss problems and ideas,
45
+ so please make sure to participate and follow up on questions. In case noone comments
46
+ on your ticket, please keep updating the ticket with additional information.
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
  gemspec
3
3
 
4
4
  gem "httpclient", "~> 2.3.0"
data/README.md CHANGED
@@ -1,14 +1,16 @@
1
- Savon [![Build Status](https://secure.travis-ci.org/savonrb/savon.png)](http://travis-ci.org/savonrb/savon)
2
- =====
1
+ # Savon
3
2
 
4
3
  Heavy metal SOAP client
5
4
 
6
5
  [Documentation](http://savonrb.com) | [RDoc](http://rubydoc.info/gems/savon) |
7
6
  [Mailing list](https://groups.google.com/forum/#!forum/savonrb) | [Twitter](http://twitter.com/savonrb)
8
7
 
8
+ [![Build Status](https://secure.travis-ci.org/savonrb/savon.png)](http://travis-ci.org/savonrb/savon)
9
+ [![Gem Version](https://badge.fury.io/rb/savon.png)](http://badge.fury.io/rb/savon)
10
+ [![Code Climate](https://codeclimate.com/github/savonrb/savon.png)](https://codeclimate.com/github/savonrb/savon)
9
11
 
10
- Installation
11
- ------------
12
+
13
+ ## Installation
12
14
 
13
15
  Savon is available through [Rubygems](http://rubygems.org/gems/savon) and can be installed via:
14
16
 
@@ -16,30 +18,40 @@ Savon is available through [Rubygems](http://rubygems.org/gems/savon) and can be
16
18
  $ gem install savon
17
19
  ```
18
20
 
21
+ or add it to your Gemfile like this:
22
+
23
+ ```
24
+ gem 'savon', '~> 2.1.0'
25
+ ```
26
+
19
27
 
20
- Introduction
21
- ------------
28
+ ## Usage example
22
29
 
23
30
  ``` ruby
24
- require "savon"
31
+ require 'savon'
25
32
 
26
- # create a client for your SOAP service
27
- client = Savon.client(wsdl: "http://service.example.com?wsdl")
33
+ # create a client for the service
34
+ client = Savon.client(wsdl: 'http://service.example.com?wsdl')
28
35
 
29
36
  client.operations
30
- # => [:create_user, :get_user, :get_all_users]
37
+ # => [:find_user, :list_users]
31
38
 
32
- # execute a SOAP request to call the "getUser" action
33
- response = client.call(:get_user) do
34
- message(user_id: 1)
35
- end
39
+ # call the 'findUser' operation
40
+ response = client.call(:find_user, message: { id: 42 })
36
41
 
37
42
  response.body
38
- # => { :get_user_response => { :first_name => "The", :last_name => "Hoff" } }
43
+ # => { find_user_response: { id: 42, name: 'Hoff' } }
39
44
  ```
40
45
 
46
+ For more examples, you should check out the [integration tests](https://github.com/savonrb/savon/tree/master/spec/integration).
47
+
48
+
49
+ ## Documentation
50
+
51
+ Please make sure to read the documentation for your version:
41
52
 
42
- Documentation
43
- -------------
53
+ * [Version 2](http://savonrb.com/version2.html)
54
+ * [Version 1](http://savonrb.com)
44
55
 
45
- Continue reading at [savonrb.com](http://savonrb.com)
56
+ And if you find any problems with it or if you think something's missing,
57
+ feel free to [help out and improve the documentation](https://github.com/savonrb/savonrb.com).
@@ -1,8 +1,10 @@
1
1
  module Savon
2
2
 
3
- Error = Class.new(RuntimeError)
4
- InitializationError = Class.new(Error)
5
- InvalidResponseError = Class.new(Error)
3
+ Error = Class.new(RuntimeError)
4
+ InitializationError = Class.new(Error)
5
+ UnknownOptionError = Class.new(Error)
6
+ UnknownOperationError = Class.new(Error)
7
+ InvalidResponseError = Class.new(Error)
6
8
 
7
9
  def self.client(globals = {}, &block)
8
10
  Client.new(globals, &block)
@@ -1,5 +1,6 @@
1
1
  require "savon/header"
2
2
  require "savon/message"
3
+ require "nokogiri"
3
4
  require "builder"
4
5
  require "gyoku"
5
6
 
@@ -27,6 +28,10 @@ module Savon
27
28
  @used_namespaces = convert_type_namespaces_to_hash
28
29
  end
29
30
 
31
+ def pretty
32
+ Nokogiri.XML(to_s).to_xml(:indent => 2)
33
+ end
34
+
30
35
  def to_s
31
36
  return @locals[:xml] if @locals.include? :xml
32
37
 
@@ -72,7 +77,12 @@ module Savon
72
77
  def namespaces
73
78
  @namespaces ||= begin
74
79
  namespaces = SCHEMA_TYPES.dup
75
- namespaces["xmlns:#{namespace_identifier}"] = @globals[:namespace] || @wsdl.namespace
80
+
81
+ if namespace_identifier == nil
82
+ namespaces["xmlns"] = @globals[:namespace] || @wsdl.namespace
83
+ else
84
+ namespaces["xmlns:#{namespace_identifier}"] = @globals[:namespace] || @wsdl.namespace
85
+ end
76
86
 
77
87
  key = ["xmlns"]
78
88
  key << env_namespace if env_namespace && env_namespace != ""
@@ -91,7 +101,9 @@ module Savon
91
101
  end
92
102
 
93
103
  def namespaced_message_tag
94
- if @used_namespaces[[@operation_name.to_s]]
104
+ if namespace_identifier == nil
105
+ [message_tag, message_attributes]
106
+ elsif @used_namespaces[[@operation_name.to_s]]
95
107
  [@used_namespaces[[@operation_name.to_s]], message_tag, message_attributes]
96
108
  else
97
109
  [namespace_identifier, message_tag, message_attributes]
@@ -12,9 +12,7 @@ module Savon
12
12
  raise_version1_initialize_error! globals
13
13
  end
14
14
 
15
- @globals = GlobalOptions.new(globals)
16
-
17
- BlockInterface.new(@globals).evaluate(block) if block
15
+ set_globals(globals, block)
18
16
 
19
17
  unless wsdl_or_endpoint_and_namespace_specified?
20
18
  raise_initialization_error!
@@ -38,14 +36,27 @@ module Savon
38
36
  operation(operation_name).call(locals, &block)
39
37
  end
40
38
 
39
+ def service_name
40
+ raise_missing_wsdl_error! unless @wsdl.document?
41
+ @wsdl.service_name
42
+ end
43
+
41
44
  private
42
45
 
46
+ def set_globals(globals, block)
47
+ globals = GlobalOptions.new(globals)
48
+ BlockInterface.new(globals).evaluate(block) if block
49
+
50
+ @globals = globals
51
+ end
52
+
43
53
  def build_wsdl_document
44
54
  @wsdl = Wasabi::Document.new
45
55
 
46
- @wsdl.document = @globals[:wsdl] if @globals.include? :wsdl
47
- @wsdl.endpoint = @globals[:endpoint] if @globals.include? :endpoint
48
- @wsdl.namespace = @globals[:namespace] if @globals.include? :namespace
56
+ @wsdl.document = @globals[:wsdl] if @globals.include? :wsdl
57
+ @wsdl.endpoint = @globals[:endpoint] if @globals.include? :endpoint
58
+ @wsdl.namespace = @globals[:namespace] if @globals.include? :namespace
59
+ @wsdl.servicename = @globals[:servicename] if @globals.include? :servicename
49
60
 
50
61
  @wsdl.request = WSDLRequest.new(@globals).build
51
62
  end
@@ -20,6 +20,8 @@ module Savon
20
20
 
21
21
  if @element_form_default == :qualified
22
22
  translated_operation_name = Gyoku.xml_tag(@operation_name, :key_converter => @key_converter).to_s
23
+ # XXX: there is no `@request_key_converter` instance variable!
24
+ # the third argument is therefore always `nil`. [dh, 2013-03-09]
23
25
  @message = QualifiedMessage.new(@types, @used_namespaces, @request_key_converter).to_hash(@message, [translated_operation_name])
24
26
  end
25
27
 
@@ -1,5 +1,5 @@
1
1
  module Savon
2
- class ExpectationError < Error; end
2
+ class ExpectationError < StandardError; end
3
3
  end
4
4
 
5
5
  require "savon/mock/expectation"
@@ -19,8 +19,8 @@ module Savon
19
19
 
20
20
  def self.ensure_exists!(operation_name, wsdl)
21
21
  unless wsdl.soap_actions.include? operation_name
22
- raise ArgumentError, "Unable to find SOAP operation: #{operation_name.inspect}\n" \
23
- "Operations provided by your service: #{wsdl.soap_actions.inspect}"
22
+ raise UnknownOperationError, "Unable to find SOAP operation: #{operation_name.inspect}\n" \
23
+ "Operations provided by your service: #{wsdl.soap_actions.inspect}"
24
24
  end
25
25
  end
26
26
 
@@ -37,12 +37,13 @@ module Savon
37
37
  @globals = globals
38
38
  end
39
39
 
40
- def call(locals = {}, &block)
41
- @locals = LocalOptions.new(locals)
42
-
43
- BlockInterface.new(@locals).evaluate(block) if block
40
+ def build(locals = {}, &block)
41
+ set_locals(locals, block)
42
+ Builder.new(@name, @wsdl, @globals, @locals)
43
+ end
44
44
 
45
- builder = Builder.new(@name, @wsdl, @globals, @locals)
45
+ def call(locals = {}, &block)
46
+ builder = build(locals, &block)
46
47
 
47
48
  response = Savon.notify_observers(@name, builder, @globals, @locals)
48
49
  response ||= call! build_request(builder)
@@ -54,6 +55,13 @@ module Savon
54
55
 
55
56
  private
56
57
 
58
+ def set_locals(locals, block)
59
+ locals = LocalOptions.new(locals)
60
+ BlockInterface.new(locals).evaluate(block) if block
61
+
62
+ @locals = locals
63
+ end
64
+
57
65
  def call!(request)
58
66
  log_request(request) if log?
59
67
  response = HTTPI.post(request)
@@ -9,6 +9,8 @@ module Savon
9
9
  assign options
10
10
  end
11
11
 
12
+ attr_reader :option_type
13
+
12
14
  def [](option)
13
15
  @options[option]
14
16
  end
@@ -30,11 +32,17 @@ module Savon
30
32
  end
31
33
  end
32
34
 
35
+ def method_missing(option, _)
36
+ raise UnknownOptionError, "Unknown #{option_type} option: #{option.inspect}"
37
+ end
38
+
33
39
  end
34
40
 
35
41
  class GlobalOptions < Options
36
42
 
37
43
  def initialize(options = {})
44
+ @option_type = :global
45
+
38
46
  defaults = {
39
47
  :encoding => "UTF-8",
40
48
  :soap_version => 1,
@@ -243,6 +251,8 @@ module Savon
243
251
  class LocalOptions < Options
244
252
 
245
253
  def initialize(options = {})
254
+ @option_type = :local
255
+
246
256
  defaults = {
247
257
  :advanced_typecasting => true,
248
258
  :response_parser => :nokogiri
@@ -19,20 +19,28 @@ module Savon
19
19
  attr_reader :http, :nori
20
20
 
21
21
  def to_s
22
- message_by_version to_hash[:fault]
22
+ fault = nori.find(to_hash, 'Fault')
23
+ message_by_version(fault)
23
24
  end
24
25
 
25
26
  def to_hash
26
- nori.parse(@http.body)[:envelope][:body]
27
+ parsed = nori.parse(@http.body)
28
+ nori.find(parsed, 'Envelope', 'Body')
27
29
  end
28
30
 
29
31
  private
30
32
 
31
33
  def message_by_version(fault)
32
- if fault[:faultcode]
33
- "(#{fault[:faultcode]}) #{fault[:faultstring]}"
34
- elsif fault[:code]
35
- "(#{fault[:code][:value]}) #{fault[:reason][:text]}"
34
+ if nori.find(fault, 'faultcode')
35
+ code = nori.find(fault, 'faultcode')
36
+ text = nori.find(fault, 'faultstring')
37
+
38
+ "(#{code}) #{text}"
39
+ elsif nori.find(fault, 'Code')
40
+ code = nori.find(fault, 'Code', 'Value')
41
+ text = nori.find(fault, 'Reason', 'Text')
42
+
43
+ "(#{code}) #{text}"
36
44
  end
37
45
  end
38
46
 
@@ -1,5 +1,5 @@
1
1
  module Savon
2
2
 
3
- VERSION = "2.1.0"
3
+ VERSION = "2.2.0"
4
4
 
5
5
  end
@@ -11,13 +11,13 @@ Gem::Specification.new do |s|
11
11
  s.email = "me@rubiii.com"
12
12
  s.homepage = "http://savonrb.com"
13
13
  s.summary = "Heavy metal SOAP client"
14
- s.description = "Delicious SOAP for the Ruby community"
14
+ s.description = s.summary
15
15
 
16
16
  s.rubyforge_project = s.name
17
17
 
18
- s.add_dependency "nori", "~> 2.0.3"
18
+ s.add_dependency "nori", "~> 2.1.0"
19
19
  s.add_dependency "httpi", "~> 2.0.2"
20
- s.add_dependency "wasabi", "~> 3.0.0"
20
+ s.add_dependency "wasabi", "~> 3.1.0"
21
21
  s.add_dependency "akami", "~> 1.2.0"
22
22
  s.add_dependency "gyoku", "~> 1.0.0"
23
23
 
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_dependency "nokogiri", ">= 1.4.0"
26
26
 
27
27
  s.add_development_dependency "rack"
28
- s.add_development_dependency "puma", ">= 2.0.0.b3"
28
+ s.add_development_dependency "puma", "2.0.0.b4"
29
29
 
30
30
  s.add_development_dependency "rake", "~> 0.9"
31
31
  s.add_development_dependency "rspec", "~> 2.10"
@@ -33,7 +33,7 @@ Gem::Specification.new do |s|
33
33
  s.add_development_dependency "json", "~> 1.7"
34
34
 
35
35
  ignores = File.readlines(".gitignore").grep(/\S+/).map(&:chomp)
36
- dotfiles = %w[.gitignore .rspec .travis.yml .yardopts]
36
+ dotfiles = %w[.gitignore .travis.yml .yardopts]
37
37
 
38
38
  all_files_without_ignores = Dir["**/*"].reject { |f|
39
39
  File.directory?(f) || ignores.any? { |i| File.fnmatch(i, f) }