kinda-hookable 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README.rdoc +1 -4
  2. data/Rakefile +20 -0
  3. data/lib/hookable.rb +51 -55
  4. 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 and documentation will come later.
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
- module ClassMethods
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 hooked_method_defined?(method_name)
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?(:method_defined_in_this_class?)
95
- if ancestor.method_defined_in_this_class?(method_name)
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 :before
112
- delegate_to_class :after
113
- alias_method :on, :after
114
- delegate_to_class :around
115
- delegate_to_class :singleton_method_added, :method_added
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 singleton_class.hooked_method_defined?(method_name)
119
- singleton_class.exec_method(method_name, nil, self, *args, &block)
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.3
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.2.0
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