From c80a28d616758d20987e73a8fe37795ba2caaf5d Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 12 Oct 2019 20:53:17 -0600 Subject: [PATCH] More work on method stubs --- src/spectator/double.cr | 28 ++++++++++++---------------- src/spectator/dsl/mocks.cr | 2 +- src/spectator/generic_method_stub.cr | 12 +++++++++--- src/spectator/method_call.cr | 12 ++++++++++++ src/spectator/method_stub.cr | 7 ++----- 5 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 src/spectator/method_call.cr diff --git a/src/spectator/double.cr b/src/spectator/double.cr index 7423d0a..4301370 100644 --- a/src/spectator/double.cr +++ b/src/spectator/double.cr @@ -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 %} diff --git a/src/spectator/dsl/mocks.cr b/src/spectator/dsl/mocks.cr index f9088e6..532b058 100644 --- a/src/spectator/dsl/mocks.cr +++ b/src/spectator/dsl/mocks.cr @@ -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 diff --git a/src/spectator/generic_method_stub.cr b/src/spectator/generic_method_stub.cr index e9682fd..78042b1 100644 --- a/src/spectator/generic_method_stub.cr +++ b/src/spectator/generic_method_stub.cr @@ -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 diff --git a/src/spectator/method_call.cr b/src/spectator/method_call.cr new file mode 100644 index 0000000..da94054 --- /dev/null +++ b/src/spectator/method_call.cr @@ -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 diff --git a/src/spectator/method_stub.cr b/src/spectator/method_stub.cr index 7a710a0..856ed1e 100644 --- a/src/spectator/method_stub.cr +++ b/src/spectator/method_stub.cr @@ -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