soaspec 0.2.23 → 0.2.24

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -15
  3. data/.gitlab-ci.yml +33 -33
  4. data/.rspec +3 -3
  5. data/.rubocop.yml +2 -2
  6. data/CODE_OF_CONDUCT.md +74 -74
  7. data/ChangeLog +577 -573
  8. data/Gemfile +6 -6
  9. data/LICENSE.txt +21 -21
  10. data/README.md +230 -230
  11. data/Rakefile +42 -42
  12. data/Todo.md +15 -15
  13. data/exe/soaspec +123 -123
  14. data/exe/xml_to_yaml_file +42 -42
  15. data/lib/soaspec.rb +101 -101
  16. data/lib/soaspec/core_ext/hash.rb +35 -35
  17. data/lib/soaspec/cucumber/generic_steps.rb +85 -85
  18. data/lib/soaspec/demo.rb +4 -4
  19. data/lib/soaspec/exchange/exchange.rb +111 -111
  20. data/lib/soaspec/exchange/exchange_extractor.rb +83 -83
  21. data/lib/soaspec/exchange/exchange_properties.rb +26 -26
  22. data/lib/soaspec/exchange/exchange_repeater.rb +19 -19
  23. data/lib/soaspec/exchange/request_builder.rb +68 -68
  24. data/lib/soaspec/exchange/variable_storer.rb +22 -22
  25. data/lib/soaspec/exchange_handlers/exchange_handler.rb +126 -126
  26. data/lib/soaspec/exchange_handlers/handler_accessors.rb +130 -130
  27. data/lib/soaspec/exchange_handlers/response_extractor.rb +82 -82
  28. data/lib/soaspec/exchange_handlers/rest_exchanger_factory.rb +109 -109
  29. data/lib/soaspec/exchange_handlers/rest_handler.rb +259 -259
  30. data/lib/soaspec/exchange_handlers/rest_methods.rb +44 -44
  31. data/lib/soaspec/exchange_handlers/rest_parameters.rb +86 -86
  32. data/lib/soaspec/exchange_handlers/rest_parameters_defaults.rb +21 -21
  33. data/lib/soaspec/exchange_handlers/soap_handler.rb +235 -235
  34. data/lib/soaspec/exe_helpers.rb +92 -92
  35. data/lib/soaspec/generate_server.rb +37 -37
  36. data/lib/soaspec/generator/.rspec.erb +5 -5
  37. data/lib/soaspec/generator/.travis.yml.erb +5 -5
  38. data/lib/soaspec/generator/Gemfile.erb +8 -8
  39. data/lib/soaspec/generator/README.md.erb +29 -29
  40. data/lib/soaspec/generator/Rakefile.erb +19 -19
  41. data/lib/soaspec/generator/config/data/default.yml.erb +2 -2
  42. data/lib/soaspec/generator/css/bootstrap.css +6833 -6833
  43. data/lib/soaspec/generator/generate_exchange.html.erb +35 -35
  44. data/lib/soaspec/generator/lib/blz_service.rb.erb +26 -26
  45. data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -12
  46. data/lib/soaspec/generator/lib/new_rest_service.rb.erb +51 -51
  47. data/lib/soaspec/generator/lib/new_soap_service.rb.erb +29 -29
  48. data/lib/soaspec/generator/lib/package_service.rb.erb +2 -2
  49. data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -8
  50. data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +12 -12
  51. data/lib/soaspec/generator/spec/rest_spec.rb.erb +9 -9
  52. data/lib/soaspec/generator/spec/soap_spec.rb.erb +51 -51
  53. data/lib/soaspec/generator/spec/spec_helper.rb.erb +23 -23
  54. data/lib/soaspec/generator/template/soap_template.xml +6 -6
  55. data/lib/soaspec/indifferent_hash.rb +7 -7
  56. data/lib/soaspec/interpreter.rb +39 -39
  57. data/lib/soaspec/matchers.rb +114 -114
  58. data/lib/soaspec/not_found_errors.rb +13 -13
  59. data/lib/soaspec/o_auth2.rb +128 -128
  60. data/lib/soaspec/soaspec_shared_examples.rb +24 -24
  61. data/lib/soaspec/spec_logger.rb +121 -121
  62. data/lib/soaspec/template_reader.rb +28 -28
  63. data/lib/soaspec/test_server/bank.wsdl +90 -90
  64. data/lib/soaspec/test_server/get_bank.rb +164 -164
  65. data/lib/soaspec/test_server/id_manager.rb +39 -39
  66. data/lib/soaspec/test_server/invoices.rb +27 -27
  67. data/lib/soaspec/test_server/namespace.xml +14 -14
  68. data/lib/soaspec/test_server/note.xml +5 -5
  69. data/lib/soaspec/test_server/puppy_service.rb +19 -19
  70. data/lib/soaspec/test_server/test_attribute.rb +12 -12
  71. data/lib/soaspec/test_server/test_namespace.rb +12 -12
  72. data/lib/soaspec/version.rb +4 -3
  73. data/lib/soaspec/virtual_server.rb +174 -174
  74. data/lib/soaspec/wait.rb +41 -41
  75. data/lib/soaspec/wsdl_generator.rb +215 -215
  76. data/soaspec.gemspec +53 -53
  77. data/test.wsdl +116 -116
  78. data/test.xml +10 -10
  79. data/test_wsdl.rb +41 -41
  80. metadata +3 -4
