soaspec 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +15 -15
  3. data/.gitlab-ci.yml +48 -48
  4. data/.rspec +3 -3
  5. data/.rubocop.yml +2 -2
  6. data/CODE_OF_CONDUCT.md +74 -74
  7. data/ChangeLog +404 -400
  8. data/Gemfile +6 -6
  9. data/LICENSE.txt +21 -21
  10. data/README.md +113 -113
  11. data/Rakefile +24 -24
  12. data/Todo.md +6 -6
  13. data/exe/soaspec +109 -109
  14. data/exe/soaspec-virtual-server +156 -155
  15. data/exe/xml_to_yaml_file +60 -60
  16. data/lib/soaspec.rb +103 -103
  17. data/lib/soaspec/core_ext/hash.rb +83 -83
  18. data/lib/soaspec/exchange.rb +235 -235
  19. data/lib/soaspec/exchange_handlers/exchange_handler.rb +103 -103
  20. data/lib/soaspec/exchange_handlers/handler_accessors.rb +106 -106
  21. data/lib/soaspec/exchange_handlers/rest_accessors.rb +92 -92
  22. data/lib/soaspec/exchange_handlers/rest_handler.rb +314 -314
  23. data/lib/soaspec/exchange_handlers/rest_methods.rb +44 -44
  24. data/lib/soaspec/exchange_handlers/soap_handler.rb +236 -236
  25. data/lib/soaspec/exe_helpers.rb +60 -60
  26. data/lib/soaspec/generator/.rspec.erb +5 -5
  27. data/lib/soaspec/generator/.travis.yml.erb +5 -5
  28. data/lib/soaspec/generator/Gemfile.erb +8 -8
  29. data/lib/soaspec/generator/README.md.erb +29 -29
  30. data/lib/soaspec/generator/Rakefile.erb +19 -19
  31. data/lib/soaspec/generator/config/data/default.yml.erb +1 -1
  32. data/lib/soaspec/generator/lib/blz_service.rb.erb +26 -26
  33. data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -12
  34. data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -8
  35. data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +12 -12
  36. data/lib/soaspec/generator/spec/soap_spec.rb.erb +51 -51
  37. data/lib/soaspec/generator/spec/spec_helper.rb.erb +20 -20
  38. data/lib/soaspec/generator/template/soap_template.xml +6 -6
  39. data/lib/soaspec/interpreter.rb +40 -40
  40. data/lib/soaspec/matchers.rb +65 -65
  41. data/lib/soaspec/not_found_errors.rb +13 -13
  42. data/lib/soaspec/soaspec_shared_examples.rb +24 -24
  43. data/lib/soaspec/spec_logger.rb +27 -27
  44. data/lib/soaspec/test_server/bank.wsdl +90 -90
  45. data/lib/soaspec/test_server/get_bank.rb +160 -160
  46. data/lib/soaspec/test_server/id_manager.rb +31 -31
  47. data/lib/soaspec/test_server/invoices.rb +27 -27
  48. data/lib/soaspec/test_server/namespace.xml +14 -14
  49. data/lib/soaspec/test_server/note.xml +5 -5
  50. data/lib/soaspec/test_server/puppy_service.rb +20 -20
  51. data/lib/soaspec/test_server/test_attribute.rb +13 -13
  52. data/lib/soaspec/test_server/test_namespace.rb +12 -12
  53. data/lib/soaspec/version.rb +2 -2
  54. data/lib/soaspec/wsdl_generator.rb +144 -144
  55. data/soaspec.gemspec +46 -47
  56. data/test.wsdl +116 -116
  57. data/test.xml +10 -10
  58. data/test_wsdl.rb +43 -43
  59. metadata +6 -6
@@ -1,45 +1,45 @@
1
-
2
- module Soaspec
3
- # Contains commonly used REST methods
4
- module RestMethods
5
- # Make REST Post Exchange
6
- # @param [String] name Name of test displayed
7
- # @param [Hash] params Exchange parameters
8
- # @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
9
- def post(name, params = {})
10
- Exchange.new(name, method: :post, **params)
11
- end
12
-
13
- # Make REST Patch Exchange
14
- # @param [String] name Name of test displayed
15
- # @param [Hash] params Exchange parameters
16
- # @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
17
- def patch(name, params = {})
18
- Exchange.new(name, method: :patch, **params)
19
- end
20
-
21
- # Make REST Put Exchange
22
- # @param [String] name Name of test displayed
23
- # @param [Hash] params Exchange parameters
24
- # @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
25
- def put(name, params = {})
26
- Exchange.new(name, method: :put, **params)
27
- end
28
-
29
- # Make REST Get Exchange
30
- # @param [String] name Name of test displayed
31
- # @param [Hash] params Exchange parameters
32
- # @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
33
- def get(name, params = {})
34
- Exchange.new(name, method: :get, **params)
35
- end
36
-
37
- # Make REST Delete Exchange
38
- # @param [String] name Name of test displayed
39
- # @param [Hash] params Exchange parameters
40
- # @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
41
- def delete(name, params = {})
42
- Exchange.new(name, method: :delete, **params)
43
- end
44
- end
1
+
2
+ module Soaspec
3
+ # Contains commonly used REST methods
4
+ module RestMethods
5
+ # Make REST Post Exchange
6
+ # @param [String] name Name of test displayed
7
+ # @param [Hash] params Exchange parameters
8
+ # @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
9
+ def post(name, params = {})
10
+ Exchange.new(name, method: :post, **params)
11
+ end
12
+
13
+ # Make REST Patch Exchange
14
+ # @param [String] name Name of test displayed
15
+ # @param [Hash] params Exchange parameters
16
+ # @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
17
+ def patch(name, params = {})
18
+ Exchange.new(name, method: :patch, **params)
19
+ end
20
+
21
+ # Make REST Put Exchange
22
+ # @param [String] name Name of test displayed
23
+ # @param [Hash] params Exchange parameters
24
+ # @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
25
+ def put(name, params = {})
26
+ Exchange.new(name, method: :put, **params)
27
+ end
28
+
29
+ # Make REST Get Exchange
30
+ # @param [String] name Name of test displayed
31
+ # @param [Hash] params Exchange parameters
32
+ # @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
33
+ def get(name, params = {})
34
+ Exchange.new(name, method: :get, **params)
35
+ end
36
+
37
+ # Make REST Delete Exchange
38
+ # @param [String] name Name of test displayed
39
+ # @param [Hash] params Exchange parameters
40
+ # @return [Exchange] Instance of Exchange class. Assertions are made by default on the response body
41
+ def delete(name, params = {})
42
+ Exchange.new(name, method: :delete, **params)
43
+ end
44
+ end
45
45
  end
