Class: Rigor::Type::HashShape

Inherits:
Object
  • Object
show all
Includes:
AcceptanceRouter, ValueSemantics
Defined in:
lib/rigor/type/hash_shape.rb

Overview

A hash shape with statically known keys. Inhabitants are Ruby ‘Hash` instances whose known entries inhabit the corresponding value types. RBS records correspond to the exact closed subset; Rigor extends that carrier with optional keys, read-only entry views, and an open/closed extra-key policy.

Keys are restricted to Symbol and String values. Exact closed symbol-keyed shapes erase to the RBS record syntax ‘{ a: Integer, ?b: String }`; all other shapes degrade to `Hash[K, V]` or raw `Hash` when no useful bounds are available.

Equality and hashing are structural over the (key -> Rigor::Type) pair set and policy fields. Hash insertion order is preserved by the underlying storage but does NOT affect equality (matching Ruby’s ‘Hash#==`).

See docs/type-specification/rbs-compatible-types.md (records) and docs/type-specification/rigor-extensions.md (hash shape).

Constant Summary collapse

ALLOWED_KEY_CLASSES =
[Symbol, String].freeze
EXTRA_KEY_POLICIES =
%i[open closed].freeze
POLICY_KEYWORDS =
%i[required_keys optional_keys read_only_keys extra_keys].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ValueSemantics

included

Methods included from AcceptanceRouter

#accepts

Constructor Details

#initialize(pairs = nil, **keywords) ⇒ HashShape

Returns a new instance of HashShape.

Parameters:

  • pairs (Hash{Symbol|String => Rigor::Type}) (defaults to: nil)

    ordered map of keys to declared types. Keys MUST be Symbol or String; values MUST be Rigor::Type instances. The hash is duped and frozen at construction; callers MUST NOT mutate the input afterwards (mutation does not affect the carrier, but the carrier is a value object).

  • required_keys (Array<Symbol|String>, nil)

    keys that MUST be present. When omitted, every non-optional key is required. When supplied without optional_keys, every remaining known key is treated as optional.

  • optional_keys (Array<Symbol|String>, nil)

    keys that MAY be absent. Optional absence is not a stored nil.

  • read_only_keys (Array<Symbol|String>)

    entries that cannot be written through this shape view.

  • extra_keys (Symbol)

    :closed rejects keys outside pairs; :open permits them.



50
51
52
53
54
55
56
57
# File 'lib/rigor/type/hash_shape.rb', line 50

def initialize(pairs = nil, **keywords)
  pairs, policy = split_constructor_args(pairs, keywords)
  validate_pairs!(pairs)

  @pairs = pairs.dup.freeze
  apply_policy!(policy)
  freeze
end

Instance Attribute Details

#extra_keysObject (readonly)

Returns the value of attribute extra_keys.



32
33
34
# File 'lib/rigor/type/hash_shape.rb', line 32

def extra_keys
  @extra_keys
end

#optional_keysObject (readonly)

Returns the value of attribute optional_keys.



32
33
34
# File 'lib/rigor/type/hash_shape.rb', line 32

def optional_keys
  @optional_keys
end

#pairsObject (readonly)

Returns the value of attribute pairs.



32
33
34
# File 'lib/rigor/type/hash_shape.rb', line 32

def pairs
  @pairs
end

#read_only_keysObject (readonly)

Returns the value of attribute read_only_keys.



32
33
34
# File 'lib/rigor/type/hash_shape.rb', line 32

def read_only_keys
  @read_only_keys
end

#required_keysObject (readonly)

Returns the value of attribute required_keys.



32
33
34
# File 'lib/rigor/type/hash_shape.rb', line 32

def required_keys
  @required_keys
end

Instance Method Details

#botObject



103
104
105
# File 'lib/rigor/type/hash_shape.rb', line 103

def bot
  Trinary.no
end

#closed?Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/rigor/type/hash_shape.rb', line 83

def closed?
  extra_keys == :closed
end

#describe(verbosity = :short) ⇒ Object



59
60
61
62
63
64
65
# File 'lib/rigor/type/hash_shape.rb', line 59

def describe(verbosity = :short)
  return "{}" if pairs.empty?

  rendered = pairs.map { |k, v| render_entry(k, v, verbosity) }
  rendered << "..." if open?
  "{ #{rendered.join(', ')} }"
end

#dynamicObject



107
108
109
# File 'lib/rigor/type/hash_shape.rb', line 107

def dynamic
  Trinary.no
end

#erase_to_rbsObject

Erases to the RBS record form ‘{ a: Integer, ?b: String }` for exact closed symbol-keyed shapes. Open shapes and string-keyed closed shapes degrade to a generic Hash bound.



70
71
72
73
74
75
76
77
# File 'lib/rigor/type/hash_shape.rb', line 70

def erase_to_rbs
  return "{}" if pairs.empty? && closed?
  return hash_erasure unless closed?
  return hash_erasure if pairs.each_key.any? { |k| !k.is_a?(Symbol) }

  rendered = pairs.map { |k, v| "#{record_key(k)}: #{v.erase_to_rbs}" }
  "{ #{rendered.join(', ')} }"
end

#inspectObject



117
118
119
# File 'lib/rigor/type/hash_shape.rb', line 117

def inspect
  "#<Rigor::Type::HashShape #{describe(:short)}>"
end

#open?Boolean

Returns:

  • (Boolean)


79
80
81
# File 'lib/rigor/type/hash_shape.rb', line 79

def open?
  extra_keys == :open
end

#optional_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/rigor/type/hash_shape.rb', line 91

def optional_key?(key)
  optional_keys.include?(key)
end

#read_only_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


95
96
97
# File 'lib/rigor/type/hash_shape.rb', line 95

def read_only_key?(key)
  read_only_keys.include?(key)
end

#required_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


87
88
89
# File 'lib/rigor/type/hash_shape.rb', line 87

def required_key?(key)
  required_keys.include?(key)
end

#topObject



99
100
101
# File 'lib/rigor/type/hash_shape.rb', line 99

def top
  Trinary.no
end