module RSpec::Core::MemoizedHelpers

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

@see ClassMethods

Attributes

__memoized[R]

@private should just be placed in private section, but Ruby issues warnings on private attributes. and expanding it to the equivalent method upsets Rubocop, b/c it should obviously be a reader

Public Class Methods

new(*) click to toggle source

@private

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

Private Class Methods

define_helpers_on(example_group) click to toggle source

@private

# File lib/rspec/core/memoized_helpers.rb, line 542
def self.define_helpers_on(example_group)
  example_group.__send__(:include, module_for(example_group))
end
get_constant_or_yield(example_group, name) { || ... } click to toggle source

@private

Gets the named constant or yields. On 1.8, const_defined? / const_get do not take into account the inheritance hierarchy. :nocov:

# File lib/rspec/core/memoized_helpers.rb, line 553
def self.get_constant_or_yield(example_group, name)
  if example_group.const_defined?(name)
    example_group.const_get(name)
  else
    yield
  end
end
module_for(example_group) click to toggle source

@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 lib/rspec/core/memoized_helpers.rb, line 528
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

Public Instance Methods

is_expected() click to toggle source

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 @see should @see should_not

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

# File lib/rspec/core/memoized_helpers.rb, line 120
def is_expected
  expect(subject)
end
should(matcher=nil, message=nil) click to toggle source

When ‘should` is called with no explicit receiver, the call is delegated to the object returned by `subject`. Combined with an implicit subject this supports very concise expressions.

@example

RSpec.describe Person do
  it { should be_eligible_to_vote }
end

@see subject @see is_expected

@note This only works if you are using rspec-expectations. @note If you are using RSpec’s newer expect-based syntax you may

want to use `is_expected.to` instead of `should`.
# File lib/rspec/core/memoized_helpers.rb, line 80
def should(matcher=nil, message=nil)
  enforce_value_expectation(matcher, 'should')
  RSpec::Expectations::PositiveExpectationHandler.handle_matcher(subject, matcher, message)
end
should_not(matcher=nil, message=nil) click to toggle source

Just like ‘should`, `should_not` delegates to the subject (implicit or explicit) of the example group.

@example

RSpec.describe Person do
  it { should_not be_eligible_to_vote }
end

@see subject @see is_expected

@note This only works if you are using rspec-expectations. @note If you are using RSpec’s newer expect-based syntax you may

want to use `is_expected.to_not` instead of `should_not`.
# File lib/rspec/core/memoized_helpers.rb, line 100
def should_not(matcher=nil, message=nil)
  enforce_value_expectation(matcher, 'should_not')
  RSpec::Expectations::NegativeExpectationHandler.handle_matcher(subject, matcher, message)
end
subject() click to toggle source

@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) }
      # or
      it { should 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 "should be eligible to vote" do
    subject.should be_eligible_to_vote
    # ^ ^ explicit reference to subject not recommended
  end
end

# Implicit subject => { Person.new }.
RSpec.describe Person do
  it "should be eligible to vote" do
    subject.should be_eligible_to_vote
    # ^ ^ explicit reference to subject not recommended
  end
end

# One-liner syntax - expectation is set on the subject.
RSpec.describe Person do
  it { is_expected.to be_eligible_to_vote }
  # or
  it { should 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 should @see should_not @see is_expected

# File lib/rspec/core/memoized_helpers.rb, line 57
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

Private Instance Methods

__init_memoized() click to toggle source

@private

# File lib/rspec/core/memoized_helpers.rb, line 141
def __init_memoized
  @__memoized = if RSpec.configuration.threadsafe?
                  ThreadsafeMemoized.new
                else
                  NonThreadSafeMemoized.new
                end
end
enforce_value_expectation(matcher, method_name) click to toggle source

@private

# File lib/rspec/core/memoized_helpers.rb, line 150
def enforce_value_expectation(matcher, method_name)
  return if matcher_supports_value_expectations?(matcher)

  RSpec.deprecate(
    "#{method_name} #{RSpec::Support::ObjectFormatter.format(matcher)}",
    :message =>
      "The implicit block expectation syntax is deprecated, you should pass " \
      "a block to `expect` to use the provided block expectation matcher " \
      "(#{RSpec::Support::ObjectFormatter.format(matcher)}), " \
      "or the matcher must implement `supports_value_expectations?`."
  )
end
matcher_supports_value_expectations?(matcher) click to toggle source
# File lib/rspec/core/memoized_helpers.rb, line 163
def matcher_supports_value_expectations?(matcher)
  matcher.supports_value_expectations?
rescue
  true
end