rhook 0.1.5 → 0.1.6

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/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --no-private
2
+ --title "rhook"
data/README.rdoc CHANGED
@@ -1,9 +1,16 @@
1
1
  = rhook - Easily drive AOP & hacking existing library with Ruby
2
2
 
3
+ - Homepage & Source -- http://github.com/kaorukobo/rhook
4
+ - Download -- http://rubygems.org/gems/rhook
5
+ - API Documentation (RDoc) -- http://rubydoc.info/github/kaorukobo/rhook/master/frames
6
+
7
+ == Summary
8
+
3
9
  - You can provide hook point in your code,
4
10
  - and can customize its behavior from outside.
5
11
  - Also you can 'hack' (== injecting hook point from outside) any methods in existing code.
6
12
 
13
+
7
14
  == Install
8
15
 
9
16
  gem install rhook
@@ -65,20 +72,21 @@
65
72
 
66
73
  === about '_rhook'
67
74
 
68
- Once you require 'rhook', any objects has '_rhook' method to access any rhook services. (that returns RHook::RHookService object.)
75
+ Once you require 'rhook', any objects has '_rhook' method to access any rhook services. (that returns {RHook::RHookService} object.)
69
76
 
70
77
  any_object = Object.new
71
78
  any_object._rhook.RHOOK_METHOD
72
79
 
80
+ See http://rubydoc.info/github/kaorukobo/rhook/master/RHook/RHookService
81
+
73
82
  === What is 'inv' ?
74
83
 
75
- RHook::Invocation object, that contains:
84
+ {RHook::Invocation} object, that contains:
76
85
 
77
86
  - call() method to proceed method invocation.
78
- - receiver
79
- - arguments passed to method
80
- - blocks passed to method
81
- - returned value by call()
87
+ - receiver, arguments/blcoks passed to method, and the other informations. See {RHook::Invocation}.
88
+
89
+ See http://rubydoc.info/github/kaorukobo/rhook/master/RHook/Invocation
82
90
 
83
91
  === If you want 'bind' to not only an object, but any instances of class:
84
92
 
@@ -113,6 +121,16 @@ for class method:
113
121
 
114
122
  Please see spec: http://github.com/kaorukobo/rhook/blob/master/spec/rhook_spec.rb
115
123
 
124
+ == Practical Examples
125
+
126
+ === 1. Log Buffer
127
+
128
+ Log Buffer allows you to capture any messages written to Logger and keep in buffer.
129
+
130
+ For example, you can examine the target program's log messages in testing code.
131
+
132
+ http://github.com/kaorukobo/rhook/blob/master/spec/examples/log_buffer_example_spec.rb
133
+
116
134
  == ...
117
135
 
118
136
  === Note on Patches/Pull Requests
data/Rakefile CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
3
 
4
+ require "logger"
5
+ log = Logger.new(STDERR)
6
+
4
7
  begin
5
8
  require 'jeweler'
6
9
  Jeweler::Tasks.new do |gem|
@@ -11,6 +14,8 @@ begin
11
14
  gem.homepage = "http://github.com/kaorukobo/rhook"
12
15
  gem.authors = ["Kaoru Kobo"]
13
16
  gem.add_development_dependency "rspec", ">= 1.2.9"
17
+ gem.add_development_dependency "yard", "~> 0.6.0"
18
+ gem.has_rdoc = "yard"
14
19
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
20
  end
16
21
  Jeweler::GemcutterTasks.new
@@ -34,12 +39,11 @@ task :spec => :check_dependencies
34
39
 
35
40
  task :default => :spec
36
41
 
