Class: Contracts::Constraints::Shape

Inherits:
Base
  • Object
show all
Defined in:
lib/contracts/structured.rb

Overview

Matches a Hash with required and optional key contracts.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(required: {}, optional: {}, allow_extra: false) ⇒ Shape

Returns a new instance of Shape.

Raises:



31
32
33
34
35
36
37
38
39
# File 'lib/contracts/structured.rb', line 31

def initialize(required: {}, optional: {}, allow_extra: false)
  @required = coerce_map(required)
  @optional = coerce_map(optional)
  overlap = @required.keys & @optional.keys
  raise DefinitionError, "shape keys cannot be both required and optional: #{overlap.join(', ')}" unless overlap.empty?

  @allow_extra = allow_extra
  freeze
end

Instance Attribute Details

#allow_extraObject (readonly)

Returns the value of attribute allow_extra.



29
30
31
# File 'lib/contracts/structured.rb', line 29

def allow_extra
  @allow_extra
end

#optionalObject (readonly)

Returns the value of attribute optional.



29
30
31
# File 'lib/contracts/structured.rb', line 29

def optional
  @optional
end

#requiredObject (readonly)

Returns the value of attribute required.



29
30
31
# File 'lib/contracts/structured.rb', line 29

def required
  @required
end

Instance Method Details

#descriptionObject



50
51
52
53
54
55
# File 'lib/contracts/structured.rb', line 50

def description
  required_text = required.map { |key, constraint| "#{key}: #{constraint.description}" }
  optional_text = optional.map { |key, constraint| "#{key}?: #{constraint.description}" }
  suffix = allow_extra ? ", ..." : ""
  "Shape<{#{(required_text + optional_text).join(', ')}#{suffix}}>"
end

#matches?(value) ⇒ Boolean

Returns:

  • (Boolean)


41
42
43
44
45
46
47
48
# File 'lib/contracts/structured.rb', line 41

def matches?(value)
  return false unless value.is_a?(Hash)
  return false unless required.all? { |key, constraint| value.key?(key) && constraint.matches?(value[key]) }
  return false unless optional.all? { |key, constraint| !value.key?(key) || constraint.matches?(value[key]) }
  return true if allow_extra

  (value.keys - required.keys - optional.keys).empty?
end

#to_hObject



57
58
59
60
61
62
63
# File 'lib/contracts/structured.rb', line 57

def to_h
  super.merge(
    required: required.transform_values(&:description),
    optional: optional.transform_values(&:description),
    allow_extra: allow_extra
  )
end