module Soaspec::WsdlGenerator

Produce test content from a WSDL

Public Instance Methods

ask_wsdl() click to toggle source

Prompt user for wsdl

# File lib/soaspec/wsdl_generator.rb, line 179
    def ask_wsdl
      prompt = <<-WSDL_LOC
  Enter WSDL:
      WSDL_LOC
      print prompt.chop
      @wsdl = $stdin.gets.strip
      puts
    end
camel_case(underscore_separated) click to toggle source

@param [String, Symbol] underscore_separated Snakecase value to be converted to camel case @return [String] CamelCased value

# File lib/soaspec/wsdl_generator.rb, line 111
def camel_case(underscore_separated)
  underscore_separated.to_s.split('_').collect(&:capitalize).join
end
complex_type?(element) click to toggle source

@param [Nokogiri::XML::Element] element Element to check @return [Boolean] True if Nokogiri element is a complex type, that is, has a complexType element underneath itself

# File lib/soaspec/wsdl_generator.rb, line 105
def complex_type?(element)
  element.children.any? { |child| name_after_namespace(child) == 'complexType' }
end
document_type_for(element, depth = 1) click to toggle source

Adds documentation content for all children of XML element This will be an example yaml for setting SOAP requests @param [Nokogiri::XML::Element] element Type to document for @param [Integer] depth How many times to iterate depth for

# File lib/soaspec/wsdl_generator.rb, line 148
def document_type_for(element, depth = 1)
  # raise "Too far deep for #{element}" unless depth < 6
  return unless depth < 6

  if complex_type? element
    complex_type = element.children.find { |c| name_after_namespace(c) == 'complexType' }
    sequence = complex_type.children.find { |c| name_after_namespace(c) == 'sequence' }
    sequence.children.select { |node| node.class == Nokogiri::XML::Element }.each do |sub_element|
      document_type_for sub_element, depth + 1
    end
  else
    return "No type seen for #{element}, #{element.class}" unless element['type']

    name = element['name']
    type = value_after_namespace(element['type'])
    @use_camel_case = true unless /[[:upper:]]/.match(name[0]).nil?
    spaces = '  ' * depth
    @content += "#{spaces}#{name.snakecase}: #{fill_in_field_from_type(type)} # #{type} \n"
  end
end
enter_auth_details() click to toggle source

Prompt user to enter basic auth details @return [Array] Array with Basic auth username and password entered

# File lib/soaspec/wsdl_generator.rb, line 200
    def enter_auth_details
      prompt = <<-AUTH_PROMPT
  User Name:
      AUTH_PROMPT
      print prompt.chop
      auth_name = $stdin.gets.strip
      puts

      prompt = <<-PASSWORD
  User Password:
      PASSWORD
      print prompt.chop
      auth_password = $stdin.gets.strip
      puts
      [auth_name, auth_password]
    end
enumeration?(type) click to toggle source

@param [Nokogiri::XML::NodeSet] type WSDL element type @return [Boolean] Whether WSDL type is an enumeration

# File lib/soaspec/wsdl_generator.rb, line 70
def enumeration?(type)
  return false unless type.first

  !type.xpath("*/#{type.first.namespace.prefix}:enumeration").empty?
end
fill_in_field_from_type(type) click to toggle source

Based on WSDL type return a valid value @param [String] type Type without the WSDL @return [Object] Value representing type to fill in

# File lib/soaspec/wsdl_generator.rb, line 92
def fill_in_field_from_type(type)
  case type
  when 'string' then options[:string_default] # 'test string'
  when 'int' then 2
  when 'boolean' then true
  when 'double' then '1.5'
  else
    try_enum_for type
  end
end
generate_from_wsdl(options) click to toggle source

Generate from WSDL

# File lib/soaspec/wsdl_generator.rb, line 9
def generate_from_wsdl(options)
  if options[:auth] == 'basic'
    auth_name, auth_password = enter_auth_details
    savon_options[:basic_auth] = [auth_name, auth_password]
  end
  @virtual = false
  savon_options = { wsdl: options[:wsdl] }

  wsdl_doc = Savon.client(**savon_options).wsdl
  @wsdl_schemas = wsdl_doc.parser.schemas
  # Create basic project files
  create_files %w[Rakefile Gemfile README.md spec/spec_helper.rb], ignore_if_present: true
  create_file(filename: '.rspec')
  create_file(filename: '.travis.yml') if options[:ci] == 'travis'
  create_folder 'logs'
  create_file filename: "lib/#{options[:name].snakecase}.rb", content: class_content

  # Files according to WSDL
  wsdl_doc.operations.each do |operation, op_details|
    puts "Creating files for operation: #{operation}"
    @content = "default:\n"
    @use_camel_case = false
    puts 'Message params: ' + op_details.to_s
    # From namespace identifier, find namespace, and for that find schemaLocation xsd and use that to build request
    op_details[:parameters]&.each do |element, details|
      @use_camel_case = true unless /[[:upper:]]/.match(element.to_s[0]).nil?
      @content += "  #{element.to_s.snakecase}: #{fill_in_field_from_type(details[:type])} # #{details[:type]} \n"
      # TODO: If details is a Hash need to loop again
    end
    wsdl_to_yaml_for root_elements_for(op_details)
    params = []
    params << 'convert_request_keys_to: :camelcase' if @use_camel_case
    params_string = params == [] ? '' : ', ' + params.join(', ')
    @class_params = "'#{camel_case(operation)}'#{params_string}"

    create_file(filename: "config/data/#{operation}.yml", content: @content)
    create_file(filename: "spec/#{operation}_spec.rb", content: generated_soap_spec_for(operation))
  end
end
name_after_namespace(element) click to toggle source

@param [Nokogiri::XML::Element] element @return [String] Name of element excluding namespace

# File lib/soaspec/wsdl_generator.rb, line 78
def name_after_namespace(element)
  value_after_namespace(element.name)
end
name_of_wsdl() click to toggle source

Prompt user for Service name for wsdl

# File lib/soaspec/wsdl_generator.rb, line 189
    def name_of_wsdl
      prompt = <<-WSDL_NAME
  Enter what you would like to name WSDL (CamelCase):
      WSDL_NAME
      print prompt.chop
      @name = $stdin.gets.strip
      puts
    end
root_element_for(op_details) click to toggle source

Element at the root of an operation @param [Hash] op_details Hash with details from WSDL for an operation

# File lib/soaspec/wsdl_generator.rb, line 117
def root_element_for(op_details)
  root_element = @wsdl_schemas.at_xpath("//*[@name='#{op_details[:input]}']")
  raise 'Operation has no input defined' if root_element.nil?

  root_element
end
root_elements_for(op_details) click to toggle source

Returns list of elements present at the root of an operation @param [Hash] op_details Hash with details from WSDL for an operation @return [Nokogiri::XML::NodeSet] List of the root elements in the SOAP body

# File lib/soaspec/wsdl_generator.rb, line 127
def root_elements_for(op_details)
  raise "'@wsdl_schemas' must be defined" if @wsdl_schemas.nil?

  root_element = root_element_for(op_details)
  schema_namespace = root_element.namespace.prefix
  root_type = root_element['type']
  if root_type
    @wsdl_schemas.xpath("//*[@name='#{value_after_namespace(root_type)}']//#{schema_namespace}:element")
  else
    return [] unless complex_type? root_element # Empty Array if there are no root elements

    complex_type = root_element.children.find { |c| c.name == 'complexType' }
    sequence = complex_type.children.find { |c| c.name == 'sequence' }
    sequence.xpath("#{schema_namespace}:element")
  end
end
try_enum_for(type) click to toggle source

Attempt to calculate values of enumeration by looking up type in Schema @param [String] type Try out filling enumeration for type. Return Custom Type if can't be done

# File lib/soaspec/wsdl_generator.rb, line 51
def try_enum_for(type)
  raise "'@wsdl_schemas' must be defined" if @wsdl_schemas.nil?

  custom_type = @wsdl_schemas.xpath("//*[@name='#{type}']")
  if enumeration? custom_type
    prefix = custom_type.first.namespace.prefix
    enumerations = custom_type.xpath("//#{prefix}:enumeration")
    return 'Custom Type' if enumerations.empty?

    @enums_values = []
    enumerations.each { |enum_value| @enums_values << "'#{enum_value['value']}'" }
    "~randomize [#{@enums_values.join(', ')}]"
  else
    'Custom Type'
  end
end
value_after_namespace(string) click to toggle source

Return value of string after a namespace @param [String] string String to parse for part after namespace @return [String] Part after the namespace, demonstrated by ':'

# File lib/soaspec/wsdl_generator.rb, line 85
def value_after_namespace(string)
  string.split(':').last
end
wsdl_to_yaml_for(list) click to toggle source

@todo This should return YAML rather than just set an instance variable Makes a yaml string in a '@content' instance variable @param [Nokogiri::XML::NodeSet] list List to convert to YAML

# File lib/soaspec/wsdl_generator.rb, line 172
def wsdl_to_yaml_for(list)
  raise "'@content' string must be set" if @content.nil?

  list.each { |element| document_type_for element }
end