Class: Rigor::Type::HashShape

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

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
BARE_RECORD_KEY =

A Symbol whose text matches renders as a bare RBS record key (lang:) in #erase_to_rbs; anything else must be quoted with a fat arrow ("data-contrast" =>). See #erase_key_prefix.

/\A[A-Za-z_][A-Za-z0-9_]*[?!]?\z/

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ValueSemantics

included

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.

  • keywords (Object)


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_keysSymbol (readonly)

Returns the value of attribute extra_keys.

Returns:

  • (Symbol)


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

def extra_keys
  @extra_keys
end

#optional_keysArray[untyped] (readonly)

Returns the value of attribute optional_keys.

Returns:

  • (Array[untyped])


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

def optional_keys
  @optional_keys
end

#pairsHash[untyped, Type::t] (readonly)

Returns the value of attribute pairs.

Returns:

  • (Hash[untyped, Type::t])


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

def pairs
  @pairs
end

#read_only_keysArray[untyped] (readonly)

Returns the value of attribute read_only_keys.

Returns:

  • (Array[untyped])


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

def read_only_keys
  @read_only_keys
end

#required_keysArray[untyped] (readonly)

Returns the value of attribute required_keys.

Returns:

  • (Array[untyped])


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

def required_keys
  @required_keys
end

Instance Method Details

#==Boolean

Parameters:

  • other (Object)

Returns:

  • (Boolean)


243
# File 'sig/rigor/type.rbs', line 243

def ==: (untyped other) -> bool

#acceptsAcceptsResult

Parameters:

  • other (Type::t)
  • mode: (accepts_mode)

Returns:



242
# File 'sig/rigor/type.rbs', line 242

def accepts: (Type::t other, ?mode: accepts_mode) -> AcceptsResult

#botTrinary

Returns:



240
# File 'sig/rigor/type.rbs', line 240

def bot: () -> Trinary

#closed?Boolean

Returns:

  • (Boolean)


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

def closed?
  extra_keys == :closed
end

#describe(verbosity = :short) ⇒ String

Parameters:

  • verbosity (Symbol) (defaults to: :short)

Returns:

  • (String)


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

#dynamicTrinary

Returns:



241
# File 'sig/rigor/type.rbs', line 241

def dynamic: () -> Trinary

#erase_to_rbsString

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.

Returns:

  • (String)


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

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| "#{erase_key_prefix(k)} #{v.erase_to_rbs}" }
  "{ #{rendered.join(', ')} }"
end

#hashInteger

Returns:

  • (Integer)


244
# File 'sig/rigor/type.rbs', line 244

def hash: () -> Integer

#inspectString

Returns:

  • (String)


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

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

#open?Boolean

Returns:

  • (Boolean)


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

def open?
  extra_keys == :open
end

#optional_key?(key) ⇒ Boolean

Parameters:

  • key (Object)

Returns:

  • (Boolean)


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

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

#read_only_key?(key) ⇒ Boolean

Parameters:

  • key (Object)

Returns:

  • (Boolean)


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

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

#required_key?(key) ⇒ Boolean

Parameters:

  • key (Object)

Returns:

  • (Boolean)


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

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

#topTrinary

Returns:



239
# File 'sig/rigor/type.rbs', line 239

def top: () -> Trinary