Class: Qrb::SubType

Inherits:
Type
  • Object
show all
Defined in:
lib/qrb/type/sub_type.rb

Overview

A sub type generator, through specialization by constraints.

A sub type captures a subset of the values of a super type, through a constraint. For instance, a Byte type can be defined as a subset of all integers, as follows:

Byte := Integer( i | i >= 0 and i <= 255 )

This class allows defining such sub types with multiple named constraints. For instance,

Int  = BuiltinType.new(Integer)
Byte = SubType.new(Int, positive: ->(i){ i >= 0 },
                        small:    ->(i){ i <= 255 })

The concrete representation of the super type is kept as representation of the sub type. In other words:

R(Byte) = R(Int) = Fixnum

Accordingly, the ‘dress` transformation function has the following signature:

dress :: Alpha  -> Byte   throws TypeError
dress :: Object -> Fixnum throws TypeError

Constant Summary collapse

DEFAULT_CONSTRAINT_NAMES =
[:default, :predicate].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Type

#name, #name=, #to_s

Constructor Details

#initialize(super_type, constraints, name = nil) ⇒ SubType

Returns a new instance of SubType.



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/qrb/type/sub_type.rb', line 32

def initialize(super_type, constraints, name = nil)
  unless super_type.is_a?(Type)
    raise ArgumentError, "Qrb::Type expected, got #{super_type}"
  end

  unless constraints.is_a?(Hash)
    raise ArgumentError, "Hash expected for constraints, got #{constraints}"
  end

  super(name)
  @super_type, @constraints = super_type, constraints.freeze
end

Instance Attribute Details

#constraintsObject (readonly)

Returns the value of attribute constraints.



44
45
46
# File 'lib/qrb/type/sub_type.rb', line 44

def constraints
  @constraints
end

#super_typeObject (readonly)

Returns the value of attribute super_type.



44
45
46
# File 'lib/qrb/type/sub_type.rb', line 44

def super_type
  @super_type
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



75
76
77
78
79
# File 'lib/qrb/type/sub_type.rb', line 75

def ==(other)
  return false unless other.is_a?(SubType)
  other.super_type == super_type and \
  set_equal?(constraints.values, other.constraints.values)
end

#default_nameObject



46
47
48
# File 'lib/qrb/type/sub_type.rb', line 46

def default_name
  constraints.keys.first.to_s.capitalize
end

#dress(value, handler = DressHelper.new) ⇒ Object

Check that ‘value` can be uped through the supertype, then verify all constraints. Raise an error if anything goes wrong.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/qrb/type/sub_type.rb', line 56

def dress(value, handler = DressHelper.new)
  # Check that the supertype is able to dress the value.
  # Rewrite and set cause to any encountered TypeError.
  uped = handler.try(self, value) do
    super_type.dress(value, handler)
  end

  # Check each constraint in turn
  constraints.each_pair do |name, constraint|
    next if constraint===uped
    msg = handler.default_error_message(self, value)
    msg << " (not #{name})" unless default_constraint?(name)
    handler.fail!(msg)
  end

  # seems good, return the uped value
  uped
end

#hashObject



82
83
84
# File 'lib/qrb/type/sub_type.rb', line 82

def hash
  self.class.hash ^ super_type.hash ^ set_hash(constraints.values)
end

#include?(value) ⇒ Boolean

Returns:

  • (Boolean)


50
51
52
# File 'lib/qrb/type/sub_type.rb', line 50

def include?(value)
  super_type.include?(value) && constraints.all?{|_,c| c===value }
end