rhook 0.1.6 → 0.1.7

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.6
1
+ 0.1.7
@@ -0,0 +1,43 @@
1
+ require "rubygems"
2
+ # $LOAD_PATH.unshift(File.dirname(__FILE__)+"/../lib")
3
+ require "rhook"
4
+
5
+ require "benchmark"
6
+
7
+ class Target
8
+ def target
9
+
10
+ end
11
+ end
12
+
13
+ n = 30000
14
+ Benchmark.bm(24) do |x|
15
+ t = Target.new
16
+
17
+ doit = lambda do
18
+ n.times do
19
+ t.target
20
+ end
21
+ end
22
+
23
+ # ========================================================================
24
+ x.report("direct:") do
25
+ doit.call
26
+ end
27
+
28
+ # ========================================================================
29
+ hook = Target._rhook.hack(:target) do |inv|
30
+ inv.call
31
+ end
32
+
33
+ x.report("rhook enabled:") do
34
+ doit.call
35
+ end
36
+
37
+ # ========================================================================
38
+ hook.disable
39
+
40
+ x.report("rhook disabled:") do
41
+ doit.call
42
+ end
43
+ end
@@ -0,0 +1,38 @@
1
+ require "rubygems"
2
+ # $LOAD_PATH.unshift(File.dirname(__FILE__)+"/../lib")
3
+ require "rhook"
4
+
5
+ require "benchmark"
6
+ require "logger"
7
+
8
+ n = 30000
9
+ Benchmark.bm(24) do |x|
10
+ logger = Logger.new(open("/dev/null", "w"))
11
+
12
+ doit = lambda do
13
+ n.times do
14
+ logger.info("msg")
15
+ end
16
+ end
17
+
18
+ # ========================================================================
19
+ x.report("direct:") do
20
+ doit.call
21
+ end
22
+
23
+ # ========================================================================
24
+ hook = Logger._rhook.hack(:add) do |inv|
25
+ inv.call
26
+ end
27
+
28
+ x.report("rhook enabled:") do
29
+ doit.call
30
+ end
31
+
32
+ # ========================================================================
33
+ hook.disable
34
+
35
+ x.report("rhook disabled:") do
36
+ doit.call
37
+ end
38
+ end
@@ -21,6 +21,8 @@ module RHook
21
21
  class RHookService
22
22
  # @private
23
23
  attr_reader :hooks_map
24
+ # @private
25
+ attr_accessor :last_name_call_method_done
24
26
 
25
27
  # @private
26
28
  def initialize(obj)
@@ -42,7 +44,8 @@ module RHook
42
44
  # Add hook to the {#bound_object}. If it is a kind of Class, the hook is affected to all instance & subclasses of the class.
43
45
  #
44
46
  # @param [Symbol] name hook-point's name (commonly equals to method name)
45
- # @option opt [true] :disable Create hook but make disabled. (by default, automatically enabled.)
47
+ # @option opt [true] :disable Creates hook but make disabled. (by default, automatically enabled.)
48
+ # @option opt [RHook::HookGroup] :group Adds itself into the specified hook-group.
46
49
  # @yield [inv] The hook block.
47
50
  # @yieldparam [Invocation] inv
48
51
  # @yieldreturn The result value. (Returned value of called method.)
@@ -53,7 +56,11 @@ module RHook
53
56
  (@hooks_map[name.to_sym] ||= []).unshift( hook )
54
57
  RHook.registry.class_cached_flag_map.delete(name)
55
58
  opt[:disable] or hook.enable()
56
- HookGroup.add_to_current_groups(hook)
59
+ if opt[:group]
60
+ opt[:group].add(hook)
61
+ else
62
+ HookGroup.add_to_current_groups(hook)
63
+ end
57
64
  hook
58
65
  end
59
66
 
@@ -124,6 +131,11 @@ module RHook
124
131
 
125
132
  # @private
126
133
  def call_method(name, method_name, args, block, opt = {})
134
+ if @last_name_call_method_done == name
135
+ return @obj.__send__(method_name, *args, &block)
136
+ end
137
+ @last_name_call_method_done = name
138
+
127
139
  hooks = concat_hooks([], name)
128
140
  hooks.empty? and return @obj.__send__(method_name, *args, &block)
129
141
 
@@ -133,9 +145,13 @@ module RHook
133
145
  inv.args = args
134
146
  inv.block = block
135
147
  inv.hooks = hooks
136
- inv.target_proc = @obj.method(method_name)
148
+ inv.target_proc = lambda do |*args, &block|
149
+ @obj.__send__(method_name, *args, &block)
150
+ end
137
151
  inv.hint = opt[:hint] || {}
138
152
  inv.proceed()
153
+ ensure
154
+ @last_name_call_method_done = nil
139
155
  end
140
156
 
141
157
  # Wraps the code block to be hookable.
