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