Module: Lutaml::Model::Validation

Included in:
Serialize
Defined in:
lib/lutaml/model/validation_framework.rb,
lib/lutaml/model/validation.rb,
lib/lutaml/model/validation/rule.rb,
lib/lutaml/model/validation/issue.rb,
lib/lutaml/model/validation/report.rb,
lib/lutaml/model/validation/context.rb,
lib/lutaml/model/validation/profile.rb,
lib/lutaml/model/validation/registry.rb,
lib/lutaml/model/validation/remediation.rb,
lib/lutaml/model/validation/layer_result.rb,
lib/lutaml/model/validation/remediation_result.rb,
lib/lutaml/model/validation/concerns/has_issues.rb

Overview

Document-level validation framework. Orthogonal to the existing attribute-level Validation module — this validates structural integrity, cross-references, and conformance against domain rules.

Examples:

Run all registered rules

issues = Lutaml::Model::Validation.validate(context, registry)

Run and raise on errors

Lutaml::Model::Validation.validate!(context, registry)

Defined Under Namespace

Modules: HasIssues Classes: Context, Issue, LayerResult, Profile, Registry, Remediation, RemediationResult, Report, Rule, ValidationError

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.new_registryObject



25
26
27
# File 'lib/lutaml/model/validation_framework.rb', line 25

def new_registry
  Registry.new
end

.validate(context, registry, profile: nil) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/lutaml/model/validation_framework.rb', line 29

def validate(context, registry, profile: nil)
  rules = if profile
            profile.resolve(registry)
          else
            registry.all
          end

  all_issues = []
  rules.each do |rule|
    next unless rule.applicable?(context)

    issues = rule.check(context)
    if context.respond_to?(:add_error)
      issues.each { |i| context.add_error(i) }
    end
    all_issues.concat(issues)
  end

  all_issues
end

.validate!(context, registry, profile: nil) ⇒ Object



50
51
52
53
54
55
56
57
58
# File 'lib/lutaml/model/validation_framework.rb', line 50

def validate!(context, registry, profile: nil)
  issues = validate(context, registry, profile: profile)
  return if issues.empty?

  errors = issues.select(&:error?)
  unless errors.empty?
    raise ValidationError.new(format_errors(errors), issues: errors)
  end
end

Instance Method Details

#format_element_sequences(_register) ⇒ Array?

Hook for getting format-specific element sequences for validation. XML overrides via InstanceMethods prepend.

Parameters:

  • _register (Symbol, nil)

    The register context

Returns:

  • (Array, nil)

    Element sequences or nil



73
74
75
# File 'lib/lutaml/model/validation.rb', line 73

def format_element_sequences(_register)
  nil
end

#order_namesObject



77
78
79
80
81
82
83
84
85
# File 'lib/lutaml/model/validation.rb', line 77

def order_names
  return [] unless respond_to?(:element_order) && element_order

  element_order.each_with_object([]) do |element, arr|
    next if element.text?

    arr << element.name
  end
end

#validate(register: Lutaml::Model::Config.default_register) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/lutaml/model/validation.rb', line 6

def validate(register: Lutaml::Model::Config.default_register)
  errors = []

  self.class.attributes(register).each do |name, attr|
    value = public_send(:"#{name}")

    begin
      if value.respond_to?(:validate)
        sub_errors = value.validate
        errors.concat(sub_errors) if sub_errors.is_a?(Array)
      else
        resolver = Lutaml::Model::Services::DefaultValueResolver.new(
          attr, register, self
        )
        attr.validate_value!(value, register, resolver)
      end
    rescue Lutaml::Model::CollectionCountOutOfRangeError => e
      errors << e unless attr.choice
    rescue Lutaml::Model::InvalidValueError,
           Lutaml::Model::CollectionTrueMissingError,
           Lutaml::Model::PolymorphicError,
           Lutaml::Model::ValidationFailedError,
           Lutaml::Model::RequiredAttributeMissingError,
           Lutaml::Model::PatternNotMatchedError => e
      errors << e
    end
  end

  validate_helper(errors, register)
end

#validate!(register: Lutaml::Model::Config.default_register) ⇒ Object



37
38
39
40
# File 'lib/lutaml/model/validation.rb', line 37

def validate!(register: Lutaml::Model::Config.default_register)
  errors = validate(register: register)
  raise Lutaml::Model::ValidationError.new(errors) if errors.any?
end

#validate_helper(errors, register) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
# File 'lib/lutaml/model/validation.rb', line 42

def validate_helper(errors, register)
  self.class.choice_attributes.each do |attribute|
    attribute.validate_content!(self, register)
  end

  validate_sequence!(errors, order_names, register)
  errors
rescue Lutaml::Model::ChoiceUpperBoundError,
       Lutaml::Model::ChoiceLowerBoundError => e
  errors << e
end

#validate_sequence!(errors, names, register) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/lutaml/model/validation.rb', line 54

def validate_sequence!(errors, names, register)
  sequences = format_element_sequences(register)
  return errors if names.empty? || sequences.nil?

  sequences.each do |sequence|
    sequence.validate_content!(names, self, register)
  end
  errors
rescue Lutaml::Model::IncorrectSequenceError,
       Lutaml::Model::ChoiceUpperBoundError,
       Lutaml::Model::ChoiceLowerBoundError => e
  errors << e
end