Module: Lutaml::Model::Schema::XmlCompiler

Extended by:
XmlCompiler
Included in:
XmlCompiler
Defined in:
lib/lutaml/model/schema/xml_compiler.rb

Constant Summary collapse

DEFAULT_CLASSES =
%w[string integer int boolean].freeze
ELEMENT_ORDER_IGNORABLE =
%w[import include].freeze
MODEL_TEMPLATE =
ERB.new(<<~TEMPLATE, trim_mode: "-")
  # frozen_string_literal: true
  require "lutaml/model"
  <%=
    requiring_files = resolve_required_files(content)
    if requiring_files&.any?
      requiring_files.map { |file| "require_relative \\\"\#{file}\\\"" }.join("\n") + "\n"
    end
  -%>

  class <%= Utils.camel_case(name) %> < <%= resolve_parent_class(content) %>
  <%=
    if content&.key_exist?(:attributes)
      output = content.attributes.map do |attribute|
        attribute = @attributes[attribute.ref_class.split(":").last] if attribute.key?(:ref_class)
        "  attribute :\#{Utils.snake_case(attribute.name)}, \#{resolve_attribute_class(attribute)}\#{resolve_attribute_default(attribute) if attribute.key_exist?(:default)}"
      end.join("\n")
      output + "\n" if output && !output&.empty?
    end
  -%>
  <%=
    if content&.key_exist?(:sequence) || content&.key_exist?(:choice) || content&.key_exist?(:group)
      output = resolve_content(content).map do |element_name, element|
        element = @elements[element.ref_class.split(":")&.last] if element&.key_exist?(:ref_class)
        "  attribute :\#{Utils.snake_case(element_name)}, \#{resolve_element_class(element)}\#{resolve_occurs(element.arguments) if element.key_exist?(:arguments)}"
      end.join("\n")
      output + "\n" if output && !output&.empty?
    end
  -%>
  <%=
    if content&.key_exist?(:complex_content)
      resolve_complex_content(content.complex_content).map do |element_name, element|
        if element_name == :attributes
          element.map { |attribute| "  attribute :\#{Utils.snake_case(attribute.name)}, \#{resolve_attribute_class(attribute)}\#{resolve_attribute_default(attribute.default) if attribute.key_exist?(:default)}" }.join("\n")
        else
          element = @elements[element.ref_class.split(":")&.last] if element&.key_exist?(:ref_class)
          "  attribute :\#{Utils.snake_case(element_name)}, \#{resolve_element_class(element)}\#{resolve_occurs(element.arguments) if element.key_exist?(:arguments)}"
        end
      end.join("\n")
      output + "\n" if output && !output&.empty?
    end
  -%>
  <%= "  attribute :content, \#{content[:mixed] ? ':string' : content.simple_content.extension_base}" if content_exist = (content.key_exist?(:simple_content) && content.simple_content.key_exist?(:extension_base)) || content[:mixed] -%>

    xml do
      root "<%= name %>", mixed: true
  <%= resolve_namespace(options) %>
  <%= "    map_content to: :content\n" if content_exist -%>
  <%=
    if content&.key_exist?(:attributes)
      output = content.attributes.map do |attribute|
        attribute = @attributes[attribute.ref_class.split(":").last] if attribute.key?(:ref_class)
        "    map_attribute :\#{Utils.snake_case(attribute.name)}, to: :\#{Utils.snake_case(attribute.name)}"
      end.join("\n")
      output + "\n" if output && !output&.empty?
    end
  -%>
  <%=
    if content&.key_exist?(:sequence) || content&.key_exist?(:choice) || content&.key_exist?(:group)
      output = resolve_content(content).map do |element_name, element|
        element = @elements[element.ref_class.split(":")&.last] if element&.key_exist?(:ref_class)
        "    map_element :\#{element_name}, to: :\#{Utils.snake_case(element_name)}"
      end.join("\n")
      output + "\n" if output && !output&.empty?
    end
  -%>
  <%=
    if content&.key_exist?(:complex_content)
      output = resolve_complex_content(content.complex_content).map do |element_name, element|
        if element_name == :attributes
          element.map { |attribute| "    map_attribute :\#{Utils.snake_case(attribute.name)}, to: :\#{Utils.snake_case(attribute.name)}" }.join("\n")
        else
          element = @elements[element.ref_class.split(":")&.last] if element&.key_exist?(:ref_class)
          "    map_element :\#{element_name}, to: :\#{Utils.snake_case(element_name)}"
        end
      end.join("\n")
      output + "\n" if output && !output&.empty?
    end
  -%>
    end
  end

TEMPLATE
XML_ADAPTER_NOT_SET_MESSAGE =
<<~MSG
  Nokogiri is not set as XML Adapter.
  Make sure Nokogiri is installed and set as XML Adapter eg.
  execute: gem install nokogiri
  require 'lutaml/model/adapter/nokogiri'
  Lutaml::Model.xml_adapter = Lutaml::Model::Adapter::Nokogiri
MSG

Instance Method Summary collapse

Instance Method Details

#to_models(schema, options = {}) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/lutaml/model/schema/xml_compiler.rb', line 109

def to_models(schema, options = {})
  as_models(schema, options: options)
  @data_types_classes = Templates::SimpleType.create_simple_types(@simple_types)
  if options[:create_files]
    dir = options.fetch(:output_dir, "lutaml_models_#{Time.now.to_i}")
    FileUtils.mkdir_p(dir)
    @data_types_classes.each do |name, content|
      create_file(name, content, dir)
    end
    @complex_types.each do |name, content|
      create_file(name, MODEL_TEMPLATE.result(binding), dir)
    end
    nil
  else
    simple_types = @data_types_classes.transform_keys do |key|
      Utils.camel_case(key.to_s)
    end
    complex_types = @complex_types.to_h do |name, content|
      [Utils.camel_case(name), MODEL_TEMPLATE.result(binding)]
    end
    classes_hash = simple_types.merge(complex_types)
    require_classes(classes_hash) if options[:load_classes]
    classes_hash
  end
end