Class: RDL::Type::FiniteHashType
- Defined in:
- lib/rdl/types/finite_hash.rb
Overview
Type for finite maps from values to types; values are compared with ==. These are used for “named” arguments in Ruby, in which case the values are symbols. Finite hashes can also have a “rest” type (okay, they’re not exactly finite in this case…) which is treated as a hash from Symbol to the type.
Instance Attribute Summary collapse
-
#elts ⇒ Object
readonly
Returns the value of attribute elts.
-
#lbounds ⇒ Object
lower bounds…
-
#rest ⇒ Object
readonly
Returns the value of attribute rest.
-
#the_hash ⇒ Object
readonly
either nil or hash type if self has been promoted to hash.
-
#ubounds ⇒ Object
upper bounds this tuple has been compared with using <=.
Instance Method Summary collapse
- #<=(other) ⇒ Object
-
#==(other) ⇒ Object
(also: #eql?)
:nodoc:.
- #canonical ⇒ Object
- #cant_promote! ⇒ Object
- #hash ⇒ Object
-
#initialize(elts, rest) ⇒ FiniteHashType
constructor
- + elts +
-
is a map from keys to types.
- #instantiate(inst) ⇒ Object
- #match(other) ⇒ Object
- #member?(obj, *args) ⇒ Boolean
- #promote! ⇒ Object
- #to_s ⇒ Object
Methods inherited from Type
leq, #nil_type?, #optional?, #to_contract, #vararg?
Constructor Details
#initialize(elts, rest) ⇒ FiniteHashType
- + elts +
-
is a map from keys to types
16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/rdl/types/finite_hash.rb', line 16 def initialize(elts, rest) elts.each { |k, t| raise RuntimeError, "Got #{t.inspect} where Type expected" unless t.is_a? Type raise RuntimeError, "Type may not be annotated or vararg" if (t.instance_of? AnnotatedArgType) || (t.instance_of? VarargType) } @elts = elts @rest = rest @the_hash = nil @cant_promote = false @ubounds = [] @lbounds = [] super() end |
Instance Attribute Details
#elts ⇒ Object (readonly)
Returns the value of attribute elts.
9 10 11 |
# File 'lib/rdl/types/finite_hash.rb', line 9 def elts @elts end |
#lbounds ⇒ Object
lower bounds…
13 14 15 |
# File 'lib/rdl/types/finite_hash.rb', line 13 def lbounds @lbounds end |
#rest ⇒ Object (readonly)
Returns the value of attribute rest.
10 11 12 |
# File 'lib/rdl/types/finite_hash.rb', line 10 def rest @rest end |
#the_hash ⇒ Object (readonly)
either nil or hash type if self has been promoted to hash
11 12 13 |
# File 'lib/rdl/types/finite_hash.rb', line 11 def the_hash @the_hash end |
#ubounds ⇒ Object
upper bounds this tuple has been compared with using <=
12 13 14 |
# File 'lib/rdl/types/finite_hash.rb', line 12 def ubounds @ubounds end |
Instance Method Details
#<=(other) ⇒ Object
80 81 82 |
# File 'lib/rdl/types/finite_hash.rb', line 80 def <=(other) return Type.leq(self, other) end |
#==(other) ⇒ Object Also known as: eql?
:nodoc:
40 41 42 43 44 45 |
# File 'lib/rdl/types/finite_hash.rb', line 40 def ==(other) # :nodoc: return false if other.nil? return (@the_hash == other) if @the_hash other = other.canonical return (other.instance_of? FiniteHashType) && (other.elts == @elts) && (other.rest == @rest) end |
#canonical ⇒ Object
30 31 32 33 |
# File 'lib/rdl/types/finite_hash.rb', line 30 def canonical return @the_hash if @the_hash return self end |
#cant_promote! ⇒ Object
75 76 77 78 |
# File 'lib/rdl/types/finite_hash.rb', line 75 def cant_promote! raise RuntimeError, "already promoted!" if @the_hash @cant_promote = true end |
#hash ⇒ Object
117 118 119 120 |
# File 'lib/rdl/types/finite_hash.rb', line 117 def hash # note don't change hash value if @the_hash becomes non-nil return 229 * @elts.hash * @rest.hash end |
#instantiate(inst) ⇒ Object
112 113 114 115 |
# File 'lib/rdl/types/finite_hash.rb', line 112 def instantiate(inst) return @the_hash.instantiate(inst) if @the_hash return FiniteHashType.new(Hash[@elts.map { |k, t| [k, t.instantiate(inst)] }], (if @rest then @rest.instantiate(inst) end)) end |
#match(other) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/rdl/types/finite_hash.rb', line 49 def match(other) return @the_hash.match(other) if @the_hash other = other.canonical other = other.type if other.instance_of? AnnotatedArgType return true if other.instance_of? WildQuery return false unless other.instance_of? FiniteHashType return false unless ((@rest.nil? && other.rest.nil?) || (!@rest.nil? && !other.rest.nil? && @rest.match(other.rest))) return (@elts.length == other.elts.length && @elts.all? { |k, v| (other.elts.has_key? k) && (v.match(other.elts[k]))}) end |
#member?(obj, *args) ⇒ Boolean
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/rdl/types/finite_hash.rb', line 84 def member?(obj, *args) return @the_hash.member(obj, *args) if @the_hash t = RDL::Util.rdl_type obj return t <= self if t right_elts = @elts.clone # shallow copy return false unless obj.instance_of? Hash # Check that every mapping in obj exists in @map and matches the type obj.each_pair { |k, v| if @elts.has_key? k t = @elts[k] t = t.type if t.instance_of? OptionalType return false unless t.member? v right_elts.delete k else return false unless @rest && @rest.member?(v) end } # Check that any remaining types are optional right_elts.each_pair { |k, vt| return false unless vt.instance_of? OptionalType } return true end |
#promote! ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/rdl/types/finite_hash.rb', line 61 def promote! return false if @cant_promote # TODO look at key types domain_type = UnionType.new(*(@elts.keys.map { |k| NominalType.new(k.class) })) range_type = UnionType.new(*@elts.values) if @rest domain_type = UnionType.new(domain_type, RDL::Globals.types[:symbol]) range_type = UnionType.new(range_type, @rest) end @the_hash = GenericType.new(RDL::Globals.types[:hash], domain_type, range_type) # same logic as Tuple return (@lbounds.all? { |lbound| lbound <= self }) && (@ubounds.all? { |ubound| self <= ubound }) end |
#to_s ⇒ Object
35 36 37 38 |
# File 'lib/rdl/types/finite_hash.rb', line 35 def to_s return @the_hash.to_s if @the_hash return "{ " + @elts.map { |k, t| k.to_s + ": " + t.to_s }.join(', ') + (if @rest then ", **" + @rest.to_s else "" end) + " }" end |