More work on method stubs

This commit is contained in:
Michael Miller 2019-10-12 20:53:17 -06:00
parent 0b6465e6bc
commit c80a28d616
5 changed files with 36 additions and 25 deletions

View file

@ -4,16 +4,7 @@ module Spectator
abstract class Double
@stubs = Deque(MethodStub).new
private macro delegate_internal(method, *args)
# Modified version of Object#delegate
{% if method.id.ends_with?('=') && method.id != "[]=" %}
@internal.{{method.id}} {{args.splat}}
{% else %}
@internal.{{method.id}}({{args.splat}})
{% end %}
end
macro stub(definition, &block)
private macro stub(definition, &block)
{%
name = nil
params = nil
@ -34,17 +25,22 @@ module Spectator
end
%}
def {{name}}({{params.splat}})
%stub = @stubs.find(&.callable?({{name.symbolize}}{% unless args.empty? %}, {{args.splat}}{% end %}))
if %stub
%stub.call({{args.splat}})
def {{name}}(*args, **options){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %}
call = ::Spectator::MethodCall.new({{name.symbolize}}, args, options)
stub = @stubs.find(&.callable?(call))
if stub
stub.as(::Spectator::GenericMethodStub(typeof(@internal.{{name}}(*args, **options)))).call(call)
else
delegate_internal({{name}}{% unless args.empty? %}, {{args.splat}}{% end %})
@internal.{{name}}(*args, **options)
end
end
def {{name}}(*args, **options, &block){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %}
@internal.{{name}}(*args, **options, &block)
end
private class Internal
def {{name}}({{params.splat}})
def {{name}}({{params.splat}}){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %}
{% if body && !body.is_a?(Nop) %}
{{body.body}}
{% else %}

View file

@ -30,6 +30,6 @@ module Spectator::DSL
macro receive(method_name, _source_file = __FILE__, _source_line = __LINE__)
%source = ::Spectator::Source.new({{_source_file}}, {{_source_line}})
::Spectator::GenericMethodStub(Nil).new({{method_name.symbolize}}, %source)
::Spectator::GenericMethodStub(Nil).new({{method_name.symbolize}}, %source, ->{ nil })
end
end

View file

@ -1,13 +1,19 @@
require "./method_call"
require "./method_stub"
require "./source"
module Spectator
class GenericMethodStub(ReturnType, *ArgumentTypes) < MethodStub
def callable?(name : Symbol, *args) : Bool
class GenericMethodStub(ReturnType) < MethodStub
def initialize(name : Symbol, source : Source, @proc : -> ReturnType)
super(name, source)
end
def callable?(call : MethodCall) : Bool
super
end
def call(*args)
def call(call : MethodCall) : ReturnType
@proc.call
end
end
end

View file

@ -0,0 +1,12 @@
module Spectator
class MethodCall(T, NT)
getter name : Symbol
getter args : T
getter options : NT
def initialize(@name : Symbol, @args : T, @options : NT)
end
end
end

View file

@ -5,11 +5,8 @@ module Spectator
def initialize(@name : Symbol, @source : Source)
end
def callable?(name : Symbol, *args) : Bool
name == @name
end
def call(*args)
def callable?(call : MethodCall) : Bool
@name == call.name
end
end
end