regenersis-savon 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/.gitignore +10 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +12 -0
  4. data/CHANGELOG.md +639 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +20 -0
  7. data/README.md +42 -0
  8. data/Rakefile +7 -0
  9. data/lib/regenersis-savon.rb +1 -0
  10. data/lib/savon.rb +15 -0
  11. data/lib/savon/client.rb +168 -0
  12. data/lib/savon/core_ext/object.rb +14 -0
  13. data/lib/savon/core_ext/string.rb +23 -0
  14. data/lib/savon/error.rb +6 -0
  15. data/lib/savon/global.rb +115 -0
  16. data/lib/savon/hooks/group.rb +46 -0
  17. data/lib/savon/hooks/hook.rb +36 -0
  18. data/lib/savon/http/error.rb +42 -0
  19. data/lib/savon/model.rb +103 -0
  20. data/lib/savon/soap.rb +21 -0
  21. data/lib/savon/soap/fault.rb +59 -0
  22. data/lib/savon/soap/request.rb +71 -0
  23. data/lib/savon/soap/response.rb +109 -0
  24. data/lib/savon/soap/xml.rb +227 -0
  25. data/lib/savon/version.rb +5 -0
  26. data/lib/savon/wasabi/document.rb +41 -0
  27. data/regenersis-savon.gemspec +35 -0
  28. data/spec/fixtures/gzip/message.gz +0 -0
  29. data/spec/fixtures/response/another_soap_fault.xml +14 -0
  30. data/spec/fixtures/response/authentication.xml +14 -0
  31. data/spec/fixtures/response/header.xml +13 -0
  32. data/spec/fixtures/response/list.xml +18 -0
  33. data/spec/fixtures/response/multi_ref.xml +39 -0
  34. data/spec/fixtures/response/soap_fault.xml +8 -0
  35. data/spec/fixtures/response/soap_fault12.xml +18 -0
  36. data/spec/fixtures/response/taxcloud.xml +1 -0
  37. data/spec/fixtures/wsdl/authentication.xml +63 -0
  38. data/spec/fixtures/wsdl/lower_camel.xml +52 -0
  39. data/spec/fixtures/wsdl/multiple_namespaces.xml +61 -0
  40. data/spec/fixtures/wsdl/multiple_types.xml +60 -0
  41. data/spec/fixtures/wsdl/taxcloud.xml +934 -0
  42. data/spec/savon/client_spec.rb +461 -0
  43. data/spec/savon/core_ext/object_spec.rb +19 -0
  44. data/spec/savon/core_ext/string_spec.rb +37 -0
  45. data/spec/savon/http/error_spec.rb +52 -0
  46. data/spec/savon/model_spec.rb +194 -0
  47. data/spec/savon/savon_spec.rb +85 -0
  48. data/spec/savon/soap/fault_spec.rb +89 -0
  49. data/spec/savon/soap/request_spec.rb +57 -0
  50. data/spec/savon/soap/response_spec.rb +224 -0
  51. data/spec/savon/soap/xml_spec.rb +309 -0
  52. data/spec/savon/soap_spec.rb +16 -0
  53. data/spec/savon/wasabi/document_spec.rb +45 -0
  54. data/spec/spec_helper.rb +15 -0
  55. data/spec/support/endpoint.rb +25 -0
  56. data/spec/support/fixture.rb +35 -0
  57. metadata +323 -0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+ gemspec
3
+
4
+ gem "httpclient", "~> 2.1.5"
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,42 @@
1
+ Savon [![Build Status](https://secure.travis-ci.org/rubiii/savon.png)](http://travis-ci.org/rubiii/savon)
2
+ =====
3
+
4
+ Heavy metal Ruby SOAP client
5
+
6
+ [Documentation](http://savonrb.com) | [RDoc](http://rubydoc.info/gems/savon) |
7
+ [Mailing list](https://groups.google.com/forum/#!forum/savonrb) | [Twitter](http://twitter.com/savonrb)
8
+
9
+ Installation
10
+ ------------
11
+
12
+ Savon is available through [Rubygems](http://rubygems.org/gems/savon) and can be installed via:
13
+
14
+ ```
15
+ $ gem install savon
16
+ ```
17
+
18
+ Introduction
19
+ ------------
20
+
21
+ ``` ruby
22
+ require "savon"
23
+
24
+ # create a client for your SOAP service
25
+ client = Savon::Client.new("http://service.example.com?wsdl")
26
+
27
+ client.wsdl.soap_actions
28
+ # => [:create_user, :get_user, :get_all_users]
29
+
30
+ # execute a SOAP request to call the "getUser" action
31
+ response = client.request(:get_user) do
32
+ soap.body = { :id => 1 }
33
+ end
34
+
35
+ response.body
36
+ # => { :get_user_response => { :first_name => "The", :last_name => "Hoff" } }
37
+ ```
38
+
39
+ Documentation
40
+ -------------
41
+
42
+ Continue reading at [savonrb.com](http://savonrb.com)
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
7
+ task :test => :spec
@@ -0,0 +1 @@
1
+ require "savon"
@@ -0,0 +1,15 @@
1
+ require "savon/version"
2
+ require "savon/global"
3
+ require "savon/client"
4
+ require "savon/model"
5
+
6
+ module Savon
7
+ extend Global
8
+
9
+ # Yields this module to a given +block+. Please refer to the
10
+ # <tt>Savon::Global</tt> module for configuration options.
11
+ def self.configure
12
+ yield self if block_given?
13
+ end
14
+
15
+ end
@@ -0,0 +1,168 @@
1
+ require "httpi/request"
2
+ require "akami"
3
+
4
+ require "savon/wasabi/document"
5
+ require "savon/soap/xml"
6
+ require "savon/soap/request"
7
+ require "savon/soap/response"
8
+
9
+ module Savon
10
+
11
+ # = Savon::Client
12
+ #
13
+ # Savon::Client is the main object for connecting to a SOAP service.
14
+ class Client
15
+
16
+ # Initializes the Savon::Client for a SOAP service. Accepts a +block+ which is evaluated in the
17
+ # context of this object to let you access the +wsdl+, +http+, and +wsse+ methods.
18
+ #
19
+ # == Examples
20
+ #
21
+ # # Using a remote WSDL
22
+ # client = Savon::Client.new("http://example.com/UserService?wsdl")
23
+ #
24
+ # # Using a local WSDL
25
+ # client = Savon::Client.new File.expand_path("../wsdl/service.xml", __FILE__)
26
+ #
27
+ # # Directly accessing a SOAP endpoint
28
+ # client = Savon::Client.new do
29
+ # wsdl.endpoint = "http://example.com/UserService"
30
+ # wsdl.namespace = "http://users.example.com"
31
+ # end
32
+ def initialize(wsdl_document = nil, &block)
33
+ wsdl.document = wsdl_document if wsdl_document
34
+ process 1, &block if block
35
+ wsdl.request = http
36
+ end
37
+
38
+ # Returns the <tt>Savon::Wasabi::Document</tt>.
39
+ def wsdl
40
+ @wsdl ||= Wasabi::Document.new
41
+ end
42
+
43
+ # Returns the <tt>HTTPI::Request</tt>.
44
+ def http
45
+ @http ||= HTTPI::Request.new
46
+ end
47
+
48
+ # Returns the <tt>Akami::WSSE</tt> object.
49
+ def wsse
50
+ @wsse ||= Akami.wsse
51
+ end
52
+
53
+ # Returns the <tt>Savon::SOAP::XML</tt> object. Please notice, that this object is only available
54
+ # in a block given to <tt>Savon::Client#request</tt>. A new instance of this object is created
55
+ # per SOAP request.
56
+ attr_reader :soap
57
+
58
+ # Executes a SOAP request for a given SOAP action. Accepts a +block+ which is evaluated in the
59
+ # context of this object to let you access the +soap+, +wsdl+, +http+ and +wsse+ methods.
60
+ #
61
+ # == Examples
62
+ #
63
+ # # Calls a "getUser" SOAP action with the payload of "<userId>123</userId>"
64
+ # client.request(:get_user) { soap.body = { :user_id => 123 } }
65
+ #
66
+ # # Prefixes the SOAP input tag with a given namespace: "<wsdl:GetUser>...</wsdl:GetUser>"
67
+ # client.request(:wsdl, "GetUser") { soap.body = { :user_id => 123 } }
68
+ #
69
+ # # SOAP input tag with attributes: <getUser xmlns:wsdl="http://example.com">...</getUser>"
70
+ # client.request(:get_user, "xmlns:wsdl" => "http://example.com")
71
+ def request(*args, &block)
72
+ raise ArgumentError, "Savon::Client#request requires at least one argument" if args.empty?
73
+
74
+ self.soap = SOAP::XML.new
75
+ preconfigure extract_options(args)
76
+ process &block if block
77
+ soap.wsse = wsse
78
+
79
+ response = SOAP::Request.new(http, soap).response
80
+ set_cookie response.http.headers
81
+ response
82
+ end
83
+
84
+ private
85
+
86
+ # Writer for the <tt>Savon::SOAP::XML</tt> object.
87
+ attr_writer :soap
88
+
89
+ # Accessor for the original self of a given block.
90
+ attr_accessor :original_self
91
+
92
+ # Passes a cookie from the last request +headers+ to the next one.
93
+ def set_cookie(headers)
94
+ http.headers["Cookie"] = headers["Set-Cookie"] if headers["Set-Cookie"]
95
+ end
96
+
97
+ # Expects an Array of +args+ and returns an Array containing the namespace (might be +nil+),
98
+ # the SOAP input and a Hash of attributes for the input tag (which might be empty).
99
+ def extract_options(args)
100
+ attributes = Hash === args.last ? args.pop : {}
101
+ namespace = args.size > 1 ? args.shift.to_sym : nil
102
+ input = args.first
103
+
104
+ [namespace, input, attributes]
105
+ end
106
+
107
+ # Expects an Array of +args+ to preconfigure the system.
108
+ def preconfigure(args)
109
+ soap.endpoint = wsdl.endpoint
110
+ soap.namespace_identifier = args[0]
111
+ soap.namespace = wsdl.namespace
112
+ soap.element_form_default = wsdl.element_form_default if wsdl.document?
113
+
114
+ body = args[2].delete(:body)
115
+ soap.body = body if body
116
+
117
+ wsdl.type_namespaces.each do |path, uri|
118
+ soap.use_namespace(path, uri)
119
+ end
120
+
121
+ wsdl.type_definitions.each do |path, type|
122
+ soap.types[path] = type
123
+ end
124
+
125
+ set_soap_action args[1]
126
+ set_soap_input *args
127
+ end
128
+
129
+ # Expects an +input+ and sets the +SOAPAction+ HTTP headers.
130
+ def set_soap_action(input_tag)
131
+ soap_action = wsdl.soap_action(input_tag.to_sym) if wsdl.document?
132
+ soap_action ||= Gyoku::XMLKey.create(input_tag).to_sym
133
+ http.headers["SOAPAction"] = %{"#{soap_action}"}
134
+ end
135
+
136
+ # Expects a +namespace+, +input+ and +attributes+ and sets the SOAP input.
137
+ def set_soap_input(namespace, input, attributes)
138
+ new_input_tag = wsdl.soap_input(input.to_sym) if wsdl.document?
139
+ new_input_tag ||= Gyoku::XMLKey.create(input)
140
+ soap.input = [namespace, new_input_tag.to_sym, attributes]
141
+ end
142
+
143
+ # Processes a given +block+. Yields objects if the block expects any arguments.
144
+ # Otherwise evaluates the block in the context of this object.
145
+ def process(offset = 0, &block)
146
+ block.arity > 0 ? yield_objects(offset, &block) : evaluate(&block)
147
+ end
148
+
149
+ # Yields a number of objects to a given +block+ depending on how many arguments
150
+ # the block is expecting.
151
+ def yield_objects(offset, &block)
152
+ yield *[soap, wsdl, http, wsse][offset, block.arity]
153
+ end
154
+
155
+ # Evaluates a given +block+ inside this object. Stores the original block binding.
156
+ def evaluate(&block)
157
+ self.original_self = eval "self", block.binding
158
+ instance_eval &block
159
+ end
160
+
161
+ # Handles calls to undefined methods by delegating to the original block binding.
162
+ def method_missing(method, *args, &block)
163
+ super unless original_self
164
+ original_self.send method, *args, &block
165
+ end
166
+
167
+ end
168
+ end
@@ -0,0 +1,14 @@
1
+ module Savon
2
+ module CoreExt
3
+ module Object
4
+
5
+ # Returns +true+ if the Object is nil, false or empty. Implementation from ActiveSupport.
6
+ def blank?
7
+ respond_to?(:empty?) ? empty? : !self
8
+ end unless method_defined?(:blank?)
9
+
10
+ end
11
+ end
12
+ end
13
+
14
+ Object.send :include, Savon::CoreExt::Object
@@ -0,0 +1,23 @@
1
+ require "savon/soap"
2
+
3
+ module Savon
4
+ module CoreExt
5
+ module String
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)
18
+
19
+ end
20
+ end
21
+ end
22
+
23
+ String.send :include, Savon::CoreExt::String
@@ -0,0 +1,6 @@
1
+ module Savon
2
+
3
+ # Base class for Savon errors.
4
+ class Error < RuntimeError; end
5
+
6
+ end
@@ -0,0 +1,115 @@
1
+ require "logger"
2
+ require "savon/soap"
3
+ require "savon/hooks/group"
4
+
5
+ module Savon
6
+ module Global
7
+
8
+ # Sets whether to log HTTP requests.
9
+ attr_writer :log
10
+
11
+ # Returns whether to log HTTP requests. Defaults to +true+.
12
+ def log?
13
+ @log != false
14
+ end
15
+
16
+ # Sets the logger to use.
17
+ attr_writer :logger
18
+
19
+ # Returns the logger. Defaults to an instance of +Logger+ writing to STDOUT.
20
+ def logger
21
+ @logger ||= ::Logger.new STDOUT
22
+ end
23
+
24
+ # Sets the log level.
25
+ attr_writer :log_level
26
+
27
+ # Returns the log level. Defaults to :debug.
28
+ def log_level
29
+ @log_level ||= :debug
30
+ end
31
+
32
+ # Logs a given +message+.
33
+ def log(message)
34
+ logger.send log_level, message if log?
35
+ end
36
+
37
+ # Sets whether to raise HTTP errors and SOAP faults.
38
+ attr_writer :raise_errors
39
+
40
+ # Returns whether to raise errors. Defaults to +true+.
41
+ def raise_errors?
42
+ @raise_errors != false
43
+ end
44
+
45
+ # Sets the global SOAP version.
46
+ def soap_version=(version)
47
+ raise ArgumentError, "Invalid SOAP version: #{version}" unless SOAP::Versions.include? version
48
+ @version = version
49
+ end
50
+
51
+ # Returns SOAP version. Defaults to +DefaultVersion+.
52
+ def soap_version
53
+ @version ||= SOAP::DefaultVersion
54
+ end
55
+
56
+ # Returns whether to strip namespaces in a SOAP response Hash.
57
+ # Defaults to +true+.
58
+ def strip_namespaces?
59
+ Savon.deprecate("use Nori.strip_namespaces? instead of Savon.strip_namespaces?")
60
+ Nori.strip_namespaces?
61
+ end
62
+
63
+ # Sets whether to strip namespaces in a SOAP response Hash.
64
+ def strip_namespaces=(strip)
65
+ Savon.deprecate("use Nori.strip_namespaces= instead of Savon.strip_namespaces=")
66
+ Nori.strip_namespaces = strip
67
+ end
68
+
69
+ # Returns the global env_namespace.
70
+ attr_reader :env_namespace
71
+
72
+ # Sets the global env_namespace.
73
+ attr_writer :env_namespace
74
+
75
+ # Returns the global soap_header.
76
+ attr_reader :soap_header
77
+
78
+ # Sets the global soap_header.
79
+ attr_writer :soap_header
80
+
81
+ # Expects a +message+ and raises a warning if configured.
82
+ def deprecate(message)
83
+ warn("Deprecation: #{message}") if deprecate?
84
+ end
85
+
86
+ # Sets whether to warn about deprecations.
87
+ def deprecate=(deprecate)
88
+ @deprecate = deprecate
89
+ end
90
+
91
+ # Returns whether to warn about deprecation.
92
+ def deprecate?
93
+ @deprecate != false
94
+ end
95
+
96
+ # Returns the hooks.
97
+ def hooks
98
+ @hooks ||= Hooks::Group.new
99
+ end
100
+
101
+ # Reset to default configuration.
102
+ def reset_config!
103
+ self.log = true
104
+ self.logger = ::Logger.new STDOUT
105
+ self.log_level = :debug
106
+ self.raise_errors = true
107
+ self.soap_version = SOAP::DefaultVersion
108
+ self.strip_namespaces = true
109
+ self.env_namespace = nil
110
+ self.soap_header = {}
111
+ end
112
+
113
+ end
114
+ end
115
+
@@ -0,0 +1,46 @@
1
+ require "savon/hooks/hook"
2
+
3
+ module Savon
4
+ module Hooks
5
+
6
+ # = Savon::Hooks::Group
7
+ #
8
+ # Manages a list of hooks.
9
+ class Group
10
+
11
+ # Accepts an Array of +hooks+ to start with.
12
+ def initialize(hooks = nil)
13
+ self.hooks = hooks
14
+ end
15
+
16
+ attr_writer :hooks
17
+
18
+ def hooks
19
+ @hooks ||= []
20
+ end
21
+
22
+ # Adds a new hook.
23
+ def define(id, hook, &block)
24
+ hooks << Hook.new(id, hook, &block)
25
+ end
26
+
27
+ # Removes hooks matching the given +ids+.
28
+ def reject!(*ids)
29
+ ids = ids.flatten
30
+ hooks.reject! { |hook| ids.include? hook.id }
31
+ end
32
+
33
+ # Returns a new group for a given +hook+.
34
+ def select(hook)
35
+ Group.new hooks.select { |h| h.hook == hook }
36
+ end
37
+
38
+ # Calls the hooks with the given +args+ and returns the
39
+ # value of the last hooks.
40
+ def call(*args)
41
+ hooks.inject(nil) { |memo, hook| hook.call(*args) }
42
+ end
43
+
44
+ end
45
+ end
46
+ end