From 541dc661ca0de5908c5ff420cc0fd31dd92c2145 Mon Sep 17 00:00:00 2001 From: Michael Miller Date: Sat, 2 Nov 2019 09:45:34 -0600 Subject: [PATCH] Only accept exact parameters, don't use splats --- src/spectator/double.cr | 63 ++++++++++++---------------- src/spectator/generic_method_call.cr | 4 ++ 2 files changed, 30 insertions(+), 37 deletions(-) diff --git a/src/spectator/double.cr b/src/spectator/double.cr index 4d3a12a..424f850 100644 --- a/src/spectator/double.cr +++ b/src/spectator/double.cr @@ -16,9 +16,15 @@ module Spectator args = nil body = nil if definition.is_a?(Call) # stub foo { :bar } + named = false name = definition.name.id params = definition.args - args = params.map { |p| p.is_a?(TypeDeclaration) ? p.var : p.id } + args = params.map do |p| + n = p.is_a?(TypeDeclaration) ? p.var : p.id + r = named ? "#{n}: #{n}".id : n + named = true if n.starts_with?('*') + r + end body = definition.block.is_a?(Nop) ? block : definition.block elsif definition.is_a?(TypeDeclaration) # stub foo : Symbol name = definition.var @@ -30,51 +36,34 @@ module Spectator end %} - {% if name.ends_with?('=') && name.id != "[]=" %} - def {{name}}(arg) - call = ::Spectator::GenericMethodCall.new({{name.symbolize}}, {arg}, NamedTuple.new) - @spectator_stub_calls << call - stub = @spectator_stubs.find(&.callable?(call)) - if stub - stub.as(::Spectator::GenericMethodStub(typeof(%method(arg)))).call(call) - else - %method(arg) - end - end - {% else %} - def {{name}}(*args, **options){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} - call = ::Spectator::GenericMethodCall.new({{name.symbolize}}, args, options) - @spectator_stub_calls << call - stub = @spectator_stubs.find(&.callable?(call)) - if stub - stub.as(::Spectator::GenericMethodStub(typeof(%method(*args, **options)))).call(call) - else - %method(*args, **options) - end + def {{name}}({{params.splat}}){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} + %call = ::Spectator::GenericMethodCall.create({{name.symbolize}}{% unless args.empty? %}, {{args.splat}}{% end %}) + @spectator_stub_calls << %call + if (%stub = @spectator_stubs.find(&.callable?(%call))) + %stub.as(::Spectator::GenericMethodStub(typeof(%method({{args.splat}})))).call(%call) + else + %method({{args.splat}}) end + end - {% if name != "[]=" %} - def {{name}}(*args, **options){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} - call = ::Spectator::GenericMethodCall.new({{name.symbolize}}, args, options) - @spectator_stub_calls << call - stub = @spectator_stubs.find(&.callable?(call)) - if stub - stub.as(::Spectator::GenericMethodStub(typeof(%method(*args, **options) { |*yield_args| yield *yield_args }))).call(call) - else - %method(*args, **options) do |*yield_args| - yield *yield_args - end - end + def {{name}}({{params.splat}}){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} + %call = ::Spectator::GenericMethodCall.create({{name.symbolize}}{% unless args.empty? %}, {{args.splat}}{% end %}) + @spectator_stub_calls << %call + if (%stub = @spectator_stubs.find(&.callable?(%call))) + %stub.as(::Spectator::GenericMethodStub(typeof(%method({{args.splat}}) { |*%yield_args| yield *%yield_args }))).call(%call) + else + %method({{args.splat}}) do |*%yield_args| + yield *%yield_args end - {% end %} - {% end %} + end + end def %method({{params.splat}}){% if definition.is_a?(TypeDeclaration) %} : {{definition.type}}{% end %} {% if body && !body.is_a?(Nop) %} {{body.body}} {% else %} raise "Stubbed method called without being allowed" - # This code shouldn't be reached, but makes the compiler happy to have a matching type. + # This code shouldn't be reached, but makes the compiler happy to have a matching return type. {% if definition.is_a?(TypeDeclaration) %} %x = uninitialized {{definition.type}} {% else %} diff --git a/src/spectator/generic_method_call.cr b/src/spectator/generic_method_call.cr index 1afac3a..75050ce 100644 --- a/src/spectator/generic_method_call.cr +++ b/src/spectator/generic_method_call.cr @@ -10,6 +10,10 @@ module Spectator super(name) end + def self.create(name : Symbol, *args, **options) + GenericMethodCall.new(name, args, options) + end + def to_s(io) io << name return if @args.empty? && @options.empty?