@@ -398,6 +414,12 @@ module RHook
398
414
  self
399
415
  end
400
416
 
417
+ # Tests the given hook is registered in this group.
418
+ # @return [Boolean]
419
+ def include?(hook)
420
+ @hooks.include?(hook)
421
+ end
422
+
401
423
  # @private
402
424
  def self.add_to_current_groups(hook)
403
425
  (Thread.current["rhook_group"] || []).each do |group|
@@ -415,8 +437,14 @@ module RHook
415
437
  # }
416
438
  # XXX_feature_for_library.disable
417
439
  #
440
+ # @example
441
+ # grp = RHook.group
442
+ # Target._rhook.bind(..., :group => grp) { ... }
443
+ #
418
444
  # @return [HookGroup]
419
445
  def self.group(&block)
420
- HookGroup.new.wrap(&block)
446
+ group = HookGroup.new
447
+ block and group.wrap(&block)
448
+ group
421
449
  end
422
450
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rhook}
8
- s.version = "0.1.6"
8
+ s.version = "0.1.7"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Kaoru Kobo"]
12
- s.date = %q{2010-12-01}
12
+ s.date = %q{2011-01-14}
13
13
  s.description = %q{You can provide hook point in your code, and can customize its behavior from outside. Also you can 'hack' (== injecting hook point from outside) any methods in existing code.}
14
14
  s.email = %q{}
