Module: Lutaml::Model::RestrictionValidation

Included in:
Attribute
Defined in:
lib/lutaml/model/restriction_validation.rb

Overview

Module for enforcing value restrictions on attributes.

Provides the lazy validation seam used by Attribute#validate_value!: a configuration check (applicability of the effective facets to the resolved type) and a value check (ordered bounds / string length) that reuses the shared Type validators and translates their errors into model-level errors carrying the attribute name.

The effective facet set is the conjunctive merge of Layer-1 attribute options (lowered to canonical keys) and the Layer-2 facets declared on a Type::Value subclass; the tightest constraint per key wins.

Instance Method Summary collapse

Instance Method Details

#effective_restriction_facets(resolved_type) ⇒ Object

Effective facet set for schema emission: the validator's merge plus the pre-#191 values:/pattern: options. Those are enforced at runtime by a separate path (so they are absent from the validation facet set); fold them in here so the exported XSD is not weaker than what is enforced.



79
80
81
82
83
84
85
86
87
88
# File 'lib/lutaml/model/restriction_validation.rb', line 79

def effective_restriction_facets(resolved_type)
  facets = effective_facets(resolved_type)
  facets = merge_values_option(facets, resolved_type) if @options.key?(:values)
  facets = merge_pattern_option(facets) if @options.key?(:pattern)
  # Folding in the values: option can empty an enumeration (a disjoint
  # set enforced by both layers); that is an unsatisfiable restriction,
  # not an unrestricted one, so reject it as the merged interval does.
  reject_empty_enumeration!(facets)
  facets
end

#validate_restriction_configuration!(resolved_type) ⇒ Object

Verify the effective facets are applicable to the resolved type. The type is only known after register resolution, so this runs at validation time and raises ahead of the value checks.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/lutaml/model/restriction_validation.rb', line 20

def validate_restriction_configuration!(resolved_type)
  facets = effective_facets(resolved_type)

  if @options.key?(:signed) && !numeric_type?(resolved_type)
    raise ArgumentError,
          "Invalid options for `#{name}`: " \
          "`signed` is only allowed for numeric types"
  end

  if ordered_facets?(facets) && !ordered_type?(resolved_type)
    raise ArgumentError,
          "Invalid options for `#{name}`: " \
          "`min`, `max`, `inclusive` and `exclusive` are only allowed " \
          "for numeric types or temporal (date/time) types"
  end

  if length_facets?(facets) && !string_type?(resolved_type)
    raise ArgumentError,
          "Invalid options for `#{name}`: " \
          "`min_length` and `max_length` are only allowed for :string type"
  end

  if facets.key?(:pattern) && !string_type?(resolved_type)
    raise ArgumentError,
          "Invalid options for `#{name}`: " \
          "`pattern` is only allowed for string-derived types"
  end

  if digit_facets?(facets) && !digit_type?(resolved_type)
    raise ArgumentError,
          "Invalid options for `#{name}`: " \
          "`total_digits` and `fraction_digits` are only allowed " \
          "for :integer and :decimal types"
  end
end

#validate_restriction_values!(value, resolved_type) ⇒ Object

Enforce the effective facets against the value, translating the reused validator's Type::* errors into model-level errors that carry the attribute name so validate can collect them.



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/lutaml/model/restriction_validation.rb', line 59

def validate_restriction_values!(value, resolved_type)
  facets = effective_facets(resolved_type)
  return if facets.empty?
  return if value.nil? || Utils.uninitialized?(value)

  unless collection? && collection_instance?(value)
    return validate_element_facets!(value, resolved_type, facets)
  end

  value.each do |element|
    next if element.nil? || Utils.uninitialized?(element)

    validate_element_facets!(element, resolved_type, facets)
  end
end