@@ -1,35 +1,35 @@
1
- # Override Hash class with convenience methods
2
- class Hash
3
- # Transform each key in Hash to a symbol. Privately used by non-self method
4
- # @param [Object] value Value inside hash to transform keys under
5
- def self.transform_keys_to_symbols(value)
6
- return value unless value.is_a?(Hash)
7
-
8
- hash = value.each_with_object({}) { |(k, v), memo| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); }
9
- hash
10
- end
11
-
12
- # Take keys of hash and transform those to a symbols
13
- def transform_keys_to_symbols
14
- each_with_object({}) { |(k, v), memo| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); }
15
- end
16
-
17
- # Value present in nested Hash.
18
- # @return [Boolean] Whether value is included in nested Hash
19
- def include_value?(value)
20
- each_value do |v|
21
- return true if v == value
22
- next unless v.is_a? Hash
23
-
24
- v.each_value do |v|
25
- return true if v == value
26
- next unless v.is_a? Hash
27
-
28
- v.each_value do |v|
29
- return true if v == value
30
- end
31
- end
32
- end
33
- false
34
- end
35
- end
1
+ # Override Hash class with convenience methods
2
+ class Hash
3
+ # Transform each key in Hash to a symbol. Privately used by non-self method
4
+ # @param [Object] value Value inside hash to transform keys under
5
+ def self.transform_keys_to_symbols(value)
6
+ return value unless value.is_a?(Hash)
7
+
8
+ hash = value.each_with_object({}) { |(k, v), memo| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); }
9
+ hash
10
+ end
11
+
12
+ # Take keys of hash and transform those to a symbols
13
+ def transform_keys_to_symbols
14
+ each_with_object({}) { |(k, v), memo| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); }
15
+ end
16
+
17
+ # Value present in nested Hash.
18
+ # @return [Boolean] Whether value is included in nested Hash
19
+ def include_value?(value)
20
+ each_value do |v|
21
+ return true if v == value
22
+ next unless v.is_a? Hash
23
+
24
+ v.each_value do |v|
25
+ return true if v == value
26
+ next unless v.is_a? Hash
27
+
28
+ v.each_value do |v|
29
+ return true if v == value
30
+ end
31
+ end
32
+ end
33
+ false
34
+ end
35
+ end
@@ -1,85 +1,85 @@
1
- require 'active_support/core_ext/string/inflections'
2
-
3
- # @return [Exchange] Return current or last exchange used in Cucumber
4
- def current_exchange
5
- @current_exchange ||= Soaspec.last_exchange
6
- end
7
-
8
- # Pass in the operation (HTTP method or SOAP operation) in first parameter and api name as second.
9
- # API name can be mulitple words and it will be converted to camel case to find the ExchangeHandler class
10
- # @example Create an Exchange representing an HTTP 'post' based on the 'Puppy' RestHandler class
11
- # I am performing a post on the Puppy API
12
- # @example Create an Exchange for a 'get_bank' operation on for a 'Banking' SoapHandler class
13
- # I am performing a get_bank on the Banking API
14
- Given 'I am performing a {word} on the {string} API' do |operation, api_name|
15
- @current_exchange = api_name.tr(' ', '_').camelize.constantize.send operation
16
- end
17
-
18
- # Set a parameter in the request body
19
- # @example Set the name element in the request body to Charlie
20
- # And I set the name to 'Charlie'
21
- # @param [String] Element in request body to set
22
- # @param [String] Value to set it to
23
- Given 'I set the {word} to {string}' do |key, value|
24
- current_exchange[key] = value
25
- end
26
-
27
- # Add onto the base_url to make a complete url for the test
28
- # @example base_url is 'http://petstore.swagger.io/v2' and I want a post to 'http://petstore.swagger.io/v2/pet'
29
- # I use the path pet
30
- Given 'I use the path {word}' do |suburl|
31
- current_exchange.suburl = suburl
32
- end
33
-
34
- # Add a query parameter for http 'get' requests. e.g. will add '?filter_key=filter_value' onto URL
35
- # @example To create a query for '?status=sold'
36
- # And I filter 'status' by 'sold'
37
- # @example To add a query for 'area' being 'australia' to make a total of '?status=sold&area=austrialia'
38
- # And I filter 'area' by 'australia'
39
- Given 'I filter {string} by {string}' do |filter_key, filter_value|
40
- transformed_key = filter_key.to_sym
41
- if current_exchange.override_parameters[:q]
42
- current_exchange.override_parameters[:q][transformed_key] = filter_value
43
- else
44
- current_exchange.override_parameters[:q] = { transformed_key => filter_value }
45
- end
46
- end
47
-
48
- # Add HTTP header 'header_name' as 'header_value'
49
- # @example
50
- # And I set header 'accept' to 'application/xml'
51
- Given 'I set header {string} to {string}' do |header_name, header_value|
52
- if current_exchange.override_parameters[:params]
53
- current_exchange.override_parameters[:params][header_name] = header_value
54
- else
55
- current_exchange.override_parameters[:params] = { header_name => header_value }
56
- end
57
- end
58
-
59
- # Make the API call. This is automatically done when any method extracting a response is made. It can be done
60
- # explicitly here as it is a meaningful step
61
- When 'I make the request' do
62
- current_exchange.call
63
- end
64
-
65
- # Extract the value from the response that is at the path 'key' and verify it is eq to expected_value
66
- # @example Assert response body has at the path 'name', the value 'Charlie'
67
- # Then it should have the name 'Charlie'
68
- Then 'it should have the {word} {string}' do |key, expected_value|
69
- expect(current_exchange[key]).to eq expected_value
70
- end
71
-
72
- # Extract the value from the response that is at the path 'key_string' and verify it is eq to expected_value
73
- # Conversion is made on key_string to make it one snake case word
74
- # @example Assert response body has at the path 'customer_name', the value 'Charlie'
75
- # Then it should have the 'customer name' 'Charlie'
76
- Then 'it should have the {string} {string}' do |key_string, expected_value|
77
- key = key_string.tr(' ', '_')
78
- actual_value = current_exchange.respond_to?(key) ? current_exchange.send(key) : current_exchange[key]
79
- expect(actual_value.to_s).to eq expected_value
80
- end
81
-
82
- # Verify that the HTTP status code is 200..299 and that any defined mandatory elements / mandatory values are as expected
83
- Then 'it should be successful' do
84
- expect(current_exchange).to be_successful
85
- end
1
+ require 'active_support/core_ext/string/inflections'
2
+
3
+ # @return [Exchange] Return current or last exchange used in Cucumber
4
+ def current_exchange
5
+ @current_exchange ||= Soaspec.last_exchange
6
+ end
7
+
8
+ # Pass in the operation (HTTP method or SOAP operation) in first parameter and api name as second.
9
+ # API name can be mulitple words and it will be converted to camel case to find the ExchangeHandler class
10
+ # @example Create an Exchange representing an HTTP 'post' based on the 'Puppy' RestHandler class
11
+ # I am performing a post on the Puppy API
12
+ # @example Create an Exchange for a 'get_bank' operation on for a 'Banking' SoapHandler class
13
+ # I am performing a get_bank on the Banking API
14
+ Given 'I am performing a {word} on the {string} API' do |operation, api_name|
15
+ @current_exchange = api_name.tr(' ', '_').camelize.constantize.send operation
16
+ end
17
+
18
+ # Set a parameter in the request body
19
+ # @example Set the name element in the request body to Charlie
20
+ # And I set the name to 'Charlie'
21
+ # @param [String] Element in request body to set
22
+ # @param [String] Value to set it to
23
+ Given 'I set the {word} to {string}' do |key, value|
24
+ current_exchange[key] = value
25
+ end
26
+
27
+ # Add onto the base_url to make a complete url for the test
28
+ # @example base_url is 'http://petstore.swagger.io/v2' and I want a post to 'http://petstore.swagger.io/v2/pet'
29
+ # I use the path pet
30
+ Given 'I use the path {word}' do |suburl|
31
+ current_exchange.suburl = suburl
32
+ end
33
+
34
+ # Add a query parameter for http 'get' requests. e.g. will add '?filter_key=filter_value' onto URL
35
+ # @example To create a query for '?status=sold'
36
+ # And I filter 'status' by 'sold'
37
+ # @example To add a query for 'area' being 'australia' to make a total of '?status=sold&area=austrialia'
38
+ # And I filter 'area' by 'australia'
39
+ Given 'I filter {string} by {string}' do |filter_key, filter_value|
40
+ transformed_key = filter_key.to_sym
41
+ if current_exchange.override_parameters[:q]
42
+ current_exchange.override_parameters[:q][transformed_key] = filter_value
43
+ else
44
+ current_exchange.override_parameters[:q] = { transformed_key => filter_value }
45
+ end
46
+ end
47
+
48
+ # Add HTTP header 'header_name' as 'header_value'
49
+ # @example
50
+ # And I set header 'accept' to 'application/xml'
51
+ Given 'I set header {string} to {string}' do |header_name, header_value|
52
+ if current_exchange.override_parameters[:params]
53
+ current_exchange.override_parameters[:params][header_name] = header_value
54
+ else
55
+ current_exchange.override_parameters[:params] = { header_name => header_value }
56
+ end
57
+ end
58
+
59
+ # Make the API call. This is automatically done when any method extracting a response is made. It can be done
60
+ # explicitly here as it is a meaningful step
61
+ When 'I make the request' do
62
+ current_exchange.call
63
+ end
64
+
65
+ # Extract the value from the response that is at the path 'key' and verify it is eq to expected_value
66
+ # @example Assert response body has at the path 'name', the value 'Charlie'
67
+ # Then it should have the name 'Charlie'
68
+ Then 'it should have the {word} {string}' do |key, expected_value|
69
+ expect(current_exchange[key]).to eq expected_value
70
+ end
71
+
72
+ # Extract the value from the response that is at the path 'key_string' and verify it is eq to expected_value
73
+ # Conversion is made on key_string to make it one snake case word
74
+ # @example Assert response body has at the path 'customer_name', the value 'Charlie'
75
+ # Then it should have the 'customer name' 'Charlie'
76
+ Then 'it should have the {string} {string}' do |key_string, expected_value|
77
+ key = key_string.tr(' ', '_')
78
+ actual_value = current_exchange.respond_to?(key) ? current_exchange.send(key) : current_exchange[key]
79
+ expect(actual_value.to_s).to eq expected_value
80
+ end
81
+
82
+ # Verify that the HTTP status code is 200..299 and that any defined mandatory elements / mandatory values are as expected
83
+ Then 'it should be successful' do
84
+ expect(current_exchange).to be_successful
85
+ end
@@ -1,4 +1,4 @@
1
- # Load this file for demoing Soaspec (e.g in IRB). Has common settings applicable for demoing
2
-
3
- require_relative '../soaspec'
4
- Soaspec::SpecLogger.output_to_terminal = true
1
+ # Load this file for demoing Soaspec (e.g in IRB). Has common settings applicable for demoing
2
+
3
+ require_relative '../soaspec'
4
+ Soaspec::SpecLogger.output_to_terminal = true
@@ -1,111 +1,111 @@
1
- require_relative '../../soaspec'
2
- require_relative 'exchange_properties'
3
- require_relative 'exchange_extractor'
4
- require_relative 'request_builder'
5
- require_relative 'exchange_repeater'
6
- require_relative 'variable_storer'
7
-
8
- # This represents a request / response pair
9
- # Essentially, params in the exchange that are set are related to the request
10
- # What is returned is related to the response
11
- class Exchange
12
- extend Soaspec::ExchangeProperties
13
- include Soaspec::ExchangeExtractor
14
- include Soaspec::RequestBuilder
15
- include Soaspec::ExchangeRepeater
16
- include Soaspec::VariableStorer
17
-
18
- # Instance of ExchangeHandler for which this exchange is made
19
- attr_accessor :exchange_handler
20
- # How many times to retry for a success
21
- attr_accessor :retry_count
22
- # Name used for displaying class
23
- attr_accessor :test_name
24
- # Expect Factory to fail upon trying to create
25
- attr_writer :fail_factory
26
- # Parameters to override for default params
27
- attr_accessor :override_parameters
28
-
29
- # Set retry for success variable to true so that request will be retried
30
- # for retry_count until it's true
31
- def retry_for_success
32
- @retry_for_success = true
33
- self
34
- end
35
-
36
- # @return [Bool] Whether to keep making request until success code reached
37
- def retry_for_success?
38
- @retry_for_success
39
- end
40
-
41
- # @return [Boolean] Soaspec::ExchangeHandler used by this exchange
42
- def default_handler_used
43
- nil
44
- end
45
-
46
- # Create new Exchange according to parameters set. A response will be made if called
47
- # explicitly with 'response' method or through other methods that use it like 'status_code'
48
- # @param [Symbol, String] name Name shown in RSpec run
49
- # @param [Hash] override_parameters Parameters to override for default params
50
- def initialize(name = self.class.to_s, override_parameters = {})
51
- self.test_name ||= name.to_s
52
- # As a last resort this uses the global parameter. The handler should be set straight before an exchange is made to use this
53
- @exchange_handler ||= default_handler_used || Soaspec.api_handler
54
- raise '@exchange_handler not set. Set either with `Soaspec.api_handler = Handler.new` or within the exchange' unless @exchange_handler
55
-
56
- @fail_factory = nil
57
- @override_parameters = override_parameters
58
- @retry_for_success = false
59
- self.retry_count = 3
60
- @exchange_handler.elements.each { |element| methods_for_element(element) }
61
- end
62
-
63
- # Make request to handler with parameters defined
64
- # Will retry until success code reached if retry_for_success? is set
65
- # @return [Response] Response from Api handler
66
- def make_request
67
- Soaspec::SpecLogger.info 'Example ' + test_name
68
- request_params = @override_parameters
69
- (0..retry_count).each do |count|
70
- response = exchange_handler.make_request(request_params)
71
- return response unless retry_for_success?
72
- return response if (200..299).cover? exchange_handler.status_code_for(response)
73
-
74
- sleep 0.5 # Time before retrying
75
- break response if count == retry_count
76
- end
77
- end
78
-
79
- # Name describing this class when used with `RSpec.describe`
80
- # This will make the request and store the response
81
- # @return [String] Name given when initializing
82
- def to_s
83
- test_name
84
- end
85
-
86
- # @return [RestClient::Response,Savon::Response] Returns response object from Api.
87
- # Will make the request if not made and then cache it for later on
88
- # @example For SOAP it will be a Savon response
89
- # response.body (body of response as Hash)
90
- # response.header (head of response as Hash)
91
- # @example For REST it will be a RestClient::Response
92
- def response
93
- require 'forwardable'
94
- Soaspec.last_exchange = self
95
- @response ||= make_request
96
- @response.define_singleton_method(:exchange) { Soaspec.last_exchange } unless @response.respond_to?(:exchange)
97
- @response.extend Forwardable
98
- @response.delegate %i[value_from_path values_from_path] => :exchange
99
- @response
100
- end
101
-
102
- # @return [ResponseObject] Currently returning response object. This will change (in 0.3) to be itself to
103
- # allow easy method chaining
104
- def call
105
- if Soaspec.log_warnings
106
- warn 'This "call" method will be changed to return "Exchange" object in 0.3. ' \
107
- 'Use "response" method if you want the "response" object'
108
- end
109
- response
110
- end
111
- end
1
+ require_relative '../../soaspec'
2
+ require_relative 'exchange_properties'
3
+ require_relative 'exchange_extractor'
4
+ require_relative 'request_builder'
5
+ require_relative 'exchange_repeater'
6
+ require_relative 'variable_storer'
7
+
8
+ # This represents a request / response pair
9
+ # Essentially, params in the exchange that are set are related to the request
10
+ # What is returned is related to the response
11
+ class Exchange
12
+ extend Soaspec::ExchangeProperties
13
+ include Soaspec::ExchangeExtractor
14
+ include Soaspec::RequestBuilder
15
+ include Soaspec::ExchangeRepeater
16
+ include Soaspec::VariableStorer
17
+
18
+ # Instance of ExchangeHandler for which this exchange is made
19
+ attr_accessor :exchange_handler
20
+ # How many times to retry for a success
21
+ attr_accessor :retry_count
22
+ # Name used for displaying class
23
+ attr_accessor :test_name
24
+ # Expect Factory to fail upon trying to create
25
+ attr_writer :fail_factory
26
+ # Parameters to override for default params
27
+ attr_accessor :override_parameters
28
+
29
+ # Set retry for success variable to true so that request will be retried
30
+ # for retry_count until it's true
31
+ def retry_for_success
32
+ @retry_for_success = true
33
+ self
34
+ end
35
+
36
+ # @return [Bool] Whether to keep making request until success code reached
37
+ def retry_for_success?
38
+ @retry_for_success
39
+ end
40
+
41
+ # @return [Boolean] Soaspec::ExchangeHandler used by this exchange
42
+ def default_handler_used
43
+ nil
44
+ end
45
+
46
+ # Create new Exchange according to parameters set. A response will be made if called
47
+ # explicitly with 'response' method or through other methods that use it like 'status_code'
48
+ # @param [Symbol, String] name Name shown in RSpec run
49
+ # @param [Hash] override_parameters Parameters to override for default params
50
+ def initialize(name = self.class.to_s, override_parameters = {})
51
+ self.test_name ||= name.to_s
52
+ # As a last resort this uses the global parameter. The handler should be set straight before an exchange is made to use this
53
+ @exchange_handler ||= default_handler_used || Soaspec.api_handler
54
+ raise '@exchange_handler not set. Set either with `Soaspec.api_handler = Handler.new` or within the exchange' unless @exchange_handler
55
+
56
+ @fail_factory = nil
57
+ @override_parameters = override_parameters
58
+ @retry_for_success = false
59
+ self.retry_count = 3
60
+ @exchange_handler.elements.each { |element| methods_for_element(element) }
61
+ end
62
+
63
+ # Make request to handler with parameters defined
64
+ # Will retry until success code reached if retry_for_success? is set
65
+ # @return [Response] Response from Api handler
66
+ def make_request
67
+ Soaspec::SpecLogger.info 'Example ' + test_name
68
+ request_params = @override_parameters
69
+ (0..retry_count).each do |count|
70
+ response = exchange_handler.make_request(request_params)
71
+ return response unless retry_for_success?
72
+ return response if (200..299).cover? exchange_handler.status_code_for(response)
73
+
74
+ sleep 0.5 # Time before retrying
75
+ break response if count == retry_count
76
+ end
77
+ end
78
+
79
+ # Name describing this class when used with `RSpec.describe`
80
+ # This will make the request and store the response
81
+ # @return [String] Name given when initializing
82
+ def to_s
83
+ test_name
84
+ end
85
+
86
+ # @return [RestClient::Response,Savon::Response] Returns response object from Api.
87
+ # Will make the request if not made and then cache it for later on
88
+ # @example For SOAP it will be a Savon response
89
+ # response.body (body of response as Hash)
90
+ # response.header (head of response as Hash)
91
+ # @example For REST it will be a RestClient::Response
92
+ def response
93
+ require 'forwardable'
94
+ Soaspec.last_exchange = self
95
+ @response ||= make_request
96
+ @response.define_singleton_method(:exchange) { Soaspec.last_exchange } unless @response.respond_to?(:exchange)
97
+ @response.extend Forwardable
98
+ @response.delegate %i[value_from_path values_from_path] => :exchange
99
+ @response
100
+ end
101
+
102
+ # @return [ResponseObject] Currently returning response object. This will change (in 0.3) to be itself to
103
+ # allow easy method chaining
104
+ def call
105
+ if Soaspec.log_warnings
106
+ warn 'This "call" method will be changed to return "Exchange" object in 0.3. ' \
107
+ 'Use "response" method if you want the "response" object'
108
+ end
109
+ response
110
+ end
111
+ end