/
hooks.rb
105 lines (86 loc) · 2.67 KB
/
hooks.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
module RSpec
module Core
module Hooks
class Hook
attr_reader :options
def initialize(options, block)
@options = options
@block = block
end
def options_apply?(group)
!group || group.all_apply?(options)
end
def to_proc
@block
end
def call
@block.call
end
def run_in(example)
example ? example.instance_eval(&self) : call
end
end
class BeforeHook < Hook; end
class AfterHook < Hook; end
class AroundHook < Hook
def call(wrapped_example)
@block.call(wrapped_example)
end
end
class HookCollection < Array
def find_hooks_for(group)
dup.reject {|hook| !hook.options_apply?(group)}
end
end
class BeforeHooks < HookCollection
def run_all(example)
each {|h| h.run_in(example) }
end
def run_all!(example)
shift.run_in(example) until empty?
end
end
class AfterHooks < HookCollection
def run_all(example)
reverse.each {|h| h.run_in(example) }
end
def run_all!(example)
pop.run_in(example) until empty?
end
end
class AroundHooks < HookCollection; end
def hooks
@hooks ||= {
:around => { :each => AroundHooks.new },
:before => { :each => BeforeHooks.new, :all => BeforeHooks.new, :suite => BeforeHooks.new },
:after => { :each => AfterHooks.new, :all => AfterHooks.new, :suite => AfterHooks.new }
}
end
def before(scope=:each, options={}, &block)
hooks[:before][scope] << BeforeHook.new(options, block)
end
def after(scope=:each, options={}, &block)
hooks[:after][scope] << AfterHook.new(options, block)
end
def around(scope=:each, options={}, &block)
hooks[:around][scope] << AroundHook.new(options, block)
end
# Runs all of the blocks stored with the hook in the context of the
# example. If no example is provided, just calls the hook directly.
def run_hook(hook, scope, example=nil)
hooks[hook][scope].run_all(example)
end
# Just like run_hook, except it removes the blocks as it evalutes them,
# ensuring that they will only be run once.
def run_hook!(hook, scope, example)
hooks[hook][scope].run_all!(example)
end
def run_hook_filtered(hook, scope, group, example)
find_hook(hook, scope, group).run_all(example)
end
def find_hook(hook, scope, group)
hooks[hook][scope].find_hooks_for(group)
end
end
end
end