rspec-expectations 2.8.0 → 2.9.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.yardopts +3 -0
- data/Changelog.md +176 -0
- data/README.md +2 -13
- data/features/custom_matchers/access_running_example.feature +1 -1
- data/features/step_definitions/additional_cli_steps.rb +4 -4
- data/lib/rspec/expectations/fail_with.rb +3 -3
- data/lib/rspec/expectations/handler.rb +3 -5
- data/lib/rspec/expectations/version.rb +1 -1
- data/lib/rspec/matchers.rb +387 -21
- data/lib/rspec/matchers/built_in.rb +33 -0
- data/lib/rspec/matchers/built_in/base_matcher.rb +58 -0
- data/lib/rspec/matchers/built_in/be.rb +183 -0
- data/lib/rspec/matchers/built_in/be_instance_of.rb +13 -0
- data/lib/rspec/matchers/built_in/be_kind_of.rb +13 -0
- data/lib/rspec/matchers/built_in/be_within.rb +39 -0
- data/lib/rspec/matchers/built_in/change.rb +132 -0
- data/lib/rspec/matchers/built_in/cover.rb +22 -0
- data/lib/rspec/matchers/built_in/eq.rb +26 -0
- data/lib/rspec/matchers/built_in/eql.rb +25 -0
- data/lib/rspec/matchers/built_in/equal.rb +48 -0
- data/lib/rspec/matchers/built_in/exist.rb +28 -0
- data/lib/rspec/matchers/built_in/has.rb +47 -0
- data/lib/rspec/matchers/built_in/have.rb +107 -0
- data/lib/rspec/matchers/built_in/include.rb +52 -0
- data/lib/rspec/matchers/built_in/match.rb +13 -0
- data/lib/rspec/matchers/built_in/match_array.rb +52 -0
- data/lib/rspec/matchers/built_in/raise_error.rb +96 -0
- data/lib/rspec/matchers/built_in/respond_to.rb +73 -0
- data/lib/rspec/matchers/built_in/satisfy.rb +29 -0
- data/lib/rspec/matchers/built_in/throw_symbol.rb +93 -0
- data/lib/rspec/matchers/dsl.rb +1 -1
- data/lib/rspec/matchers/matcher.rb +263 -233
- data/lib/rspec/matchers/method_missing.rb +2 -2
- data/lib/rspec/matchers/operator_matcher.rb +19 -20
- data/spec/rspec/expectations/handler_spec.rb +1 -1
- data/spec/rspec/matchers/base_matcher_spec.rb +1 -2
- data/spec/rspec/matchers/change_spec.rb +3 -3
- data/spec/rspec/matchers/cover_spec.rb +46 -46
- data/spec/rspec/matchers/dsl_spec.rb +36 -3
- data/spec/rspec/matchers/have_spec.rb +2 -2
- data/spec/rspec/matchers/include_spec.rb +1 -1
- data/spec/rspec/matchers/matcher_spec.rb +319 -305
- data/spec/rspec/matchers/method_missing_spec.rb +1 -0
- data/spec/rspec/matchers/operator_matcher_spec.rb +2 -2
- data/spec/rspec/matchers/throw_symbol_spec.rb +103 -105
- metadata +93 -39
- data/lib/rspec/matchers/base_matcher.rb +0 -56
- data/lib/rspec/matchers/be.rb +0 -232
- data/lib/rspec/matchers/be_instance_of.rb +0 -24
- data/lib/rspec/matchers/be_kind_of.rb +0 -24
- data/lib/rspec/matchers/be_within.rb +0 -47
- data/lib/rspec/matchers/change.rb +0 -197
- data/lib/rspec/matchers/cover.rb +0 -36
- data/lib/rspec/matchers/eq.rb +0 -36
- data/lib/rspec/matchers/eql.rb +0 -35
- data/lib/rspec/matchers/equal.rb +0 -58
- data/lib/rspec/matchers/errors.rb +0 -5
- data/lib/rspec/matchers/exist.rb +0 -34
- data/lib/rspec/matchers/has.rb +0 -44
- data/lib/rspec/matchers/have.rb +0 -162
- data/lib/rspec/matchers/include.rb +0 -66
- data/lib/rspec/matchers/match.rb +0 -21
- data/lib/rspec/matchers/match_array.rb +0 -65
- data/lib/rspec/matchers/raise_error.rb +0 -116
- data/lib/rspec/matchers/respond_to.rb +0 -80
- data/lib/rspec/matchers/satisfy.rb +0 -46
- data/lib/rspec/matchers/throw_symbol.rb +0 -112
@@ -0,0 +1,22 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class Cover
|
5
|
+
include BaseMatcher
|
6
|
+
|
7
|
+
def initialize(*expected)
|
8
|
+
super(expected)
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(range)
|
12
|
+
expected.all? {|e| super(range).cover?(e)}
|
13
|
+
end
|
14
|
+
|
15
|
+
def does_not_match?(range)
|
16
|
+
@actual = range
|
17
|
+
expected.none? {|e| range.cover?(e)}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class Eq
|
5
|
+
include BaseMatcher
|
6
|
+
|
7
|
+
def matches?(actual)
|
8
|
+
super(actual) == expected
|
9
|
+
end
|
10
|
+
|
11
|
+
def failure_message_for_should
|
12
|
+
"\nexpected: #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using ==)\n"
|
13
|
+
end
|
14
|
+
|
15
|
+
def failure_message_for_should_not
|
16
|
+
"\nexpected: value != #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using ==)\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
def diffable?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class Eql
|
5
|
+
include BaseMatcher
|
6
|
+
|
7
|
+
def matches?(actual)
|
8
|
+
super(actual).eql?(expected)
|
9
|
+
end
|
10
|
+
|
11
|
+
def failure_message_for_should
|
12
|
+
"\nexpected: #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using eql?)\n"
|
13
|
+
end
|
14
|
+
|
15
|
+
def failure_message_for_should_not
|
16
|
+
"\nexpected: value != #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using eql?)\n"
|
17
|
+
end
|
18
|
+
|
19
|
+
def diffable?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class Equal
|
5
|
+
include BaseMatcher
|
6
|
+
|
7
|
+
def matches?(actual)
|
8
|
+
super(actual).equal?(expected)
|
9
|
+
end
|
10
|
+
|
11
|
+
def failure_message_for_should
|
12
|
+
return <<-MESSAGE
|
13
|
+
|
14
|
+
expected #{inspect_object(expected)}
|
15
|
+
got #{inspect_object(actual)}
|
16
|
+
|
17
|
+
Compared using equal?, which compares object identity,
|
18
|
+
but expected and actual are not the same object. Use
|
19
|
+
'actual.should == expected' if you don't care about
|
20
|
+
object identity in this example.
|
21
|
+
|
22
|
+
MESSAGE
|
23
|
+
end
|
24
|
+
|
25
|
+
def failure_message_for_should_not
|
26
|
+
return <<-MESSAGE
|
27
|
+
|
28
|
+
expected not #{inspect_object(actual)}
|
29
|
+
got #{inspect_object(expected)}
|
30
|
+
|
31
|
+
Compared using equal?, which compares object identity.
|
32
|
+
|
33
|
+
MESSAGE
|
34
|
+
end
|
35
|
+
|
36
|
+
def diffable?
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def inspect_object(o)
|
43
|
+
"#<#{o.class}:#{o.object_id}> => #{o.inspect}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class Exist
|
5
|
+
include BaseMatcher
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
super(args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(actual)
|
12
|
+
super(actual)
|
13
|
+
predicates = [:exist?, :exists?].select { |p| actual.respond_to?(p) }
|
14
|
+
existance_values = predicates.map { |p| actual.send(p, *expected) }
|
15
|
+
uniq_truthy_values = existance_values.map { |v| !!v }.uniq
|
16
|
+
|
17
|
+
case uniq_truthy_values.size
|
18
|
+
when 0; raise NoMethodError.new("#{actual.inspect} does not respond to either #exist? or #exists?")
|
19
|
+
when 1; existance_values.first
|
20
|
+
else raise "#exist? and #exists? returned different values:\n\n" +
|
21
|
+
" exist?: #{existance_values.first}\n" +
|
22
|
+
"exists?: #{existance_values.last}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class Has
|
5
|
+
def initialize(expected, *args)
|
6
|
+
@expected, @args = expected, args
|
7
|
+
end
|
8
|
+
|
9
|
+
def matches?(actual)
|
10
|
+
actual.__send__(predicate(@expected), *@args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def failure_message_for_should
|
14
|
+
"expected ##{predicate(@expected)}#{failure_message_args_description} to return true, got false"
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure_message_for_should_not
|
18
|
+
"expected ##{predicate(@expected)}#{failure_message_args_description} to return false, got true"
|
19
|
+
end
|
20
|
+
|
21
|
+
def description
|
22
|
+
[method_description(@expected), args_description].compact.join(' ')
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def predicate(sym)
|
28
|
+
"#{sym.to_s.sub("have_","has_")}?".to_sym
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_description(method)
|
32
|
+
method.to_s.gsub('_', ' ')
|
33
|
+
end
|
34
|
+
|
35
|
+
def args_description
|
36
|
+
return nil if @args.empty?
|
37
|
+
@args.map { |arg| arg.inspect }.join(', ')
|
38
|
+
end
|
39
|
+
|
40
|
+
def failure_message_args_description
|
41
|
+
desc = args_description
|
42
|
+
"(#{desc})" if desc
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class Have
|
5
|
+
def initialize(expected, relativity=:exactly)
|
6
|
+
@expected = case expected
|
7
|
+
when :no then 0
|
8
|
+
when String then expected.to_i
|
9
|
+
else expected
|
10
|
+
end
|
11
|
+
@relativity = relativity
|
12
|
+
@actual = @collection_name = @plural_collection_name = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def relativities
|
16
|
+
@relativities ||= {
|
17
|
+
:exactly => "",
|
18
|
+
:at_least => "at least ",
|
19
|
+
:at_most => "at most "
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def matches?(collection_or_owner)
|
24
|
+
collection = determine_collection(collection_or_owner)
|
25
|
+
query_method = determine_query_method(collection)
|
26
|
+
raise not_a_collection unless query_method
|
27
|
+
@actual = collection.send(query_method)
|
28
|
+
case @relativity
|
29
|
+
when :at_least then @actual >= @expected
|
30
|
+
when :at_most then @actual <= @expected
|
31
|
+
else @actual == @expected
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def determine_collection(collection_or_owner)
|
36
|
+
if collection_or_owner.respond_to?(@collection_name)
|
37
|
+
collection_or_owner.send(@collection_name, *@args, &@block)
|
38
|
+
elsif (@plural_collection_name && collection_or_owner.respond_to?(@plural_collection_name))
|
39
|
+
collection_or_owner.send(@plural_collection_name, *@args, &@block)
|
40
|
+
elsif determine_query_method(collection_or_owner)
|
41
|
+
collection_or_owner
|
42
|
+
else
|
43
|
+
collection_or_owner.send(@collection_name, *@args, &@block)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def determine_query_method(collection)
|
48
|
+
[:size, :length, :count].detect {|m| collection.respond_to?(m)}
|
49
|
+
end
|
50
|
+
|
51
|
+
def not_a_collection
|
52
|
+
"expected #{@collection_name} to be a collection but it does not respond to #length, #size or #count"
|
53
|
+
end
|
54
|
+
|
55
|
+
def failure_message_for_should
|
56
|
+
"expected #{relative_expectation} #{@collection_name}, got #{@actual}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def failure_message_for_should_not
|
60
|
+
if @relativity == :exactly
|
61
|
+
return "expected target not to have #{@expected} #{@collection_name}, got #{@actual}"
|
62
|
+
elsif @relativity == :at_most
|
63
|
+
return <<-EOF
|
64
|
+
Isn't life confusing enough?
|
65
|
+
Instead of having to figure out the meaning of this:
|
66
|
+
should_not have_at_most(#{@expected}).#{@collection_name}
|
67
|
+
We recommend that you use this instead:
|
68
|
+
should have_at_least(#{@expected + 1}).#{@collection_name}
|
69
|
+
EOF
|
70
|
+
elsif @relativity == :at_least
|
71
|
+
return <<-EOF
|
72
|
+
Isn't life confusing enough?
|
73
|
+
Instead of having to figure out the meaning of this:
|
74
|
+
should_not have_at_least(#{@expected}).#{@collection_name}
|
75
|
+
We recommend that you use this instead:
|
76
|
+
should have_at_most(#{@expected - 1}).#{@collection_name}
|
77
|
+
EOF
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def description
|
82
|
+
"have #{relative_expectation} #{@collection_name}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def respond_to?(m)
|
86
|
+
@expected.respond_to?(m) || super
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def method_missing(method, *args, &block)
|
92
|
+
@collection_name = method
|
93
|
+
if inflector = (defined?(ActiveSupport::Inflector) && ActiveSupport::Inflector.respond_to?(:pluralize) ? ActiveSupport::Inflector : (defined?(Inflector) ? Inflector : nil))
|
94
|
+
@plural_collection_name = inflector.pluralize(method.to_s)
|
95
|
+
end
|
96
|
+
@args = args
|
97
|
+
@block = block
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
def relative_expectation
|
102
|
+
"#{relativities[@relativity]}#{@expected}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class Include
|
5
|
+
include BaseMatcher
|
6
|
+
|
7
|
+
def initialize(*expected)
|
8
|
+
super(expected)
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(actual)
|
12
|
+
perform_match(:all?, :all?, super(actual), expected)
|
13
|
+
end
|
14
|
+
|
15
|
+
def does_not_match?(actual)
|
16
|
+
@actual = actual
|
17
|
+
perform_match(:none?, :any?, actual, expected)
|
18
|
+
end
|
19
|
+
|
20
|
+
def description
|
21
|
+
"include#{expected_to_sentence}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def diffable?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def perform_match(predicate, hash_predicate, actuals, expecteds)
|
31
|
+
expecteds.send(predicate) do |expected|
|
32
|
+
if comparing_hash_values?(actuals, expected)
|
33
|
+
expected.send(hash_predicate) {|k,v| actuals[k] == v}
|
34
|
+
elsif comparing_hash_keys?(actuals, expected)
|
35
|
+
actuals.has_key?(expected)
|
36
|
+
else
|
37
|
+
actuals.include?(expected)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def comparing_hash_keys?(actual, expected)
|
43
|
+
actual.is_a?(Hash) && !expected.is_a?(Hash)
|
44
|
+
end
|
45
|
+
|
46
|
+
def comparing_hash_values?(actual, expected)
|
47
|
+
actual.is_a?(Hash) && expected.is_a?(Hash)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class MatchArray
|
5
|
+
include RSpec::Matchers::Pretty
|
6
|
+
|
7
|
+
def initialize(expected)
|
8
|
+
@expected = expected
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(actual)
|
12
|
+
@actual = actual
|
13
|
+
@extra_items = difference_between_arrays(@actual, @expected)
|
14
|
+
@missing_items = difference_between_arrays(@expected, @actual)
|
15
|
+
@extra_items.empty? & @missing_items.empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure_message_for_should
|
19
|
+
message = "expected collection contained: #{safe_sort(@expected).inspect}\n"
|
20
|
+
message += "actual collection contained: #{safe_sort(@actual).inspect}\n"
|
21
|
+
message += "the missing elements were: #{safe_sort(@missing_items).inspect}\n" unless @missing_items.empty?
|
22
|
+
message += "the extra elements were: #{safe_sort(@extra_items).inspect}\n" unless @extra_items.empty?
|
23
|
+
message
|
24
|
+
end
|
25
|
+
|
26
|
+
def failure_message_for_should_not
|
27
|
+
"Matcher does not support should_not"
|
28
|
+
end
|
29
|
+
|
30
|
+
def description
|
31
|
+
"contain exactly #{_pretty_print(@expected)}"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def safe_sort(array)
|
37
|
+
array.sort rescue array
|
38
|
+
end
|
39
|
+
|
40
|
+
def difference_between_arrays(array_1, array_2)
|
41
|
+
difference = array_1.dup
|
42
|
+
array_2.each do |element|
|
43
|
+
if index = difference.index(element)
|
44
|
+
difference.delete_at(index)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
difference
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class RaiseError
|
5
|
+
def initialize(expected_error_or_message=Exception, expected_message=nil, &block)
|
6
|
+
@block = block
|
7
|
+
@actual_error = nil
|
8
|
+
case expected_error_or_message
|
9
|
+
when String, Regexp
|
10
|
+
@expected_error, @expected_message = Exception, expected_error_or_message
|
11
|
+
else
|
12
|
+
@expected_error, @expected_message = expected_error_or_message, expected_message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def matches?(given_proc)
|
17
|
+
@raised_expected_error = false
|
18
|
+
@with_expected_message = false
|
19
|
+
@eval_block = false
|
20
|
+
@eval_block_passed = false
|
21
|
+
begin
|
22
|
+
given_proc.call
|
23
|
+
rescue @expected_error => @actual_error
|
24
|
+
@raised_expected_error = true
|
25
|
+
@with_expected_message = verify_message
|
26
|
+
rescue Exception => @actual_error
|
27
|
+
# This clause should be empty, but rcov will not report it as covered
|
28
|
+
# unless something (anything) is executed within the clause
|
29
|
+
"http://eigenclass.org/hiki.rb?rcov-0.8.0"
|
30
|
+
end
|
31
|
+
|
32
|
+
unless negative_expectation?
|
33
|
+
eval_block if @raised_expected_error && @with_expected_message && @block
|
34
|
+
end
|
35
|
+
ensure
|
36
|
+
return (@raised_expected_error & @with_expected_message) ? (@eval_block ? @eval_block_passed : true) : false
|
37
|
+
end
|
38
|
+
|
39
|
+
def eval_block
|
40
|
+
@eval_block = true
|
41
|
+
begin
|
42
|
+
@block[@actual_error]
|
43
|
+
@eval_block_passed = true
|
44
|
+
rescue Exception => err
|
45
|
+
@actual_error = err
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def verify_message
|
50
|
+
case @expected_message
|
51
|
+
when nil
|
52
|
+
true
|
53
|
+
when Regexp
|
54
|
+
@expected_message =~ @actual_error.message
|
55
|
+
else
|
56
|
+
@expected_message == @actual_error.message
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def failure_message_for_should
|
61
|
+
@eval_block ? @actual_error.message : "expected #{expected_error}#{given_error}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def failure_message_for_should_not
|
65
|
+
"expected no #{expected_error}#{given_error}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def description
|
69
|
+
"raise #{expected_error}"
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def expected_error
|
75
|
+
case @expected_message
|
76
|
+
when nil
|
77
|
+
@expected_error
|
78
|
+
when Regexp
|
79
|
+
"#{@expected_error} with message matching #{@expected_message.inspect}"
|
80
|
+
else
|
81
|
+
"#{@expected_error} with #{@expected_message.inspect}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def given_error
|
86
|
+
@actual_error.nil? ? " but nothing was raised" : ", got #{@actual_error.inspect}"
|
87
|
+
end
|
88
|
+
|
89
|
+
def negative_expectation?
|
90
|
+
# YES - I'm a bad person... help me find a better way - ryand
|
91
|
+
caller.first(3).find { |s| s =~ /should_not/ }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|