Jwan622 Jwan622 - 1 month ago 5
Ruby Question

RSpec custom matchers syntax. What is going on structurally?

From the RSpec docs:

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 going on here? When defining a matcher what is this section of code:

:be_a_multiple_of do |expected|
match do |actual|
actual % expected == 0
end
end


Is that a
Proc
? What is being passed to the
.define
method? What is
|expected|
? Is that the 3 that we pass into the method? How does
:be_a_multiple_of
become a method? There seems to be a lot of metaprogrammy magic going on so I'd like to just figure out what is happening.

What is this
match do
method?

Answer

You can look at the rspec source docs for starters - http://www.rubydoc.info/gems/rspec-expectations/RSpec/Matchers/DSL/Matcher

if you wanted to make a method callable like this:

some_method :symbol do
end

# one-liner version (parens are needed for arg)
some_method(:symbol) { }

you could define this:

def some_method(arg, &block)
  # the block gets called in here
end

See Blocks and yields in Ruby

As far as the symbol being turned into a method - this is actually pretty common, and is one of the main things that distinguishes symbols from strings.

So on that RSpec doc page, it says:

The block passed to RSpec::Matchers.define will be evaluated in the context of the singleton class of an instance, and will have the Macros methods available.

If you want to see exactly what's going on here you can go through the RSpec source code. However the internals aren't necessarily as well documented,

See What exactly is the singleton class in ruby?