1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
# frozen_string_literal: true
require 'rspec/its/subject'
require 'rspec/its/version'
require 'rspec/core'
RSpec::Core::ExampleGroup.define_example_method :__its_example
module RSpec
# Adds the `its` to RSpec Example Groups, included by default.
module Its
# Creates a nested example group named by the submitted `attribute`,
# and then generates an example using the submitted block.
#
# @example
#
# # This ...
# RSpec.describe Array do
# its(:size) { is_expected.to eq(0) }
# end
#
# # ... generates the same runtime structure as this:
# RSpec.describe Array do
# describe "size" do
# it "is_expected.to eq(0)" do
# expect(subject.size).to eq(0)
# end
# end
# end
#
# The attribute can be a `Symbol` or a `String`. Given a `String`
# with dots, the result is as though you concatenated that `String`
# onto the subject in an expression.
#
# @example
#
# RSpec.describe Person do
# subject(:person) do
# Person.new.tap do |person|
# person.phone_numbers << "555-1212"
# end
# end
#
# its("phone_numbers.first") { is_expected.to eq("555-1212") }
# end
#
# When the subject is a `Hash`, you can refer to the Hash keys by
# specifying a `Symbol` or `String` in an array.
#
# @example
#
# RSpec.describe "a configuration Hash" do
# subject do
# { :max_users => 3,
# 'admin' => :all_permissions.
# 'john_doe' => {:permissions => [:read, :write]}}
# end
#
# its([:max_users]) { is_expected.to eq(3) }
# its(['admin']) { is_expected.to eq(:all_permissions) }
# its(['john_doe', :permissions]) { are_expected.to eq([:read, :write]) }
#
# # You can still access its regular methods this way:
# its(:keys) { is_expected.to include(:max_users) }
# its(:count) { is_expected.to eq(2) }
# end
#
# With an implicit subject, `should` can be used as an alternative
# to `is_expected` (e.g. for one-liner use). An `are_expected` alias is also
# supplied.
#
# @example
#
# RSpec.describe Array do
# its(:size) { should eq(0) }
# end
#
# With an implicit subject, `will` can be used as an alternative
# to `expect { subject.attribute }.to matcher` (e.g. for one-liner use).
#
# @example
#
# RSpec.describe Array do
# its(:foo) { will raise_error(NoMethodError) }
# end
#
# With an implicit subject, `will_not` can be used as an alternative
# to `expect { subject.attribute }.to_not matcher` (e.g. for one-liner use).
#
# @example
#
# RSpec.describe Array do
# its(:size) { will_not raise_error }
# end
#
# You can pass more than one argument on the `its` block to add
# some metadata to the generated example
#
# @example
#
# # This ...
# RSpec.describe Array do
# its(:size, :focus) { is_expected.to eq(0) }
# end
#
# # ... generates the same runtime structure as this:
# RSpec.describe Array do
# describe "size" do
# it "is expected to eq(0)", :focus do
# expect(subject.size).to eq(0)
# end
# end
# end
#
# Note that this method does not modify `subject` in any way, so if you
# refer to `subject` in `let` or `before` blocks, you're still
# referring to the outer subject.
#
# @example
#
# RSpec.describe Person do
# subject { Person.new }
#
# before { subject.age = 25 }
#
# its(:age) { is_expected.to eq(25) }
# end
def its(attribute, *options, &block)
its_caller = caller.grep_v(%r{/lib/rspec/its})
describe(attribute.to_s, caller: its_caller) do
let(:__its_subject) { RSpec::Its::Subject.for(attribute, subject) }
def is_expected
expect(__its_subject)
end
alias_method :are_expected, :is_expected
def will(matcher = nil, message = nil)
raise ArgumentError, "`will` only supports block expectations" unless matcher.supports_block_expectations?
expect { __its_subject }.to matcher, message
end
def will_not(matcher = nil, message = nil)
raise ArgumentError, "`will_not` only supports block expectations" unless matcher.supports_block_expectations?
expect { __its_subject }.to_not matcher, message
end
def should(matcher = nil, message = nil)
RSpec::Expectations::PositiveExpectationHandler.handle_matcher(__its_subject, matcher, message)
end
def should_not(matcher = nil, message = nil)
RSpec::Expectations::NegativeExpectationHandler.handle_matcher(__its_subject, matcher, message)
end
options << {} unless options.last.is_a?(Hash)
options.last.merge!(caller: its_caller)
__its_example(nil, *options, &block)
end
end
end
end
RSpec.configure do |rspec|
rspec.extend RSpec::Its
rspec.backtrace_exclusion_patterns << %r{/lib/rspec/its}
end
RSpec::SharedContext.send(:include, RSpec::Its)
|