Module: Lutaml::Model::Schema::RngCompiler::RngHelpers
- Defined in:
- lib/lutaml/model/schema/rng_compiler/rng_helpers.rb
Overview
RNG-specific helpers used by ElementVisitor, DefineClassifier, and
ValueTypeResolver. Centralising these here avoids the three-way
semantic drift the first refactor introduced (e.g. inconsistent
pure_value_choice? implementations).
Constant Summary collapse
- STRUCTURAL_CHILD_NAMES =
%i[ element ref attribute choice group optional zeroOrMore oneOrMore ].freeze
Class Method Summary collapse
- .apply_param(facet, name, value) ⇒ Object
-
.branching_structural?(node) ⇒ Boolean
True when
nodehas branching structure that needs its own class. -
.facet_from_data(data) ⇒ Object
Build a Definitions::Facet from an RNG 's children.
-
.facet_from_values(values) ⇒ Object
Build a Definitions::Facet from an array of
elements. -
.fragment_model?(klass) ⇒ Boolean
True iff
klassis a fragment model (no rooted xml element). - .numeric_or_string(value) ⇒ Object
-
.parent_class_for(base_symbol) ⇒ Object
Maps an RNG/XSD base symbol to its Ruby parent class string, defaulting to the string type when unknown.
-
.present_children?(node, attrs) ⇒ Boolean
True iff any of
attrsis a populated array-child ofnode. -
.pure_union_choice?(choice) ⇒ Boolean
True iff
choiceis a union: at least 2 alternatives and no other content. -
.pure_value_choice?(choice) ⇒ Boolean
True iff
choiceis aconsisting purely of alternatives (no , , , or ). -
.simple_type?(klass) ⇒ Boolean
True if the compiled define renders as a value type (RestrictedType or UnionType) rather than its own Serializable class.
-
.single(collection) ⇒ Object
Returns the only element of a collection, or nil if the collection is empty or has more than one element.
-
.structural_content?(node) ⇒ Boolean
An RNG node has structural content when any of its element / ref / attribute / choice / group / optional / repetition children are populated.
-
.type_symbol(class_name) ⇒ Object
Snake_case symbol used as the registry key for a generated simple-type/union-type/namespace class.
-
.unique_class_name(classes, base_name) ⇒ Object
A class name derived from base_name that does not collide with an existing key in
classes(appends 2, 3, ... on collision).
Class Method Details
.apply_param(facet, name, value) ⇒ Object
124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 124 def apply_param(facet, name, value) case name when "minInclusive" then facet.min_inclusive = numeric_or_string(value) when "maxInclusive" then facet.max_inclusive = numeric_or_string(value) when "minExclusive" then facet.min_exclusive = numeric_or_string(value) when "maxExclusive" then facet.max_exclusive = numeric_or_string(value) when "minLength" then facet.min_length = value.to_i when "maxLength" then facet.max_length = value.to_i when "length" then facet.length = value.to_i when "pattern" then facet.pattern = value end end |
.branching_structural?(node) ⇒ Boolean
True when node has branching structure that needs its own
class. Pure value-choices and <ref>s to simple types are NOT
branching — they're typed leaves.
52 53 54 55 56 57 58 59 60 61 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 52 def branching_structural?(node) return false unless node non_leaf = STRUCTURAL_CHILD_NAMES - %i[choice ref] return true if present_children?(node, non_leaf) return false unless node.respond_to?(:choice) Array(node.choice).any? { |c| !pure_value_choice?(c) } end |
.facet_from_data(data) ⇒ Object
Build a Definitions::Facet from an RNG 's children.
85 86 87 88 89 90 91 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 85 def facet_from_data(data) facet = Definitions::Facet.new Array(data.param).each do |param| apply_param(facet, param.name, param.value.to_s) end facet end |
.facet_from_values(values) ⇒ Object
Build a Definitions::Facet from an array of
94 95 96 97 98 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 94 def facet_from_values(values) Definitions::Facet.new( enumerations: Array(values).map(&:value), ) end |
.fragment_model?(klass) ⇒ Boolean
True iff klass is a fragment model (no rooted xml element).
23 24 25 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 23 def fragment_model?(klass) klass.is_a?(Definitions::Model) && klass.xml_root.kind == :fragment end |
.numeric_or_string(value) ⇒ Object
137 138 139 140 141 142 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 137 def numeric_or_string(value) return value.to_i if /\A-?\d+\z/.match?(value) return value.to_f if /\A-?\d+\.\d+\z/.match?(value) value end |
.parent_class_for(base_symbol) ⇒ Object
Maps an RNG/XSD base symbol to its Ruby parent class string, defaulting to the string type when unknown.
118 119 120 121 122 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 118 def parent_class_for(base_symbol) Lutaml::Model::Type::TYPE_CODES.fetch( base_symbol, Lutaml::Model::Type::TYPE_CODES[:string] ).to_s end |
.present_children?(node, attrs) ⇒ Boolean
True iff any of attrs is a populated array-child of node.
43 44 45 46 47 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 43 def present_children?(node, attrs) attrs.any? do |attr| node.respond_to?(attr) && Array(node.public_send(attr)).any? end end |
.pure_union_choice?(choice) ⇒ Boolean
True iff choice is a union: at least 2 alternatives
and no other content.
77 78 79 80 81 82 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 77 def pure_union_choice?(choice) return false unless choice return false unless choice.respond_to?(:data) && Array(choice.data).size >= 2 !present_children?(choice, %i[element ref value]) end |
.pure_value_choice?(choice) ⇒ Boolean
True iff choice is a text | "x" is a plain
string, not an enum restricted to "x".
67 68 69 70 71 72 73 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 67 def pure_value_choice?(choice) return false unless choice return false unless choice.respond_to?(:value) && Array(choice.value).any? return false if choice.respond_to?(:text) && Utils.present?(choice.text) !present_children?(choice, %i[element ref data]) end |
.simple_type?(klass) ⇒ Boolean
True if the compiled define renders as a value type (RestrictedType or UnionType) rather than its own Serializable class. Single source of truth — used by ElementVisitor and ValueTypeResolver.
17 18 19 20 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 17 def simple_type?(klass) klass.is_a?(Definitions::RestrictedType) || klass.is_a?(Definitions::UnionType) end |
.single(collection) ⇒ Object
Returns the only element of a collection, or nil if the collection is empty or has more than one element. Treats nil as an empty collection.
30 31 32 33 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 30 def single(collection) arr = Array(collection) arr.size == 1 ? arr.first : nil end |
.structural_content?(node) ⇒ Boolean
An RNG node has structural content when any of its element / ref / attribute / choice / group / optional / repetition children are populated.
38 39 40 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 38 def structural_content?(node) node && present_children?(node, STRUCTURAL_CHILD_NAMES) end |
.type_symbol(class_name) ⇒ Object
Snake_case symbol used as the registry key for a generated simple-type/union-type/namespace class.
102 103 104 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 102 def type_symbol(class_name) Utils.snake_case(class_name).to_sym end |
.unique_class_name(classes, base_name) ⇒ Object
A class name derived from base_name that does not collide with an
existing key in classes (appends 2, 3, ... on collision).
108 109 110 111 112 113 114 |
# File 'lib/lutaml/model/schema/rng_compiler/rng_helpers.rb', line 108 def unique_class_name(classes, base_name) return base_name unless classes.key?(base_name) counter = 2 counter += 1 while classes.key?("#{base_name}#{counter}") "#{base_name}#{counter}" end |