Class: Metaschema::ConstraintValidator

Inherits:
Object
  • Object
show all
Defined in:
lib/metaschema/constraint_validator.rb

Defined Under Namespace

Classes: ConstraintError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConstraintValidator

Returns a new instance of ConstraintValidator.



7
8
9
# File 'lib/metaschema/constraint_validator.rb', line 7

def initialize
  @errors = []
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



5
6
7
# File 'lib/metaschema/constraint_validator.rb', line 5

def errors
  @errors
end

Class Method Details

.validate_occurrences(instance, occurrence_constraints) ⇒ Object

Validate min/max occurrence constraints on an instance. occurrence_constraints is a Hash of => {min: N, max: N}



422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
# File 'lib/metaschema/constraint_validator.rb', line 422

def self.validate_occurrences(instance, occurrence_constraints)
  errors = []
  return errors unless occurrence_constraints && !occurrence_constraints.empty?

  occurrence_constraints.each do |attr_name, constraints|
    value = instance.respond_to?(attr_name) ? instance.send(attr_name) : nil
    count = case value
            when nil then 0
            when Array then value.length
            else 1
            end

    min = constraints[:min]
    max = constraints[:max]

    if min&.positive? && count < min
      errors << ConstraintError.new(
        constraint_type: :occurrence,
        level: "ERROR",
        message: "Expected at least #{min} '#{attr_name}', got #{count}",
        target: attr_name.to_s,
      )
    end

    if max && count > max
      errors << ConstraintError.new(
        constraint_type: :occurrence,
        level: "ERROR",
        message: "Expected at most #{max} '#{attr_name}', got #{count}",
        target: attr_name.to_s,
      )
    end
  end

  errors
end

.validate_tree(instance) ⇒ Object

Recursively validate an entire instance tree. Validates each node’s own constraints, then recurses into children.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/metaschema/constraint_validator.rb', line 41

def self.validate_tree(instance)
  errors = []

  if instance.is_a?(Lutaml::Model::Serializable)
    # Validate this instance's own constraints
    if instance.respond_to?(:validate_constraints)
      errors.concat(instance.validate_constraints)
    end

    # Validate occurrence constraints (min/max-occurs)
    if instance.respond_to?(:validate_occurrences)
      errors.concat(instance.validate_occurrences)
    end

    # Recurse into all attribute values
    instance.class.attributes.each_key do |attr_name|
      value = instance.send(attr_name)
      next if value.nil?

      if value.is_a?(Array)
        value.each { |v| errors.concat(validate_tree(v)) if v.is_a?(Lutaml::Model::Serializable) }
      elsif value.is_a?(Lutaml::Model::Serializable)
        errors.concat(validate_tree(value))
      end
    end
  end

  errors
end

Instance Method Details

#validate(instance, constraint_def) ⇒ Object

Validate a generated class instance against its metaschema constraints. Returns an array of ConstraintError objects.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/metaschema/constraint_validator.rb', line 13

def validate(instance, constraint_def)
  @errors = []
  return @errors unless constraint_def

  validate_allowed_values(instance, constraint_def)
  validate_matches(instance, constraint_def)
  if constraint_def.respond_to?(:has_cardinality)
    validate_has_cardinality(instance,
                             constraint_def)
  end
  if constraint_def.respond_to?(:is_unique)
    validate_is_unique(instance,
                       constraint_def)
  end
  if constraint_def.respond_to?(:expect)
    validate_expect(instance,
                    constraint_def)
  end
  if constraint_def.respond_to?(:index_has_key)
    validate_index_has_key(instance,
                           constraint_def)
  end

  @errors
end