Class: Finitio::UnionType

Inherits:
Type
  • Object
show all
Defined in:
lib/finitio/type/union_type.rb,
lib/finitio/generation/union_type.rb,
lib/finitio/json_schema/union_type.rb

Overview

A union type (aka algebraic type) allows capturing information types through generalization/disjunction. For instance,

Numeric = Int|Real

This class allows capturing such union types, as follows:

Int     = BuiltinType.new(Fixnum)
Real    = BuiltinType.new(Float)
Numeric = UnionType.new([ Int, Real ])

When transforming a value through ‘dress`, the different candidate types are tried in specified order. The first one that succeeds at building the value ends the process and the value is simply returned. Accordingly, the concrete representation will be

R(Numeric) = R(Int) ^ R(Real) = Fixnum ^ Float = Numeric

where ‘^` denotes the `least common super type` operator on ruby classes.

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

dress :: Alpha  -> Numeric throws TypeError
dress :: Object -> Numeric throws TypeError

Constant Summary collapse

NIL_TYPE =
BuiltinType.new(NilClass)
FALSE_TYPE =
BuiltinType.new(TrueClass)
TRUE_TYPE =
BuiltinType.new(FalseClass)
BOOLEAN_TYPE =
UnionType.new([TRUE_TYPE, FALSE_TYPE])

Constants included from Metadata

Metadata::EMPTY_METADATA

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Type

#anonymous?, #name, #name=, #named?, #to_s

Methods included from Metadata

#metadata, #metadata=, #metadata?

Constructor Details

#initialize(candidates, name = nil, metadata = nil) ⇒ UnionType

Returns a new instance of UnionType.



32
33
34
35
36
37
38
39
# File 'lib/finitio/type/union_type.rb', line 32

def initialize(candidates, name = nil,  = nil)
  unless candidates.all?{|c| c.is_a?(Type) }
    raise ArgumentError, "[Finitio::Type] expected, got #{candidates}"
  end

  super(name, )
  @candidates = candidates.freeze
end

Instance Attribute Details

#candidatesObject (readonly)

Returns the value of attribute candidates.



40
41
42
# File 'lib/finitio/type/union_type.rb', line 40

def candidates
  @candidates
end

Instance Method Details

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



84
85
86
87
88
# File 'lib/finitio/type/union_type.rb', line 84

def ==(other)
  super || (
    other.is_a?(UnionType) && set_equal?(candidates, other.candidates)
  )
end

#default_nameObject



69
70
71
# File 'lib/finitio/type/union_type.rb', line 69

def default_name
  candidates.map(&:name).join('|')
end

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

Invoke ‘dress` on each candidate type in turn. Return the value returned by the first one that does not fail. Fail with an TypeError if no candidate succeeds at tranforming `value`.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/finitio/type/union_type.rb', line 53

def dress(value, handler = DressHelper.new)
  error = nil

  # Do nothing on TypeError as the next candidate could be the good one!
  candidates.each do |c|
    success, uped = handler.just_try do
      c.dress(value, handler)
    end
    return uped if success
    error ||= uped
  end

  # No one succeed, just fail
  handler.failed!(self, value, error)
end

#generate_data(generator, world = nil) ⇒ Object



4
5
6
7
# File 'lib/finitio/generation/union_type.rb', line 4

def generate_data(generator, world = nil)
  picked = generator.flip_one_out_of(candidates)
  generator.call(picked, world)
end

#hashObject



91
92
93
# File 'lib/finitio/type/union_type.rb', line 91

def hash
  self.class.hash ^ set_hash(self.candidates)
end

#include?(value) ⇒ Boolean

Returns:

  • (Boolean)


46
47
48
# File 'lib/finitio/type/union_type.rb', line 46

def include?(value)
  candidates.any?{|c| c.include?(value) }
end

#representatorObject

Raises:

  • (NotImplementedError)


42
43
44
# File 'lib/finitio/type/union_type.rb', line 42

def representator
  raise NotImplementedError
end

#resolve_proxies(system) ⇒ Object



95
96
97
# File 'lib/finitio/type/union_type.rb', line 95

def resolve_proxies(system)
  UnionType.new(candidates.map{|t| t.resolve_proxies(system)}, name, )
end

#suppremum(other) ⇒ Object Also known as: _suppremum



73
74
75
76
77
78
79
80
81
# File 'lib/finitio/type/union_type.rb', line 73

def suppremum(other)
  return self if other == self
  cs = if (other.is_a?(UnionType))
    candidates + other.candidates
  else
    candidates + [other]
  end
  UnionType.new(cs.uniq)
end

#to_json_schema(*args, &bl) ⇒ Object



12
13
14
15
16
17
18
19
20
# File 'lib/finitio/json_schema/union_type.rb', line 12

def to_json_schema(*args, &bl)
  cs = candidates.reject{|c| c == NIL_TYPE }
  return { type: 'boolean'} if self == BOOLEAN_TYPE
  return cs.first.to_json_schema(*args, &bl) if cs.size == 1

  {
    anyOf: cs.map{|c| c.to_json_schema(*args, &bl) }
  }
end

#unconstrainedObject



99
100
101
# File 'lib/finitio/type/union_type.rb', line 99

def unconstrained
  UnionType.new(candidates.map{|c| c.unconstrained }, name, )
end