module RSpec::Core::MemoizedHelpers

This module is included in {ExampleGroup}, making the methods available to be called from within example blocks.

@see ClassMethods

Public Class Methods

@private

# File rspec-core/lib/rspec/core/memoized_helpers.rb, line 469
def self.define_helpers_on(example_group)
  example_group.include(module_for(example_group))
end

@private

Gets the named constant or yields. const_defined? / const_get take into account the the inheritance by default, and accept an argument to disable this behavior. It’s important that we don’t consider inheritance here; each example group level that uses a ‘let` should get its own `LetDefinitions` module.

# File rspec-core/lib/rspec/core/memoized_helpers.rb, line 481
def self.get_constant_or_yield(example_group, name)
  if example_group.const_defined?(name, false)
    example_group.const_get(name, false)
  else
    yield
  end
end

@private

Gets the LetDefinitions module. The module is mixed into the example group and is used to hold all let definitions. This is done so that the block passed to ‘let` can be forwarded directly on to `define_method`, so that all method constructs (including `super` and `return`) can be used in a `let` block.

The memoization is provided by a method definition on the example group that supers to the LetDefinitions definition in order to get the value to memoize.

# File rspec-core/lib/rspec/core/memoized_helpers.rb, line 455
def self.module_for(example_group)
  get_constant_or_yield(example_group, :LetDefinitions) do
    mod = Module.new do
      include(Module.new {
        example_group.const_set(:NamedSubjectPreventSuper, self)
      })
    end

    example_group.const_set(:LetDefinitions, mod)
    mod
  end
end

@private

Calls superclass method
# File rspec-core/lib/rspec/core/memoized_helpers.rb, line 84
def initialize(*)
  __init_memoized
  super
end

Public Instance Methods

Wraps the ‘subject` in `expect` to make it the target of an expectation. Designed to read nicely for one-liners.

@example

describe [1, 2, 3] do
  it { is_expected.to be_an Array }
  it { is_expected.not_to include 4 }
end

@see subject

@note This only works if you are using rspec-expectations.

# File rspec-core/lib/rspec/core/memoized_helpers.rb, line 69
def is_expected
  expect(subject)
end

@note ‘subject` was contributed by Joe Ferris to support the one-liner

syntax embraced by shoulda matchers:

    RSpec.describe Widget do
      it { is_expected.to validate_presence_of(:name) }
    end

While the examples below demonstrate how to use `subject`
explicitly in examples, we recommend that you define a method with
an intention revealing name instead.

@example

# Explicit declaration of subject.
RSpec.describe Person do
  subject { Person.new(:birthdate => 19.years.ago) }
  it "is eligible to vote" do
    is_expected.to be_eligible_to_vote
  end
end

# Implicit subject => { Person.new }.
RSpec.describe Person do
  it "is eligible to vote" do
    is_expected.to be_eligible_to_vote
  end
end

# One-liner syntax - expectation is set on the subject.
RSpec.describe Person do
  it { is_expected.to be_eligible_to_vote }
end

@note Because ‘subject` is designed to create state that is reset

between each example, and `before(:context)` is designed to setup
state that is shared across _all_ examples in an example group,
`subject` is _not_ intended to be used in a `before(:context)` hook.

@see is_expected

# File rspec-core/lib/rspec/core/memoized_helpers.rb, line 49
def subject
  __memoized.fetch_or_store(:subject) do
    described = described_class || self.class.metadata.fetch(:description_args).first
    Class === described ? described.new : described
  end
end