@@ -1,237 +1,237 @@
1
-
2
- require_relative 'exchange_handler'
3
- require_relative '../core_ext/hash'
4
- require_relative '../not_found_errors'
5
- require_relative 'handler_accessors'
6
- require_relative '../interpreter'
7
- require 'forwardable'
8
-
9
- module Soaspec
10
-
11
- # Accessors specific to SOAP handler
12
- module SoapAccessors
13
- # Define attributes set on root SOAP element
14
- def root_attributes(attributes)
15
- define_method('request_root_attributes') do
16
- attributes
17
- end
18
- end
19
- end
20
-
21
- # Wraps around Savon client defining default values dependent on the soap request
22
- class SoapHandler < ExchangeHandler
23
- extend Soaspec::SoapAccessors
24
- extend Forwardable
25
-
26
- delegate [:operations] => :client
27
-
28
- # Savon client used to make SOAP calls
29
- attr_accessor :client
30
- # SOAP Operation to use by default
31
- attr_accessor :operation
32
-
33
- # Attributes set at the root XML element of SOAP request
34
- def request_root_attributes
35
- nil
36
- end
37
-
38
- # Options to log xml request and response
39
- def logging_options
40
- {
41
- log: true, # See request and response. (Put this in traffic file)
42
- log_level: :debug,
43
- logger: Soaspec::SpecLogger.create,
44
- pretty_print_xml: true # Prints XML pretty
45
- }
46
- end
47
-
48
- # Default Savon options. See http://savonrb.com/version2/globals.html for details
49
- # @return [Hash] Default Savon options for all BasicSoapHandler
50
- def default_options
51
- {
52
- ssl_verify_mode: :none, # Easier for testing. Not so secure
53
- follow_redirects: true, # Necessary for many API calls
54
- soap_version: 2, # use SOAP 1.2. You will get 415 error if this is incorrect
55
- raise_errors: false # HTTP errors not cause failure as often negative test scenarios expect not 200 response
56
- # Things could go wrong if not set properly
57
- # env_namespace: :soap, # Change environment namespace
58
- # namespace_identifier: :tst, # Change namespace element
59
- # element_form_default: :qualified # Populate each element with namespace
60
- # namespace: 'http://Extended_namespace.xsd' change root namespace
61
- # basic_auth: 'user', 'password'
62
- }
63
- end
64
-
65
- # Add values to here when extending this class to have default Savon options.
66
- # See http://savonrb.com/version2/globals.html for details
67
- # @return [Hash] Savon options adding to & overriding defaults
68
- def savon_options
69
- {
70
- }
71
- end
72
-
73
- # Setup object to handle communicating with a particular SOAP WSDL
74
- # @param [Hash] options Options defining SOAP request. WSDL, authentication, see http://savonrb.com/version2/globals.html for list of options
75
- def initialize(name = self.class.to_s, options = {})
76
- @default_hash = {}
77
- @request_option = :hash
78
- if name.is_a?(Hash) && options == {} # If name is not set
79
- options = name
80
- name = self.class.to_s
81
- end
82
- super
83
- set_remove_key(options, :operation)
84
- set_remove_key(options, :default_hash)
85
- set_remove_key(options, :template_name)
86
- merged_options = Soaspec.log_api_traffic? ? default_options.merge(logging_options) : default_options
87
- merged_options.merge! savon_options
88
- merged_options.merge!(options)
89
- self.client = Savon.client(merged_options)
90
- end
91
-
92
- # Used in making request via hash or in template via Erb
93
- def request_body_params(request_parameters)
94
- test_values = request_parameters[:body] || request_parameters
95
- test_values.transform_keys_to_symbols if Soaspec.always_use_keys?
96
- end
97
-
98
- # Used in together with Exchange request that passes such override parameters
99
- # @param [Hash] request_parameters Parameters used to overwrite defaults in request
100
- def make_request(request_parameters)
101
- test_values = request_body_params request_parameters
102
- begin
103
- if @request_option == :template
104
- request_body = File.read(File.join(Soaspec.template_folder, template_name))
105
- render_body = ERB.new(request_body).result(binding)
106
- client.call(operation, xml: render_body) # Call the SOAP operation with the request XML provided
107
- elsif @request_option == :hash
108
- client.call(operation, message: @default_hash.merge(test_values), attributes: request_root_attributes)
109
- end
110
- rescue Savon::HTTPError => e
111
- e
112
- end
113
- end
114
-
115
- # @param [Hash] format Format of expected result
116
- # @return [Object] Generic body to be displayed in error messages
117
- def response_body(response, format: :hash)
118
- case format
119
- when :hash
120
- response.body
121
- when :raw
122
- response.xml
123
- else
124
- response.body
125
- end
126
- end
127
-
128
- # @return [Boolean] Whether the request found the desired value or not
129
- def found?(response)
130
- status_code_for(response) != 404
131
- end
132
-
133
- # Response status code for response. '200' indicates a success
134
- # @param [Savon::Response] response
135
- # @return [Integer] Status code
136
- def status_code_for(response)
137
- response.http.code
138
- end
139
-
140
- # @return [Boolean] Whether response includes provided string within it
141
- def include_in_body?(response, expected)
142
- response.to_xml.to_s.include? expected
143
- end
144
-
145
- # @param [Symbol] expected
146
- # @return [Boolean] Whether response body contains expected key
147
- def include_key?(response, expected)
148
- body = response.body
149
- body.extend Hashie::Extensions::DeepFind
150
- !body.deep_find_all(expected).empty?
151
- end
152
-
153
- # Convert all XML nodes to lowercase
154
- # @param [Nokogiri::XML::Document]
155
- def convert_to_lower_case(xml_doc)
156
- xml_doc.traverse do |node|
157
- node.name = node.name.downcase if node.kind_of?(Nokogiri::XML::Element)
158
- end
159
- end
160
-
161
- # Returns the value at the provided xpath
162
- # @param [Savon::Response] response
163
- # @param [String] xpath
164
- # @return [Enumerable] Elements found through Xpath
165
- def xpath_elements_for(response: nil, xpath: nil, attribute: nil)
166
- raise ArgumentError('response and xpath must be passed to method') unless response && xpath
167
- xpath = "//*[@#{attribute}]" unless attribute.nil?
168
- xpath = '//' + xpath if xpath[0] != '/'
169
- temp_doc = response.doc.dup
170
- convert_to_lower_case(temp_doc) if convert_to_lower?
171
- if strip_namespaces? && !xpath.include?(':')
172
- temp_doc.remove_namespaces!
173
- temp_doc.xpath(xpath)
174
- else
175
- temp_doc.xpath(xpath, temp_doc.collect_namespaces)
176
- end
177
- end
178
-
179
- # Based on a exchange, return the value at the provided xpath
180
- # If the path does not begin with a '/', a '//' is added to it
181
- # @param [Savon::Response] response
182
- # @param [String] path Xpath
183
- # @param [String] attribute Generic attribute to find. Will override path
184
- # @return [String] Value at Xpath
185
- def value_from_path(response, path, attribute: nil)
186
- results = xpath_elements_for(response: response, xpath: path, attribute: attribute)
187
- raise NoElementAtPath, "No value at Xpath '#{path}' in XML #{response.doc}" if results.empty?
188
- return results.first.inner_text if attribute.nil?
189
- results.first.attributes[attribute].inner_text
190
- end
191
-
192
- # @return [Enumerable] List of values returned from path
193
- def values_from_path(response, path, attribute: nil)
194
- xpath_elements_for(response: response, xpath: path, attribute: attribute).map(&:inner_text)
195
- end
196
-
197
- # alias elements xpath_elements_for
198
-
199
- # @return [Boolean] Whether any of the keys of the Body Hash include value
200
- def include_value?(response, expected_value)
201
- response.body.include_value?(expected_value)
202
- end
203
-
204
- # Hash of response body
205
- def to_hash(response)
206
- response.body
207
- end
208
-
209
- # Convenience methods for once off usage of a SOAP request
210
- class << self
211
-
212
- # Implement undefined setter with []= for FactoryBot to use without needing to define params to set
213
- # @param [Object] method_name Name of method not defined
214
- # @param [Object] args Arguments passed to method
215
- # @param [Object] block
216
- def method_missing(method_name, *args, &block)
217
- tmp_class = new(method_name)
218
- operations = tmp_class.operations
219
- if operations.include? method_name
220
- tmp_class.operation = method_name
221
- exchange = Exchange.new(method_name, *args)
222
- exchange.exchange_handler = tmp_class
223
- exchange
224
- else
225
- super
226
- end
227
- end
228
-
229
- def respond_to_missing?(method_name, *args)
230
- tmp_class = new(args)
231
- operations = tmp_class.operations
232
- operations.include?(method_name) || super
233
- end
234
- end
235
-
236
- end
1
+
2
+ require_relative 'exchange_handler'
3
+ require_relative '../core_ext/hash'
4
+ require_relative '../not_found_errors'
5
+ require_relative 'handler_accessors'
6
+ require_relative '../interpreter'
7
+ require 'forwardable'
8
+
9
+ module Soaspec
10
+
11
+ # Accessors specific to SOAP handler
12
+ module SoapAccessors
13
+ # Define attributes set on root SOAP element
14
+ def root_attributes(attributes)
15
+ define_method('request_root_attributes') do
16
+ attributes
17
+ end
18
+ end
19
+ end
20
+
21
+ # Wraps around Savon client defining default values dependent on the soap request
22
+ class SoapHandler < ExchangeHandler
23
+ extend Soaspec::SoapAccessors
24
+ extend Forwardable
25
+
26
+ delegate [:operations] => :client
27
+
28
+ # Savon client used to make SOAP calls
29
+ attr_accessor :client
30
+ # SOAP Operation to use by default
31
+ attr_accessor :operation
32
+
33
+ # Attributes set at the root XML element of SOAP request
34
+ def request_root_attributes
35
+ nil
36
+ end
37
+
38
+ # Options to log xml request and response
39
+ def logging_options
40
+ {
41
+ log: true, # See request and response. (Put this in traffic file)
42
+ log_level: :debug,
43
+ logger: Soaspec::SpecLogger.create,
44
+ pretty_print_xml: true # Prints XML pretty
45
+ }
46
+ end
47
+
48
+ # Default Savon options. See http://savonrb.com/version2/globals.html for details
49
+ # @return [Hash] Default Savon options for all BasicSoapHandler
50
+ def default_options
51
+ {
52
+ ssl_verify_mode: :none, # Easier for testing. Not so secure
53
+ follow_redirects: true, # Necessary for many API calls
54
+ soap_version: 2, # use SOAP 1.2. You will get 415 error if this is incorrect
55
+ raise_errors: false # HTTP errors not cause failure as often negative test scenarios expect not 200 response
56
+ # Things could go wrong if not set properly
57
+ # env_namespace: :soap, # Change environment namespace
58
+ # namespace_identifier: :tst, # Change namespace element
59
+ # element_form_default: :qualified # Populate each element with namespace
60
+ # namespace: 'http://Extended_namespace.xsd' change root namespace
61
+ # basic_auth: 'user', 'password'
62
+ }
63
+ end
64
+
65
+ # Add values to here when extending this class to have default Savon options.
66
+ # See http://savonrb.com/version2/globals.html for details
67
+ # @return [Hash] Savon options adding to & overriding defaults
68
+ def savon_options
69
+ {
70
+ }
71
+ end
72
+
73
+ # Setup object to handle communicating with a particular SOAP WSDL
74
+ # @param [Hash] options Options defining SOAP request. WSDL, authentication, see http://savonrb.com/version2/globals.html for list of options
75
+ def initialize(name = self.class.to_s, options = {})
76
+ @default_hash = {}
77
+ @request_option = :hash
78
+ if name.is_a?(Hash) && options == {} # If name is not set
79
+ options = name
80
+ name = self.class.to_s
81
+ end
82
+ super
83
+ set_remove_key(options, :operation)
84
+ set_remove_key(options, :default_hash)
85
+ set_remove_key(options, :template_name)
86
+ merged_options = Soaspec.log_api_traffic? ? default_options.merge(logging_options) : default_options
87
+ merged_options.merge! savon_options
88
+ merged_options.merge!(options)
89
+ self.client = Savon.client(merged_options)
90
+ end
91
+
92
+ # Used in making request via hash or in template via Erb
93
+ def request_body_params(request_parameters)
94
+ test_values = request_parameters[:body] || request_parameters
95
+ test_values.transform_keys_to_symbols if Soaspec.always_use_keys?
96
+ end
97
+
98
+ # Used in together with Exchange request that passes such override parameters
99
+ # @param [Hash] request_parameters Parameters used to overwrite defaults in request
100
+ def make_request(request_parameters)
101
+ test_values = request_body_params request_parameters
102
+ begin
103
+ if @request_option == :template
104
+ request_body = File.read(File.join(Soaspec.template_folder, template_name))
105
+ render_body = ERB.new(request_body).result(binding)
106
+ client.call(operation, xml: render_body) # Call the SOAP operation with the request XML provided
107
+ elsif @request_option == :hash
108
+ client.call(operation, message: @default_hash.merge(test_values), attributes: request_root_attributes)
109
+ end
110
+ rescue Savon::HTTPError => e
111
+ e
112
+ end
113
+ end
114
+
115
+ # @param [Hash] format Format of expected result
116
+ # @return [Object] Generic body to be displayed in error messages
117
+ def response_body(response, format: :hash)
118
+ case format
119
+ when :hash
120
+ response.body
121
+ when :raw
122
+ response.xml
123
+ else
124
+ response.body
125
+ end
126
+ end
127
+
128
+ # @return [Boolean] Whether the request found the desired value or not
129
+ def found?(response)
130
+ status_code_for(response) != 404
131
+ end
132
+
133
+ # Response status code for response. '200' indicates a success
134
+ # @param [Savon::Response] response
135
+ # @return [Integer] Status code
136
+ def status_code_for(response)
137
+ response.http.code
138
+ end
139
+
140
+ # @return [Boolean] Whether response includes provided string within it
141
+ def include_in_body?(response, expected)
142
+ response.to_xml.to_s.include? expected
143
+ end
144
+
145
+ # @param [Symbol] expected
146
+ # @return [Boolean] Whether response body contains expected key
147
+ def include_key?(response, expected)
148
+ body = response.body
149
+ body.extend Hashie::Extensions::DeepFind
150
+ !body.deep_find_all(expected).empty?
151
+ end
152
+
153
+ # Convert all XML nodes to lowercase
154
+ # @param [Nokogiri::XML::Document]
155
+ def convert_to_lower_case(xml_doc)
156
+ xml_doc.traverse do |node|
157
+ node.name = node.name.downcase if node.kind_of?(Nokogiri::XML::Element)
158
+ end
159
+ end
160
+
161
+ # Returns the value at the provided xpath
162
+ # @param [Savon::Response] response
163
+ # @param [String] xpath
164
+ # @return [Enumerable] Elements found through Xpath
165
+ def xpath_elements_for(response: nil, xpath: nil, attribute: nil)
166
+ raise ArgumentError('response and xpath must be passed to method') unless response && xpath
167
+ xpath = "//*[@#{attribute}]" unless attribute.nil?
168
+ xpath = '//' + xpath if xpath[0] != '/'
169
+ temp_doc = response.doc.dup
170
+ convert_to_lower_case(temp_doc) if convert_to_lower?
171
+ if strip_namespaces? && !xpath.include?(':')
172
+ temp_doc.remove_namespaces!
173
+ temp_doc.xpath(xpath)
174
+ else
175
+ temp_doc.xpath(xpath, temp_doc.collect_namespaces)
176
+ end
177
+ end
178
+
179
+ # Based on a exchange, return the value at the provided xpath
180
+ # If the path does not begin with a '/', a '//' is added to it
181
+ # @param [Savon::Response] response
182
+ # @param [String] path Xpath
183
+ # @param [String] attribute Generic attribute to find. Will override path
184
+ # @return [String] Value at Xpath
185
+ def value_from_path(response, path, attribute: nil)
186
+ results = xpath_elements_for(response: response, xpath: path, attribute: attribute)
187
+ raise NoElementAtPath, "No value at Xpath '#{path}' in XML #{response.doc}" if results.empty?
188
+ return results.first.inner_text if attribute.nil?
189
+ results.first.attributes[attribute].inner_text
190
+ end
191
+
192
+ # @return [Enumerable] List of values returned from path
193
+ def values_from_path(response, path, attribute: nil)
194
+ xpath_elements_for(response: response, xpath: path, attribute: attribute).map(&:inner_text)
195
+ end
196
+
197
+ # alias elements xpath_elements_for
198
+
199
+ # @return [Boolean] Whether any of the keys of the Body Hash include value
200
+ def include_value?(response, expected_value)
201
+ response.body.include_value?(expected_value)
202
+ end
203
+
204
+ # Hash of response body
205
+ def to_hash(response)
206
+ response.body
207
+ end
208
+
209
+ # Convenience methods for once off usage of a SOAP request
210
+ class << self
211
+
212
+ # Implement undefined setter with []= for FactoryBot to use without needing to define params to set
213
+ # @param [Object] method_name Name of method not defined
214
+ # @param [Object] args Arguments passed to method
215
+ # @param [Object] block
216
+ def method_missing(method_name, *args, &block)
217
+ tmp_class = new(method_name)
218
+ operations = tmp_class.operations
219
+ if operations.include? method_name
220
+ tmp_class.operation = method_name
221
+ exchange = Exchange.new(method_name, *args)
222
+ exchange.exchange_handler = tmp_class
223
+ exchange
224
+ else
225
+ super
226
+ end
227
+ end
228
+
229
+ def respond_to_missing?(method_name, *args)
230
+ tmp_class = new(args)
231
+ operations = tmp_class.operations
232
+ operations.include?(method_name) || super
233
+ end
234
+ end
235
+
236
+ end
237
237
  end