Class: Mocktail::RedefinesSingletonMethods

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/mocktail/replaces_type/redefines_singleton_methods.rb,
lib/mocktail/sorbet/mocktail/replaces_type/redefines_singleton_methods.rb

Instance Method Summary collapse

Constructor Details

#initializeRedefinesSingletonMethods

Returns a new instance of RedefinesSingletonMethods.



5
6
7
# File 'lib/mocktail/replaces_type/redefines_singleton_methods.rb', line 5

def initialize
  @handles_dry_call = HandlesDryCall.new
end

Instance Method Details

#declare_singleton_method_missing_errors!(type) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/mocktail/replaces_type/redefines_singleton_methods.rb', line 42

def declare_singleton_method_missing_errors!(type)
  return if type.singleton_methods.include?(:method_missing)

  raises_neato_no_method_error = RaisesNeatoNoMethodError.new
  type.define_singleton_method :method_missing,
    ->(name, *args, **kwargs, &block) {
      raises_neato_no_method_error.call(
        Call.new(
          singleton: true,
          double: self,
          original_type: type,
          dry_type: self.class,
          method: name,
          original_method: nil,
          args: args,
          kwargs: kwargs,
          block: block
        )
      )
    }
end

#redefine(type) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/mocktail/replaces_type/redefines_singleton_methods.rb', line 9

def redefine(type)
  type_replacement = TopShelf.instance.type_replacement_for(type)
  return unless type_replacement.replacement_methods.nil?

  type_replacement.original_methods = type.singleton_methods.map { |name|
    type.method(name)
  }.reject { |method| sorbet_method_hook?(method) } - [type_replacement.replacement_new]

  declare_singleton_method_missing_errors!(type)
  handles_dry_call = @handles_dry_call
  type_replacement.replacement_methods = type_replacement.original_methods&.map { |original_method|
    type.singleton_class.send(:undef_method, original_method.name)
    type.define_singleton_method original_method.name, ->(*args, **kwargs, &block) {
      if TopShelf.instance.singleton_methods_replaced?(type)
        handles_dry_call.handle(Call.new(
          singleton: true,
          double: type,
          original_type: type,
          dry_type: type,
          method: original_method.name,
          original_method: original_method,
          args: args,
          kwargs: kwargs,
          block: block
        ))
      else
        original_method.call(*args, **kwargs, &block)
      end
    }
    type.singleton_method(original_method.name)
  }
end