This repository has been archived by the owner on Oct 27, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 171
/
change.rb
151 lines (135 loc) · 4.57 KB
/
change.rb
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
module Spec
module Matchers
#Based on patch from Wilson Bilkovich
class Change #:nodoc:
def initialize(receiver=nil, message=nil, &block)
@message = message || "result"
@value_proc = block || lambda {receiver.__send__(message)}
@to = @from = @minimum = @maximum = @amount = nil
end
def matches?(event_proc)
raise_block_syntax_error if block_given?
@before = evaluate_value_proc
event_proc.call
@after = evaluate_value_proc
return (@to = false) if @from unless @from == @before
return false if @to unless @to == @after
return (@before + @amount == @after) if @amount
return ((@after - @before) >= @minimum) if @minimum
return ((@after - @before) <= @maximum) if @maximum
return @before != @after
end
def raise_block_syntax_error
raise MatcherError.new(<<-MESSAGE
block passed to should or should_not change must use {} instead of do/end
MESSAGE
)
end
def evaluate_value_proc
@value_proc.call
end
def failure_message_for_should
if @to
"#{@message} should have been changed to #{@to.inspect}, but is now #{@after.inspect}"
elsif @from
"#{@message} should have initially been #{@from.inspect}, but was #{@before.inspect}"
elsif @amount
"#{@message} should have been changed by #{@amount.inspect}, but was changed by #{actual_delta.inspect}"
elsif @minimum
"#{@message} should have been changed by at least #{@minimum.inspect}, but was changed by #{actual_delta.inspect}"
elsif @maximum
"#{@message} should have been changed by at most #{@maximum.inspect}, but was changed by #{actual_delta.inspect}"
else
"#{@message} should have changed, but is still #{@before.inspect}"
end
end
def actual_delta
@after - @before
end
def failure_message_for_should_not
"#{@message} should not have changed, but did change from #{@before.inspect} to #{@after.inspect}"
end
def by(amount)
@amount = amount
self
end
def by_at_least(minimum)
@minimum = minimum
self
end
def by_at_most(maximum)
@maximum = maximum
self
end
def to(to)
@to = to
self
end
def from (from)
@from = from
self
end
def description
"change ##{@message}"
end
end
# :call-seq:
# should change(receiver, message, &block)
# should change(receiver, message, &block).by(value)
# should change(receiver, message, &block).from(old).to(new)
# should_not change(receiver, message, &block)
#
# Allows you to specify that a Proc will cause some value to change.
#
# == Examples
#
# lambda {
# team.add_player(player)
# }.should change(roster, :count)
#
# lambda {
# team.add_player(player)
# }.should change(roster, :count).by(1)
#
# lambda {
# team.add_player(player)
# }.should change(roster, :count).by_at_least(1)
#
# lambda {
# team.add_player(player)
# }.should change(roster, :count).by_at_most(1)
#
# string = "string"
# lambda {
# string.reverse!
# }.should change { string }.from("string").to("gnirts")
#
# lambda {
# person.happy_birthday
# }.should change(person, :birthday).from(32).to(33)
#
# lambda {
# employee.develop_great_new_social_networking_app
# }.should change(employee, :title).from("Mail Clerk").to("CEO")
#
# Evaluates <tt>receiver.message</tt> or <tt>block</tt> before and after
# it evaluates the c object (generated by the lambdas in the examples
# above).
#
# Then compares the values before and after the <tt>receiver.message</tt>
# and evaluates the difference compared to the expected difference.
#
# == WARNING
# <tt>should_not change</tt> only supports the form with no
# subsequent calls to <tt>by</tt>, <tt>by_at_least</tt>,
# <tt>by_at_most</tt>, <tt>to</tt> or <tt>from</tt>.
#
# blocks passed to <tt>should</tt> <tt>change</tt> and <tt>should_not</tt>
# <tt>change</tt> must use the <tt>{}</tt> form (<tt>do/end</tt> is not
# supported).
#
def change(receiver=nil, message=nil, &block)
Matchers::Change.new(receiver, message, &block)
end
end
end