SusSourceSusMock

class Mock

Represents a mock object that can intercept and replace method calls on a target object.

Definitions

def initialize(target)

Initialize a new mock for the given target.

Signature

parameter target Object

The object to mock.

Implementation

def initialize(target)
	@target = target
	@interceptor = Module.new
	
	@target.singleton_class.prepend(@interceptor)
end

attr :target

Signature

attribute Object

The target object being mocked.

def print(output)

Print a representation of this mock.

Signature

parameter output Output

The output target.

Implementation

def print(output)
	output.write("mock ", :context, @target.inspect)
end

def clear

Clear all mocked methods from the target.

Implementation

def clear
	@interceptor.instance_methods.each do |method_name|
		@interceptor.remove_method(method_name)
	end
end

def replace(method, &hook)

Replace a method implementation.

Signature

parameter method Symbol

The method name to replace.

yields {|*arguments, **options, &block| ...}

The replacement implementation.

returns Mock

Returns self for method chaining.

Implementation

def replace(method, &hook)
	execution_context = Thread.current
	
	@interceptor.define_method(method) do |*arguments, **options, &block|
		if execution_context == Thread.current
			hook.call(*arguments, **options, &block)
		else
			super(*arguments, **options, &block)
		end
	end
	
	return self
end

def before(method, &hook)

Add a hook that runs before a method is called.

Signature

parameter method Symbol

The method name to hook.

yields {|*arguments, **options, &block| ...}

The hook to execute before the method.

returns Mock

Returns self for method chaining.

Implementation

def before(method, &hook)
	execution_context = Thread.current
	
	@interceptor.define_method(method) do |*arguments, **options, &block|
		hook.call(*arguments, **options, &block) if execution_context == Thread.current
		super(*arguments, **options, &block)
	end
	
	return self
end

def after(method, &hook)

Add a hook that runs after a method is called.

Signature

parameter method Symbol

The method name to hook.

yields {|result, *arguments, **options, &block| ...}

The hook to execute after the method, receiving the result as the first argument.

returns Mock

Returns self for method chaining.

Implementation

def after(method, &hook)
	execution_context = Thread.current
	
	@interceptor.define_method(method) do |*arguments, **options, &block|
		result = super(*arguments, **options, &block)
		hook.call(result, *arguments, **options, &block) if execution_context == Thread.current
		return result
	end
	
	return self
end

def wrap(method, &hook)

Wrap a method, yielding the original method as the first argument, so you can call it from within the hook.

Signature

parameter method Symbol

The method name to wrap.

yields {|original, *arguments, **options, &block| ...}

The wrapper implementation, receiving the original method as the first argument.

Implementation

def wrap(method, &hook)
	execution_context = Thread.current
	
	@interceptor.define_method(method) do |*arguments, **options, &block|
		if execution_context == Thread.current
			original = proc do |*arguments, **options, &block|
				super(*arguments, **options, &block)
			end
			
			hook.call(original, *arguments, **options, &block) 
		else
			super(*arguments, **options, &block)
		end
	end
end