kinda-hookable 0.0.3 → 0.0.4
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 +1 -4
- data/Rakefile +20 -0
- data/lib/hookable.rb +51 -55
- metadata +4 -2
data/README.rdoc
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
Author:: Manuel Vila (mailto:mvila@3base.com)
|
2
|
-
License:: Don't know yet
|
3
|
-
|
4
1
|
= Hookable
|
5
2
|
|
6
3
|
Patch any method with before, after and around hooks.
|
@@ -11,4 +8,4 @@ Patch any method with before, after and around hooks.
|
|
11
8
|
|
12
9
|
== Usage
|
13
10
|
|
14
|
-
Still very alpha
|
11
|
+
Still very alpha, documentation will come later.
|
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
CHANGED
@@ -5,14 +5,7 @@ module Kinda
|
|
5
5
|
module Hookable
|
6
6
|
include Core
|
7
7
|
|
8
|
-
|
9
|
-
extend container.extensions
|
10
|
-
|
11
|
-
def add_hook(kind, method_name, &block)
|
12
|
-
hooked_methods[method_name.to_sym].hooks[kind] << block
|
13
|
-
patch_method_if_necessary(method_name.to_sym)
|
14
|
-
end
|
15
|
-
|
8
|
+
ClassMethods = inheritable_extend do
|
16
9
|
[:before, :after, :around].each do |kind|
|
17
10
|
define_method(kind) do |method_name, &block|
|
18
11
|
add_hook(kind, method_name, &block)
|
@@ -21,6 +14,41 @@ module Kinda
|
|
21
14
|
|
22
15
|
alias_method :on, :after
|
23
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
|
+
|
24
52
|
def exec_method(method_name, original_method, original_self, *args, &block)
|
25
53
|
result = nil
|
26
54
|
|
@@ -45,12 +73,6 @@ module Kinda
|
|
45
73
|
result
|
46
74
|
end
|
47
75
|
|
48
|
-
def hooked_methods
|
49
|
-
@hooked_methods ||= Hash.new do |hash, method_name|
|
50
|
-
hash[method_name] = HookedMethod.new(self, method_name)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
76
|
def find_hooks(method_name, kind)
|
55
77
|
hooks = []
|
56
78
|
self_and_ancestors.each do |ancestor|
|
@@ -61,70 +83,44 @@ module Kinda
|
|
61
83
|
end
|
62
84
|
hooks
|
63
85
|
end
|
64
|
-
|
65
|
-
def hooked_method_defined?(method_name)
|
66
|
-
self_and_ancestors.each do |ancestor|
|
67
|
-
ancestor.is_a?(Module) ? next : break unless ancestor.respond_to?(:hooked_methods)
|
68
|
-
return true if ancestor.hooked_methods.include?(method_name)
|
69
|
-
end
|
70
|
-
false
|
71
|
-
end
|
72
|
-
|
86
|
+
|
73
87
|
def method_added(method_name)
|
74
88
|
super
|
75
|
-
if
|
89
|
+
if method_hooked?(method_name)
|
76
90
|
patch_method(method_name)
|
77
91
|
end
|
78
92
|
end
|
79
93
|
|
80
|
-
def patch_method(method_name)
|
81
|
-
return if Thread.current[:__adding_method__]
|
82
|
-
# puts "Patching method ##{method_name} in #{self.inspect}"
|
83
|
-
original_method = instance_method(method_name)
|
84
|
-
Thread.current[:__adding_method__] = true
|
85
|
-
define_method(method_name) do |*args, &block|
|
86
|
-
singleton_class.exec_method(method_name, original_method, self, *args, &block)
|
87
|
-
end
|
88
|
-
Thread.current[:__adding_method__] = false
|
89
|
-
hooked_methods[method_name].method_patched = true
|
90
|
-
end
|
91
|
-
|
92
94
|
def patch_method_if_necessary(method_name)
|
93
95
|
self_and_ancestors.each do |ancestor|
|
94
|
-
ancestor.is_a?(Module) ? next : break unless ancestor.respond_to?(:
|
95
|
-
|
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
|
96
99
|
ancestor.patch_method(method_name) unless ancestor.hooked_methods[method_name].method_patched
|
97
100
|
break
|
98
101
|
end
|
99
102
|
end
|
100
103
|
end
|
101
|
-
|
102
|
-
def method_defined_in_this_class?(name) # Works for singleton class too
|
103
|
-
instance_method(name).owner == self rescue false
|
104
|
-
end
|
105
104
|
end
|
106
105
|
|
107
|
-
inheritable_extension ClassMethods
|
108
|
-
|
109
106
|
###
|
110
107
|
|
111
|
-
delegate_to_class
|
112
|
-
delegate_to_class :
|
113
|
-
|
114
|
-
|
115
|
-
|
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
116
|
|
117
117
|
def method_missing(method_name, *args, &block)
|
118
|
-
if
|
119
|
-
|
118
|
+
if method_hooked?(method_name)
|
119
|
+
singleton_class_send(:exec_method, method_name, nil, self, *args, &block)
|
120
120
|
else
|
121
121
|
super
|
122
122
|
end
|
123
123
|
end
|
124
|
-
|
125
|
-
def respond_to?(method_name, include_private=false)
|
126
|
-
super || singleton_class.hooked_method_defined?(method_name)
|
127
|
-
end
|
128
124
|
|
129
125
|
###
|
130
126
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kinda-hookable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manuel Vila
|
@@ -31,11 +31,13 @@ extensions: []
|
|
31
31
|
extra_rdoc_files:
|
32
32
|
- README.rdoc
|
33
33
|
files:
|
34
|
+
- Rakefile
|
34
35
|
- lib/hookable.rb
|
35
36
|
- lib/kinda-hookable.rb
|
36
37
|
- README.rdoc
|
37
38
|
has_rdoc: true
|
38
39
|
homepage: http://github.com/kinda/hookable
|
40
|
+
licenses:
|
39
41
|
post_install_message:
|
40
42
|
rdoc_options: []
|
41
43
|
|
@@ -56,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
58
|
requirements: []
|
57
59
|
|
58
60
|
rubyforge_project: kinda-hookable
|
59
|
-
rubygems_version: 1.
|
61
|
+
rubygems_version: 1.3.5
|
60
62
|
signing_key:
|
61
63
|
specification_version: 2
|
62
64
|
summary: Patch any method with before, after and around hooks
|