15
15
  s.extra_rdoc_files = [
@@ -23,6 +23,8 @@ Gem::Specification.new do |s|
23
23
  "README.rdoc",
24
24
  "Rakefile",
25
25
  "VERSION",
26
+ "examples/benchmark_empty_method.rb",
27
+ "examples/benchmark_logger.rb",
26
28
  "examples/log_socket_data.rb",
27
29
  "lib/rhook.rb",
28
30
  "rhook.gemspec",
@@ -38,6 +40,8 @@ Gem::Specification.new do |s|
38
40
  s.rubygems_version = %q{1.3.7}
39
41
  s.summary = %q{Easily drive AOP & hacking existing library with Ruby}
40
42
  s.test_files = [
43
+ "examples/benchmark_empty_method.rb",
44
+ "examples/benchmark_logger.rb",
41
45
  "examples/log_socket_data.rb",
42
46
  "spec/examples/log_buffer_example_spec.rb",
43
47
  "spec/rhook_minor_spec.rb",
@@ -31,7 +31,7 @@ describe "rhook (minor specifications / behavior, and bugs)" do
31
31
  # [bug] It calls the target method/procedure twice when no hooks are registered.
32
32
  t.order_call
33
33
  t.order_ary.should == ["orig"]
34
-
34
+
35
35
  t._rhook.bind(:order_target) do |inv|
36
36
  t.order_ary << "before_call"
37
37
  inv.call
@@ -119,6 +119,71 @@ describe "rhook (minor specifications / behavior, and bugs)" do
119
119
  result = Target._rhook.on_method(:on_method_test_non_existent, :ifdef => true)
120
120
  result.should == true
121
121
  end
122
+
123
+ end
124
+
125
+ # ========================================================================
126
+ describe "is applied to the method (== 'hack'ed), and also it is called via _rhook.to(), " do
127
+ class Target
128
+ def both_on_method_and_to
129
+ _rhook.to.both_on_method_and_to_target
130
+ end
131
+
132
+ def both_on_method_and_to_target
133
+
134
+ end
135
+ end
136
+
137
+ example "even though, the hook should be just called once." do
138
+ m = mock
139
+ m.should_receive(:called).once
140
+
141
+ Target._rhook.hack(:both_on_method_and_to_target) { |inv|
142
+ m.called
143
+ inv.call
144
+ }
145
+ Target.new.both_on_method_and_to()
146
+ end
122
147
  end
123
148
  end
149
+
150
+ # ========================================================================
151
+ describe "#call_method(#to): " do
152
+ before :each do
153
+ end
154
+
155
+ example "[bugfix] super: no superclass method" do
156
+ class CallMethodSuperTest_Super
157
+ def the_method
158
+
159
+ end
160
+ end
161
+
162
+ module CallMethodSuperTest_Module
163
+ def the_method
164
+ super
165
+ end
166
+ end
167
+
168
+ class CallMethodSuperTest_Inherited < CallMethodSuperTest_Super
169
+ include CallMethodSuperTest_Module
170
+ end
171
+
172
+ # This bug does not appear without hooks.
173
+ CallMethodSuperTest_Inherited._rhook.bind(:the_method) do |inv|
174
+ inv.call
175
+ end
176
+
177
+ # OK.
178
+ CallMethodSuperTest_Inherited.new.the_method
179
+
180
+ # We fixed the bug this cause error:
181
+ lambda {
182
+ CallMethodSuperTest_Inherited.new._rhook.to.the_method
183
+ }.should_not raise_error
184
+ # - super: no superclass method `the_method'
185
+ end
186
+ end
187
+ # ========================================================================
188
+
124
189
  end
@@ -213,6 +213,16 @@ describe "rhook (advanced usage)" do
213
213
  t.group_1.should == "hack1"
214
214
  t.group_2.should == "hack2"
215
215
  end
216
+
217
+ example "Adding a hook to group with bind()'s :group option." do
218
+ # Instantiate a group with RHook.group() without block.
219
+ group = RHook.group
220
+ t = Target.new
221
+ hook = t._rhook.hack(:group_1, :group => group) do |inv|
222
+ inv.call
223
+ end
224
+ group.include?(hook).should be_true
225
+ end
216
226
  end
217
227
  # ================================================================
218
228
 
@@ -234,29 +244,31 @@ describe "rhook (advanced usage)" do
234
244
 
235
245
  end
236
246
 
237
- lambda { |called|
238
- t = Target.new
239
- t._rhook.bind(:invocation_object_target) { |inv|
240
- # first hook
241
- called.yes
242
- inv.call()
243
- inv.returned.should == :returned_value
247
+ m = mock
248
+ m.should_receive(:second).once.ordered
249
+ m.should_receive(:first).once.ordered
250
+
251
+ t = Target.new
252
+ t._rhook.bind(:invocation_object_target) { |inv|
253
+ # first hook
254
+ m.first
255
+ inv.call()
256
+ inv.returned.should == :returned_value
244
257
  :returned_value_hooked
245
- }
246
- t._rhook.bind(:invocation_object_target) { |inv|
247
- # second hook
248
- called.yes
249
- inv.args.should == args
250
- inv.block.should == block
251
- inv.hint[:hintkey].should == :hintval
252
- inv.receiver.should == t
253
- inv.target.should == t
254
- inv.returned.should be_nil
255
- inv.call()
256
- inv.returned.should == :returned_value_hooked
257
- }
258
- t.invocation_object(*args, &block)
259
- }.should calls_hook(:times => 2)
258
+ }
259
+ t._rhook.bind(:invocation_object_target) { |inv|
260
+ # second hook
261
+ m.second
262
+ inv.args.should == args
263
+ inv.block.should == block
264
+ inv.hint[:hintkey].should == :hintval
265
+ inv.receiver.should == t
266
+ inv.target.should == t
267
+ inv.returned.should be_nil
268
+ inv.call()
269
+ inv.returned.should == :returned_value_hooked
270
+ }
271
+ t.invocation_object(*args, &block)
260
272
  end
261
273
  end
262
274
  # ========================================================================
@@ -11,44 +11,3 @@ Spec::Runner.configure do |config|
11
11
 
12
12
  end
13
13
 
14
- # ========================================================================
15
- # Defines custom matcher to test the hook was called.
16
-
17
- module ::Spec::Matchers
18
- class HookCalledMatcher
19
- def initialize(opt)
20
- @times = opt[:times]
21
- @count = 0
22
- end
23
-
24
- def yes
25
- @count += 1
26
- end
27
-
28
- def matches?(block)
29
- block.call(self)
30
- if @times
31
- begin
32
- @count.should == @times
33
- rescue
34
- @times_msg = " (Exactly called count: #{$!})"
35
- false
36
- end
37
- else
38
- @count > 0
39
- end
40
- end
41
-
42
- def failure_message
43
- "Expected the hook to be called.#{@times_msg}"
44
- end
45
-
46
- def negative_failure_message
47
- "Expected the hook not to be called.#{@times_msg}"
48
- end
49
- end
50
-
51
- def calls_hook(opt = {})
52
- HookCalledMatcher.new(opt)
53
- end
54
- end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rhook
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 6
10
- version: 0.1.6
9
+ - 7
10
+ version: 0.1.7
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kaoru Kobo
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-12-01 00:00:00 +09:00
18
+ date: 2011-01-14 00:00:00 +09:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -66,6 +66,8 @@ files:
66
66
  - README.rdoc
67
67
  - Rakefile
68
68
  - VERSION
69
+ - examples/benchmark_empty_method.rb
70
+ - examples/benchmark_logger.rb
69
71
  - examples/log_socket_data.rb
70
72
  - lib/rhook.rb
71
73
  - rhook.gemspec
@@ -109,6 +111,8 @@ signing_key:
109
111
  specification_version: 3
110
112
  summary: Easily drive AOP & hacking existing library with Ruby
111
113
  test_files:
114
+ - examples/benchmark_empty_method.rb
115
+ - examples/benchmark_logger.rb
112
116
  - examples/log_socket_data.rb
113
117
  - spec/examples/log_buffer_example_spec.rb
114
118
  - spec/rhook_minor_spec.rb