Jwan622 Jwan622 - 1 month ago 5
Ruby Question

Custom matchers in Rspec. What is the match do block?

I am reading this code from RSpec:

require 'rspec/expectations'

RSpec::Matchers.define :be_a_multiple_of do |expected|
match do |actual|
actual % expected == 0
end
end

RSpec.describe 9 do
it { is_expected.to be_a_multiple_of(3) }
end


What is the
match do
block? It's a block inside a proc? The syntax is a bit odd... is the
define
method taking two arguments; the first is a symbol and the second is a
Proc
?

Under the hood... how does
actual
refer to the integer 9?

Answer
expect(object).to eq(value)
         |         |   |
         |         |  expected (matcher argument)
         |         |
       actual      |
                matcher

What's happening in this code?

RSpec::Matchers.define :be_a_multiple_of do |expected|

When RSpec::Matcher.define is called, it is passed the name of a matcher ( which in this case is be_a_multiple_of ) and a block

The argument passed to that block is the expected value. This is the value passed as the matcher argument when running a spec, which would be 3 in this case be_a_multiple_of(3)

match do |actual|

Inisde that block, the match method is called which is also passed a block. That block takes one argument, actual, which is the value passed to expect when the matcher is invoked. In this case that would be 9, expect(9).to be_multipe_of(3)

The block just does some calculation using actual and expected to return true or false.

How does actual refer to 9?

RSpec.describe 9 do

In this case the value 9 is exposed as the subject for the example group because it is passed as the argument to the outermost example group as stated here In other words it's the same as writing subject { 9 }

If you check the RSpec doc is_expected is basically the same as writing expect(subject).

{ is_expected.to be_a_multiple_of(3) }

is the same as

{ expect(subject).to be_a_multiple_of(3) }

And as stated earlier the object passed to expect method is what is used as the actual argument for the block passed to the match method. That's how actual refers to 9

Comments