Skip to content

Instantly share code, notes, and snippets.

@maxim
Created November 16, 2023 03:33
Show Gist options
  • Save maxim/6beb74980632d5a0d8afbef651ba44ed to your computer and use it in GitHub Desktop.
Save maxim/6beb74980632d5a0d8afbef651ba44ed to your computer and use it in GitHub Desktop.
require 'minitest/mock'
module StubStrict
module_function
def render_parameters(ruby_parameters)
ruby_parameters.map { |type, name|
case type
when :req; name.to_s
when :opt; "#{name} = 'value'"
when :rest; "*#{name}"
when :key; "#{name}: 'value'"
when :keyreq; "#{name}:"
when :keyrest; "**#{name}"
when :block; "&#{name}"
end
}.join(', ')
end
def wrap_with_verifier(val, name, rendered_args)
obj = Object.new
eval "def obj.verify_args(#{rendered_args}); end",
binding, __FILE__, __LINE__ - 1
->(*a, **k, &b) {
begin
obj.verify_args(*a, **k, &b)
rescue ArgumentError
raise ArgumentError,
'Stubbed args are incompatible with the original method. ' \
"Expected signature: #{name}(#{rendered_args})"
end
val.respond_to?(:call) ? val.call(*a, **k, &b) : val
}
end
module ObjectExt
def stub_strict(name, val, *, **, &)
expected_args =
if name == :new && method(:new).source_location.nil?
instance_method(:initialize).parameters
else
method(name).parameters
end
rendered_args = StubStrict.render_parameters(expected_args)
wrapped_args = StubStrict.wrap_with_verifier(val, name, rendered_args)
stub(name, wrapped_args, *, **, &)
end
end
end
class Object
include StubStrict::ObjectExt
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment