lutaml-model 0.7.3 → 0.7.5
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/.envrc +1 -0
- data/.github/workflows/release.yml +3 -0
- data/.gitignore +6 -1
- data/.irbrc +1 -0
- data/.pryrc +1 -0
- data/.rubocop_todo.yml +25 -52
- data/README.adoc +2177 -192
- data/docs/custom_registers.adoc +228 -0
- data/docs/schema_generation.adoc +898 -0
- data/docs/schema_import.adoc +364 -0
- data/flake.lock +114 -0
- data/flake.nix +103 -0
- data/lib/lutaml/model/attribute.rb +230 -94
- data/lib/lutaml/model/choice.rb +30 -0
- data/lib/lutaml/model/collection.rb +194 -0
- data/lib/lutaml/model/comparable_model.rb +3 -3
- data/lib/lutaml/model/config.rb +26 -3
- data/lib/lutaml/model/constants.rb +2 -0
- data/lib/lutaml/model/error/element_count_out_of_range_error.rb +29 -0
- data/lib/lutaml/model/error/invalid_attribute_name_error.rb +15 -0
- data/lib/lutaml/model/error/invalid_attribute_options_error.rb +16 -0
- data/lib/lutaml/model/error/invalid_choice_range_error.rb +3 -5
- data/lib/lutaml/model/error/register/not_registrable_class_error.rb +11 -0
- data/lib/lutaml/model/error/type/invalid_value_error.rb +5 -3
- data/lib/lutaml/model/error/type/max_bound_error.rb +20 -0
- data/lib/lutaml/model/error/type/max_length_error.rb +20 -0
- data/lib/lutaml/model/error/type/min_bound_error.rb +20 -0
- data/lib/lutaml/model/error/type/min_length_error.rb +20 -0
- data/lib/lutaml/model/error/type/pattern_not_matched_error.rb +18 -0
- data/lib/lutaml/model/error/validation_failed_error.rb +9 -0
- data/lib/lutaml/model/error.rb +10 -0
- data/lib/lutaml/model/errors.rb +36 -0
- data/lib/lutaml/model/format_registry.rb +5 -2
- data/lib/lutaml/model/global_register.rb +41 -0
- data/lib/lutaml/model/{hash.rb → hash_adapter.rb} +5 -5
- data/lib/lutaml/model/jsonl/document.rb +14 -0
- data/lib/lutaml/model/jsonl/mapping.rb +19 -0
- data/lib/lutaml/model/jsonl/mapping_rule.rb +9 -0
- data/lib/lutaml/model/jsonl/standard_adapter.rb +33 -0
- data/lib/lutaml/model/jsonl/transform.rb +19 -0
- data/lib/lutaml/model/jsonl.rb +21 -0
- data/lib/lutaml/model/key_value_document.rb +3 -2
- data/lib/lutaml/model/mapping/key_value_mapping.rb +64 -4
- data/lib/lutaml/model/mapping/key_value_mapping_rule.rb +4 -0
- data/lib/lutaml/model/mapping/mapping_rule.rb +8 -3
- data/lib/lutaml/model/register.rb +105 -0
- data/lib/lutaml/model/registrable.rb +6 -0
- data/lib/lutaml/model/schema/base_schema.rb +64 -0
- data/lib/lutaml/model/schema/decorators/attribute.rb +114 -0
- data/lib/lutaml/model/schema/decorators/choices.rb +31 -0
- data/lib/lutaml/model/schema/decorators/class_definition.rb +85 -0
- data/lib/lutaml/model/schema/decorators/definition_collection.rb +97 -0
- data/lib/lutaml/model/schema/generator/definition.rb +53 -0
- data/lib/lutaml/model/schema/generator/definitions_collection.rb +81 -0
- data/lib/lutaml/model/schema/generator/properties_collection.rb +63 -0
- data/lib/lutaml/model/schema/generator/property.rb +110 -0
- data/lib/lutaml/model/schema/generator/ref.rb +24 -0
- data/lib/lutaml/model/schema/helpers/template_helper.rb +49 -0
- data/lib/lutaml/model/schema/json_schema.rb +42 -49
- data/lib/lutaml/model/schema/relaxng_schema.rb +14 -10
- data/lib/lutaml/model/schema/renderer.rb +36 -0
- data/lib/lutaml/model/schema/shared_methods.rb +24 -0
- data/lib/lutaml/model/schema/templates/model.erb +9 -0
- data/lib/lutaml/model/schema/xml_compiler/attribute.rb +85 -0
- data/lib/lutaml/model/schema/xml_compiler/attribute_group.rb +45 -0
- data/lib/lutaml/model/schema/xml_compiler/choice.rb +65 -0
- data/lib/lutaml/model/schema/xml_compiler/complex_content.rb +27 -0
- data/lib/lutaml/model/schema/xml_compiler/complex_content_restriction.rb +34 -0
- data/lib/lutaml/model/schema/xml_compiler/complex_type.rb +136 -0
- data/lib/lutaml/model/schema/xml_compiler/element.rb +104 -0
- data/lib/lutaml/model/schema/xml_compiler/group.rb +97 -0
- data/lib/lutaml/model/schema/xml_compiler/restriction.rb +101 -0
- data/lib/lutaml/model/schema/xml_compiler/sequence.rb +50 -0
- data/lib/lutaml/model/schema/xml_compiler/simple_content.rb +36 -0
- data/lib/lutaml/model/schema/xml_compiler/simple_type.rb +189 -0
- data/lib/lutaml/model/schema/xml_compiler.rb +231 -587
- data/lib/lutaml/model/schema/xsd_schema.rb +12 -8
- data/lib/lutaml/model/schema/yaml_schema.rb +41 -35
- data/lib/lutaml/model/schema.rb +1 -0
- data/lib/lutaml/model/sequence.rb +60 -30
- data/lib/lutaml/model/serialize.rb +175 -53
- data/lib/lutaml/model/services/base.rb +11 -0
- data/lib/lutaml/model/services/logger.rb +2 -2
- data/lib/lutaml/model/services/rule_value_extractor.rb +92 -0
- data/lib/lutaml/model/services/type/validator/number.rb +25 -0
- data/lib/lutaml/model/services/type/validator/string.rb +52 -0
- data/lib/lutaml/model/services/type/validator.rb +43 -0
- data/lib/lutaml/model/services/validator.rb +145 -0
- data/lib/lutaml/model/services.rb +3 -0
- data/lib/lutaml/model/transform/key_value_transform.rb +60 -50
- data/lib/lutaml/model/transform/xml_transform.rb +46 -57
- data/lib/lutaml/model/transform.rb +22 -8
- data/lib/lutaml/model/type/boolean.rb +1 -1
- data/lib/lutaml/model/type/date.rb +1 -1
- data/lib/lutaml/model/type/date_time.rb +1 -1
- data/lib/lutaml/model/type/decimal.rb +11 -9
- data/lib/lutaml/model/type/float.rb +2 -1
- data/lib/lutaml/model/type/integer.rb +24 -21
- data/lib/lutaml/model/type/string.rb +4 -2
- data/lib/lutaml/model/type/time.rb +1 -1
- data/lib/lutaml/model/type/time_without_date.rb +1 -1
- data/lib/lutaml/model/type/value.rb +5 -1
- data/lib/lutaml/model/type.rb +5 -2
- data/lib/lutaml/model/utils.rb +30 -8
- data/lib/lutaml/model/validation.rb +6 -4
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/xml/document.rb +37 -19
- data/lib/lutaml/model/xml/mapping.rb +74 -13
- data/lib/lutaml/model/xml/mapping_rule.rb +10 -2
- data/lib/lutaml/model/xml/nokogiri_adapter.rb +5 -3
- data/lib/lutaml/model/xml/oga/element.rb +4 -1
- data/lib/lutaml/model/xml/oga_adapter.rb +4 -3
- data/lib/lutaml/model/xml/ox_adapter.rb +20 -6
- data/lib/lutaml/model/xml/xml_element.rb +3 -28
- data/lib/lutaml/model/xml_adapter/element.rb +1 -1
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +1 -1
- data/lib/lutaml/model/xml_adapter/oga_adapter.rb +1 -1
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +1 -1
- data/lib/lutaml/model/yamls/document.rb +14 -0
- data/lib/lutaml/model/yamls/mapping.rb +19 -0
- data/lib/lutaml/model/yamls/mapping_rule.rb +9 -0
- data/lib/lutaml/model/yamls/standard_adapter.rb +34 -0
- data/lib/lutaml/model/yamls/transform.rb +19 -0
- data/lib/lutaml/model/yamls.rb +21 -0
- data/lib/lutaml/model.rb +7 -31
- data/spec/benchmarks/xml_parsing_benchmark_spec.rb +4 -5
- data/spec/fixtures/xml/advanced_test_schema.xsd +134 -0
- data/spec/fixtures/xml/examples/nested_categories.xml +55 -0
- data/spec/fixtures/xml/examples/valid_catalog.xml +43 -0
- data/spec/fixtures/xml/product_catalog.xsd +151 -0
- data/spec/fixtures/xml/specifications_schema.xsd +38 -0
- data/spec/lutaml/model/attribute_collection_spec.rb +101 -0
- data/spec/lutaml/model/attribute_spec.rb +41 -44
- data/spec/lutaml/model/choice_spec.rb +44 -0
- data/spec/lutaml/model/custom_collection_spec.rb +830 -0
- data/spec/lutaml/model/custom_model_spec.rb +15 -3
- data/spec/lutaml/model/defaults_spec.rb +5 -1
- data/spec/lutaml/model/global_register_spec.rb +108 -0
- data/spec/lutaml/model/group_spec.rb +9 -3
- data/spec/lutaml/model/jsonl/standard_adapter_spec.rb +91 -0
- data/spec/lutaml/model/jsonl_spec.rb +229 -0
- data/spec/lutaml/model/multiple_mapping_spec.rb +1 -1
- data/spec/lutaml/model/register/key_value_spec.rb +275 -0
- data/spec/lutaml/model/register/xml_spec.rb +187 -0
- data/spec/lutaml/model/register_spec.rb +147 -0
- data/spec/lutaml/model/rule_value_extractor_spec.rb +162 -0
- data/spec/lutaml/model/schema/generator/definitions_collection_spec.rb +120 -0
- data/spec/lutaml/model/schema/json_schema_spec.rb +412 -51
- data/spec/lutaml/model/schema/json_schema_to_models_spec.rb +383 -0
- data/spec/lutaml/model/schema/xml_compiler/attribute_group_spec.rb +65 -0
- data/spec/lutaml/model/schema/xml_compiler/attribute_spec.rb +63 -0
- data/spec/lutaml/model/schema/xml_compiler/choice_spec.rb +71 -0
- data/spec/lutaml/model/schema/xml_compiler/complex_content_restriction_spec.rb +55 -0
- data/spec/lutaml/model/schema/xml_compiler/complex_content_spec.rb +37 -0
- data/spec/lutaml/model/schema/xml_compiler/complex_type_spec.rb +173 -0
- data/spec/lutaml/model/schema/xml_compiler/element_spec.rb +63 -0
- data/spec/lutaml/model/schema/xml_compiler/group_spec.rb +86 -0
- data/spec/lutaml/model/schema/xml_compiler/restriction_spec.rb +76 -0
- data/spec/lutaml/model/schema/xml_compiler/sequence_spec.rb +59 -0
- data/spec/lutaml/model/schema/xml_compiler/simple_content_spec.rb +55 -0
- data/spec/lutaml/model/schema/xml_compiler/simple_type_spec.rb +181 -0
- data/spec/lutaml/model/schema/xml_compiler_spec.rb +503 -1804
- data/spec/lutaml/model/schema/yaml_schema_spec.rb +249 -26
- data/spec/lutaml/model/sequence_spec.rb +36 -0
- data/spec/lutaml/model/serializable_spec.rb +31 -0
- data/spec/lutaml/model/type_spec.rb +8 -4
- data/spec/lutaml/model/utils_spec.rb +3 -3
- data/spec/lutaml/model/xml/derived_attributes_spec.rb +1 -1
- data/spec/lutaml/model/xml/xml_element_spec.rb +7 -1
- data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +6 -6
- data/spec/lutaml/model/xml_adapter_spec.rb +24 -0
- data/spec/lutaml/model/xml_mapping_rule_spec.rb +11 -4
- data/spec/lutaml/model/xml_mapping_spec.rb +1 -1
- data/spec/lutaml/model/yamls/standard_adapter_spec.rb +183 -0
- data/spec/lutaml/model/yamls_spec.rb +294 -0
- data/spec/spec_helper.rb +1 -0
- metadata +105 -9
- data/lib/lutaml/model/schema/templates/simple_type.rb +0 -247
- /data/lib/lutaml/model/{hash → hash_adapter}/document.rb +0 -0
- /data/lib/lutaml/model/{hash → hash_adapter}/mapping.rb +0 -0
- /data/lib/lutaml/model/{hash → hash_adapter}/mapping_rule.rb +0 -0
- /data/lib/lutaml/model/{hash → hash_adapter}/standard_adapter.rb +0 -0
- /data/lib/lutaml/model/{hash → hash_adapter}/transform.rb +0 -0
@@ -4,11 +4,14 @@ module Lutaml
|
|
4
4
|
module Model
|
5
5
|
module Schema
|
6
6
|
class RelaxngSchema
|
7
|
+
extend SharedMethods
|
8
|
+
|
7
9
|
def self.generate(klass, options = {})
|
10
|
+
register = extract_register_from(klass)
|
8
11
|
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
9
12
|
xml.grammar(xmlns: "http://relaxng.org/ns/structure/1.0") do
|
10
13
|
generate_start(xml, klass)
|
11
|
-
generate_define(xml, klass)
|
14
|
+
generate_define(xml, klass, register)
|
12
15
|
end
|
13
16
|
end
|
14
17
|
|
@@ -21,34 +24,35 @@ module Lutaml
|
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
24
|
-
def self.generate_attributes(xml, klass)
|
27
|
+
def self.generate_attributes(xml, klass, register)
|
25
28
|
klass.attributes.each do |name, attr|
|
26
|
-
|
27
|
-
|
29
|
+
attr_type = attr.type(register)
|
30
|
+
if attr_type <= Lutaml::Model::Serialize
|
31
|
+
xml.ref(name: attr_type.name)
|
28
32
|
elsif attr.collection?
|
29
33
|
xml.zeroOrMore do
|
30
34
|
xml.element(name: name) do
|
31
|
-
xml.data(type: get_relaxng_type(
|
35
|
+
xml.data(type: get_relaxng_type(attr_type))
|
32
36
|
end
|
33
37
|
end
|
34
38
|
else
|
35
39
|
xml.element(name: name) do
|
36
|
-
xml.data(type: get_relaxng_type(
|
40
|
+
xml.data(type: get_relaxng_type(attr_type))
|
37
41
|
end
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
41
45
|
|
42
|
-
def self.generate_define(xml, klass)
|
46
|
+
def self.generate_define(xml, klass, register)
|
43
47
|
xml.define(name: klass.name) do
|
44
48
|
xml.element(name: klass.name) do
|
45
|
-
generate_attributes(xml, klass)
|
49
|
+
generate_attributes(xml, klass, register)
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
49
53
|
klass.attributes.each_value do |attr|
|
50
|
-
if attr.type <= Lutaml::Model::Serialize
|
51
|
-
generate_define(xml, attr.type)
|
54
|
+
if attr.type(register) <= Lutaml::Model::Serialize
|
55
|
+
generate_define(xml, attr.type(register), register)
|
52
56
|
end
|
53
57
|
end
|
54
58
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "erb"
|
2
|
+
require "ostruct"
|
3
|
+
|
4
|
+
require_relative "helpers/template_helper"
|
5
|
+
|
6
|
+
module Lutaml
|
7
|
+
module Model
|
8
|
+
module Schema
|
9
|
+
class Context
|
10
|
+
include Lutaml::Model::Schema::Helpers::TemplateHelper
|
11
|
+
|
12
|
+
attr_reader :schema
|
13
|
+
|
14
|
+
def initialize(schema)
|
15
|
+
@schema = schema
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Renderer
|
20
|
+
def self.render(template_path, context = {})
|
21
|
+
new(template_path).render(context)
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(template_path)
|
25
|
+
@template = File.read(template_path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(context = {})
|
29
|
+
context = Context.new(context[:schema])
|
30
|
+
|
31
|
+
ERB.new(@template, trim_mode: "-").result(context.instance_eval { binding })
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Schema
|
6
|
+
module SharedMethods
|
7
|
+
def extract_register_from(klass)
|
8
|
+
register = if klass.class_variable_defined?(:@@register)
|
9
|
+
klass.class_variable_get(:@@register)
|
10
|
+
end
|
11
|
+
|
12
|
+
case register
|
13
|
+
when Lutaml::Model::Register
|
14
|
+
register.id
|
15
|
+
when String, Symbol
|
16
|
+
register.to_sym
|
17
|
+
else
|
18
|
+
Lutaml::Model::Config.default_register
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require "lutaml/model"
|
2
|
+
|
3
|
+
<%= open_namespaces(schema.namespaces) %>
|
4
|
+
<%= indent(schema.namespaces.size) %>class <%= schema.name %> < <%= schema.parent_class %>
|
5
|
+
<% schema.attributes.each do |attribute| -%>
|
6
|
+
<%= attribute_line(attribute, schema.namespaces.size + 1) %>
|
7
|
+
<% end -%>
|
8
|
+
<%= indent(schema.namespaces.size) %>end
|
9
|
+
<%= close_namespaces(schema.namespaces) %>
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Schema
|
6
|
+
module XmlCompiler
|
7
|
+
class Attribute
|
8
|
+
attr_accessor :id,
|
9
|
+
:ref,
|
10
|
+
:name,
|
11
|
+
:type,
|
12
|
+
:default
|
13
|
+
|
14
|
+
TEMPLATE = ERB.new(<<~TEMPLATE, trim_mode: "-")
|
15
|
+
<%= indent %>attribute :<%= resolved_name %>, :<%= resolved_type %>
|
16
|
+
TEMPLATE
|
17
|
+
|
18
|
+
XML_MAPPING_TEMPLATE = ERB.new(<<~XML_MAPPING_TEMPLATE, trim_mode: "-")
|
19
|
+
<%= indent %>map_attribute :<%= resolved_name(change_case: false) %>, to: :<%= resolved_name %><%= namespace_prefix_option %>
|
20
|
+
XML_MAPPING_TEMPLATE
|
21
|
+
|
22
|
+
def initialize(name: nil, ref: nil)
|
23
|
+
@name = name
|
24
|
+
@ref = ref
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_attributes(indent)
|
28
|
+
return if skippable?
|
29
|
+
|
30
|
+
TEMPLATE.result(binding)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_xml_mapping(indent)
|
34
|
+
return if skippable?
|
35
|
+
|
36
|
+
XML_MAPPING_TEMPLATE.result(binding)
|
37
|
+
end
|
38
|
+
|
39
|
+
def required_files
|
40
|
+
return if skippable?
|
41
|
+
|
42
|
+
raw_type = resolved_type(change_case: false)
|
43
|
+
if raw_type == "decimal"
|
44
|
+
"require \"bigdecimal\""
|
45
|
+
elsif !SimpleType.skippable?(raw_type)
|
46
|
+
"require_relative \"#{Utils.snake_case(raw_type)}\""
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def resolved_name(change_case: true)
|
53
|
+
@current_name ||= name || referenced_instance&.name
|
54
|
+
change_case ? Utils.snake_case(@current_name) : @current_name
|
55
|
+
end
|
56
|
+
|
57
|
+
def resolved_type(change_case: true)
|
58
|
+
@current_type ||= type || referenced_instance&.type
|
59
|
+
klass_name = last_of_split(@current_type)
|
60
|
+
change_case ? Utils.snake_case(klass_name) : klass_name
|
61
|
+
end
|
62
|
+
|
63
|
+
def referenced_instance
|
64
|
+
@referenced_instance ||= XmlCompiler.attributes[last_of_split]
|
65
|
+
end
|
66
|
+
|
67
|
+
def last_of_split(field = ref)
|
68
|
+
field&.split(":")&.last
|
69
|
+
end
|
70
|
+
|
71
|
+
def skippable?
|
72
|
+
resolved_name == "schema_location"
|
73
|
+
end
|
74
|
+
|
75
|
+
def namespace_prefix_option
|
76
|
+
return "" unless Utils.present?(ref)
|
77
|
+
return "" unless ref.start_with?("xml:")
|
78
|
+
|
79
|
+
", namespace: \"http://www.w3.org/XML/1998/namespace\", prefix: \"xml\""
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Schema
|
6
|
+
module XmlCompiler
|
7
|
+
class AttributeGroup
|
8
|
+
attr_accessor :name, :ref, :instances
|
9
|
+
|
10
|
+
def initialize(name: nil, ref: nil)
|
11
|
+
@name = name
|
12
|
+
@ref = ref
|
13
|
+
@instances = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(instance)
|
17
|
+
return if instance.nil?
|
18
|
+
|
19
|
+
@instances << instance
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_attributes(indent)
|
23
|
+
resolved_instances.map { |instance| instance.to_attributes(indent) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_xml_mapping(indent)
|
27
|
+
resolved_instances.map { |instance| instance.to_xml_mapping(indent) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def required_files
|
31
|
+
resolved_instances.map(&:required_files)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def resolved_instances
|
37
|
+
return @instances unless Utils.present?(@ref)
|
38
|
+
|
39
|
+
XmlCompiler.attribute_groups[@ref]&.instances
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Schema
|
6
|
+
module XmlCompiler
|
7
|
+
class Choice
|
8
|
+
attr_accessor :instances, :min_occurs, :max_occurs
|
9
|
+
|
10
|
+
INDENT = " "
|
11
|
+
|
12
|
+
TEMPLATE = ERB.new(<<~TEMPLATE, trim_mode: "-")
|
13
|
+
<%= indent %>choice<%= block_options %> do
|
14
|
+
<%= instances.map { |instance| instance.to_attributes(indent + INDENT) }.join -%>
|
15
|
+
<%= indent %>end
|
16
|
+
TEMPLATE
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@instances = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def <<(instance)
|
23
|
+
return if instance.nil?
|
24
|
+
|
25
|
+
@instances << instance
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_attributes(indent = INDENT)
|
29
|
+
TEMPLATE.result(binding)
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_xml_mapping(indent = INDENT)
|
33
|
+
instances.filter_map { |instance| instance.to_xml_mapping(indent) }.join
|
34
|
+
end
|
35
|
+
|
36
|
+
def required_files
|
37
|
+
@instances.map(&:required_files).flatten.compact
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def min_option
|
43
|
+
"min: #{min_occurs.nil? ? 1 : min_occurs.to_i}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def max_option
|
47
|
+
value = case max_occurs
|
48
|
+
when "unbounded"
|
49
|
+
"Float::INFINITY"
|
50
|
+
when NilClass
|
51
|
+
1
|
52
|
+
else
|
53
|
+
max_occurs.to_i
|
54
|
+
end
|
55
|
+
", max: #{value}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def block_options
|
59
|
+
["(", min_option, max_option, ")"].compact.join
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Lutaml
|
2
|
+
module Model
|
3
|
+
module Schema
|
4
|
+
module XmlCompiler
|
5
|
+
class ComplexContent
|
6
|
+
attr_accessor :restriction
|
7
|
+
|
8
|
+
def initialize(restriction = nil)
|
9
|
+
@restriction = restriction
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_attributes(indent)
|
13
|
+
restriction&.to_attributes(indent)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_xml_mapping(indent)
|
17
|
+
restriction&.to_xml_mapping(indent)
|
18
|
+
end
|
19
|
+
|
20
|
+
def required_files
|
21
|
+
restriction&.required_files
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Lutaml
|
2
|
+
module Model
|
3
|
+
module Schema
|
4
|
+
module XmlCompiler
|
5
|
+
class ComplexContentRestriction
|
6
|
+
attr_accessor :base, :instances
|
7
|
+
|
8
|
+
def initialize(base: nil, instances: [])
|
9
|
+
@base = base
|
10
|
+
@instances = instances
|
11
|
+
end
|
12
|
+
|
13
|
+
def <<(instance)
|
14
|
+
return if instance.nil?
|
15
|
+
|
16
|
+
@instances << instance
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_attributes(indent)
|
20
|
+
instances.map { |instance| instance.to_attributes(indent) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_xml_mapping(indent)
|
24
|
+
instances.map { |instance| instance.to_xml_mapping(indent) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def required_files
|
28
|
+
instances.map(&:required_files)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Lutaml
|
2
|
+
module Model
|
3
|
+
module Schema
|
4
|
+
module XmlCompiler
|
5
|
+
class ComplexType
|
6
|
+
attr_accessor :id,
|
7
|
+
:name,
|
8
|
+
:mixed,
|
9
|
+
:instances,
|
10
|
+
:base_class,
|
11
|
+
:simple_content
|
12
|
+
|
13
|
+
SERIALIZABLE_BASE_CLASS = "Lutaml::Model::Serializable".freeze
|
14
|
+
|
15
|
+
SIMPLE_CONTENT_ATTRIBUTE_TEMPLATE = ERB.new(<<~TEMPLATE, trim_mode: "-")
|
16
|
+
<%= @indent %>attribute :content, :<%= simple_content_type %>
|
17
|
+
<%= simple_content.to_attributes(@indent) if simple_content? -%>
|
18
|
+
TEMPLATE
|
19
|
+
|
20
|
+
TEMPLATE = ERB.new(<<~TEMPLATE, trim_mode: "-")
|
21
|
+
# frozen_string_literal: true
|
22
|
+
|
23
|
+
<%= required_files.uniq.join("\n") + "\n" -%>
|
24
|
+
class <%= Utils.camel_case(name) %> < <%= base_class_name %>
|
25
|
+
<%= instances.flat_map { |instance| instance.to_attributes(@indent) }.join + "\n" -%>
|
26
|
+
<%= simple_content_attribute -%>
|
27
|
+
<%= @indent %>xml do
|
28
|
+
<%= extended_indent %>root "<%= name %>"<%= root_options %>
|
29
|
+
<%= namespace_and_prefix %>
|
30
|
+
<%= "\#{extended_indent}map_content to: :content" if simple_content? || mixed %>
|
31
|
+
<%= instances.flat_map { |instance| instance.to_xml_mapping(extended_indent) }.join -%>
|
32
|
+
<%= simple_content.to_xml_mapping(extended_indent) if simple_content? -%>
|
33
|
+
<%= @indent %>end
|
34
|
+
|
35
|
+
<%= @indent %>def self.register
|
36
|
+
<%= extended_indent %>Lutaml::Model::GlobalRegister.lookup(Lutaml::Model::Config.default_register)
|
37
|
+
<%= @indent %>end
|
38
|
+
|
39
|
+
<%= @indent %>def self.register_class_with_id
|
40
|
+
<%= extended_indent %>register.register_model(self, id: :<%= Utils.snake_case(name) %>)
|
41
|
+
<%= @indent %>end
|
42
|
+
end
|
43
|
+
|
44
|
+
<%= Utils.camel_case(name) %>.register_class_with_id
|
45
|
+
TEMPLATE
|
46
|
+
|
47
|
+
def initialize(base_class: SERIALIZABLE_BASE_CLASS)
|
48
|
+
@base_class = base_class
|
49
|
+
@instances = []
|
50
|
+
end
|
51
|
+
|
52
|
+
def <<(instance)
|
53
|
+
return if instance.nil?
|
54
|
+
|
55
|
+
@instances << instance
|
56
|
+
end
|
57
|
+
|
58
|
+
def simple_content?
|
59
|
+
Utils.present?(@simple_content)
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_class(options: {})
|
63
|
+
setup_options(options)
|
64
|
+
TEMPLATE.result(binding)
|
65
|
+
end
|
66
|
+
|
67
|
+
def required_files
|
68
|
+
files = [base_class_require]
|
69
|
+
files.concat(@instances.map(&:required_files).flatten.compact.uniq)
|
70
|
+
files.concat(simple_content.required_files) if simple_content?
|
71
|
+
files
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def setup_options(options)
|
77
|
+
@namespace, @prefix = options.values_at(:namespace, :prefix)
|
78
|
+
@indent = " " * options&.fetch(:indent, 2)
|
79
|
+
end
|
80
|
+
|
81
|
+
def simple_content_type
|
82
|
+
return "string" unless simple_content?
|
83
|
+
|
84
|
+
Utils.snake_case(last_of_split(simple_content.base_class))
|
85
|
+
end
|
86
|
+
|
87
|
+
def simple_content_attribute
|
88
|
+
SIMPLE_CONTENT_ATTRIBUTE_TEMPLATE.result(binding) if simple_content? || mixed
|
89
|
+
end
|
90
|
+
|
91
|
+
def root_options
|
92
|
+
return "" unless mixed
|
93
|
+
|
94
|
+
", mixed: true"
|
95
|
+
end
|
96
|
+
|
97
|
+
def namespace_and_prefix
|
98
|
+
return "" if Utils.blank?(@namespace) && Utils.blank?(@prefix)
|
99
|
+
|
100
|
+
[namespace_option, @prefix&.inspect].compact.join(", ")
|
101
|
+
end
|
102
|
+
|
103
|
+
def extended_indent
|
104
|
+
@indent * 2
|
105
|
+
end
|
106
|
+
|
107
|
+
def namespace_option
|
108
|
+
"#{extended_indent}namespace #{@namespace.inspect}"
|
109
|
+
end
|
110
|
+
|
111
|
+
def base_class_name
|
112
|
+
case base_class
|
113
|
+
when SERIALIZABLE_BASE_CLASS
|
114
|
+
SERIALIZABLE_BASE_CLASS
|
115
|
+
else
|
116
|
+
Utils.camel_case(last_of_split(base_class))
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def base_class_require
|
121
|
+
case base_class
|
122
|
+
when SERIALIZABLE_BASE_CLASS
|
123
|
+
"require \"lutaml/model\""
|
124
|
+
else
|
125
|
+
"require_relative \"#{Utils.snake_case(last_of_split(base_class))}\""
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def last_of_split(field)
|
130
|
+
field&.split(":")&.last
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Schema
|
6
|
+
module XmlCompiler
|
7
|
+
class Element
|
8
|
+
attr_accessor :id,
|
9
|
+
:ref,
|
10
|
+
:name,
|
11
|
+
:type,
|
12
|
+
:fixed,
|
13
|
+
:default,
|
14
|
+
:max_occurs,
|
15
|
+
:min_occurs
|
16
|
+
|
17
|
+
def initialize(name: nil, ref: nil)
|
18
|
+
@name = name
|
19
|
+
@ref = ref
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_attributes(indent)
|
23
|
+
return if skippable?
|
24
|
+
return unless resolved_type
|
25
|
+
|
26
|
+
"#{indent}attribute :#{resolved_name}, :#{resolved_type}#{attribute_options}\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_xml_mapping(indent)
|
30
|
+
return if skippable?
|
31
|
+
return unless resolved_type
|
32
|
+
|
33
|
+
"#{indent}map_element :#{resolved_name(change_case: false)}, to: :#{resolved_name}#{render_default_option}\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
def required_files
|
37
|
+
return if skippable?
|
38
|
+
|
39
|
+
element_type = resolved_type(change_case: false)
|
40
|
+
return "require \"bigdecimal\"" if element_type == "decimal"
|
41
|
+
return if SimpleType.skippable?(element_type)
|
42
|
+
|
43
|
+
"require_relative \"#{Utils.snake_case(element_type)}\""
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def resolved_instance
|
49
|
+
@resolved_instance ||= XmlCompiler.instance_variable_get(:@elements)[last_of_split]
|
50
|
+
end
|
51
|
+
|
52
|
+
def resolved_type(change_case: true)
|
53
|
+
@current_type ||= type || resolved_instance&.type
|
54
|
+
klass_name = last_of_split(@current_type)
|
55
|
+
change_case ? Utils.snake_case(klass_name) : klass_name
|
56
|
+
end
|
57
|
+
|
58
|
+
def resolved_name(change_case: true)
|
59
|
+
@current_name ||= name || resolved_instance&.name
|
60
|
+
change_case ? Utils.snake_case(@current_name) : @current_name
|
61
|
+
end
|
62
|
+
|
63
|
+
def collection_option
|
64
|
+
return if min_occurs.nil? && max_occurs.nil?
|
65
|
+
|
66
|
+
min_value = min_occurs.nil? ? 1 : min_occurs.to_i
|
67
|
+
", collection: #{min_value}..#{max_value}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def max_value
|
71
|
+
return "Float::INFINITY" if max_occurs == "unbounded"
|
72
|
+
return 1 if max_occurs.nil?
|
73
|
+
|
74
|
+
max_occurs.to_i
|
75
|
+
end
|
76
|
+
|
77
|
+
def default_option
|
78
|
+
return if default.nil?
|
79
|
+
|
80
|
+
", default: -> { #{default.inspect} }"
|
81
|
+
end
|
82
|
+
|
83
|
+
def render_default_option
|
84
|
+
return if default.nil?
|
85
|
+
|
86
|
+
", render_default: true"
|
87
|
+
end
|
88
|
+
|
89
|
+
def attribute_options
|
90
|
+
[collection_option, default_option].compact.join
|
91
|
+
end
|
92
|
+
|
93
|
+
def last_of_split(field = ref)
|
94
|
+
field&.split(":")&.last
|
95
|
+
end
|
96
|
+
|
97
|
+
def skippable?
|
98
|
+
resolved_name == "schema_location"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|