37
- require 'rake/rdoctask'
38
- Rake::RDocTask.new do |rdoc|
39
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
-
41
- rdoc.rdoc_dir = 'rdoc'
42
- rdoc.title = "rhook #{version}"
43
- rdoc.rdoc_files.include('README*')
44
- rdoc.rdoc_files.include('lib/**/*.rb')
42
+ begin
43
+ gem "yard"
44
+ require "yard"
45
+ YARD::Rake::YardocTask.new do |t|
46
+ end
47
+ rescue Gem::LoadError
48
+ log.warn "Install YARD to generate document."
45
49
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.5
1
+ 0.1.6
@@ -0,0 +1,34 @@
1
+ require "socket"
2
+
3
+ require "rubygems"
4
+ require "rhook"
5
+
6
+ # Trace TCPSocket output data.
7
+ TCPSocket._rhook.hack(:write) do |inv|
8
+ STDERR.print("> ", inv.args[0].inspect, "\n")
9
+ inv.call
10
+ end
11
+
12
+ # Trace TCPSocket input data.
13
+ TCPSocket._rhook.hack(:read) do |inv|
14
+ inv.call
15
+ STDERR.print("< ", inv.returned.inspect, "\n")
16
+ inv.returned
17
+ end
18
+
19
+
20
+ require "rack"
21
+ require "rack/handler/webrick"
22
+
23
+ th = Thread.start {
24
+ Rack::Handler::WEBrick.run(lambda { |env|
25
+ [200, {}, []]
26
+ }, :Port => 9292)
27
+ }
28
+ sleep 1
29
+
30
+ sock = TCPSocket.new("localhost", 9292)
31
+ sock.print("GET / HTTP/1.0\n\n")
32
+ sock.flush
33
+
34
+ sock.read
data/lib/rhook.rb CHANGED
@@ -1,4 +1,7 @@
1
1
  module RHook
2
+ # @private
3
+ # The registry contains information globally shared. (like cache)
4
+ # You don't need to use this class.
2
5
  class Registry
3
6
  attr_reader :class_cached_flag_map
4
7
  def initialize
@@ -6,19 +9,44 @@ module RHook
6
9
  end
7
10
  end
8
11
 
12
+ # @private
13
+ # Get global +Registry+ object.
9
14
  def self.registry
10
15
  @registry ||= Registry.new
11
16
  end
12
17
 
18
+ # Most important class on rhook.
19
+ #
20
+ # If you call obj._rhook, it returns a RHookService object bound to +obj+.
13
21
  class RHookService
22
+ # @private
14
23
  attr_reader :hooks_map
15
24
 
25
+ # @private
16
26
  def initialize(obj)
17
27
  @obj = obj
18
28
  @hooks_map = {}
19
29
  @class_cached_hooks_map = {} if Class === @obj
20
30
  end
21
31
 
32
+ # Returns the object bound to this RHookService.
33
+ # ( +obj+ of +obj._rhook+ )
34
+ def bound_object
35
+ @obj
36
+ end
37
+
38
+ # ========================================================================
39
+ # @group Methods for hook-side(outside)
40
+ # ========================================================================
41
+
42
+ # 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
+ #
44
+ # @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.)
46
+ # @yield [inv] The hook block.
47
+ # @yieldparam [Invocation] inv
48
+ # @yieldreturn The result value. (Returned value of called method.)
49
+ # @return [Hook] Created hook.
22
50
  def bind(name, opt = {}, &block)
23
51
  hook = Hook.new
24
52
  hook.hook_proc = block
@@ -29,6 +57,15 @@ module RHook
29
57
  hook
30
58
  end
31
59
 
60
+ # Injects hook-point (hack) to the paticular method in {#bound_object}, and add hook same as {#bind}.
61
+ #
62
+ # The hook-point injection is done by 'alias' method.
63
+ # If the hook-point is already injected, this just does {#bind}.
64
+ #
65
+ # @param [Symbol] name The name of method to hack.
66
+ # @yield [inv]
67
+ # @return [Hook]
68
+ # @see #bind See #bind for other param/return.
32
69
  def hack(name, opt = {}, &block)
33
70
  success = false
34
71
  if Class === @obj
@@ -44,13 +81,21 @@ module RHook
44
81
  bind(name, opt, &block)
45
82
  end
46
83
 
84
+ # @group Methods for hook-side(outside)
85
+ #
86
+ # Unbind all hooks bound to {#bound_object}.
87
+ # @return [self]
47
88
  def unbind_all
48
89
  @hooks_map.clear
49
90
  @class_cached_hooks_map.clear
91
+ self
50
92
  end
51
93
 
52
- # nodoc:
53
- # Proxy class for 'to'
94
+ # ========================================================================
95
+ # @endgroup
96
+ # ========================================================================
97
+
98
+ # @private
54
99
  class Caller
55
100
  def initialize(rhook, opt)
56
101
  @rhook = rhook
@@ -62,13 +107,22 @@ module RHook
62
107
  end
63
108
  end #/Caller
64
109
 
