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 174 175 176 177 178 179 180 181 182
|
require 'rspec/its/version'
require 'rspec/core'
module RSpec
module Its
# Creates a nested example group named by the submitted `attribute`,
# and then generates an example using the submitted block.
#
# @example
#
# # This ...
# describe Array do
# its(:size) { should eq(0) }
# end
#
# # ... generates the same runtime structure as this:
# describe Array do
# describe "size" do
# it "should eq(0)" do
# subject.size.should 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
#
# describe Person do
# subject do
# Person.new.tap do |person|
# person.phone_numbers << "555-1212"
# end
# end
#
# its("phone_numbers.first") { should 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
#
# describe "a configuration Hash" do
# subject do
# { :max_users => 3,
# 'admin' => :all_permissions.
# 'john_doe' => {:permissions => [:read, :write]}}
# end
#
# its([:max_users]) { should eq(3) }
# its(['admin']) { should eq(:all_permissions) }
# its(['john_doe', :permissions]) { should eq([:read, :write]) }
#
# # You can still access its regular methods this way:
# its(:keys) { should include(:max_users) }
# its(:count) { should eq(2) }
# end
#
# With an implicit subject, `is_expected` can be used as an alternative
# to `should` (e.g. for one-liner use). An `are_expected` alias is also
# supplied.
#
# @example
#
# describe Array do
# its(:size) { is_expected.to 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
#
# 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
#
# 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 ...
# describe Array do
# its(:size, :focus) { should eq(0) }
# end
#
# # ... generates the same runtime structure as this:
# describe Array do
# describe "size" do
# it "should eq(0)", :focus do
# subject.size.should 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
#
# describe Person do
# subject { Person.new }
# before { subject.age = 25 }
# its(:age) { should eq(25) }
# end
def its(attribute, *options, &block)
its_caller = caller.select {|file_line| file_line !~ %r(/lib/rspec/its) }
describe(attribute.to_s, :caller => its_caller) do
let(:__its_subject) do
if Array === attribute
if Hash === subject
attribute.inject(subject) {|inner, attr| inner[attr] }
else
subject[*attribute]
end
else
attribute_chain = attribute.to_s.split('.')
attribute_chain.inject(subject) do |inner_subject, attr|
inner_subject.send(attr)
end
end
end
def is_expected
expect(__its_subject)
end
alias_method :are_expected, :is_expected
def will(matcher=nil, message=nil)
unless matcher.supports_block_expectations?
raise ArgumentError, "`will` only supports block expectations"
end
expect { __its_subject }.to matcher, message
end
def will_not(matcher=nil, message=nil)
unless matcher.supports_block_expectations?
raise ArgumentError, "`will_not` only supports block expectations"
end
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.kind_of?(Hash)
options.last.merge!(:caller => its_caller)
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)
|