# frozen_string_literal: true# Released under the MIT License.# Copyright, 2022-2024, by Samuel Williams.require_relative"expect"moduleSusclassMockdefinitialize(target)@target=target@interceptor=Module.new@target.singleton_class.prepend(@interceptor)endattr:targetdefprint(output)output.write("mock ",:context,@target.inspect)enddefclear@interceptor.instance_methods.eachdo|method_name|@interceptor.remove_method(method_name)endenddefreplace(method,&hook)execution_context=Thread.current@interceptor.define_method(method)do|*arguments,**options,&block|ifexecution_context==Thread.currenthook.call(*arguments,**options,&block)elsesuper(*arguments,**options,&block)endendreturnselfenddefbefore(method,&hook)execution_context=Thread.current@interceptor.define_method(method)do|*arguments,**options,&block|hook.call(*arguments,**options,&block)ifexecution_context==Thread.currentsuper(*arguments,**options,&block)endreturnselfenddefafter(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)ifexecution_context==Thread.currentreturnresultendreturnselfend# Wrap a method, yielding the original method as the first argument, so you can call it from within the hook.defwrap(method,&hook)execution_context=Thread.current@interceptor.define_method(method)do|*arguments,**options,&block|ifexecution_context==Thread.currentoriginal=procdo|*arguments,**options|super(*arguments,**options)endhook.call(original,*arguments,**options,&block)elsesuper(*arguments,**options,&block)endendendendmoduleMocksdefafter(error=nil)super@mocks&.each_value(&:clear)enddefmock(target)validate_mock!(target)mock=self.mocks[target]ifblock_given?yieldmockendreturnmockendprivateMockTargetError=Class.new(StandardError)defvalidate_mock!(target)iftarget.frozen?raiseMockTargetError,"Cannot mock frozen object #{target.inspect}!"endenddefmocks@mocks||=Hash.new{|h,k|h[k]=Mock.new(k)}.compare_by_identityendendclassBasedefmock(target,&block)# Pull in the extra functionality:self.singleton_class.prepend(Mocks)# Redirect the method to the new functionality:self.mock(target,&block)endendend