65
- # ================================================================
66
- # Target-side methods:
67
-
110
+ # ========================================================================
111
+ # @group Methods for target-side (for providing hook-point)
112
+ # ========================================================================
113
+
114
+ # Wraps {#bound_object}'s method call to be hookable.
115
+ #
116
+ # @example
117
+ # _rhook.to.method_name(arg1, arg2)
118
+ #
119
+ # @option opt [Hash] :hint Hint values used through {Invocation#hint}.
120
+ # @return Proxy to call method.
68
121
  def to(opt = {})
69
122
  Caller.new(self, opt)
70
123
  end
71
124
 
125
+ # @private
72
126
  def call_method(name, method_name, args, block, opt = {})
73
127
  hooks = concat_hooks([], name)
74
128
  hooks.empty? and return @obj.__send__(method_name, *args, &block)
@@ -84,6 +138,15 @@ module RHook
84
138
  inv.proceed()
85
139
  end
86
140
 
141
+ # Wraps the code block to be hookable.
142
+ #
143
+ # @example
144
+ # _rhook.does(:hook_name) { do_something; }
145
+ #
146
+ # @param [Symbol] name The hook-point's name specified on {#bind}.
147
+ # @option opt [Hash] :hint Hint values used through {Invocation#hint}.
148
+ # @yield The code block to be hooked.
149
+ # @return The result of code block. (Replaced if it is changed by hook.)
87
150
  def does(name, opt = {}, &block)
88
151
  hooks = concat_hooks([], name)
89
152
  hooks.empty? and return yield
@@ -99,6 +162,18 @@ module RHook
99
162
  inv.proceed()
100
163
  end
101
164
 
165
+ # Wraps the defined method to be hookable.
166
+ #
167
+ # If possible, using {#to} is recommended than {#on_method}, because if the subclass override the hookable method, the subclasse's code become out of hook target.
168
+ #
169
+ # @example
170
+ # on_method :method_name
171
+ #
172
+ # @overload on_method(*names, opt = {})
173
+ # @param [Symbol] names The method name(s).
174
+ # @option opt [Boolean] :ifdef If true, it doesn't raise error whenever the method is not defined.
175
+ # @raise [NameError] If the method is not defined.
176
+ # @return [Boolean] When :ifdef => true, returns sucess or not, otherwise always true.
102
177
  def on_method(*names_and_opt)
103
178
  success = true
104
179
 
@@ -122,9 +197,11 @@ module RHook
122
197
  success
123
198
  end
124
199
 
125
- # ================================================================
126
- # Internal methods:
127
-
200
+ # ========================================================================
201
+ # @endgroup
202
+ # ========================================================================
203
+
204
+ # @private
128
205
  def concat_hooks(dest, name)
129
206
  if Class === @obj
130
207
  concat_class_hooks(dest, name)
@@ -135,6 +212,7 @@ module RHook
135
212
  dest
136
213
  end
137
214
 
215
+ # @private
138
216
  def concat_class_hooks(dest, name)
139
217
  # use cached one if available
140
218
  if RHook.registry.class_cached_flag_map[name]
@@ -145,7 +223,7 @@ module RHook
145
223
  end
146
224
 
147
225
  hooks = []
148
-
226
+
149
227
  # collect hooks including ancestor classes
150
228
  begin
151
229
  concat_hooks_internal(hooks, name)
@@ -168,25 +246,39 @@ module RHook
168
246
  dest.concat(hooks)
169
247
  end
170
248
 
249
+ # @private
171
250
  def concat_hooks_internal(dest, name)
172
251
  hooks = @hooks_map[name]
173
252
  hooks and dest.concat(hooks)
174
253
  end
175
254
  end #/RHookService
176
255
 
256
+ # The object contains the invocation information.
257
+ #
258
+ # @attr_reader [Object] target The target object that the hook is applied. (Usually same to {#receiver})
259
+ # @attr_reader [Object] receiver The receiver object of this method invocation.
260
+ # @attr [Array<Object>] args The arguments given to the method invocation.
261
+ # @attr [Proc] block The block given to the method invocation
262
+ # @attr_reader [Object] returned The returned value by the method invocation. (Don't set this. To change it, just return by the alternative value from the hook procedure.)
263
+ # @attr_reader [Array<Hook>] hooks (Internally used) The applied hooks on this invocation.
264
+ # @attr [Proc] target_proc (Internally used) The procedure to execute the target method/procedure.
265
+ # @attr [Hash] hint Hint data given by {RHookService#does} / {RHookService#to}.
177
266
  class Invocation < Struct.new(:target, :receiver, :args, :block, :returned, :hooks, :target_proc, :hint)
267
+ # @private
178
268
  def initialize
179
269
  @hook_index = 0
180
270
  end
181
271
 
272
+ # Proceed to execute the next one on hooks-chain. If no more hooks, execute the target method/procedure.
273
+ # @return The returned value from the target method/procedure. (may changed by hook)
182
274
  def proceed
183
275
  hook = hooks[@hook_index]
184
276
  # -- If no more hook was found, calls target procedure and return
185
- hook or return target_proc.call(*args, &block)
277
+ hook or return self.returned = target_proc.call(*args, &block)
186
278
  # -- Set hook pointer to next, then call next hook
187
279
  @hook_index += 1
188
280
  begin
189
- hook.call(self)
281
+ self.returned = hook.call(self)
190
282
  ensure
191
283
  @hook_index -= 1
192
284
  end
@@ -195,15 +287,26 @@ module RHook
195
287
  alias call proceed
196
288
  end #/Invocation
197
289
 
290
+ # The registered hook instance returned by #{RHookService#bind}.
198
291
  class Hook
292
+ # Whether this hook is enabled.
293
+ # @return [Boolean]
199
294
  attr_accessor :enabled
295
+ # The hook procedure registered by {RHookService#bind}.
296
+ # @return [Proc]
200
297
  attr_accessor :hook_proc
201
298
 
299
+ # @private
202
300
  def call(inv)
203
301
  @enabled or return inv.proceed()
204
302
  hook_proc.call(inv)
205
303
  end
206
304
 
305
+ # Enable this hook.
306
+ # @overload enable()
307
+ # @overload enable(&block)
308
+ # @yield If block was given, the hook is enabled only within the given code block. (Note: This is not thread-safe.)
309
+ # @return [self]
207
310
  def enable(&block)
208
311
  @enabled = true
209
312
  if block_given?
@@ -216,31 +319,47 @@ module RHook
216
319
  self
217
320
  end
218
321
 
322
+ # Disable this hook.
323
+ # @return [self]
219
324
  def disable
220
325
  @enabled = false
221
326
  self
222
327
  end
223
328
  end #/Hook
224
329
 
330
+ #
225
331
  class ::Object
332
+ # Get {RHook::RHookService} object bound to this object.
333
+ # @return [RHook::RHookService]
226
334
  def _rhook
227
335
  @_rhook ||= RHook::RHookService.new(self)
228
336
  end
229
337
 
338
+ # @private
230
339
  def _has_rhook?
231
340
  @_rhook ? true : false
232
341
  end
233
342
  end
234
343
 
344
+ # Object to group the hooks for the certain purpose.
345
+ # You can enable/disable the grouped hooks at once.
346
+ #
347
+ # Don't instantiate this class. Use {RHook.group} method.
235
348
  class HookGroup
349
+ # @private
236
350
  def initialize
237
351
  @hooks = []
238
352
  end
239
353
 
354
+ # Add a new hook to this group.
355
+ # @return [self]
240
356
  def add(hook)
241
357
  @hooks << hook
358
+ self
242
359
  end
243
360
 
361
+ # Add any hooks to this group that was registered by #{RHookService#bind} in the given block code.
362
+ # @return [self]
244
363
  def wrap(&block)
245
364
  group_stack = (Thread.current["rhook_group"] ||= [])
246
365
  group_stack << self
@@ -252,6 +371,9 @@ module RHook
252
371
  self
253
372
  end
254
373
 
374
+ # Enable the hooks.
375
+ # @return [self]
376
+ # @see Hook#enable
255
377
  def enable(&block)
256
378
  @hooks.each do |h|
257
379
  h.enable
@@ -266,6 +388,9 @@ module RHook
266
388
  self
267
389
  end
268
390
 
391
+ # Disable the hooks.
392
+ # @return [self]
393
+ # @see Hook#disable
269
394
  def disable
270
395
  @hooks.each do |h|
271
396
  h.disable
@@ -273,13 +398,24 @@ module RHook
273
398
  self
274
399
  end
275
400
 
401
+ # @private
276
402
  def self.add_to_current_groups(hook)
277
- (Thread.current["rhook_group"] || []).each do |group|
403
+ (Thread.current["rhook_group"] || []).each do |group|
278
404
  group.add(hook)
279
405
  end
280
406
  end
281
407
  end #/HookGroup
282
408
 
