hookable 0.0.5
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/README.rdoc +11 -0
- data/Rakefile +20 -0
- data/lib/hookable.rb +141 -0
- data/lib/kinda-hookable.rb +1 -0
- data/test/hookable_test.rb +567 -0
- metadata +67 -0
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "rake/testtask"
|
2
|
+
|
3
|
+
begin
|
4
|
+
require "hanna/rdoctask"
|
5
|
+
rescue LoadError
|
6
|
+
require "rake/rdoctask"
|
7
|
+
end
|
8
|
+
|
9
|
+
task :default => [:test]
|
10
|
+
|
11
|
+
Rake::TestTask.new do |t|
|
12
|
+
t.test_files = Dir["test/*_test.rb"]
|
13
|
+
end
|
14
|
+
|
15
|
+
Rake::RDocTask.new do |t|
|
16
|
+
t.title = "Hookable Documentation"
|
17
|
+
t.main = "README.rdoc"
|
18
|
+
t.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
19
|
+
t.rdoc_dir = "doc"
|
20
|
+
end
|
data/lib/hookable.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'kinda-core'
|
3
|
+
|
4
|
+
module Kinda
|
5
|
+
module Hookable
|
6
|
+
include Core
|
7
|
+
|
8
|
+
ClassMethods = inheritable_extend do
|
9
|
+
[:before, :after, :around].each do |kind|
|
10
|
+
define_method(kind) do |method_name, &block|
|
11
|
+
add_hook(kind, method_name, &block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
alias_method :on, :after
|
16
|
+
|
17
|
+
def method_hooked?(method_name)
|
18
|
+
self_and_ancestors.each do |ancestor|
|
19
|
+
ancestor.is_a?(Module) ? next : break unless ancestor.respond_to?(:hooked_methods)
|
20
|
+
return true if ancestor.hooked_methods.include?(method_name)
|
21
|
+
end
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def hooked_methods
|
28
|
+
@hooked_methods ||= Hash.new do |hash, method_name|
|
29
|
+
hash[method_name] = Hookable::HookedMethod.new(self, method_name)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def patch_method(method_name)
|
34
|
+
return if Thread.current[:__adding_method__]
|
35
|
+
# puts "Patching method ##{method_name} in #{self.inspect}"
|
36
|
+
original_method = instance_method(method_name)
|
37
|
+
Thread.current[:__adding_method__] = true
|
38
|
+
define_method(method_name) do |*args, &block|
|
39
|
+
singleton_class_send(:exec_method, method_name, original_method, self, *args, &block)
|
40
|
+
end
|
41
|
+
Thread.current[:__adding_method__] = false
|
42
|
+
hooked_methods[method_name].method_patched = true
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def add_hook(kind, method_name, &block)
|
48
|
+
hooked_methods[method_name.to_sym].hooks[kind] << block
|
49
|
+
patch_method_if_necessary(method_name.to_sym)
|
50
|
+
end
|
51
|
+
|
52
|
+
def exec_method(method_name, original_method, original_self, *args, &block)
|
53
|
+
result = nil
|
54
|
+
|
55
|
+
chained_hooks = [] << lambda do |*args, &block|
|
56
|
+
find_hooks(method_name, :before).each do |hook|
|
57
|
+
original_self.call_with_this(hook, *args, &block)
|
58
|
+
end
|
59
|
+
result = original_method.bind(original_self).call(*args, &block) if original_method
|
60
|
+
find_hooks(method_name, :after).each do |hook|
|
61
|
+
original_self.call_with_this(hook, *args, &block)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
hooks = find_hooks(method_name, :around)
|
66
|
+
hooks.each_index do |index|
|
67
|
+
chained_hooks << lambda do |*args, &block|
|
68
|
+
original_self.call_with_this(hooks[index], chained_hooks[index], *args, &block)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
chained_hooks.last.call(*args, &block)
|
72
|
+
|
73
|
+
result
|
74
|
+
end
|
75
|
+
|
76
|
+
def find_hooks(method_name, kind)
|
77
|
+
hooks = []
|
78
|
+
self_and_ancestors.each do |ancestor|
|
79
|
+
ancestor.is_a?(Module) ? next : break unless ancestor.respond_to?(:hooked_methods)
|
80
|
+
next unless ancestor.hooked_methods.include?(method_name)
|
81
|
+
next unless ancestor.hooked_methods[method_name].hooks.include?(kind)
|
82
|
+
hooks.concat(ancestor.hooked_methods[method_name].hooks[kind])
|
83
|
+
end
|
84
|
+
hooks
|
85
|
+
end
|
86
|
+
|
87
|
+
def method_added(method_name)
|
88
|
+
super
|
89
|
+
if method_hooked?(method_name)
|
90
|
+
patch_method(method_name)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def patch_method_if_necessary(method_name)
|
95
|
+
self_and_ancestors.each do |ancestor|
|
96
|
+
ancestor.is_a?(Module) ? next : break unless ancestor.respond_to?(:patch_method)
|
97
|
+
method_defined_in_this_class = ancestor.instance_method(method_name).owner == ancestor rescue false
|
98
|
+
if method_defined_in_this_class
|
99
|
+
ancestor.patch_method(method_name) unless ancestor.hooked_methods[method_name].method_patched
|
100
|
+
break
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
###
|
107
|
+
|
108
|
+
delegate_to_class ClassMethods.public_instance_methods
|
109
|
+
delegate_to_class :singleton_method_added => :method_added
|
110
|
+
|
111
|
+
def respond_to?(method_name, include_private=false)
|
112
|
+
super || method_hooked?(method_name)
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def method_missing(method_name, *args, &block)
|
118
|
+
if method_hooked?(method_name)
|
119
|
+
singleton_class_send(:exec_method, method_name, nil, self, *args, &block)
|
120
|
+
else
|
121
|
+
super
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
###
|
126
|
+
|
127
|
+
class HookedMethod
|
128
|
+
attr_reader :klass, :name
|
129
|
+
attr_accessor :method_patched
|
130
|
+
|
131
|
+
def initialize(klass, name)
|
132
|
+
@klass = klass
|
133
|
+
@name = name
|
134
|
+
end
|
135
|
+
|
136
|
+
def hooks
|
137
|
+
@hooks ||= Hash.new { |hash, kind| hash[kind] = [] }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'hookable')
|
@@ -0,0 +1,567 @@
|
|
1
|
+
#!/usr/bin/ruby19
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib')).uniq!
|
7
|
+
require 'kinda-hookable'
|
8
|
+
|
9
|
+
class HookableClassTest < Test::Unit::TestCase
|
10
|
+
def setup
|
11
|
+
@simple_class = Class.new do
|
12
|
+
include Kinda::Hookable
|
13
|
+
end
|
14
|
+
|
15
|
+
@simple = @simple_class.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_no_method_error
|
19
|
+
assert_raise NoMethodError do
|
20
|
+
@simple.hello
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_before
|
25
|
+
result = []
|
26
|
+
@simple.before(:hello) { result << 'before' }
|
27
|
+
@simple.hello
|
28
|
+
assert_equal ['before'], result
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_before_and_after
|
32
|
+
result = []
|
33
|
+
@simple.before(:hello) { result << 'before' }
|
34
|
+
@simple.after(:hello) { result << 'after' }
|
35
|
+
@simple.hello
|
36
|
+
assert_equal ['before', 'after'], result
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_before_after_and_around
|
40
|
+
result = []
|
41
|
+
@simple.before(:hello) { result << 'before' }
|
42
|
+
@simple.after(:hello) { result << 'after' }
|
43
|
+
@simple.around(:hello) do |original_method|
|
44
|
+
result << 'around begin'
|
45
|
+
original_method.call
|
46
|
+
result << 'around end'
|
47
|
+
end
|
48
|
+
@simple.hello
|
49
|
+
assert_equal ['around begin', 'before', 'after', 'around end'], result
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_respond_to
|
53
|
+
assert @simple.respond_to?(:before)
|
54
|
+
@simple.before(:hello) { result << 'before' }
|
55
|
+
assert @simple.respond_to?(:hello)
|
56
|
+
assert !@simple.respond_to?(:undefined_method)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
###
|
61
|
+
|
62
|
+
class HookableClassWithAMethodTest < Test::Unit::TestCase
|
63
|
+
def setup
|
64
|
+
@simple_class = Class.new do
|
65
|
+
include Kinda::Hookable
|
66
|
+
|
67
|
+
attr_accessor :result
|
68
|
+
|
69
|
+
def initialize
|
70
|
+
@result = []
|
71
|
+
end
|
72
|
+
|
73
|
+
def hello
|
74
|
+
@result << 'hello'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
@simple = @simple_class.new
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_hello
|
82
|
+
@simple.hello
|
83
|
+
assert_equal ['hello'], @simple.result
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_before
|
87
|
+
@simple.before(:hello) { this.result << 'before' }
|
88
|
+
@simple.hello
|
89
|
+
assert_equal ['before', 'hello'], @simple.result
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_two_befores
|
93
|
+
@simple.before(:hello) { this.result << 'before 1' }
|
94
|
+
@simple.before(:hello) { this.result << 'before 2' }
|
95
|
+
@simple.hello
|
96
|
+
assert_equal ['before 1', 'before 2', 'hello'], @simple.result
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_before_after_and_around
|
100
|
+
@simple.before(:hello) { this.result << 'before' }
|
101
|
+
@simple.after(:hello) { this.result << 'after' }
|
102
|
+
@simple.around(:hello) do |original_method|
|
103
|
+
this.result << 'around begin'
|
104
|
+
original_method.call
|
105
|
+
this.result << 'around end'
|
106
|
+
end
|
107
|
+
@simple.hello
|
108
|
+
assert_equal ['around begin', 'before', 'hello', 'after', 'around end'], @simple.result
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_two_arounds
|
112
|
+
@simple.around(:hello) do |original_method|
|
113
|
+
this.result << 'around 1 begin'
|
114
|
+
original_method.call
|
115
|
+
this.result << 'around 1 end'
|
116
|
+
end
|
117
|
+
@simple.around(:hello) do |original_method|
|
118
|
+
this.result << 'around 2 begin'
|
119
|
+
original_method.call
|
120
|
+
this.result << 'around 2 end'
|
121
|
+
end
|
122
|
+
@simple.hello
|
123
|
+
assert_equal ['around 2 begin', 'around 1 begin', 'hello',
|
124
|
+
'around 1 end', 'around 2 end'], @simple.result
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_respond_to
|
128
|
+
assert @simple.respond_to?(:hello)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
###
|
133
|
+
|
134
|
+
class HookableClassWithAMethodWithParametersAndResultTest < Test::Unit::TestCase
|
135
|
+
def setup
|
136
|
+
@simple_class = Class.new do
|
137
|
+
include Kinda::Hookable
|
138
|
+
|
139
|
+
attr_accessor :result
|
140
|
+
|
141
|
+
def initialize
|
142
|
+
@result = []
|
143
|
+
end
|
144
|
+
|
145
|
+
def hello(first_name, last_name)
|
146
|
+
greeting = "hello #{first_name} #{last_name}"
|
147
|
+
@result << greeting
|
148
|
+
greeting
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
@simple = @simple_class.new
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_hello
|
156
|
+
greeting = @simple.hello('Manuel', 'Vila')
|
157
|
+
assert_equal 'hello Manuel Vila', greeting
|
158
|
+
assert_equal ['hello Manuel Vila'], @simple.result
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_before
|
162
|
+
@simple.before(:hello) { |first, last| this.result << "before hello #{first} #{last}" }
|
163
|
+
greeting = @simple.hello('Manuel', 'Vila')
|
164
|
+
assert_equal 'hello Manuel Vila', greeting
|
165
|
+
assert_equal ['before hello Manuel Vila', 'hello Manuel Vila'], @simple.result
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_after
|
169
|
+
@simple.after(:hello) { |first, last| this.result << "after hello #{first} #{last}" }
|
170
|
+
greeting = @simple.hello('Manuel', 'Vila')
|
171
|
+
assert_equal 'hello Manuel Vila', greeting
|
172
|
+
assert_equal ['hello Manuel Vila', 'after hello Manuel Vila'], @simple.result
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_before_and_around
|
176
|
+
@simple.before(:hello) { |first, last| this.result << "before hello #{first} #{last}" }
|
177
|
+
@simple.around(:hello) do |original_method, first, last|
|
178
|
+
this.result << "around hello #{first} #{last} begin"
|
179
|
+
original_method.call(first, last)
|
180
|
+
this.result << "around hello #{first} #{last} end"
|
181
|
+
end
|
182
|
+
greeting = @simple.hello('Manuel', 'Vila')
|
183
|
+
assert_equal 'hello Manuel Vila', greeting
|
184
|
+
assert_equal ['around hello Manuel Vila begin', 'before hello Manuel Vila',
|
185
|
+
'hello Manuel Vila', 'around hello Manuel Vila end'], @simple.result
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
###
|
190
|
+
|
191
|
+
class HookableSuperClassTest < Test::Unit::TestCase
|
192
|
+
def setup
|
193
|
+
@super_simple_class = Class.new do
|
194
|
+
include Kinda::Hookable
|
195
|
+
|
196
|
+
attr_accessor :result
|
197
|
+
|
198
|
+
def initialize
|
199
|
+
@result = []
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
@simple_class = Class.new(@super_simple_class)
|
204
|
+
|
205
|
+
@simple = @simple_class.new
|
206
|
+
end
|
207
|
+
|
208
|
+
def test_before_in_superclass
|
209
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
210
|
+
@simple.hello
|
211
|
+
assert_equal [@simple.class.superclass], @simple.result
|
212
|
+
end
|
213
|
+
|
214
|
+
def test_respond_to_with_before_in_superclass
|
215
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
216
|
+
assert @simple.respond_to?(:hello)
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_before_in_class
|
220
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
221
|
+
@simple.hello
|
222
|
+
assert_equal [@simple.class], @simple.result
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_respond_to_with_before_in_class
|
226
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
227
|
+
assert @simple.respond_to?(:hello)
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_before_in_singleton_class
|
231
|
+
@simple.before(:hello) { this.result << self }
|
232
|
+
@simple.hello
|
233
|
+
assert_equal [self], @simple.result
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_before_in_superclass_class_and_singleton_class
|
237
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
238
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
239
|
+
@simple.before(:hello) { this.result << self }
|
240
|
+
@simple.hello
|
241
|
+
assert_equal [self, @simple.class, @simple.class.superclass], @simple.result
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
###
|
246
|
+
|
247
|
+
class HookableSuperClassWithAMethodTest < Test::Unit::TestCase
|
248
|
+
def setup
|
249
|
+
@super_simple_class = Class.new do
|
250
|
+
include Kinda::Hookable
|
251
|
+
|
252
|
+
attr_accessor :result
|
253
|
+
|
254
|
+
def initialize
|
255
|
+
@result = []
|
256
|
+
end
|
257
|
+
|
258
|
+
def hello
|
259
|
+
@result << 'hello'
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
@simple_class = Class.new(@super_simple_class)
|
264
|
+
|
265
|
+
@simple = @simple_class.new
|
266
|
+
end
|
267
|
+
|
268
|
+
def test_respond_to
|
269
|
+
assert @simple.respond_to?(:hello)
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_before_in_superclass
|
273
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
274
|
+
@simple.hello
|
275
|
+
assert_equal [@simple.class.superclass, 'hello'], @simple.result
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_respond_to_with_before_in_superclass
|
279
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
280
|
+
assert @simple.respond_to?(:hello)
|
281
|
+
end
|
282
|
+
|
283
|
+
def test_before_in_class
|
284
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
285
|
+
@simple.hello
|
286
|
+
assert_equal [@simple.class, 'hello'], @simple.result
|
287
|
+
end
|
288
|
+
|
289
|
+
def test_respond_to_with_before_in_class
|
290
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
291
|
+
assert @simple.respond_to?(:hello)
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_before_in_singleton_class
|
295
|
+
@simple.before(:hello) { this.result << self }
|
296
|
+
@simple.hello
|
297
|
+
assert_equal [self, 'hello'], @simple.result
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_before_in_superclass_class_and_singleton_class
|
301
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
302
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
303
|
+
@simple.before(:hello) { this.result << self }
|
304
|
+
@simple.hello
|
305
|
+
assert_equal [self, @simple.class, @simple.class.superclass, 'hello'], @simple.result
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
###
|
310
|
+
|
311
|
+
class HookableSuperClassWithAMethodInClassTest < Test::Unit::TestCase
|
312
|
+
def setup
|
313
|
+
@super_simple_class = Class.new do
|
314
|
+
include Kinda::Hookable
|
315
|
+
|
316
|
+
attr_accessor :result
|
317
|
+
|
318
|
+
def initialize
|
319
|
+
@result = []
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
@simple_class = Class.new(@super_simple_class) do
|
324
|
+
def hello
|
325
|
+
@result << 'hello'
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
@simple = @simple_class.new
|
330
|
+
end
|
331
|
+
|
332
|
+
def test_respond_to
|
333
|
+
assert @simple.respond_to?(:hello)
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_before_in_superclass
|
337
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
338
|
+
@simple.hello
|
339
|
+
assert_equal ['hello'], @simple.result
|
340
|
+
end
|
341
|
+
|
342
|
+
def test_before_in_class
|
343
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
344
|
+
@simple.hello
|
345
|
+
assert_equal [@simple.class, 'hello'], @simple.result
|
346
|
+
end
|
347
|
+
|
348
|
+
def test_before_in_singleton_class
|
349
|
+
@simple.before(:hello) { this.result << self }
|
350
|
+
@simple.hello
|
351
|
+
assert_equal [self, 'hello'], @simple.result
|
352
|
+
end
|
353
|
+
|
354
|
+
def test_before_in_superclass_class_and_singleton_class
|
355
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
356
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
357
|
+
@simple.before(:hello) { this.result << self }
|
358
|
+
@simple.hello
|
359
|
+
assert_equal [self, @simple.class, @simple.class.superclass, 'hello'], @simple.result
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
###
|
364
|
+
|
365
|
+
class HookableSuperClassWithAMethodInSingletonClassTest < Test::Unit::TestCase
|
366
|
+
def setup
|
367
|
+
@super_simple_class = Class.new do
|
368
|
+
include Kinda::Hookable
|
369
|
+
|
370
|
+
attr_accessor :result
|
371
|
+
|
372
|
+
def initialize
|
373
|
+
@result = []
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
@simple_class = Class.new(@super_simple_class)
|
378
|
+
|
379
|
+
@simple = @simple_class.new
|
380
|
+
|
381
|
+
def @simple.hello
|
382
|
+
@result << 'hello'
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
def test_respond_to
|
387
|
+
assert @simple.respond_to?(:hello)
|
388
|
+
end
|
389
|
+
|
390
|
+
def test_before_in_superclass
|
391
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
392
|
+
@simple.hello
|
393
|
+
assert_equal ['hello'], @simple.result
|
394
|
+
end
|
395
|
+
|
396
|
+
def test_before_in_class
|
397
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
398
|
+
@simple.hello
|
399
|
+
assert_equal ['hello'], @simple.result
|
400
|
+
end
|
401
|
+
|
402
|
+
def test_before_in_singleton_class
|
403
|
+
@simple.before(:hello) { this.result << self }
|
404
|
+
@simple.hello
|
405
|
+
assert_equal [self, 'hello'], @simple.result
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_before_in_superclass_class_and_singleton_class
|
409
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
410
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
411
|
+
@simple.before(:hello) { this.result << self }
|
412
|
+
@simple.hello
|
413
|
+
assert_equal [self, @simple.class, @simple.class.superclass, 'hello'], @simple.result
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
###
|
418
|
+
|
419
|
+
class HookableModuleTest < Test::Unit::TestCase
|
420
|
+
def setup
|
421
|
+
@super_simple_class = Class.new do
|
422
|
+
include Kinda::Hookable
|
423
|
+
|
424
|
+
attr_accessor :result
|
425
|
+
|
426
|
+
def initialize
|
427
|
+
@result = []
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
@simple_module = Module.new do
|
432
|
+
include Kinda::Hookable
|
433
|
+
end
|
434
|
+
|
435
|
+
@simple_class = Class.new(@super_simple_class)
|
436
|
+
@simple_class.send(:include, @simple_module)
|
437
|
+
|
438
|
+
@simple = @simple_class.new
|
439
|
+
end
|
440
|
+
|
441
|
+
def test_before_in_superclass
|
442
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
443
|
+
@simple.hello
|
444
|
+
assert_equal [@simple.class.superclass], @simple.result
|
445
|
+
end
|
446
|
+
|
447
|
+
def test_respond_to_with_before_in_superclass
|
448
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
449
|
+
assert @simple.respond_to?(:hello)
|
450
|
+
end
|
451
|
+
|
452
|
+
def test_before_in_module
|
453
|
+
@simple_module.module_eval { before(:hello) { this.result << self } }
|
454
|
+
@simple.hello
|
455
|
+
assert_equal [@simple_module], @simple.result
|
456
|
+
end
|
457
|
+
|
458
|
+
def test_respond_to_with_before_in_module
|
459
|
+
@simple_module.module_eval { before(:hello) { this.result << self } }
|
460
|
+
assert @simple.respond_to?(:hello)
|
461
|
+
end
|
462
|
+
|
463
|
+
def test_before_in_class
|
464
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
465
|
+
@simple.hello
|
466
|
+
assert_equal [@simple.class], @simple.result
|
467
|
+
end
|
468
|
+
|
469
|
+
def test_respond_to_with_before_in_class
|
470
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
471
|
+
assert @simple.respond_to?(:hello)
|
472
|
+
end
|
473
|
+
|
474
|
+
def test_before_in_singleton_class
|
475
|
+
@simple.before(:hello) { this.result << self }
|
476
|
+
@simple.hello
|
477
|
+
assert_equal [self], @simple.result
|
478
|
+
end
|
479
|
+
|
480
|
+
def test_before_in_superclass_class_and_singleton_class
|
481
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
482
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
483
|
+
@simple.before(:hello) { this.result << self }
|
484
|
+
@simple.hello
|
485
|
+
assert_equal [self, @simple.class, @simple.class.superclass], @simple.result
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
###
|
490
|
+
|
491
|
+
class HookableModuleWithAMethodTest < Test::Unit::TestCase
|
492
|
+
def setup
|
493
|
+
@super_simple_class = Class.new do
|
494
|
+
include Kinda::Hookable
|
495
|
+
|
496
|
+
attr_accessor :result
|
497
|
+
|
498
|
+
def initialize
|
499
|
+
@result = []
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
@simple_module = Module.new do
|
504
|
+
include Kinda::Hookable
|
505
|
+
|
506
|
+
def hello
|
507
|
+
@result << 'hello'
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
@simple_class = Class.new(@super_simple_class)
|
512
|
+
@simple_class.send(:include, @simple_module)
|
513
|
+
|
514
|
+
@simple = @simple_class.new
|
515
|
+
end
|
516
|
+
|
517
|
+
def test_respond_to
|
518
|
+
assert @simple.respond_to?(:hello)
|
519
|
+
end
|
520
|
+
|
521
|
+
def test_before_in_superclass
|
522
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } } # not executed
|
523
|
+
@simple.hello
|
524
|
+
assert_equal ['hello'], @simple.result
|
525
|
+
end
|
526
|
+
|
527
|
+
def test_respond_to_with_before_in_superclass
|
528
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
529
|
+
assert @simple.respond_to?(:hello)
|
530
|
+
end
|
531
|
+
|
532
|
+
def test_before_in_module
|
533
|
+
@simple_module.module_eval { before(:hello) { this.result << self } }
|
534
|
+
@simple.hello
|
535
|
+
assert_equal [@simple_module, 'hello'], @simple.result
|
536
|
+
end
|
537
|
+
|
538
|
+
def test_respond_to_with_before_in_module
|
539
|
+
@simple_module.module_eval { before(:hello) { this.result << self } }
|
540
|
+
assert @simple.respond_to?(:hello)
|
541
|
+
end
|
542
|
+
|
543
|
+
def test_before_in_class
|
544
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
545
|
+
@simple.hello
|
546
|
+
assert_equal [@simple.class, 'hello'], @simple.result
|
547
|
+
end
|
548
|
+
|
549
|
+
def test_respond_to_with_before_in_class
|
550
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
551
|
+
assert @simple.respond_to?(:hello)
|
552
|
+
end
|
553
|
+
|
554
|
+
def test_before_in_singleton_class
|
555
|
+
@simple.before(:hello) { this.result << self }
|
556
|
+
@simple.hello
|
557
|
+
assert_equal [self, 'hello'], @simple.result
|
558
|
+
end
|
559
|
+
|
560
|
+
def test_before_in_superclass_class_and_singleton_class
|
561
|
+
@super_simple_class.class_eval { before(:hello) { this.result << self } }
|
562
|
+
@simple_class.class_eval { before(:hello) { this.result << self } }
|
563
|
+
@simple.before(:hello) { this.result << self }
|
564
|
+
@simple.hello
|
565
|
+
assert_equal [self, @simple.class, @simple.class.superclass, 'hello'], @simple.result
|
566
|
+
end
|
567
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hookable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Manuel Vila
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-12 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: kinda-core
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.1
|
24
|
+
version:
|
25
|
+
description: Patch any method with before, after and around hooks
|
26
|
+
email: mvila@3base.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README.rdoc
|
33
|
+
files:
|
34
|
+
- Rakefile
|
35
|
+
- lib/hookable.rb
|
36
|
+
- lib/kinda-hookable.rb
|
37
|
+
- README.rdoc
|
38
|
+
has_rdoc: true
|
39
|
+
homepage: http://github.com/kinda/hookable
|
40
|
+
licenses: []
|
41
|
+
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: 1.9.1
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project: kinda-hookable
|
62
|
+
rubygems_version: 1.3.5
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: Patch any method with before, after and around hooks
|
66
|
+
test_files:
|
67
|
+
- test/hookable_test.rb
|