forked from cardmagic/dm-core
/
hook_spec.rb
327 lines (254 loc) · 6.91 KB
/
hook_spec.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
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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
require 'pathname'
require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
require ROOT_DIR + 'lib/data_mapper/hook'
describe "DataMapper::Hook" do
before(:each) do
@class = Class.new do
include DataMapper::Hook
def a_method
end
end
end
it 'should generate the correct argument signature' do
@class.class_eval do
def some_method(a, b, c)
[a, b, c]
end
def yet_another(a, *heh)p
[a, *heh]
end
end
@class.args_for(@class.instance_method(:a_method)).should == ""
@class.args_for(@class.instance_method(:some_method)).should == "_1, _2, _3"
@class.args_for(@class.instance_method(:yet_another)).should == "_1, *args"
end
it 'should install the block under the appropriate hook' do
@class.class_eval do
def a_hook
end
end
@class.before :a_hook, &c = lambda { 1 }
@class.hooks.should have_key(:a_hook)
@class.hooks[:a_hook][:before].should have(1).item
end
it 'should run an advice block' do
@class.class_eval do
def hook
end
before :hook do
hi_mom!
end
end
inst = @class.new
inst.should_receive(:hi_mom!)
inst.hook
end
it 'should run an advice method' do
@class.class_eval do
def hook
end
def before_method()
hi_mom!
end
before :hook, :before_method
end
inst = @class.new
inst.should_receive(:hi_mom!)
inst.hook
end
describe "using before hook" do
it "should install the advice block under the appropriate hook" do
c = lambda { 1 }
@class.should_receive(:install_hook).with(:before, :a_method, nil, &c)
@class.class_eval do
before :a_method, &c
end
end
it 'should install the advice method under the appropriate hook' do
@class.class_eval do
def a_hook
end
end
@class.should_receive(:install_hook).with(:before, :a_method, :a_hook)
@class.before :a_method, :a_hook
end
it 'should run the advice before the advised method' do
tester = mock("tester")
tester.should_receive(:one).ordered
tester.should_receive(:two).ordered
@class.send(:define_method, :a_method) do
tester.two
end
@class.before :a_method do
tester.one
end
@class.new.a_method
end
it 'should execute all advices once' do
tester = mock("tester")
tester.should_receive(:before1).once
tester.should_receive(:before2).once
@class.before :a_method do
tester.before1
end
@class.before :a_method do
tester.before2
end
@class.new.a_method
end
end
describe 'using after hook' do
it "should install the advice block under the appropriate hook" do
c = lambda { 1 }
@class.should_receive(:install_hook).with(:after, :a_method, nil, &c)
@class.class_eval do
after :a_method, &c
end
end
it 'should install the advice method under the appropriate hook' do
@class.class_eval do
def a_hook
end
end
@class.should_receive(:install_hook).with(:after, :a_method, :a_hook)
@class.after :a_method, :a_hook
end
it 'should run the advice after the advised method' do
tester = mock("tester")
tester.should_receive(:one).ordered
tester.should_receive(:two).ordered
tester.should_receive(:three).ordered
@class.send(:define_method, :a_method) do
tester.one
end
@class.after :a_method do
tester.two
end
@class.after :a_method do
tester.three
end
@class.new.a_method
end
it 'should execute all advices once' do
tester = mock("tester")
tester.should_receive(:after1).once
tester.should_receive(:after2).once
@class.after :a_method do
tester.after1
end
@class.after :a_method do
tester.after2
end
@class.new.a_method
end
it "the advised method should still return its normal value" do
@class.class_eval do
def returner
1
end
after :returner do
2
end
end
@class.new.returner.should == 1
end
end
it 'should allow the use of before and after together' do
tester = mock("tester")
tester.should_receive(:before).ordered.once
tester.should_receive(:method).ordered.once
tester.should_receive(:after).ordered.once
@class.class_eval do
define_method :a_method do
tester.method
end
before :a_method do
tester.before
end
after :a_method do
tester.after
end
end
@class.new.a_method
end
it "should allow advising methods ending in ? or !" do
tester = mock("tester")
tester.should_receive(:before).ordered.once
tester.should_receive(:method!).ordered.once
tester.should_receive(:method?).ordered.once
tester.should_receive(:after).ordered.once
@class.class_eval do
define_method :a_method! do
tester.method!
end
define_method :a_method? do
tester.method?
end
before :a_method! do
tester.before
end
after :a_method? do
tester.after
end
end
@class.new.a_method!
@class.new.a_method?
end
it "should allow advising methods ending in ?, ! or = when passing methods as advices" do
tester = mock("tester")
tester.should_receive(:before_bang).ordered.once
tester.should_receive(:method!).ordered.once
tester.should_receive(:before_eq).ordered.once
tester.should_receive(:method_eq).ordered.once
tester.should_receive(:method?).ordered.once
tester.should_receive(:after).ordered.once
@class.class_eval do
define_method :a_method! do
tester.method!
end
define_method :a_method? do
tester.method?
end
define_method :a_method= do |value|
tester.method_eq
end
define_method :before_a_method_bang do
tester.before_bang
end
before :a_method!, :before_a_method_bang
define_method :before_a_method_eq do
tester.before_eq
end
before :a_method=, :before_a_method_eq
define_method :after_a_method_question do
tester.after
end
after :a_method?, :after_a_method_question
end
@class.new.a_method!
@class.new.a_method = 1
@class.new.a_method?
end
it "should complain when only one argument is passed" do
lambda do
@class.class_eval do
before :a_method
after :a_method
end
end.should raise_error(ArgumentError)
end
it "should complain when target_method is not a symbol" do
lambda do
@class.class_eval do
before "target", :something
end
end.should raise_error(ArgumentError)
end
it "should complain when method_sym is not a symbol" do
lambda do
@class.class_eval do
before :target, "something"
end
end.should raise_error(ArgumentError)
end
end