rspec-expectations 2.8.0 → 2.9.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,73 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class RespondTo
|
5
|
+
def initialize(*names)
|
6
|
+
@names = names
|
7
|
+
@expected_arity = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches?(actual)
|
11
|
+
find_failing_method_names(actual, :reject).empty?
|
12
|
+
end
|
13
|
+
|
14
|
+
def does_not_match?(actual)
|
15
|
+
find_failing_method_names(actual, :select).empty?
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure_message_for_should
|
19
|
+
"expected #{@actual.inspect} to respond to #{@failing_method_names.collect {|name| name.inspect }.join(', ')}#{with_arity}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def failure_message_for_should_not
|
23
|
+
failure_message_for_should.sub(/to respond to/, 'not to respond to')
|
24
|
+
end
|
25
|
+
|
26
|
+
def description
|
27
|
+
"respond to #{pp_names}#{with_arity}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def with(n)
|
31
|
+
@expected_arity = n
|
32
|
+
self
|
33
|
+
end
|
34
|
+
|
35
|
+
def argument
|
36
|
+
self
|
37
|
+
end
|
38
|
+
alias :arguments :argument
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def find_failing_method_names(actual, filter_method)
|
43
|
+
@actual = actual
|
44
|
+
@failing_method_names = @names.send(filter_method) do |name|
|
45
|
+
@actual.respond_to?(name) && matches_arity?(actual, name)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def matches_arity?(actual, name)
|
50
|
+
return true unless @expected_arity
|
51
|
+
|
52
|
+
actual_arity = actual.method(name).arity
|
53
|
+
if actual_arity < 0
|
54
|
+
# ~ inverts the one's complement and gives us the number of required args
|
55
|
+
~actual_arity <= @expected_arity
|
56
|
+
else
|
57
|
+
actual_arity == @expected_arity
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def with_arity
|
62
|
+
@expected_arity.nil?? "" :
|
63
|
+
" with #{@expected_arity} argument#{@expected_arity == 1 ? '' : 's'}"
|
64
|
+
end
|
65
|
+
|
66
|
+
def pp_names
|
67
|
+
# Ruby 1.9 returns the same thing for array.to_s as array.inspect, so just use array.inspect here
|
68
|
+
@names.length == 1 ? "##{@names.first}" : @names.inspect
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class Satisfy
|
5
|
+
def initialize(&block)
|
6
|
+
@block = block
|
7
|
+
end
|
8
|
+
|
9
|
+
def matches?(actual, &block)
|
10
|
+
@block = block if block
|
11
|
+
@actual = actual
|
12
|
+
@block.call(actual)
|
13
|
+
end
|
14
|
+
|
15
|
+
def failure_message_for_should
|
16
|
+
"expected #{@actual} to satisfy block"
|
17
|
+
end
|
18
|
+
|
19
|
+
def failure_message_for_should_not
|
20
|
+
"expected #{@actual} not to satisfy block"
|
21
|
+
end
|
22
|
+
|
23
|
+
def description
|
24
|
+
"satisfy block"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Matchers
|
3
|
+
module BuiltIn
|
4
|
+
class ThrowSymbol
|
5
|
+
def initialize(expected_symbol = nil, expected_arg=nil)
|
6
|
+
@expected_symbol = expected_symbol
|
7
|
+
@expected_arg = expected_arg
|
8
|
+
@caught_symbol = @caught_arg = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def matches?(given_proc)
|
12
|
+
begin
|
13
|
+
if @expected_symbol.nil?
|
14
|
+
given_proc.call
|
15
|
+
else
|
16
|
+
@caught_arg = catch :proc_did_not_throw_anything do
|
17
|
+
catch @expected_symbol do
|
18
|
+
given_proc.call
|
19
|
+
throw :proc_did_not_throw_anything, :nothing_thrown
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
if @caught_arg == :nothing_thrown
|
24
|
+
@caught_arg = nil
|
25
|
+
else
|
26
|
+
@caught_symbol = @expected_symbol
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Ruby 1.8 uses NameError with `symbol'
|
31
|
+
# Ruby 1.9 uses ArgumentError with :symbol
|
32
|
+
rescue NameError, ArgumentError => e
|
33
|
+
unless e.message =~ /uncaught throw (`|\:)([a-zA-Z0-9_]*)(')?/
|
34
|
+
other_exception = e
|
35
|
+
raise
|
36
|
+
end
|
37
|
+
@caught_symbol = $2.to_sym
|
38
|
+
rescue => other_exception
|
39
|
+
raise
|
40
|
+
ensure
|
41
|
+
unless other_exception
|
42
|
+
if @expected_symbol.nil?
|
43
|
+
return !@caught_symbol.nil?
|
44
|
+
else
|
45
|
+
if @expected_arg.nil?
|
46
|
+
return @caught_symbol == @expected_symbol
|
47
|
+
else
|
48
|
+
return (@caught_symbol == @expected_symbol) & (@caught_arg == @expected_arg)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def failure_message_for_should
|
56
|
+
"expected #{expected} to be thrown, got #{caught}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def failure_message_for_should_not
|
60
|
+
"expected #{expected('no Symbol')}#{' not' if @expected_symbol} to be thrown, got #{caught}"
|
61
|
+
end
|
62
|
+
|
63
|
+
def description
|
64
|
+
"throw #{expected}"
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def expected(symbol_desc = 'a Symbol')
|
70
|
+
throw_description(@expected_symbol || symbol_desc, @expected_arg)
|
71
|
+
end
|
72
|
+
|
73
|
+
def caught
|
74
|
+
throw_description(@caught_symbol || 'nothing', @caught_arg)
|
75
|
+
end
|
76
|
+
|
77
|
+
def throw_description(symbol, arg)
|
78
|
+
symbol_description = symbol.is_a?(String) ? symbol : symbol.inspect
|
79
|
+
|
80
|
+
arg_description = if arg
|
81
|
+
" with #{arg.inspect}"
|
82
|
+
elsif @expected_arg && @caught_symbol == @expected_symbol
|
83
|
+
" with no argument"
|
84
|
+
else
|
85
|
+
""
|
86
|
+
end
|
87
|
+
|
88
|
+
symbol_description + arg_description
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/lib/rspec/matchers/dsl.rb
CHANGED
@@ -4,7 +4,7 @@ module RSpec
|
|
4
4
|
# Defines a custom matcher.
|
5
5
|
# @see RSpec::Matchers
|
6
6
|
def define(name, &declarations)
|
7
|
-
matcher = RSpec::Matchers::Matcher.new(name, &declarations)
|
7
|
+
matcher = RSpec::Matchers::DSL::Matcher.new(name, &declarations)
|
8
8
|
define_method name do |*expected|
|
9
9
|
$matcher_execution_context = self
|
10
10
|
matcher.for_expected(*expected)
|
@@ -1,266 +1,296 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
1
3
|
module RSpec
|
2
4
|
module Matchers
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
module DSL
|
6
|
+
# Provides the context in which the block passed to RSpec::Matchers.define
|
7
|
+
# will be evaluated.
|
8
|
+
class Matcher
|
9
|
+
include RSpec::Matchers::Extensions::InstanceEvalWithArgs
|
10
|
+
include RSpec::Matchers::Pretty
|
11
|
+
include RSpec::Matchers
|
9
12
|
|
10
|
-
|
13
|
+
attr_reader :expected, :actual, :rescued_exception
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
# @api private
|
16
|
+
def initialize(name, &declarations)
|
17
|
+
@name = name
|
18
|
+
@declarations = declarations
|
19
|
+
@actual = nil
|
20
|
+
@diffable = false
|
21
|
+
@expected_exception, @rescued_exception = nil, nil
|
22
|
+
@match_for_should_not_block = nil
|
23
|
+
@messages = {}
|
24
|
+
end
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
26
|
+
PERSISENT_INSTANCE_VARIABLES = [
|
27
|
+
:@name, :@declarations, :@diffable, :@messages,
|
28
|
+
:@match_block, :@match_for_should_not_block,
|
29
|
+
:@expected_exception
|
30
|
+
].to_set
|
27
31
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
# @api private
|
33
|
+
def for_expected(*expected)
|
34
|
+
@expected = expected
|
35
|
+
dup.instance_eval do
|
36
|
+
instance_variables.map {|ivar| ivar.intern}.each do |ivar|
|
37
|
+
instance_variable_set(ivar, nil) unless (PERSISENT_INSTANCE_VARIABLES + [:@expected]).include?(ivar)
|
38
|
+
end
|
39
|
+
making_declared_methods_public do
|
40
|
+
instance_eval_with_args(*@expected, &@declarations)
|
41
|
+
end
|
42
|
+
self
|
43
|
+
end
|
33
44
|
end
|
34
|
-
self
|
35
|
-
end
|
36
45
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
# @api private
|
47
|
+
# Used internally by +should+ and +should_not+.
|
48
|
+
def matches?(actual)
|
49
|
+
@actual = actual
|
50
|
+
if @expected_exception
|
51
|
+
begin
|
52
|
+
instance_eval_with_args(actual, &@match_block)
|
53
|
+
true
|
54
|
+
rescue @expected_exception => @rescued_exception
|
55
|
+
false
|
56
|
+
end
|
57
|
+
else
|
58
|
+
begin
|
59
|
+
instance_eval_with_args(actual, &@match_block)
|
60
|
+
rescue RSpec::Expectations::ExpectationNotMetError
|
61
|
+
false
|
62
|
+
end
|
53
63
|
end
|
54
64
|
end
|
55
|
-
end
|
56
65
|
|
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
|
-
|
66
|
+
# Stores the block that is used to determine whether this matcher passes
|
67
|
+
# or fails. The block should return a boolean value. When the matcher is
|
68
|
+
# passed to `should` and the block returns `true`, then the expectation
|
69
|
+
# passes. Similarly, when the matcher is passed to `should_not` and the
|
70
|
+
# block returns `false`, then the expectation passes.
|
71
|
+
#
|
72
|
+
# Use `match_for_should` when used in conjuntion with
|
73
|
+
# `match_for_should_not`.
|
74
|
+
#
|
75
|
+
# @example
|
76
|
+
#
|
77
|
+
# RSpec::Matchers.define :be_even do
|
78
|
+
# match do |actual|
|
79
|
+
# actual.even?
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# 4.should be_even # passes
|
84
|
+
# 3.should_not be_even # passes
|
85
|
+
# 3.should be_even # fails
|
86
|
+
# 4.should_not be_even # fails
|
87
|
+
#
|
88
|
+
# @yield [Object] actual the actual value (or receiver of should)
|
89
|
+
def match(&block)
|
90
|
+
@match_block = block
|
91
|
+
end
|
83
92
|
|
84
|
-
|
93
|
+
alias_method :match_for_should, :match
|
85
94
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
+
# Use this to define the block for a negative expectation (`should_not`)
|
96
|
+
# when the positive and negative forms require different handling. This
|
97
|
+
# is rarely necessary, but can be helpful, for example, when specifying
|
98
|
+
# asynchronous processes that require different timeouts.
|
99
|
+
#
|
100
|
+
# @yield [Object] actual the actual value (or receiver of should)
|
101
|
+
def match_for_should_not(&block)
|
102
|
+
@match_for_should_not_block = block
|
103
|
+
end
|
95
104
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
105
|
+
# Use this instead of `match` when the block will raise an exception
|
106
|
+
# rather than returning false to indicate a failure.
|
107
|
+
#
|
108
|
+
# @example
|
109
|
+
#
|
110
|
+
# RSpec::Matchers.define :accept_as_valid do |candidate_address|
|
111
|
+
# match_unless_raises ValidationException do |validator|
|
112
|
+
# validator.validate(candidate_address)
|
113
|
+
# end
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# email_validator.should accept_as_valid("person@company.com")
|
117
|
+
def match_unless_raises(exception=Exception, &block)
|
118
|
+
@expected_exception = exception
|
119
|
+
match(&block)
|
120
|
+
end
|
112
121
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
122
|
+
# Customize the failure messsage to use when this matcher is invoked with
|
123
|
+
# `should`. Only use this when the message generated by default doesn't
|
124
|
+
# suit your needs.
|
125
|
+
#
|
126
|
+
# @example
|
127
|
+
#
|
128
|
+
# RSpec::Matchers.define :have_strength do |expected|
|
129
|
+
# match { ... }
|
130
|
+
#
|
131
|
+
# failure_message_for_should do |actual|
|
132
|
+
# "Expected strength of #{expected}, but had #{actual.strength}"
|
133
|
+
# end
|
134
|
+
# end
|
135
|
+
#
|
136
|
+
# @yield [Object] actual the actual object
|
137
|
+
def failure_message_for_should(&block)
|
138
|
+
cache_or_call_cached(:failure_message_for_should, &block)
|
139
|
+
end
|
131
140
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
141
|
+
# Customize the failure messsage to use when this matcher is invoked with
|
142
|
+
# `should_not`. Only use this when the message generated by default
|
143
|
+
# doesn't suit your needs.
|
144
|
+
#
|
145
|
+
# @example
|
146
|
+
#
|
147
|
+
# RSpec::Matchers.define :have_strength do |expected|
|
148
|
+
# match { ... }
|
149
|
+
#
|
150
|
+
# failure_message_for_should_not do |actual|
|
151
|
+
# "Expected not to have strength of #{expected}, but did"
|
152
|
+
# end
|
153
|
+
# end
|
154
|
+
#
|
155
|
+
# @yield [Object] actual the actual object
|
156
|
+
# @yield [Object] actual the actual object
|
157
|
+
def failure_message_for_should_not(&block)
|
158
|
+
cache_or_call_cached(:failure_message_for_should_not, &block)
|
159
|
+
end
|
151
160
|
|
152
161
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
162
|
+
# Customize the description to use for one-liners. Only use this when
|
163
|
+
# the description generated by default doesn't suit your needs.
|
164
|
+
#
|
165
|
+
# @example
|
166
|
+
#
|
167
|
+
# RSpec::Matchers.define :qualify_for do |expected|
|
168
|
+
# match { ... }
|
169
|
+
#
|
170
|
+
# description do
|
171
|
+
# "qualify for #{expected}"
|
172
|
+
# end
|
173
|
+
# end
|
174
|
+
def description(&block)
|
175
|
+
cache_or_call_cached(:description, &block)
|
176
|
+
end
|
168
177
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
end
|
174
|
-
|
175
|
-
# Convenience for defining methods on this matcher to create a fluent
|
176
|
-
# interface. The trick about fluent interfaces is that each method must
|
177
|
-
# return self in order to chain methods together. `chain` handles that
|
178
|
-
# for you.
|
179
|
-
#
|
180
|
-
# @example
|
181
|
-
#
|
182
|
-
# RSpec::Matchers.define :have_errors_on do |key|
|
183
|
-
# chain :with do |message|
|
184
|
-
# @message = message
|
185
|
-
# end
|
186
|
-
#
|
187
|
-
# match do |actual|
|
188
|
-
# actual.errors[key] == @message
|
189
|
-
# end
|
190
|
-
# end
|
191
|
-
#
|
192
|
-
# minor.should have_errors_on(:age).with("Not old enough to participate")
|
193
|
-
def chain(method, &block)
|
194
|
-
define_method method do |*args|
|
195
|
-
block.call(*args)
|
196
|
-
self
|
178
|
+
# Tells the matcher to diff the actual and expected values in the failure
|
179
|
+
# message.
|
180
|
+
def diffable
|
181
|
+
@diffable = true
|
197
182
|
end
|
198
|
-
end
|
199
|
-
|
200
|
-
# @api private
|
201
|
-
# Used internally by objects returns by +should+ and +should_not+.
|
202
|
-
def diffable?
|
203
|
-
@diffable
|
204
|
-
end
|
205
183
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
184
|
+
# Convenience for defining methods on this matcher to create a fluent
|
185
|
+
# interface. The trick about fluent interfaces is that each method must
|
186
|
+
# return self in order to chain methods together. `chain` handles that
|
187
|
+
# for you.
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
#
|
191
|
+
# RSpec::Matchers.define :have_errors_on do |key|
|
192
|
+
# chain :with do |message|
|
193
|
+
# @message = message
|
194
|
+
# end
|
195
|
+
#
|
196
|
+
# match do |actual|
|
197
|
+
# actual.errors[key] == @message
|
198
|
+
# end
|
199
|
+
# end
|
200
|
+
#
|
201
|
+
# minor.should have_errors_on(:age).with("Not old enough to participate")
|
202
|
+
def chain(method, &block)
|
203
|
+
define_method method do |*args|
|
204
|
+
block.call(*args)
|
205
|
+
self
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
# @api private
|
210
|
+
# Used internally by objects returns by +should+ and +should_not+.
|
211
|
+
def diffable?
|
212
|
+
@diffable
|
213
|
+
end
|
214
214
|
|
215
|
-
|
215
|
+
# @api private
|
216
|
+
# Used internally by +should_not+
|
217
|
+
def does_not_match?(actual)
|
218
|
+
@actual = actual
|
219
|
+
@match_for_should_not_block ?
|
220
|
+
instance_eval_with_args(actual, &@match_for_should_not_block) :
|
221
|
+
!matches?(actual)
|
222
|
+
end
|
216
223
|
|
217
|
-
|
218
|
-
|
219
|
-
|
224
|
+
def respond_to?(method, include_private=false)
|
225
|
+
$matcher_execution_context.respond_to?(method, include_private) || super
|
226
|
+
end
|
220
227
|
|
221
|
-
|
222
|
-
singleton_class.__send__(:define_method, name, &block)
|
223
|
-
end
|
228
|
+
private
|
224
229
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
+
def method_missing(method, *args, &block)
|
231
|
+
if $matcher_execution_context.respond_to?(method)
|
232
|
+
$matcher_execution_context.send method, *args, &block
|
233
|
+
else
|
234
|
+
super(method, *args, &block)
|
235
|
+
end
|
230
236
|
end
|
231
|
-
end
|
232
|
-
|
233
|
-
def making_declared_methods_public
|
234
|
-
# Our home-grown instance_exec in ruby 1.8.6 results in any methods
|
235
|
-
# declared in the block eval'd by instance_exec in the block to which we
|
236
|
-
# are yielding here are scoped private. This is NOT the case for Ruby
|
237
|
-
# 1.8.7 or 1.9.
|
238
|
-
#
|
239
|
-
# Also, due some crazy scoping that I don't understand, these methods
|
240
|
-
# are actually available in the specs (something about the matcher being
|
241
|
-
# defined in the scope of RSpec::Matchers or within an example), so not
|
242
|
-
# doing the following will not cause specs to fail, but they *will*
|
243
|
-
# cause features to fail and that will make users unhappy. So don't.
|
244
|
-
orig_private_methods = private_methods
|
245
|
-
yield
|
246
|
-
(private_methods - orig_private_methods).each {|m| singleton_class.__send__ :public, m}
|
247
|
-
end
|
248
237
|
|
249
|
-
|
250
|
-
|
251
|
-
|
238
|
+
def include(*args)
|
239
|
+
singleton_class.__send__(:include, *args)
|
240
|
+
end
|
252
241
|
|
253
|
-
|
254
|
-
|
255
|
-
|
242
|
+
def define_method(name, &block)
|
243
|
+
singleton_class.__send__(:define_method, name, &block)
|
244
|
+
end
|
256
245
|
|
257
|
-
|
258
|
-
|
259
|
-
|
246
|
+
def making_declared_methods_public
|
247
|
+
# Our home-grown instance_exec in ruby 1.8.6 results in any methods
|
248
|
+
# declared in the block eval'd by instance_exec in the block to which we
|
249
|
+
# are yielding here are scoped private. This is NOT the case for Ruby
|
250
|
+
# 1.8.7 or 1.9.
|
251
|
+
#
|
252
|
+
# Also, due some crazy scoping that I don't understand, these methods
|
253
|
+
# are actually available in the specs (something about the matcher being
|
254
|
+
# defined in the scope of RSpec::Matchers or within an example), so not
|
255
|
+
# doing the following will not cause specs to fail, but they *will*
|
256
|
+
# cause features to fail and that will make users unhappy. So don't.
|
257
|
+
orig_private_methods = private_methods
|
258
|
+
yield
|
259
|
+
(private_methods - orig_private_methods).each {|m| singleton_class.__send__ :public, m}
|
260
|
+
end
|
260
261
|
|
261
|
-
|
262
|
-
|
263
|
-
|
262
|
+
def cache_or_call_cached(key, &block)
|
263
|
+
block ? cache(key, &block) : call_cached(key)
|
264
|
+
end
|
265
|
+
|
266
|
+
def cache(key, &block)
|
267
|
+
@messages[key] = block
|
268
|
+
end
|
269
|
+
|
270
|
+
def call_cached(key)
|
271
|
+
if @messages.has_key?(key)
|
272
|
+
@messages[key].arity == 1 ? @messages[key].call(@actual) : @messages[key].call
|
273
|
+
else
|
274
|
+
send("default_#{key}")
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def default_description
|
279
|
+
"#{name_to_sentence}#{expected_to_sentence}"
|
280
|
+
end
|
281
|
+
|
282
|
+
def default_failure_message_for_should
|
283
|
+
"expected #{actual.inspect} to #{name_to_sentence}#{expected_to_sentence}"
|
284
|
+
end
|
285
|
+
|
286
|
+
def default_failure_message_for_should_not
|
287
|
+
"expected #{actual.inspect} not to #{name_to_sentence}#{expected_to_sentence}"
|
288
|
+
end
|
289
|
+
|
290
|
+
unless method_defined?(:singleton_class)
|
291
|
+
def singleton_class
|
292
|
+
class << self; self; end
|
293
|
+
end
|
264
294
|
end
|
265
295
|
end
|
266
296
|
end
|