Class: Smartest::SimpleStub

Inherits:
Object
  • Object
show all
Defined in:
lib/smartest/simple_stub.rb

Defined Under Namespace

Classes: AlreadyAppliedError, NotAppliedError, StubEntry

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass, method_name, &implementation) ⇒ SimpleStub

Returns a new instance of SimpleStub.

Raises:

  • (ArgumentError)


137
138
139
140
141
142
143
144
# File 'lib/smartest/simple_stub.rb', line 137

def initialize(klass, method_name, &implementation)
  raise ArgumentError, "klass must be a Class. #{klass.class} specified." unless klass.is_a?(Class)
  raise ArgumentError, "method name must be a Symbol." unless method_name.is_a?(Symbol)

  @klass = klass
  @method_name = method_name
  @implementation = implementation
end

Class Method Details

.activate_stub(stub, stub_key, implementation) ⇒ Object



19
20
21
22
23
24
25
26
27
# File 'lib/smartest/simple_stub.rb', line 19

def activate_stub(stub, stub_key, implementation)
  stub_registry_mutex.synchronize do
    stack = active_stubs[stub_key] ||= []
    return false if stack.any? { |entry| entry.owner.equal?(stub) }

    stack << StubEntry.new(stub, implementation)
    true
  end
end

.call_implementation(receiver, implementation, args, kwargs, block) ⇒ Object



66
67
68
69
70
71
72
73
74
# File 'lib/smartest/simple_stub.rb', line 66

def call_implementation(receiver, implementation, args, kwargs, block)
  return call_implementation_with_block(receiver, implementation, args, kwargs, block) if block

  if kwargs.empty?
    receiver.instance_exec(*args, &implementation)
  else
    receiver.instance_exec(*args, **kwargs, &implementation)
  end
end

.call_implementation_with_block(receiver, implementation, args, kwargs, block) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/smartest/simple_stub.rb', line 76

def call_implementation_with_block(receiver, implementation, args, kwargs, block)
  method_name = next_call_method_name
  singleton_class = receiver.singleton_class
  singleton_class.__send__(:define_method, method_name, &implementation)

  if kwargs.empty?
    receiver.__send__(method_name, *args, &block)
  else
    receiver.__send__(method_name, *args, **kwargs, &block)
  end
ensure
  if singleton_class &&
      (singleton_class.method_defined?(method_name) || singleton_class.private_method_defined?(method_name))
    singleton_class.__send__(:remove_method, method_name)
  end
end

.deactivate_stub(stub, stub_key) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/smartest/simple_stub.rb', line 29

def deactivate_stub(stub, stub_key)
  stub_registry_mutex.synchronize do
    stack = active_stubs.fetch(stub_key, nil)
    return false unless stack

    index = stack.index { |entry| entry.owner.equal?(stub) }
    return false unless index

    stack.delete_at(index)
    active_stubs.delete(stub_key) if stack.empty?
    true
  end
end

.ensure_dispatcher_method(klass, klass_key, method_name) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/smartest/simple_stub.rb', line 43

def ensure_dispatcher_method(klass, klass_key, method_name)
  dispatcher_mutex.synchronize do
    mod = dispatcher_module_for(klass, klass_key)
    next if mod.method_defined?(method_name) || mod.private_method_defined?(method_name)

    mod.define_method(method_name) do |*args, **kwargs, &block|
      implementation = SimpleStub.implementation_for(klass_key, method_name)

      if implementation
        SimpleStub.call_implementation(self, implementation, args, kwargs, block)
      elsif kwargs.empty?
        super(*args, &block)
      else
        super(*args, **kwargs, &block)
      end
    end
  end
end

.implementation_for(klass_key, method_name) ⇒ Object



13
14
15
16
17
# File 'lib/smartest/simple_stub.rb', line 13

def implementation_for(klass_key, method_name)
  stub_registry_mutex.synchronize do
    active_stubs.fetch(stub_key(klass_key, method_name), nil)&.last&.implementation
  end
end

.stub_key(klass_key, method_name) ⇒ Object



62
63
64
# File 'lib/smartest/simple_stub.rb', line 62

def stub_key(klass_key, method_name)
  [klass_key, method_name]
end

Instance Method Details

#applyObject



146
147
148
# File 'lib/smartest/simple_stub.rb', line 146

def apply
  apply_stub
end

#resetObject



150
151
152
# File 'lib/smartest/simple_stub.rb', line 150

def reset
  reset_stub
end