123456789_123456789_123456789_123456789_123456789_

Module: RSpec::Core::MemoizedHelpers

Relationships & Source Files
Namespace Children
Modules:
Classes:
Extension / Inclusion / Inheritance Descendants
Included In:
Defined in: rspec-core/lib/rspec/core/memoized_helpers.rb

Overview

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

See Also:

Class Method Summary

Instance Attribute Summary

  • #__memoized readonly private Internal use only Internal use only

    should just be placed in private section, but Ruby issues warnings on private attributes.

Instance Method Summary

Class Method Details

.define_helpers_on(example_group)

This method is for internal use only.
[ GitHub ]

  
# File 'rspec-core/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)

This method is for internal use only.

Gets the named constant or yields. On 1.9, 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.

See additional method definition at line 553.

[ GitHub ]

  
# File 'rspec-core/lib/rspec/core/memoized_helpers.rb', line 570

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)

This method is for internal use only.

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.

[ GitHub ]

  
# File 'rspec-core/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

Instance Attribute Details

#__memoized (readonly, private)

This method is for internal use only.

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

[ GitHub ]

  
# File 'rspec-core/lib/rspec/core/memoized_helpers.rb', line 129

attr_reader :__memoized

Instance Method Details

#__init_memoized (private)

This method is for internal use only.
[ GitHub ]

  
# File 'rspec-core/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) (private)

This method is for internal use only.
[ GitHub ]

  
# File 'rspec-core/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

#initialize (private)

This method is for internal use only.
[ GitHub ]

  
# File 'rspec-core/lib/rspec/core/memoized_helpers.rb', line 135

def initialize(*)
  __init_memoized
  super
end

#is_expected

Note:

This only works if you are using rspec-expectations.

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

Examples:

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

See Also:

[ GitHub ]

  
# File 'rspec-core/lib/rspec/core/memoized_helpers.rb', line 120

def is_expected
  expect(subject)
end

#matcher_supports_value_expectations?(matcher) ⇒ Boolean (private)

[ GitHub ]

  
# File 'rspec-core/lib/rspec/core/memoized_helpers.rb', line 163

def matcher_supports_value_expectations?(matcher)
  matcher.supports_value_expectations?
rescue
  true
end

#should(matcher = nil, message = nil)

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.

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.

Examples:

RSpec.describe Person do
  it { should be_eligible_to_vote }
end

See Also:

[ GitHub ]

  
# File 'rspec-core/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)

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.

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

Examples:

RSpec.describe Person do
  it { should_not be_eligible_to_vote }
end

See Also:

[ GitHub ]

  
# File 'rspec-core/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

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.

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.

Examples:

# 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

See Also:

[ GitHub ]

  
# File 'rspec-core/lib/rspec/core/memoized_helpers.rb', line 57

def subject
  __memoized.fetch_or_store(:subject) do
    described = described_class || self.class..fetch(:description_args).first
    Class === described ? described.new : described
  end
end