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.
- checksums.yaml +4 -4
- data/.gitignore +15 -15
- data/.gitlab-ci.yml +33 -33
- data/.rspec +3 -3
- data/.rubocop.yml +2 -2
- data/CODE_OF_CONDUCT.md +74 -74
- data/ChangeLog +577 -573
- data/Gemfile +6 -6
- data/LICENSE.txt +21 -21
- data/README.md +230 -230
- data/Rakefile +42 -42
- data/Todo.md +15 -15
- data/exe/soaspec +123 -123
- data/exe/xml_to_yaml_file +42 -42
- data/lib/soaspec.rb +101 -101
- data/lib/soaspec/core_ext/hash.rb +35 -35
- data/lib/soaspec/cucumber/generic_steps.rb +85 -85
- data/lib/soaspec/demo.rb +4 -4
- data/lib/soaspec/exchange/exchange.rb +111 -111
- data/lib/soaspec/exchange/exchange_extractor.rb +83 -83
- data/lib/soaspec/exchange/exchange_properties.rb +26 -26
- data/lib/soaspec/exchange/exchange_repeater.rb +19 -19
- data/lib/soaspec/exchange/request_builder.rb +68 -68
- data/lib/soaspec/exchange/variable_storer.rb +22 -22
- data/lib/soaspec/exchange_handlers/exchange_handler.rb +126 -126
- data/lib/soaspec/exchange_handlers/handler_accessors.rb +130 -130
- data/lib/soaspec/exchange_handlers/response_extractor.rb +82 -82
- data/lib/soaspec/exchange_handlers/rest_exchanger_factory.rb +109 -109
- data/lib/soaspec/exchange_handlers/rest_handler.rb +259 -259
- data/lib/soaspec/exchange_handlers/rest_methods.rb +44 -44
- data/lib/soaspec/exchange_handlers/rest_parameters.rb +86 -86
- data/lib/soaspec/exchange_handlers/rest_parameters_defaults.rb +21 -21
- data/lib/soaspec/exchange_handlers/soap_handler.rb +235 -235
- data/lib/soaspec/exe_helpers.rb +92 -92
- data/lib/soaspec/generate_server.rb +37 -37
- data/lib/soaspec/generator/.rspec.erb +5 -5
- data/lib/soaspec/generator/.travis.yml.erb +5 -5
- data/lib/soaspec/generator/Gemfile.erb +8 -8
- data/lib/soaspec/generator/README.md.erb +29 -29
- data/lib/soaspec/generator/Rakefile.erb +19 -19
- data/lib/soaspec/generator/config/data/default.yml.erb +2 -2
- data/lib/soaspec/generator/css/bootstrap.css +6833 -6833
- data/lib/soaspec/generator/generate_exchange.html.erb +35 -35
- data/lib/soaspec/generator/lib/blz_service.rb.erb +26 -26
- data/lib/soaspec/generator/lib/dynamic_class_content.rb.erb +12 -12
- data/lib/soaspec/generator/lib/new_rest_service.rb.erb +51 -51
- data/lib/soaspec/generator/lib/new_soap_service.rb.erb +29 -29
- data/lib/soaspec/generator/lib/package_service.rb.erb +2 -2
- data/lib/soaspec/generator/lib/shared_example.rb.erb +8 -8
- data/lib/soaspec/generator/spec/dynamic_soap_spec.rb.erb +12 -12
- data/lib/soaspec/generator/spec/rest_spec.rb.erb +9 -9
- data/lib/soaspec/generator/spec/soap_spec.rb.erb +51 -51
- data/lib/soaspec/generator/spec/spec_helper.rb.erb +23 -23
- data/lib/soaspec/generator/template/soap_template.xml +6 -6
- data/lib/soaspec/indifferent_hash.rb +7 -7
- data/lib/soaspec/interpreter.rb +39 -39
- data/lib/soaspec/matchers.rb +114 -114
- data/lib/soaspec/not_found_errors.rb +13 -13
- data/lib/soaspec/o_auth2.rb +128 -128
- data/lib/soaspec/soaspec_shared_examples.rb +24 -24
- data/lib/soaspec/spec_logger.rb +121 -121
- data/lib/soaspec/template_reader.rb +28 -28
- data/lib/soaspec/test_server/bank.wsdl +90 -90
- data/lib/soaspec/test_server/get_bank.rb +164 -164
- data/lib/soaspec/test_server/id_manager.rb +39 -39
- data/lib/soaspec/test_server/invoices.rb +27 -27
- data/lib/soaspec/test_server/namespace.xml +14 -14
- data/lib/soaspec/test_server/note.xml +5 -5
- data/lib/soaspec/test_server/puppy_service.rb +19 -19
- data/lib/soaspec/test_server/test_attribute.rb +12 -12
- data/lib/soaspec/test_server/test_namespace.rb +12 -12
- data/lib/soaspec/version.rb +4 -3
- data/lib/soaspec/virtual_server.rb +174 -174
- data/lib/soaspec/wait.rb +41 -41
- data/lib/soaspec/wsdl_generator.rb +215 -215
- data/soaspec.gemspec +53 -53
- data/test.wsdl +116 -116
- data/test.xml +10 -10
- data/test_wsdl.rb +41 -41
- metadata +3 -4
data/lib/soaspec/wait.rb
CHANGED
@@ -1,41 +1,41 @@
|
|
1
|
-
module Soaspec
|
2
|
-
class TimeOutError < StandardError; end
|
3
|
-
# Class to enable waiting for an expected condition to return true
|
4
|
-
class Wait
|
5
|
-
DEFAULT_TIMEOUT = 5
|
6
|
-
DEFAULT_INTERVAL = 0.2
|
7
|
-
|
8
|
-
#
|
9
|
-
# Wait until the given block returns a true value.
|
10
|
-
#
|
11
|
-
# @param [Hash] opts Options for this instance
|
12
|
-
# @option opts [Numeric] :timeout (5) Seconds to wait before timing out.
|
13
|
-
# @option opts [Numeric] :interval (0.2) Seconds to sleep between polls.
|
14
|
-
# @option opts [String] :message Exception mesage if timed out.
|
15
|
-
# @option opts [Array, Exception] :ignore Exceptions to ignore while polling (default: Error::NoSuchElementError)
|
16
|
-
# @raise [Error::TimeOutError]
|
17
|
-
# @return [Object] the result of the block
|
18
|
-
#
|
19
|
-
def self.until(opts = {})
|
20
|
-
timeout = opts.fetch(:timeout, DEFAULT_TIMEOUT)
|
21
|
-
ignored = Array(opts[:ignore] || NoElementAtPath)
|
22
|
-
interval = opts.fetch(:interval, DEFAULT_INTERVAL)
|
23
|
-
end_time = Time.now + timeout
|
24
|
-
last_error = nil
|
25
|
-
|
26
|
-
until Time.now > end_time
|
27
|
-
begin
|
28
|
-
result = yield
|
29
|
-
return result if result
|
30
|
-
rescue *ignored => last_error
|
31
|
-
# swallowed
|
32
|
-
end
|
33
|
-
sleep interval
|
34
|
-
end
|
35
|
-
|
36
|
-
msg = opts[:message] ? opts[:message].dup : "timed out after #{timeout} seconds with interval of #{interval}"
|
37
|
-
msg << " (#{last_error.message})" if last_error
|
38
|
-
raise Soaspec::TimeOutError, msg
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
1
|
+
module Soaspec
|
2
|
+
class TimeOutError < StandardError; end
|
3
|
+
# Class to enable waiting for an expected condition to return true
|
4
|
+
class Wait
|
5
|
+
DEFAULT_TIMEOUT = 5
|
6
|
+
DEFAULT_INTERVAL = 0.2
|
7
|
+
|
8
|
+
#
|
9
|
+
# Wait until the given block returns a true value.
|
10
|
+
#
|
11
|
+
# @param [Hash] opts Options for this instance
|
12
|
+
# @option opts [Numeric] :timeout (5) Seconds to wait before timing out.
|
13
|
+
# @option opts [Numeric] :interval (0.2) Seconds to sleep between polls.
|
14
|
+
# @option opts [String] :message Exception mesage if timed out.
|
15
|
+
# @option opts [Array, Exception] :ignore Exceptions to ignore while polling (default: Error::NoSuchElementError)
|
16
|
+
# @raise [Error::TimeOutError]
|
17
|
+
# @return [Object] the result of the block
|
18
|
+
#
|
19
|
+
def self.until(opts = {})
|
20
|
+
timeout = opts.fetch(:timeout, DEFAULT_TIMEOUT)
|
21
|
+
ignored = Array(opts[:ignore] || NoElementAtPath)
|
22
|
+
interval = opts.fetch(:interval, DEFAULT_INTERVAL)
|
23
|
+
end_time = Time.now + timeout
|
24
|
+
last_error = nil
|
25
|
+
|
26
|
+
until Time.now > end_time
|
27
|
+
begin
|
28
|
+
result = yield
|
29
|
+
return result if result
|
30
|
+
rescue *ignored => last_error
|
31
|
+
# swallowed
|
32
|
+
end
|
33
|
+
sleep interval
|
34
|
+
end
|
35
|
+
|
36
|
+
msg = opts[:message] ? opts[:message].dup : "timed out after #{timeout} seconds with interval of #{interval}"
|
37
|
+
msg << " (#{last_error.message})" if last_error
|
38
|
+
raise Soaspec::TimeOutError, msg
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,215 +1,215 @@
|
|
1
|
-
module Soaspec
|
2
|
-
# Produce test content from a WSDL
|
3
|
-
module WsdlGenerator
|
4
|
-
include ExeHelpers
|
5
|
-
|
6
|
-
# Generate from WSDL
|
7
|
-
def generate_from_wsdl(options)
|
8
|
-
auth_name, auth_password = enter_auth_details if options[:auth] == 'basic'
|
9
|
-
@virtual = false
|
10
|
-
savon_options = { wsdl: options[:wsdl] }
|
11
|
-
savon_options[:basic_auth] = [auth_name, auth_password] if options[:auth] == 'basic'
|
12
|
-
|
13
|
-
wsdl_doc = Savon.client(**savon_options).wsdl
|
14
|
-
@wsdl_schemas = wsdl_doc.parser.schemas
|
15
|
-
# Create basic project files
|
16
|
-
create_files %w[Rakefile Gemfile README.md spec/spec_helper.rb], ignore_if_present: true
|
17
|
-
create_file(filename: '.rspec')
|
18
|
-
create_file(filename: '.travis.yml') if options[:ci] == 'travis'
|
19
|
-
create_folder 'logs'
|
20
|
-
create_file filename: "lib/#{options[:name].snakecase}.rb", content: class_content
|
21
|
-
|
22
|
-
# Files according to WSDL
|
23
|
-
wsdl_doc.operations.each do |operation, op_details|
|
24
|
-
puts "Creating files for operation: #{operation}"
|
25
|
-
@content = "default:\n"
|
26
|
-
@use_camel_case = false
|
27
|
-
puts 'Message params: ' + op_details.to_s
|
28
|
-
# From namespace identifier, find namespace, and for that find schemaLocation xsd and use that to build request
|
29
|
-
if op_details[:parameters]
|
30
|
-
op_details[:parameters].each do |element, details|
|
31
|
-
@use_camel_case = true unless /[[:upper:]]/.match(element.to_s[0]).nil?
|
32
|
-
@content += " #{element.to_s.snakecase}: #{fill_in_field_from_type(details[:type])} # #{details[:type]} \n"
|
33
|
-
# TODO: If details is a Hash need to loop again
|
34
|
-
end
|
35
|
-
end
|
36
|
-
wsdl_to_yaml_for root_elements_for(op_details)
|
37
|
-
params = []
|
38
|
-
params << 'convert_request_keys_to: :camelcase' if @use_camel_case
|
39
|
-
params_string = params == [] ? '' : ', ' + params.join(', ')
|
40
|
-
@class_params = "'#{camel_case(operation)}'#{params_string}"
|
41
|
-
|
42
|
-
create_file(filename: "config/data/#{operation}.yml", content: @content)
|
43
|
-
create_file(filename: "spec/#{operation}_spec.rb", content: generated_soap_spec_for(operation))
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# Attempt to calculate values of enumeration by looking up type in Schema
|
48
|
-
# @param [String] type Try out filling enumeration for type. Return Custom Type if can't be done
|
49
|
-
def try_enum_for(type)
|
50
|
-
raise "'@wsdl_schemas' must be defined" if @wsdl_schemas.nil?
|
51
|
-
|
52
|
-
custom_type = @wsdl_schemas.xpath("//*[@name='#{type}']")
|
53
|
-
if enumeration? custom_type
|
54
|
-
prefix = custom_type.first.namespace.prefix
|
55
|
-
enumerations = custom_type.xpath("//#{prefix}:enumeration")
|
56
|
-
return 'Custom Type' if enumerations.empty?
|
57
|
-
|
58
|
-
@enums_values = []
|
59
|
-
enumerations.each { |enum_value| @enums_values << "'#{enum_value['value']}'" }
|
60
|
-
"~randomize [#{@enums_values.join(', ')}]"
|
61
|
-
else
|
62
|
-
'Custom Type'
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# @param [Nokogiri::XML::NodeSet] type WSDL element type
|
67
|
-
# @return [Boolean] Whether WSDL type is an enumeration
|
68
|
-
def enumeration?(type)
|
69
|
-
return false unless type.first
|
70
|
-
|
71
|
-
!type.xpath("*/#{type.first.namespace.prefix}:enumeration").empty?
|
72
|
-
end
|
73
|
-
|
74
|
-
# @param [Nokogiri::XML::Element] element
|
75
|
-
# @return [String] Name of element excluding namespace
|
76
|
-
def name_after_namespace(element)
|
77
|
-
value_after_namespace(element.name)
|
78
|
-
end
|
79
|
-
|
80
|
-
# Return value of string after a namespace
|
81
|
-
# @param [String] string String to parse for part after namespace
|
82
|
-
# @return [String] Part after the namespace, demonstrated by ':'
|
83
|
-
def value_after_namespace(string)
|
84
|
-
string.split(':').last
|
85
|
-
end
|
86
|
-
|
87
|
-
# Based on WSDL type return a valid value
|
88
|
-
# @param [String] type Type without the WSDL
|
89
|
-
# @return [Object] Value representing type to fill in
|
90
|
-
def fill_in_field_from_type(type)
|
91
|
-
case type
|
92
|
-
when 'string' then options[:string_default] # 'test string'
|
93
|
-
when 'int' then 2
|
94
|
-
when 'boolean' then true
|
95
|
-
when 'double' then '1.5'
|
96
|
-
else
|
97
|
-
try_enum_for type
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# @param [Nokogiri::XML::Element] element Element to check
|
102
|
-
# @return [Boolean] True if Nokogiri element is a complex type, that is, has a complexType element underneath itself
|
103
|
-
def complex_type?(element)
|
104
|
-
element.children.any? { |child| name_after_namespace(child) == 'complexType' }
|
105
|
-
end
|
106
|
-
|
107
|
-
# @param [String, Symbol] underscore_separated Snakecase value to be converted to camel case
|
108
|
-
# @return [String] CamelCased value
|
109
|
-
def camel_case(underscore_separated)
|
110
|
-
underscore_separated.to_s.split('_').collect(&:capitalize).join
|
111
|
-
end
|
112
|
-
|
113
|
-
# Element at the root of an operation
|
114
|
-
# @param [Hash] op_details Hash with details from WSDL for an operation
|
115
|
-
def root_element_for(op_details)
|
116
|
-
root_element = @wsdl_schemas.at_xpath("//*[@name='#{op_details[:input]}']")
|
117
|
-
raise 'Operation has no input defined' if root_element.nil?
|
118
|
-
|
119
|
-
root_element
|
120
|
-
end
|
121
|
-
|
122
|
-
# Returns list of elements present at the root of an operation
|
123
|
-
# @param [Hash] op_details Hash with details from WSDL for an operation
|
124
|
-
# @return [Nokogiri::XML::NodeSet] List of the root elements in the SOAP body
|
125
|
-
def root_elements_for(op_details)
|
126
|
-
raise "'@wsdl_schemas' must be defined" if @wsdl_schemas.nil?
|
127
|
-
|
128
|
-
root_element = root_element_for(op_details)
|
129
|
-
schema_namespace = root_element.namespace.prefix
|
130
|
-
root_type = root_element['type']
|
131
|
-
if root_type
|
132
|
-
@wsdl_schemas.xpath("//*[@name='#{value_after_namespace(root_type)}']//#{schema_namespace}:element")
|
133
|
-
else
|
134
|
-
return [] unless complex_type? root_element # Empty Array if there are no root elements
|
135
|
-
|
136
|
-
complex_type = root_element.children.find { |c| c.name == 'complexType' }
|
137
|
-
sequence = complex_type.children.find { |c| c.name == 'sequence' }
|
138
|
-
sequence.xpath("#{schema_namespace}:element")
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# Adds documentation content for all children of XML element
|
143
|
-
# This will be an example yaml for setting SOAP requests
|
144
|
-
# @param [Nokogiri::XML::Element] element Type to document for
|
145
|
-
# @param [Integer] depth How many times to iterate depth for
|
146
|
-
def document_type_for(element, depth = 1)
|
147
|
-
# raise "Too far deep for #{element}" unless depth < 6
|
148
|
-
return unless depth < 6
|
149
|
-
|
150
|
-
if complex_type? element
|
151
|
-
complex_type = element.children.find { |c| name_after_namespace(c) == 'complexType' }
|
152
|
-
sequence = complex_type.children.find { |c| name_after_namespace(c) == 'sequence' }
|
153
|
-
sequence.children.select { |node| node.class == Nokogiri::XML::Element }.each do |sub_element|
|
154
|
-
document_type_for sub_element, depth + 1
|
155
|
-
end
|
156
|
-
else
|
157
|
-
return "No type seen for #{element}, #{element.class}" unless element['type']
|
158
|
-
|
159
|
-
name = element['name']
|
160
|
-
type = value_after_namespace(element['type'])
|
161
|
-
@use_camel_case = true unless /[[:upper:]]/.match(name[0]).nil?
|
162
|
-
spaces = ' ' * depth
|
163
|
-
@content += "#{spaces}#{name.snakecase}: #{fill_in_field_from_type(type)} # #{type} \n"
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
# @todo This should return YAML rather than just set an instance variable
|
168
|
-
# Makes a yaml string in a '@content' instance variable
|
169
|
-
# @param [Nokogiri::XML::NodeSet] list List to convert to YAML
|
170
|
-
def wsdl_to_yaml_for(list)
|
171
|
-
raise "'@content' string must be set" if @content.nil?
|
172
|
-
|
173
|
-
list.each { |element| document_type_for element }
|
174
|
-
end
|
175
|
-
|
176
|
-
# Prompt user for wsdl
|
177
|
-
def ask_wsdl
|
178
|
-
prompt = <<-WSDL_LOC
|
179
|
-
Enter WSDL:
|
180
|
-
WSDL_LOC
|
181
|
-
print prompt.chop
|
182
|
-
@wsdl = $stdin.gets.strip
|
183
|
-
puts
|
184
|
-
end
|
185
|
-
|
186
|
-
# Prompt user for Service name for wsdl
|
187
|
-
def name_of_wsdl
|
188
|
-
prompt = <<-WSDL_NAME
|
189
|
-
Enter what you would like to name WSDL (CamelCase):
|
190
|
-
WSDL_NAME
|
191
|
-
print prompt.chop
|
192
|
-
@name = $stdin.gets.strip
|
193
|
-
puts
|
194
|
-
end
|
195
|
-
|
196
|
-
# Prompt user to enter basic auth details
|
197
|
-
# @return [Array] Array with Basic auth username and password entered
|
198
|
-
def enter_auth_details
|
199
|
-
prompt = <<-AUTH_PROMPT
|
200
|
-
User Name:
|
201
|
-
AUTH_PROMPT
|
202
|
-
print prompt.chop
|
203
|
-
auth_name = $stdin.gets.strip
|
204
|
-
puts
|
205
|
-
|
206
|
-
prompt = <<-PASSWORD
|
207
|
-
User Password:
|
208
|
-
PASSWORD
|
209
|
-
print prompt.chop
|
210
|
-
auth_password = $stdin.gets.strip
|
211
|
-
puts
|
212
|
-
[auth_name, auth_password]
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
1
|
+
module Soaspec
|
2
|
+
# Produce test content from a WSDL
|
3
|
+
module WsdlGenerator
|
4
|
+
include ExeHelpers
|
5
|
+
|
6
|
+
# Generate from WSDL
|
7
|
+
def generate_from_wsdl(options)
|
8
|
+
auth_name, auth_password = enter_auth_details if options[:auth] == 'basic'
|
9
|
+
@virtual = false
|
10
|
+
savon_options = { wsdl: options[:wsdl] }
|
11
|
+
savon_options[:basic_auth] = [auth_name, auth_password] if options[:auth] == 'basic'
|
12
|
+
|
13
|
+
wsdl_doc = Savon.client(**savon_options).wsdl
|
14
|
+
@wsdl_schemas = wsdl_doc.parser.schemas
|
15
|
+
# Create basic project files
|
16
|
+
create_files %w[Rakefile Gemfile README.md spec/spec_helper.rb], ignore_if_present: true
|
17
|
+
create_file(filename: '.rspec')
|
18
|
+
create_file(filename: '.travis.yml') if options[:ci] == 'travis'
|
19
|
+
create_folder 'logs'
|
20
|
+
create_file filename: "lib/#{options[:name].snakecase}.rb", content: class_content
|
21
|
+
|
22
|
+
# Files according to WSDL
|
23
|
+
wsdl_doc.operations.each do |operation, op_details|
|
24
|
+
puts "Creating files for operation: #{operation}"
|
25
|
+
@content = "default:\n"
|
26
|
+
@use_camel_case = false
|
27
|
+
puts 'Message params: ' + op_details.to_s
|
28
|
+
# From namespace identifier, find namespace, and for that find schemaLocation xsd and use that to build request
|
29
|
+
if op_details[:parameters]
|
30
|
+
op_details[:parameters].each do |element, details|
|
31
|
+
@use_camel_case = true unless /[[:upper:]]/.match(element.to_s[0]).nil?
|
32
|
+
@content += " #{element.to_s.snakecase}: #{fill_in_field_from_type(details[:type])} # #{details[:type]} \n"
|
33
|
+
# TODO: If details is a Hash need to loop again
|
34
|
+
end
|
35
|
+
end
|
36
|
+
wsdl_to_yaml_for root_elements_for(op_details)
|
37
|
+
params = []
|
38
|
+
params << 'convert_request_keys_to: :camelcase' if @use_camel_case
|
39
|
+
params_string = params == [] ? '' : ', ' + params.join(', ')
|
40
|
+
@class_params = "'#{camel_case(operation)}'#{params_string}"
|
41
|
+
|
42
|
+
create_file(filename: "config/data/#{operation}.yml", content: @content)
|
43
|
+
create_file(filename: "spec/#{operation}_spec.rb", content: generated_soap_spec_for(operation))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Attempt to calculate values of enumeration by looking up type in Schema
|
48
|
+
# @param [String] type Try out filling enumeration for type. Return Custom Type if can't be done
|
49
|
+
def try_enum_for(type)
|
50
|
+
raise "'@wsdl_schemas' must be defined" if @wsdl_schemas.nil?
|
51
|
+
|
52
|
+
custom_type = @wsdl_schemas.xpath("//*[@name='#{type}']")
|
53
|
+
if enumeration? custom_type
|
54
|
+
prefix = custom_type.first.namespace.prefix
|
55
|
+
enumerations = custom_type.xpath("//#{prefix}:enumeration")
|
56
|
+
return 'Custom Type' if enumerations.empty?
|
57
|
+
|
58
|
+
@enums_values = []
|
59
|
+
enumerations.each { |enum_value| @enums_values << "'#{enum_value['value']}'" }
|
60
|
+
"~randomize [#{@enums_values.join(', ')}]"
|
61
|
+
else
|
62
|
+
'Custom Type'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param [Nokogiri::XML::NodeSet] type WSDL element type
|
67
|
+
# @return [Boolean] Whether WSDL type is an enumeration
|
68
|
+
def enumeration?(type)
|
69
|
+
return false unless type.first
|
70
|
+
|
71
|
+
!type.xpath("*/#{type.first.namespace.prefix}:enumeration").empty?
|
72
|
+
end
|
73
|
+
|
74
|
+
# @param [Nokogiri::XML::Element] element
|
75
|
+
# @return [String] Name of element excluding namespace
|
76
|
+
def name_after_namespace(element)
|
77
|
+
value_after_namespace(element.name)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Return value of string after a namespace
|
81
|
+
# @param [String] string String to parse for part after namespace
|
82
|
+
# @return [String] Part after the namespace, demonstrated by ':'
|
83
|
+
def value_after_namespace(string)
|
84
|
+
string.split(':').last
|
85
|
+
end
|
86
|
+
|
87
|
+
# Based on WSDL type return a valid value
|
88
|
+
# @param [String] type Type without the WSDL
|
89
|
+
# @return [Object] Value representing type to fill in
|
90
|
+
def fill_in_field_from_type(type)
|
91
|
+
case type
|
92
|
+
when 'string' then options[:string_default] # 'test string'
|
93
|
+
when 'int' then 2
|
94
|
+
when 'boolean' then true
|
95
|
+
when 'double' then '1.5'
|
96
|
+
else
|
97
|
+
try_enum_for type
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# @param [Nokogiri::XML::Element] element Element to check
|
102
|
+
# @return [Boolean] True if Nokogiri element is a complex type, that is, has a complexType element underneath itself
|
103
|
+
def complex_type?(element)
|
104
|
+
element.children.any? { |child| name_after_namespace(child) == 'complexType' }
|
105
|
+
end
|
106
|
+
|
107
|
+
# @param [String, Symbol] underscore_separated Snakecase value to be converted to camel case
|
108
|
+
# @return [String] CamelCased value
|
109
|
+
def camel_case(underscore_separated)
|
110
|
+
underscore_separated.to_s.split('_').collect(&:capitalize).join
|
111
|
+
end
|
112
|
+
|
113
|
+
# Element at the root of an operation
|
114
|
+
# @param [Hash] op_details Hash with details from WSDL for an operation
|
115
|
+
def root_element_for(op_details)
|
116
|
+
root_element = @wsdl_schemas.at_xpath("//*[@name='#{op_details[:input]}']")
|
117
|
+
raise 'Operation has no input defined' if root_element.nil?
|
118
|
+
|
119
|
+
root_element
|
120
|
+
end
|
121
|
+
|
122
|
+
# Returns list of elements present at the root of an operation
|
123
|
+
# @param [Hash] op_details Hash with details from WSDL for an operation
|
124
|
+
# @return [Nokogiri::XML::NodeSet] List of the root elements in the SOAP body
|
125
|
+
def root_elements_for(op_details)
|
126
|
+
raise "'@wsdl_schemas' must be defined" if @wsdl_schemas.nil?
|
127
|
+
|
128
|
+
root_element = root_element_for(op_details)
|
129
|
+
schema_namespace = root_element.namespace.prefix
|
130
|
+
root_type = root_element['type']
|
131
|
+
if root_type
|
132
|
+
@wsdl_schemas.xpath("//*[@name='#{value_after_namespace(root_type)}']//#{schema_namespace}:element")
|
133
|
+
else
|
134
|
+
return [] unless complex_type? root_element # Empty Array if there are no root elements
|
135
|
+
|
136
|
+
complex_type = root_element.children.find { |c| c.name == 'complexType' }
|
137
|
+
sequence = complex_type.children.find { |c| c.name == 'sequence' }
|
138
|
+
sequence.xpath("#{schema_namespace}:element")
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Adds documentation content for all children of XML element
|
143
|
+
# This will be an example yaml for setting SOAP requests
|
144
|
+
# @param [Nokogiri::XML::Element] element Type to document for
|
145
|
+
# @param [Integer] depth How many times to iterate depth for
|
146
|
+
def document_type_for(element, depth = 1)
|
147
|
+
# raise "Too far deep for #{element}" unless depth < 6
|
148
|
+
return unless depth < 6
|
149
|
+
|
150
|
+
if complex_type? element
|
151
|
+
complex_type = element.children.find { |c| name_after_namespace(c) == 'complexType' }
|
152
|
+
sequence = complex_type.children.find { |c| name_after_namespace(c) == 'sequence' }
|
153
|
+
sequence.children.select { |node| node.class == Nokogiri::XML::Element }.each do |sub_element|
|
154
|
+
document_type_for sub_element, depth + 1
|
155
|
+
end
|
156
|
+
else
|
157
|
+
return "No type seen for #{element}, #{element.class}" unless element['type']
|
158
|
+
|
159
|
+
name = element['name']
|
160
|
+
type = value_after_namespace(element['type'])
|
161
|
+
@use_camel_case = true unless /[[:upper:]]/.match(name[0]).nil?
|
162
|
+
spaces = ' ' * depth
|
163
|
+
@content += "#{spaces}#{name.snakecase}: #{fill_in_field_from_type(type)} # #{type} \n"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# @todo This should return YAML rather than just set an instance variable
|
168
|
+
# Makes a yaml string in a '@content' instance variable
|
169
|
+
# @param [Nokogiri::XML::NodeSet] list List to convert to YAML
|
170
|
+
def wsdl_to_yaml_for(list)
|
171
|
+
raise "'@content' string must be set" if @content.nil?
|
172
|
+
|
173
|
+
list.each { |element| document_type_for element }
|
174
|
+
end
|
175
|
+
|
176
|
+
# Prompt user for wsdl
|
177
|
+
def ask_wsdl
|
178
|
+
prompt = <<-WSDL_LOC
|
179
|
+
Enter WSDL:
|
180
|
+
WSDL_LOC
|
181
|
+
print prompt.chop
|
182
|
+
@wsdl = $stdin.gets.strip
|
183
|
+
puts
|
184
|
+
end
|
185
|
+
|
186
|
+
# Prompt user for Service name for wsdl
|
187
|
+
def name_of_wsdl
|
188
|
+
prompt = <<-WSDL_NAME
|
189
|
+
Enter what you would like to name WSDL (CamelCase):
|
190
|
+
WSDL_NAME
|
191
|
+
print prompt.chop
|
192
|
+
@name = $stdin.gets.strip
|
193
|
+
puts
|
194
|
+
end
|
195
|
+
|
196
|
+
# Prompt user to enter basic auth details
|
197
|
+
# @return [Array] Array with Basic auth username and password entered
|
198
|
+
def enter_auth_details
|
199
|
+
prompt = <<-AUTH_PROMPT
|
200
|
+
User Name:
|
201
|
+
AUTH_PROMPT
|
202
|
+
print prompt.chop
|
203
|
+
auth_name = $stdin.gets.strip
|
204
|
+
puts
|
205
|
+
|
206
|
+
prompt = <<-PASSWORD
|
207
|
+
User Password:
|
208
|
+
PASSWORD
|
209
|
+
print prompt.chop
|
210
|
+
auth_password = $stdin.gets.strip
|
211
|
+
puts
|
212
|
+
[auth_name, auth_password]
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|