409
+ # Create the {HookGroup}, and add any hooks to this group that was registered by #{RHookService#bind} in the given block code.
410
+ #
411
+ # @example
412
+ # XXX_feature_for_library = RHook.group {
413
+ # Target._rhook.bind(...) {...}
414
+ # Target2._rhook.bind(...) {...}
415
+ # }
416
+ # XXX_feature_for_library.disable
417
+ #
418
+ # @return [HookGroup]
283
419
  def self.group(&block)
284
420
  HookGroup.new.wrap(&block)
285
421
  end
data/rhook.gemspec CHANGED
@@ -1,44 +1,48 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{rhook}
8
- s.version = "0.1.5"
8
+ s.version = "0.1.6"
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-11-12}
12
+ s.date = %q{2010-12-01}
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 = [
16
16
  "LICENSE",
17
- "README.rdoc"
17
+ "README.rdoc"
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
- ".gitignore",
22
- "LICENSE",
23
- "README.rdoc",
24
- "Rakefile",
25
- "VERSION",
26
- "lib/rhook.rb",
27
- "rhook.gemspec",
28
- "spec/rhook_minor_spec.rb",
29
- "spec/rhook_spec.rb",
30
- "spec/spec.opts",
31
- "spec/spec_helper.rb"
21
+ ".yardopts",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "examples/log_socket_data.rb",
27
+ "lib/rhook.rb",
28
+ "rhook.gemspec",
29
+ "spec/examples/log_buffer_example_spec.rb",
30
+ "spec/rhook_minor_spec.rb",
31
+ "spec/rhook_spec.rb",
32
+ "spec/spec.opts",
33
+ "spec/spec_helper.rb"
32
34
  ]
35
+ s.has_rdoc = %q{yard}
33
36
  s.homepage = %q{http://github.com/kaorukobo/rhook}
34
- s.rdoc_options = ["--charset=UTF-8"]
35
37
  s.require_paths = ["lib"]
36
38
  s.rubygems_version = %q{1.3.7}
37
39
  s.summary = %q{Easily drive AOP & hacking existing library with Ruby}
38
40
  s.test_files = [
41
+ "examples/log_socket_data.rb",
42
+ "spec/examples/log_buffer_example_spec.rb",
39
43
  "spec/rhook_minor_spec.rb",
40
- "spec/rhook_spec.rb",
41
- "spec/spec_helper.rb"
44
+ "spec/rhook_spec.rb",
45
+ "spec/spec_helper.rb"
42
46
  ]
43
47
 
44
48
  if s.respond_to? :specification_version then
@@ -47,11 +51,14 @@ Gem::Specification.new do |s|
47
51
 
48
52
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
53
  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
54
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
50
55
  else
51
56
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
57
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
52
58
  end
53
59
  else
54
60
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
61
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
55
62
  end
56
63
  end
57
64
 
@@ -0,0 +1,66 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "rhook examples" do
4
+ describe "log buffer (hack Logger)" do
5
+ require "logger"
6
+
7
+ # Captures any messages written to Logger and keep in buffer.
8
+ # You can read captured messages by LogBuffer#get
9
+ # or LogBuffer##pull ( also clears buffer ).
10
+ class LogBuffer
11
+ def initialize
12
+ @buf = ""
13
+ # Any log messages are passed to Logger#format_message. Hack it!!
14
+ Logger._rhook.hack(:format_message) do |inv|
15
+ result = inv.call
16
+ @buf << result
17
+ result
18
+ end
19
+ end
20
+
21
+ def clear
22
+ @buf = ""
23
+ end
24
+
25
+ def get
26
+ @buf
27
+ end
28
+
29
+ def pull
30
+ result = get()
31
+ clear()
32
+ result
33
+ end
34
+ end #/LogBuffer
35
+
36
+ # The example application to test.
37
+ # You cannot know whether it success or failed, (by return value or exception)
38
+ # ... it only logs.
39
+ class TargetApp
40
+ def initialize
41
+ @log = Logger.new(STDERR)
42
+ end
43
+
44
+ def success
45
+ @log.info "Success!"
46
+ end
47
+
48
+ def fail
49
+ @log.error "Failed!"
50
+ end
51
+ end
52
+
53
+ example "Use LogBuffer to write test" do
54
+ app = TargetApp.new
55
+
56
+ # start to capture log.
57
+ logbuf = LogBuffer.new
58
+
59
+ app.success
60
+ logbuf.pull.should match(/Success!/)
61
+
62
+ app.fail
63
+ logbuf.pull.should match(/Failed!/)
64
+ end
65
+ end
66
+ end
data/spec/rhook_spec.rb CHANGED
@@ -216,6 +216,51 @@ describe "rhook (advanced usage)" do
216
216
  end
217
217
  # ================================================================
218
218
 
219
+ # ========================================================================
220
+ describe "Invocation object" do
221
+ class Target
222
+ def invocation_object(*args, &block)
223
+ _rhook.to(:hint => {:hintkey => :hintval}).invocation_object_target(*args, &block)
224
+ end
225
+
226
+ def invocation_object_target(*args, &block)
227
+ :returned_value
228
+ end
229
+ end #/Target
230
+
231
+ example "attributes" do
232
+ args = [1, 2]
233
+ block = lambda do
234
+
235
+ end
236
+
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
244
+ :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)
260
+ end
261
+ end
262
+ # ========================================================================
263
+
219
264
  end
220
265
 
221
266
  # ================================================================
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'rubygems'
2
- gem 'rspec'
2
+ gem 'rspec', "< 2.0"
3
3
 
4
4
  $LOAD_PATH.unshift(File.dirname(__FILE__))
5
5
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
@@ -10,3 +10,45 @@ require 'spec/autorun'
10
10
  Spec::Runner.configure do |config|
11
11
 
12
12
  end
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,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rhook
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 23
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 1
8
- - 5
9
- version: 0.1.5
9
+ - 6
10
+ version: 0.1.6
10
11
  platform: ruby
11
12
  authors:
12
13
  - Kaoru Kobo
@@ -14,7 +15,7 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-11-12 00:00:00 +09:00
18
+ date: 2010-12-01 00:00:00 +09:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
@@ -25,6 +26,7 @@ dependencies:
25
26
  requirements:
26
27
  - - ">="
27
28
  - !ruby/object:Gem::Version
29
+ hash: 13
28
30
  segments:
29
31
  - 1
30
32
  - 2
@@ -32,6 +34,22 @@ dependencies:
32
34
  version: 1.2.9
33
35
  type: :development
34
36
  version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: yard
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 7
46
+ segments:
47
+ - 0
48
+ - 6
49
+ - 0
50
+ version: 0.6.0
51
+ type: :development
52
+ version_requirements: *id002
35
53
  description: 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.
36
54
  email: ""
37
55
  executables: []
@@ -43,24 +61,26 @@ extra_rdoc_files:
43
61
  - README.rdoc
44
62
  files:
45
63
  - .document
46
- - .gitignore
64
+ - .yardopts
47
65
  - LICENSE
48
66
  - README.rdoc
49
67
  - Rakefile
50
68
  - VERSION
69
+ - examples/log_socket_data.rb
51
70
  - lib/rhook.rb
52
71
  - rhook.gemspec
72
+ - spec/examples/log_buffer_example_spec.rb
53
73
  - spec/rhook_minor_spec.rb
54
74
  - spec/rhook_spec.rb
55
75
  - spec/spec.opts
56
76
  - spec/spec_helper.rb
57
- has_rdoc: true
77
+ has_rdoc: yard
58
78
  homepage: http://github.com/kaorukobo/rhook
59
79
  licenses: []
60
80
 
61
81
  post_install_message:
62
- rdoc_options:
63
- - --charset=UTF-8
82
+ rdoc_options: []
83
+
64
84
  require_paths:
65
85
  - lib
66
86
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -68,6 +88,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
68
88
  requirements:
69
89
  - - ">="
70
90
  - !ruby/object:Gem::Version
91
+ hash: 3
71
92
  segments:
72
93
  - 0
73
94
  version: "0"
@@ -76,6 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
97
  requirements:
77
98
  - - ">="
78
99
  - !ruby/object:Gem::Version
100
+ hash: 3
79
101
  segments:
80
102
  - 0
81
103
  version: "0"
@@ -87,6 +109,8 @@ signing_key:
87
109
  specification_version: 3
88
110
  summary: Easily drive AOP & hacking existing library with Ruby
89
111
  test_files:
112
+ - examples/log_socket_data.rb
113
+ - spec/examples/log_buffer_example_spec.rb
90
114
  - spec/rhook_minor_spec.rb
91
115
  - spec/rhook_spec.rb
92
116
  - spec/spec_helper.rb
data/.gitignore DELETED
@@ -1,21 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC