module ClassMaker

Constants

XMLSchemaNS

Public Instance Methods

make_definition(node, target = Object) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 11
def make_definition(node, target = Object)
  return if is_text node
  return if node.comment?
  return if node.name === 'include'

  attrs = node.attributes.to_hash
  return unless attrs['name'].present?

  name = attrs['name'].value

  if is_element(node) || is_choice(node)
    type = attrs['type'].value if attrs.key? 'type'
    if type.nil?
      complex_node = select_children(node, 'complexType').first
      defined_class_name = define_class name, complex_node, target
      { name: name, type: defined_class_name }
    else
      { name: name, type: sanitize_class_name(type.split(':').last) }
    end
  elsif is_simple node
    unless name.nil?
      restrictions = select_children(node, 'restriction').first
      Tiss::Generator::ValidatorGenerator.call(@version, name, restrictions, target)
    end
  elsif is_complex_root node
    define_class name, node, target
  end
end

Private Instance Methods

add_error(record, attribute, message = '') click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 229
def add_error(record, attribute, message = '')
  record.errors[attribute] << (options[:message] || message)
end
define_class(name, node, _target) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 79
def define_class(name, node, _target)
  name = sanitize_class_name(name)

  extension_class = ''
  complex_content = select_children(node, 'complexContent')
  extension = select_children(complex_content.first, 'extension').first
  extension_type = extension.attributes['base'].value if extension
  if extension
    extension_class = sanitize_class_name(extension_type.split(':').last)
  end

  elems = []
  unless node.nil?

    # Take 4
    elems = elements_by_node(node)

    # Take 3
    # parent_node = node
    # until parent_node.children.empty?
    #   elems << select_children(parent_node.children, 'element')
    #   parent_node = parent_node.children.select(&:present?).first
    # end


    # Take 2
    # parent_node = select_children(node, 'sequence')
    # parent_node = select_children(node, 'choice') if !parent_node || parent_node.empty?
    #
    # choices = []
    # choices = select_children parent_node.first, 'choice' unless parent_node.empty?
    #
    # elems = select_children parent_node.first, 'element' unless parent_node.empty?
    # unless parent_node.empty? || choices.empty?
    #   elems += select_children choices.first, 'element'
    # end

    # Take 1
    # sequence = select_children node, 'sequence'
    # choices = select_children sequence.first, 'choice' unless sequence.empty?
    # elems = select_children sequence.first, 'element' unless sequence.empty?
    # unless sequence.empty? || choices.empty?
    #   elems += select_children choices.first, 'element'
    # end
  end

  attributes = elems.flatten.map do |e|
    make_definition(e, self)
  end

  return if attributes.blank?

  Tiss::Generator::ModelGenerator.append(@version, name, attributes, extension_class)
  name
end
define_validator(name, restrictions, target) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 149
def define_validator(name, restrictions, target)
  name = "#{underscore(name)}_validator"
  name = camelize(name.to_s.sub(/.*\./, ''))

  base = restrictions
         .attributes['base'].value.split(':').last

  base = case base
         when 'decimal'
           'float'
         when 'boolean'
           'true_class'
         else
           base
         end

  type = constantize classify base

  ws_action = select_children(restrictions, 'whiteSpace').first
  ws_action = ws_action.attributes['value'].value unless ws_action.nil?

  enum_values = select_children(restrictions, 'enumeration').collect do |enum|
    enum.attributes['value'].value
  end

  pattern = select_children(restrictions, 'pattern').first
  pattern = pattern.attributes['value'].value unless pattern.nil?

  cls = Class.new ActiveModel::EachValidator do
    const_set 'TYPE', type
    const_set('WS_ACTION', ws_action) unless ws_action.nil?
    const_set 'ENUM_VALUES', enum_values
    unless pattern.nil?
      const_set 'PATTERN', pattern
      const_set 'REGEXP', Regexp.new("^#{pattern}$")
    end

    def validate_each(record, attribute, value)
      validate_type record, attribute, value
      handle_whitespaces record, attribute, value
      unless self.class::ENUM_VALUES.empty?
        validate_enumeration record, attribute, value
      end
      if self.class.const_defined? 'REGEXP'
        validate_regexp record, attribute, value
      end
    end

    private

    def validate_type(record, attribute, value)
      unless value.is_a? self.class::TYPE
        add_error record, attribute, "#{value}: not a #{self.class::TYPE}"
      end
    end

    def handle_whitespaces(record, attribute, value)
      if self.class.const_defined? 'WS_ACTION'
        case self.class::WS_ACTION
        when 'replace' then value.gsub! /[\n\t\r ]/, ' '
        when 'collapse' then
          value.gsub! /[\n\t\r]/, ' '
          value = value.split.join ' '
        end
        record.send "#{attribute}=", value
      end
    end

    def validate_enumeration(record, attribute, value)
      unless self.class::ENUM_VALUES.include? value.to_s
        add_error record, attribute, "#{value}: not in #{self.class::ENUM_VALUES}"
      end
    end

    def validate_regexp(record, attribute, value)
      unless value =~ self.class::REGEXP
        add_error record, attribute, "#{value}: not matching #{self.class::PATTERN}"
      end
    end

    def add_error(record, attribute, message = '')
      record.errors[attribute] << (options[:message] || message)
    end
  end
  ap name
  target.const_set name, cls
end
elements_by_node(node) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 135
def elements_by_node(node)
  elems = []
  node.children.each do |element|
    next if element.nil?

    if is_element(element)
      elems << element
      next
    end
    elems << elements_by_node(element)
  end
  elems.flatten.compact
end
handle_whitespaces(record, attribute, value) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 205
def handle_whitespaces(record, attribute, value)
  if self.class.const_defined? 'WS_ACTION'
    case self.class::WS_ACTION
    when 'replace' then value.gsub! /[\n\t\r ]/, ' '
    when 'collapse' then
      value.gsub! /[\n\t\r]/, ' '
      value = value.split.join ' '
    end
    record.send "#{attribute}=", value
  end
end
is_choice(node) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 58
def is_choice(node)
  is_xml_schema_node(node) && (node.name == 'choice')
end
is_complex_root(node) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 66
def is_complex_root(node)
  is_xml_schema_node(node) && (node.name == 'complexType')
end
is_element(node) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 54
def is_element(node)
  is_xml_schema_node(node) && (node.name == 'element')
end
is_father(node) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 70
def is_father(node)
  is_xml_schema_node(node) && (node.name == 'complexType')
end
is_simple(node) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 62
def is_simple(node)
  is_xml_schema_node(node) && (node.name == 'simpleType')
end
is_text(node) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 46
def is_text(node)
  node.name == 'text'
end
is_xml_schema_node(node) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 50
def is_xml_schema_node(node)
  namespace_of(node) == XMLSchemaNS
end
namespace_of(node) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 42
def namespace_of(node)
  node.namespace&.href
end
sanitize_class_name(name) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 74
def sanitize_class_name(name)
  name = underscore(name)
  camelize(name.to_s.sub(/.*\./, ''))
end
select_children(node, name) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 237
def select_children(node, name)
  return [] unless node

  node.children.select { |n| n.name == name }
end
validate_each(record, attribute, value) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 186
def validate_each(record, attribute, value)
  validate_type record, attribute, value
  handle_whitespaces record, attribute, value
  unless self.class::ENUM_VALUES.empty?
    validate_enumeration record, attribute, value
  end
  if self.class.const_defined? 'REGEXP'
    validate_regexp record, attribute, value
  end
end
validate_enumeration(record, attribute, value) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 217
def validate_enumeration(record, attribute, value)
  unless self.class::ENUM_VALUES.include? value.to_s
    add_error record, attribute, "#{value}: not in #{self.class::ENUM_VALUES}"
  end
end
validate_regexp(record, attribute, value) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 223
def validate_regexp(record, attribute, value)
  unless value =~ self.class::REGEXP
    add_error record, attribute, "#{value}: not matching #{self.class::PATTERN}"
  end
end
validate_type(record, attribute, value) click to toggle source
# File lib/tiss/xsd/class_maker.rb, line 199
def validate_type(record, attribute, value)
  unless value.is_a? self.class::TYPE
    add_error record, attribute, "#{value}: not a #{self.class::TYPE}"
  end
end