Class: Qrb::SubType
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
-
#constraints ⇒ Object
readonly
Returns the value of attribute constraints.
-
#super_type ⇒ Object
readonly
Returns the value of attribute super_type.
Instance Method Summary collapse
- #==(other) ⇒ Object (also: #eql?)
- #default_name ⇒ Object
-
#dress(value, handler = DressHelper.new) ⇒ Object
Check that ‘value` can be uped through the supertype, then verify all constraints.
- #hash ⇒ Object
- #include?(value) ⇒ Boolean
-
#initialize(super_type, constraints, name = nil) ⇒ SubType
constructor
A new instance of SubType.
Methods inherited from Type
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
#constraints ⇒ Object (readonly)
Returns the value of attribute constraints.
44 45 46 |
# File 'lib/qrb/type/sub_type.rb', line 44 def constraints @constraints end |
#super_type ⇒ Object (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_name ⇒ Object
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.(self, value) msg << " (not #{name})" unless default_constraint?(name) handler.fail!(msg) end # seems good, return the uped value uped end |
#hash ⇒ Object
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
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 |