Sha256: d153f8b580556bf619458cc7b32c845b0523142f0279838f61845e263be592dd

Contents?: true

Size: 1.54 KB

Versions: 1

Compression:

Stored size: 1.54 KB

Contents

# typed: strict

module Mocktail
  class RunsSorbetSigBlocksBeforeReplacement
    extend T::Sig

    # This is necessary because when Sorbet runs a sig block of a singleton
    # method, it has the net effect of unwrapping/redefining the method. If
    # we try to use Mocktail.replace(Foo) and Foo.bar has a Sorbet sig block,
    # then we'll end up with three "versions" of the same method and no way
    # to keep straight which one == which:
    #
    #  A - Foo.bar, as defined in the original class
    #  B - Foo.bar, as redefined by RedefinesSingletonMethods
    #  C - Foo.bar, as wrapped by sorbet-runtime
    #
    # Initially, Foo.method(:bar) would == C, but after the type
    # replacement, it would == B (with a reference back to C as the original),
    # but after handling a single dry call, our invocation of
    # GrabsOriginalMethodParameters.grab(Foo.method(:bar)) would invoke the
    # Sorbet `sig` block, which has the net effect of redefining the method back
    # to A.
    #
    # It's very fun and confusing and a great time.
    sig { params(type: T.any(T::Class[T.anything], Module)).void }
    def run(type)
      return unless defined?(T::Private::Methods)

      type.singleton_methods.each do |method_name|
        method = type.method(method_name)

        # Again: calling this for the side effect of running the sig block
        #
        # https://github.com/sorbet/sorbet/blob/master/gems/sorbet-runtime/lib/types/private/methods/_methods.rb#L111
        T::Private::Methods.signature_for_method(method)
      end
    end
  end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
mocktail-2.0.0 lib/mocktail/sorbet/mocktail/replaces_type/runs_sorbet_sig_blocks_before_replacement.rb