Как работает be_some в RSpec?

November 24, 2014

Как-то раз я решил разобраться какая именно магия используется в RSpec-предикаторах be_some, так как на первый взгляд они напоминают undefined local variable or method.

class Sun
  def available?
    false
  end
end

describe Sun do
  it "sad and cold" do
    expect(Sun.new).not_to be_available
  end
end

Конечно же это method_messing. Продираться через все хитросплетения RSpec мне не захотелось, хотя код там очень основательный и щедро документированный, я нашел лишь несколько ключевых точек.

describe Sun превращается в класс RSpec::ExampleGroups::Sun, наследованный от RSpec::Core::ExampleGroup, в который при инициализации подмешивается модуль RSpec::Matchers , отлавливающий be_* с помощью method_messing .

module RSpec
  # ...
  module Matchers
  # ...

    BE_PREDICATE_REGEX = /^(be_(?:an?_)?)(.*)/
    HAS_REGEX = /^(?:have_)(.*)/

    def method_missing(method, *args, &block)
      case method.to_s
      when BE_PREDICATE_REGEX
        BuiltIn::BePredicate.new(method, *args, &block)
      when HAS_REGEX
        BuiltIn::Has.new(method, *args, &block)
      else
        super
      end
    end

Отлично, теперь можно спать спокойно.

comments powered by Disqus