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
|
require 'test/unit'
require 'active_support'
class GrandParent
include ActiveSupport::Callbacks
attr_reader :log, :action_name
def initialize(action_name)
@action_name, @log = action_name, []
end
define_callbacks :dispatch
set_callback :dispatch, :before, :before1, :before2, :per_key => {:if => proc {|c| c.action_name == "index" || c.action_name == "update" }}
set_callback :dispatch, :after, :after1, :after2, :per_key => {:if => proc {|c| c.action_name == "update" || c.action_name == "delete" }}
def before1
@log << "before1"
end
def before2
@log << "before2"
end
def after1
@log << "after1"
end
def after2
@log << "after2"
end
def dispatch
run_callbacks(:dispatch, action_name) do
@log << action_name
end
self
end
end
class Parent < GrandParent
skip_callback :dispatch, :before, :before2, :per_key => {:unless => proc {|c| c.action_name == "update" }}
skip_callback :dispatch, :after, :after2, :per_key => {:unless => proc {|c| c.action_name == "delete" }}
end
class Child < GrandParent
skip_callback :dispatch, :before, :before2, :per_key => {:unless => proc {|c| c.action_name == "update" }}, :if => :state_open?
def state_open?
@state == :open
end
def initialize(action_name, state)
super(action_name)
@state = state
end
end
class EmptyParent
include ActiveSupport::Callbacks
def performed?
@performed ||= false
end
define_callbacks :dispatch
def perform!
@performed = true
end
def dispatch
_run_dispatch_callbacks
self
end
end
class EmptyChild < EmptyParent
set_callback :dispatch, :before, :do_nothing
def do_nothing
end
end
class BasicCallbacksTest < Test::Unit::TestCase
def setup
@index = GrandParent.new("index").dispatch
@update = GrandParent.new("update").dispatch
@delete = GrandParent.new("delete").dispatch
@unknown = GrandParent.new("unknown").dispatch
end
def test_basic_per_key1
assert_equal %w(before1 before2 index), @index.log
end
def test_basic_per_key2
assert_equal %w(before1 before2 update after2 after1), @update.log
end
def test_basic_per_key3
assert_equal %w(delete after2 after1), @delete.log
end
end
class InheritedCallbacksTest < Test::Unit::TestCase
def setup
@index = Parent.new("index").dispatch
@update = Parent.new("update").dispatch
@delete = Parent.new("delete").dispatch
@unknown = Parent.new("unknown").dispatch
end
def test_inherited_excluded
assert_equal %w(before1 index), @index.log
end
def test_inherited_not_excluded
assert_equal %w(before1 before2 update after1), @update.log
end
def test_partially_excluded
assert_equal %w(delete after2 after1), @delete.log
end
end
class InheritedCallbacksTest2 < Test::Unit::TestCase
def setup
@update1 = Child.new("update", :open).dispatch
@update2 = Child.new("update", :closed).dispatch
end
def test_crazy_mix_on
assert_equal %w(before1 update after2 after1), @update1.log
end
def test_crazy_mix_off
assert_equal %w(before1 before2 update after2 after1), @update2.log
end
end
class DynamicInheritedCallbacks < Test::Unit::TestCase
def test_callbacks_looks_to_the_superclass_before_running
child = EmptyChild.new.dispatch
assert !child.performed?
EmptyParent.set_callback :dispatch, :before, :perform!
child = EmptyChild.new.dispatch
assert child.performed?
end
end
|