savon_with_adapter 2.4.1

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.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.travis.yml +11 -0
  4. data/.yardopts +6 -0
  5. data/CHANGELOG.md +1042 -0
  6. data/CONTRIBUTING.md +46 -0
  7. data/Gemfile +18 -0
  8. data/LICENSE +20 -0
  9. data/README.md +81 -0
  10. data/Rakefile +14 -0
  11. data/donate.png +0 -0
  12. data/lib/savon.rb +27 -0
  13. data/lib/savon/block_interface.rb +26 -0
  14. data/lib/savon/builder.rb +166 -0
  15. data/lib/savon/client.rb +89 -0
  16. data/lib/savon/core_ext/string.rb +29 -0
  17. data/lib/savon/header.rb +70 -0
  18. data/lib/savon/http_error.rb +27 -0
  19. data/lib/savon/log_message.rb +48 -0
  20. data/lib/savon/message.rb +35 -0
  21. data/lib/savon/mock.rb +5 -0
  22. data/lib/savon/mock/expectation.rb +71 -0
  23. data/lib/savon/mock/spec_helper.rb +62 -0
  24. data/lib/savon/model.rb +80 -0
  25. data/lib/savon/operation.rb +127 -0
  26. data/lib/savon/options.rb +336 -0
  27. data/lib/savon/qualified_message.rb +49 -0
  28. data/lib/savon/request.rb +89 -0
  29. data/lib/savon/request_logger.rb +48 -0
  30. data/lib/savon/response.rb +112 -0
  31. data/lib/savon/soap_fault.rb +48 -0
  32. data/lib/savon/version.rb +3 -0
  33. data/savon.gemspec +52 -0
  34. data/spec/fixtures/gzip/message.gz +0 -0
  35. data/spec/fixtures/response/another_soap_fault.xml +14 -0
  36. data/spec/fixtures/response/authentication.xml +14 -0
  37. data/spec/fixtures/response/header.xml +13 -0
  38. data/spec/fixtures/response/list.xml +18 -0
  39. data/spec/fixtures/response/multi_ref.xml +39 -0
  40. data/spec/fixtures/response/soap_fault.xml +8 -0
  41. data/spec/fixtures/response/soap_fault12.xml +18 -0
  42. data/spec/fixtures/response/taxcloud.xml +1 -0
  43. data/spec/fixtures/ssl/client_cert.pem +16 -0
  44. data/spec/fixtures/ssl/client_encrypted_key.pem +30 -0
  45. data/spec/fixtures/ssl/client_encrypted_key_cert.pem +24 -0
  46. data/spec/fixtures/ssl/client_key.pem +15 -0
  47. data/spec/fixtures/wsdl/authentication.xml +63 -0
  48. data/spec/fixtures/wsdl/betfair.xml +2981 -0
  49. data/spec/fixtures/wsdl/edialog.xml +15416 -0
  50. data/spec/fixtures/wsdl/interhome.xml +2137 -0
  51. data/spec/fixtures/wsdl/lower_camel.xml +52 -0
  52. data/spec/fixtures/wsdl/multiple_namespaces.xml +92 -0
  53. data/spec/fixtures/wsdl/multiple_types.xml +60 -0
  54. data/spec/fixtures/wsdl/taxcloud.xml +934 -0
  55. data/spec/fixtures/wsdl/team_software.xml +1 -0
  56. data/spec/fixtures/wsdl/vies.xml +176 -0
  57. data/spec/fixtures/wsdl/wasmuth.xml +153 -0
  58. data/spec/integration/centra_spec.rb +72 -0
  59. data/spec/integration/email_example_spec.rb +32 -0
  60. data/spec/integration/random_quote_spec.rb +23 -0
  61. data/spec/integration/ratp_example_spec.rb +28 -0
  62. data/spec/integration/stockquote_example_spec.rb +28 -0
  63. data/spec/integration/support/application.rb +82 -0
  64. data/spec/integration/support/server.rb +84 -0
  65. data/spec/integration/temperature_example_spec.rb +46 -0
  66. data/spec/integration/zipcode_example_spec.rb +42 -0
  67. data/spec/savon/builder_spec.rb +86 -0
  68. data/spec/savon/client_spec.rb +198 -0
  69. data/spec/savon/core_ext/string_spec.rb +37 -0
  70. data/spec/savon/features/message_tag_spec.rb +61 -0
  71. data/spec/savon/http_error_spec.rb +49 -0
  72. data/spec/savon/log_message_spec.rb +33 -0
  73. data/spec/savon/message_spec.rb +40 -0
  74. data/spec/savon/mock_spec.rb +157 -0
  75. data/spec/savon/model_spec.rb +154 -0
  76. data/spec/savon/observers_spec.rb +92 -0
  77. data/spec/savon/operation_spec.rb +211 -0
  78. data/spec/savon/options_spec.rb +772 -0
  79. data/spec/savon/request_spec.rb +493 -0
  80. data/spec/savon/response_spec.rb +258 -0
  81. data/spec/savon/soap_fault_spec.rb +126 -0
  82. data/spec/spec_helper.rb +30 -0
  83. data/spec/support/endpoint.rb +25 -0
  84. data/spec/support/fixture.rb +39 -0
  85. data/spec/support/integration.rb +9 -0
  86. data/spec/support/stdout.rb +25 -0
  87. metadata +310 -0
