Sha256: 878b3f5e772cf2ad658bed6aa6c3b37f32d21631b625c7a00cbeb9ffe09aca3b

Contents?: true

Size: 1.99 KB

Versions: 1

Compression:

Stored size: 1.99 KB

Contents

require "typical/type"

module Typical
  class Type
    class Union < Type
      attr_reader :types

      def initialize(types = [])
        raise TypeError, "Requires an array of types" unless types.is_a?(::Array)
        @types = ::Set.new(types.map { |type| Type.of(type) })
      end

      def prominent_type
        copy = types.dup
        copy.delete_if { |type| type.type == NilClass }
        copy.first if copy.size == 1
      end

      def empty?
        @types.empty?
      end

      def ==(other)
        other.is_a?(Union) && @types == other.types
      end

      def hash
        @types.hash
      end

      def |(other)
        raise TypeError, "Can only make a union of Type and subclasses of Type" unless other.is_a?(Type)
        Union.new((types + other.types).to_a)
      end

      def normalize(unwrap_single_type = true)
        normalized = Union.new
        types = self.types.dup

        arrays = types.select { |type| type.type == ::Array }
        unless arrays.empty?
          types -= arrays
          normalized |= Array.new(arrays.map(&:values).reduce(:|).types.to_a).normalize
        end

        sets = types.select { |type| type.type == ::Set }
        unless sets.empty?
          types -= sets
          normalized |= Set.new(::Set.new(sets.map(&:values).reduce(:|).types.to_a)).normalize
        end

        hashes = types.select { |type| type.type == ::Hash }
        unless hashes.empty?
          types -= hashes
          hash = Hash.new
          hash.keys |= hashes.map(&:keys).reduce(:|)
          hash.values |= hashes.map(&:values).reduce(:|)
          normalized |= hash.normalize
        end

        # Add remainder
        types.each { |type| normalized |= type.normalize }
        # If there’s only 1 type, unwrap it from the union type.
        normalized = normalized.types.first if unwrap_single_type && normalized.types.size == 1

        normalized
      end

      def inspect
        "#<Type:Union [#{@types.map(&:inspect).join(", ")}]>"
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
typical-0.1.0 lib/typical/type/union.rb