Skip to content

Instantly share code, notes, and snippets.

@ssimeonov
Forked from txus/delegate_matcher.rb
Last active May 21, 2020 13:56
Show Gist options
  • Save ssimeonov/5942729 to your computer and use it in GitHub Desktop.
Save ssimeonov/5942729 to your computer and use it in GitHub Desktop.
# RSpec matcher to spec delegations.
# Forked from https://gist.github.com/txus/807456 with added bug fixes
#
# Usage:
#
# describe Post do
# it { should delegate(:name).to(:author).with_prefix } # post.author_name
# it { should delegate(:month).to(:created_at) }
# it { should delegate(:year).to(:created_at) }
# it { should delegate(:something).to(:'@instance_var') }
# end
RSpec::Matchers.define :delegate do |method|
match do |delegator|
@method = @prefix ? :"#{@to}_#{method}" : method
@delegator = delegator
if @to.to_s[0] == '@'
# Delegation to an instance variable
old_value = @delegator.instance_variable_get(@to)
begin
@delegator.instance_variable_set(@to, receiver_double(method))
@delegator.send(@method) == :called
ensure
@delegator.instance_variable_set(@to, old_value)
end
elsif @delegator.respond_to?(@to, true)
unless @delegator.method(@to).arity == 0
raise "#{@delegator}'s' #{@to} method does not have zero arity (it expects parameters)"
end
@delegator.stub(@to).and_return receiver_double(method)
@delegator.send(@method) == :called
else
raise "#{@delegator} does not respond to #{@to}"
end
end
description do
"delegate :#{@method} to its #{@to}#{@prefix ? ' with prefix' : ''}"
end
failure_message_for_should do |text|
"expected #{@delegator} to delegate :#{@method} to its #{@to}#{@prefix ? ' with prefix' : ''}"
end
failure_message_for_should_not do |text|
"expected #{@delegator} not to delegate :#{@method} to its #{@to}#{@prefix ? ' with prefix' : ''}"
end
chain(:to) { |receiver| @to = receiver }
chain(:with_prefix) { @prefix = true }
def receiver_double(method)
double('receiver').tap do |receiver|
receiver.stub(method).and_return :called
end
end
end
@seanselltl
Copy link

I think that you should check if the method has an arity of -1 or 0 since either are valid.

@awinograd
Copy link

Hi Simeon,

I've forked your gist at https://gist.github.com/awinograd/6158961.

It fixes the arity preoblem seanselltl metioned (which I also experienced) as well as adds support for a custom prefix for the delegation that can be added to the model's delegation.

delegate :name, to: :author, prefix: :any
it { should delegate(:name).to(:author).with_prefix(:any) } # post.any_name

@hrieke
Copy link

hrieke commented May 20, 2020

Hello Simeon,
Do you have a license that you would like to release this code under?
I spoke with Alec Winograd about his fork, he's added an MIT License to his modifications.
Thank you, hope all is well.

@ssimeonov
Copy link
Author

I am happy to offer this code to the community under the MIT License.

@hrieke
Copy link

hrieke commented May 21, 2020

Awesome and thank you very much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment