class T::Types::Base

Public Class Methods

method_added(method_name) click to toggle source
Calls superclass method
# File lib/types/types/base.rb, line 6
def self.method_added(method_name)
  super(method_name)
  # What is now `subtype_of_single?` used to be named `subtype_of?`. Make sure people don't
  # override the wrong thing.
  #
  # NB: Outside of T::Types, we would enforce this by using `sig` and not declaring the method
  # as overridable, but doing so here would result in a dependency cycle.
  if method_name == :subtype_of? && self != T::Types::Base
    raise "`subtype_of?` should not be overridden. You probably want to override " \
          "`subtype_of_single?` instead."
  end
end

Public Instance Methods

==(other) click to toggle source
# File lib/types/types/base.rb, line 159
def ==(other)
  (T::Utils.resolve_alias(other).class == T::Utils.resolve_alias(self).class) &&
    other.name == self.name
end
Also aliased as: eql?
describe_obj(obj) click to toggle source
# File lib/types/types/base.rb, line 110
def describe_obj(obj)
  # Would be redundant to print class and value in these common cases.
  case obj
  when nil, true, false
    return "type #{obj.class}"
  end

  # In rare cases, obj.inspect may fail, or be undefined, so rescue.
  begin
    # Default inspect behavior of, eg; `#<Object:0x0...>` is ugly; just print the hash instead, which is more concise/readable.
    if obj.method(:inspect).owner == Kernel
      "type #{obj.class} with hash #{obj.hash}"
    elsif T::Configuration.include_value_in_type_errors?
      "type #{obj.class} with value #{T::Utils.string_truncate_middle(obj.inspect, 30, 30)}"
    else
      "type #{obj.class}"
    end
  rescue StandardError, SystemStackError
    "type #{obj.class} with unprintable value"
  end
end
eql?(other)
Alias for: ==
error_message_for_obj(obj) click to toggle source
# File lib/types/types/base.rb, line 132
def error_message_for_obj(obj)
  if valid?(obj)
    nil
  else
    "Expected type #{self.name}, got #{describe_obj(obj)}"
  end
end
error_message_for_obj_recursive(obj) click to toggle source
# File lib/types/types/base.rb, line 140
def error_message_for_obj_recursive(obj)
  if recursively_valid?(obj)
    nil
  else
    "Expected type #{self.name}, got #{describe_obj(obj)}"
  end
end
hash() click to toggle source

Equality methods (necessary for deduping types with `uniq`)

# File lib/types/types/base.rb, line 155
def hash
  name.hash
end
name() click to toggle source

Equality is based on name, so be sure the name reflects all relevant state when implementing.

# File lib/types/types/base.rb, line 37
def name
  raise NotImplementedError
end
recursively_valid?(obj) click to toggle source

this will be redefined in certain subclasses

# File lib/types/types/base.rb, line 20
def recursively_valid?(obj)
  valid?(obj)
end
subtype_of?(t2) click to toggle source

Mirrors ruby_typer::core::Types::isSubType See git.corp.stripe.com/stripe-internal/ruby-typer/blob/9fc8ed998c04ac0b96592ae6bb3493b8a925c5c1/core/types/subtyping.cc#L912-L950

This method cannot be overridden (see `method_added` above). Subclasses only need to implement `subtype_of_single?`).

# File lib/types/types/base.rb, line 46
def subtype_of?(t2)
  t1 = self

  if t2.is_a?(T::Private::Types::TypeAlias)
    t2 = t2.aliased_type
  end

  if t1.is_a?(T::Private::Types::TypeAlias)
    return t1.aliased_type.subtype_of?(t2)
  end

  # pairs to cover: 1  (_, _)
  #                 2  (_, And)
  #                 3  (_, Or)
  #                 4  (And, _)
  #                 5  (And, And)
  #                 6  (And, Or)
  #                 7  (Or, _)
  #                 8  (Or, And)
  #                 9  (Or, Or)

  # Note: order of cases here matters!
  if t1.is_a?(T::Types::Union) # 7, 8, 9
    # this will be incorrect if/when we have Type members
    return t1.types.all? {|t1_member| t1_member.subtype_of?(t2)}
  end

  if t2.is_a?(T::Types::Intersection) # 2, 5
    # this will be incorrect if/when we have Type members
    return t2.types.all? {|t2_member| t1.subtype_of?(t2_member)}
  end

  if t2.is_a?(T::Types::Union)
    if t1.is_a?(T::Types::Intersection) # 6
      # dropping either of parts eagerly make subtype test be too strict.
      # we have to try both cases, when we normally try only one
      return t2.types.any? {|t2_member| t1.subtype_of?(t2_member)} ||
          t1.types.any? {|t1_member| t1_member.subtype_of?(t2)}
    end
    return t2.types.any? {|t2_member| t1.subtype_of?(t2_member)} # 3
  end

  if t1.is_a?(T::Types::Intersection) # 4
    # this will be incorrect if/when we have Type members
    return t1.types.any? {|t1_member| t1_member.subtype_of?(t2)}
  end

  # 1; Start with some special cases
  if t1.is_a?(T::Private::Types::Void)
    return t2.is_a?(T::Private::Types::Void)
  end

  if t1.is_a?(T::Types::Untyped) || t2.is_a?(T::Types::Untyped)
    return true
  end

  # Rest of (1)
  subtype_of_single?(t2)
end
to_s() click to toggle source
# File lib/types/types/base.rb, line 106
def to_s
  name
end
valid?(obj) click to toggle source
# File lib/types/types/base.rb, line 24
def valid?(obj)
  raise NotImplementedError
end
validate!(obj) click to toggle source
# File lib/types/types/base.rb, line 148
def validate!(obj)
  err = error_message_for_obj(obj)
  raise TypeError.new(err) if err
end

Private Instance Methods

subtype_of_single?(type) click to toggle source

@return [T::Boolean] This method must be implemented to return whether the subclass is a subtype of `type`. This should only be called by `subtype_of?`, which guarantees that `type` will be a “single” type, by which we mean it won't be a Union or an Intersection (c.f. `isSubTypeSingle` in sorbet).

# File lib/types/types/base.rb, line 32
        def subtype_of_single?(type)
  raise NotImplementedError
end