@@ -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 you're 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 ADDED
@@ -0,0 +1,18 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem "httpclient", "~> 2.3.4"
5
+
6
+ gem "simplecov", :require => false
7
+ gem "coveralls", :require => false
8
+
9
+ platform :rbx do
10
+ gem 'json'
11
+ gem 'racc'
12
+ gem 'rubysl'
13
+ gem 'rubinius-coverage'
14
+ end
15
+
16
+ platform :jruby do
17
+ gem 'json'
18
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Daniel Harrington
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,81 @@
1
+ # Savon
2
+
3
+ Heavy metal SOAP client
4
+
5
+ [Documentation](http://savonrb.com) | [RDoc](http://rubydoc.info/gems/savon) |
6
+ [Mailing list](https://groups.google.com/forum/#!forum/savonrb) | [Twitter](http://twitter.com/savonrb)
7
+
8
+ [![Build Status](https://secure.travis-ci.org/savonrb/savon.png?branch=version2)](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)
11
+ [![Coverage Status](https://coveralls.io/repos/savonrb/savon/badge.png?branch=version2)](https://coveralls.io/r/savonrb/savon)
12
+
13
+
14
+ ## Version 2
15
+
16
+ Savon version 2 is available through [Rubygems](http://rubygems.org/gems/savon) and can be installed via:
17
+
18
+ ```
19
+ $ gem install savon
20
+ ```
21
+
22
+ or add it to your Gemfile like this:
23
+
24
+ ```
25
+ gem 'savon', '~> 2.3.0'
26
+ ```
27
+
28
+
29
+ ## Maintainer needed
30
+
31
+ So I've been maintaining Savon and its dependant projects for the last four years and it's become quite
32
+ apparent now with my schedule I do not have the time to keep this project going single-handed.
33
+
34
+ Luckily there are numerous people helping out from time to time, but maintaining this project is pretty
35
+ much a full-time job and it keeps me from working on the next major version.
36
+
37
+ I'll be able to contribute on a small scale going forward, and will do my best in the meantime to catch
38
+ up with everything I am behind on.
39
+
40
+ If you are interested, please email me at [me at rubiii dot com].
41
+ I'll do everything I can to help you get started.
42
+
43
+
44
+ ## Usage example
45
+
46
+ ``` ruby
47
+ require 'savon'
48
+
49
+ # create a client for the service
50
+ client = Savon.client(wsdl: 'http://service.example.com?wsdl')
51
+
52
+ client.operations
53
+ # => [:find_user, :list_users]
54
+
55
+ # call the 'findUser' operation
56
+ response = client.call(:find_user, message: { id: 42 })
57
+
58
+ response.body
59
+ # => { find_user_response: { id: 42, name: 'Hoff' } }
60
+ ```
61
+
62
+ For more examples, you should check out the
63
+ [integration tests](https://github.com/savonrb/savon/tree/version2/spec/integration).
64
+
65
+
66
+ ## Give back
67
+
68
+ If you're using Savon and you or your company is making money from it, then please consider
69
+ donating via [Gittip](https://www.gittip.com/rubiii/) so that I can continue to improve it.
70
+
71
+ [![donate](donate.png)](https://www.gittip.com/rubiii/)
72
+
73
+
74
+ ## Documentation
75
+
76
+ Please make sure to [read the documentation](http://savonrb.com/version2/).
77
+
78
+ And if you find any problems with it or if you think something's missing,
79
+ feel free to [help out and improve the documentation](https://github.com/savonrb/savonrb.com).
80
+
81
+ Donate icon from the [Noun Project](http://thenounproject.com/noun/donate/#icon-No285).
@@ -0,0 +1,14 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new do |t|
5
+ t.pattern = "spec/savon/**/*_spec.rb"
6
+ end
7
+
8
+ desc "Run RSpec integration examples"
9
+ RSpec::Core::RakeTask.new "spec:integration" do |t|
10
+ t.pattern = "spec/integration/**/*_spec.rb"
11
+ end
12
+
13
+ task :default => :spec
14
+ task :test => :spec
Binary file
@@ -0,0 +1,27 @@
1
+ module Savon
2
+
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)
8
+
9
+ def self.client(globals = {}, &block)
10
+ Client.new(globals, &block)
11
+ end
12
+
13
+ def self.observers
14
+ @observers ||= []
15
+ end
16
+
17
+ def self.notify_observers(operation_name, builder, globals, locals)
18
+ observers.inject(nil) do |response, observer|
19
+ observer.notify(operation_name, builder, globals, locals)
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ require "savon/version"
26
+ require "savon/client"
27
+ require "savon/model"
@@ -0,0 +1,26 @@
1
+ module Savon
2
+ class BlockInterface
3
+
4
+ def initialize(target)
5
+ @target = target
6
+ end
7
+
8
+ def evaluate(block)
9
+ if block.arity > 0
10
+ block.call(@target)
11
+ else
12
+ @original = eval("self", block.binding)
13
+ instance_eval(&block)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def method_missing(method, *args, &block)
20
+ @target.send(method, *args, &block)
21
+ rescue NoMethodError
22
+ @original.send(method, *args, &block)
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,166 @@
1
+ require "savon/header"
2
+ require "savon/message"
3
+ require "nokogiri"
4
+ require "builder"
5
+ require "gyoku"
6
+
7
+ module Savon
8
+ class Builder
9
+
10
+ SCHEMA_TYPES = {
11
+ "xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
12
+ "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance"
13
+ }
14
+
15
+ SOAP_NAMESPACE = {
16
+ 1 => "http://schemas.xmlsoap.org/soap/envelope/",
17
+ 2 => "http://www.w3.org/2003/05/soap-envelope"
18
+ }
19
+
20
+ def initialize(operation_name, wsdl, globals, locals)
21
+ @operation_name = operation_name
22
+
23
+ @wsdl = wsdl
24
+ @globals = globals
25
+ @locals = locals
26
+
27
+ @types = convert_type_definitions_to_hash
28
+ @used_namespaces = convert_type_namespaces_to_hash
29
+ end
30
+
31
+ def pretty
32
+ Nokogiri.XML(to_s).to_xml(:indent => 2)
33
+ end
34
+
35
+ def to_s
36
+ return @locals[:xml] if @locals.include? :xml
37
+
38
+ tag(builder, :Envelope, namespaces_with_globals) do |xml|
39
+ tag(xml, :Header) { xml << header.to_s } unless header.empty?
40
+ tag(xml, :Body) { xml.tag!(*namespaced_message_tag) { xml << message.to_s } }
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def convert_type_definitions_to_hash
47
+ @wsdl.type_definitions.inject({}) do |memo, (path, type)|
48
+ memo[path] = type
49
+ memo
50
+ end
51
+ end
52
+
53
+ def convert_type_namespaces_to_hash
54
+ @wsdl.type_namespaces.inject({}) do |memo, (path, uri)|
55
+ key, value = use_namespace(path, uri)
56
+ memo[key] = value
57
+ memo
58
+ end
59
+ end
60
+
61
+ def use_namespace(path, uri)
62
+ @internal_namespace_count ||= 0
63
+
64
+ unless identifier = namespace_by_uri(uri)
65
+ identifier = "ins#{@internal_namespace_count}"
66
+ namespaces["xmlns:#{identifier}"] = uri
67
+ @internal_namespace_count += 1
68
+ end
69
+
70
+ [path, identifier]
71
+ end
72
+
73
+ def namespaces_with_globals
74
+ namespaces.merge @globals[:namespaces]
75
+ end
76
+
77
+ def namespaces
78
+ @namespaces ||= begin
79
+ namespaces = SCHEMA_TYPES.dup
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
86
+
87
+ key = ["xmlns"]
88
+ key << env_namespace if env_namespace && env_namespace != ""
89
+ namespaces[key.join(":")] = SOAP_NAMESPACE[@globals[:soap_version]]
90
+
91
+ namespaces
92
+ end
93
+ end
94
+
95
+ def env_namespace
96
+ @env_namespace ||= @globals[:env_namespace] || :env
97
+ end
98
+
99
+ def header
100
+ @header ||= Header.new(@globals, @locals)
101
+ end
102
+
103
+ def namespaced_message_tag
104
+ tag_name = message_tag
105
+ if namespace_identifier == nil
106
+ [tag_name, message_attributes]
107
+ elsif @used_namespaces[[tag_name.to_s]]
108
+ [@used_namespaces[[tag_name.to_s]], tag_name, message_attributes]
109
+ else
110
+ [namespace_identifier, tag_name, message_attributes]
111
+ end
112
+ end
113
+
114
+ def message_tag
115
+ message_tag = @locals[:message_tag]
116
+ message_tag ||= @wsdl.soap_input(@operation_name.to_sym) if @wsdl.document?
117
+ message_tag ||= Gyoku.xml_tag(@operation_name, :key_converter => @globals[:convert_request_keys_to])
118
+
119
+ @message_tag = message_tag.to_sym
120
+ end
121
+
122
+ def message_attributes
123
+ @locals[:attributes] || {}
124
+ end
125
+
126
+ def message
127
+ element_form_default = @globals[:element_form_default] || @wsdl.element_form_default
128
+ # TODO: clean this up! [dh, 2012-12-17]
129
+ Message.new(message_tag, namespace_identifier, @types, @used_namespaces, @locals[:message],
130
+ element_form_default, @globals[:convert_request_keys_to])
131
+ end
132
+
133
+ def namespace_identifier
134
+ return @globals[:namespace_identifier] if @globals.include? :namespace_identifier
135
+ return @namespace_identifier if @namespace_identifier
136
+
137
+ operation = @wsdl.operations[@operation_name] if @wsdl.document?
138
+ namespace_identifier = operation[:namespace_identifier] if operation
139
+ namespace_identifier ||= "wsdl"
140
+
141
+ @namespace_identifier = namespace_identifier.to_sym
142
+ end
143
+
144
+ def namespace_by_uri(uri)
145
+ namespaces.each do |candidate_identifier, candidate_uri|
146
+ return candidate_identifier.gsub(/^xmlns:/, '') if candidate_uri == uri
147
+ end
148
+ nil
149
+ end
150
+
151
+ def builder
152
+ builder = ::Builder::XmlMarkup.new
153
+ builder.instruct!(:xml, :encoding => @globals[:encoding])
154
+ builder
155
+ end
156
+
157
+ def tag(xml, name, namespaces = {}, &block)
158
+ if env_namespace && env_namespace != ""
159
+ xml.tag! env_namespace, name, namespaces, &block
160
+ else
161
+ xml.tag! name, namespaces, &block
162
+ end
163
+ end
164
+
165
+ end
166
+ end
@@ -0,0 +1,89 @@
1
+ require "savon/operation"
2
+ require "savon/request"
3
+ require "savon/options"
4
+ require "savon/block_interface"
5
+ require "wasabi"
6
+
7
+ module Savon
8
+ class Client
9
+
10
+ def initialize(globals = {}, &block)
11
+ unless globals.kind_of? Hash
12
+ raise_version1_initialize_error! globals
13
+ end
14
+
15
+ set_globals(globals, block)
16
+
17
+ unless wsdl_or_endpoint_and_namespace_specified?
18
+ raise_initialization_error!
19
+ end
20
+
21
+ build_wsdl_document
22
+ end
23
+
24
+ attr_reader :globals
25
+
26
+ def operations
27
+ raise_missing_wsdl_error! unless @wsdl.document?
28
+ @wsdl.soap_actions
29
+ end
30
+
31
+ def operation(operation_name)
32
+ Operation.create(operation_name, @wsdl, @globals)
33
+ end
34
+
35
+ def call(operation_name, locals = {}, &block)
36
+ operation(operation_name).call(locals, &block)
37
+ end
38
+
39
+ def service_name
40
+ raise_missing_wsdl_error! unless @wsdl.document?
41
+ @wsdl.service_name
42
+ end
43
+
44
+ private
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
+
53
+ def build_wsdl_document
54
+ @wsdl = Wasabi::Document.new
55
+
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
60
+ @wsdl.adapter = @globals[:adapter] if @globals.include? :adapter
61
+
62
+ @wsdl.request = WSDLRequest.new(@globals).build
63
+ end
64
+
65
+ def wsdl_or_endpoint_and_namespace_specified?
66
+ @globals.include?(:wsdl) || (@globals.include?(:endpoint) && @globals.include?(:namespace))
67
+ end
68
+
69
+ def raise_version1_initialize_error!(object)
70
+ raise InitializationError,
71
+ "Some code tries to initialize Savon with the #{object.inspect} (#{object.class}) \n" \
72
+ "Savon 2 expects a Hash of options for creating a new client and executing requests.\n" \
73
+ "Please read the updated documentation for version 2: http://savonrb.com/version2.html"
74
+ end
75
+
76
+ def raise_initialization_error!
77
+ raise InitializationError,
78
+ "Expected either a WSDL document or the SOAP endpoint and target namespace options.\n\n" \
79
+ "Savon.client(wsdl: '/Users/me/project/service.wsdl') # to use a local WSDL document\n" \
80
+ "Savon.client(wsdl: 'http://example.com?wsdl') # to use a remote WSDL document\n" \
81
+ "Savon.client(endpoint: 'http://example.com', namespace: 'http://v1.example.com') # if you don't have a WSDL document"
82
+ end
83
+
84
+ def raise_missing_wsdl_error!
85
+ raise "Unable to inspect the service without a WSDL document."
86
+ end
87
+
88
+ end
89
+ end