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.
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