peekaboo 0.3.0 → 0.4.0
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/CHANGELOG.md +7 -0
- data/README.md +20 -7
- data/lib/peekaboo.rb +11 -19
- data/lib/peekaboo/singleton_methods.rb +53 -41
- data/lib/peekaboo/version.rb +1 -1
- data/spec/peekaboo/configuration_spec.rb +2 -2
- data/spec/peekaboo_spec.rb +54 -129
- metadata +7 -3
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -33,7 +33,7 @@ a number of class methods that can be used to create and inspect traced methods.
|
|
33
33
|
|
34
34
|
It is also possible to enable tracing without explicitly including Peekaboo. See the ["Auto-inclusion"](#Auto-inclusion) for details.
|
35
35
|
|
36
|
-
### Method Tracing
|
36
|
+
### Enabling Method Tracing
|
37
37
|
|
38
38
|
Once Peekaboo has been enabled within a class you can call `enable_tracing_for`, inside the class definition or
|
39
39
|
directly on the class object, passing it a structured hash of method names. The hash should contain 1 or 2 keys,
|
@@ -54,13 +54,26 @@ Now, with tracing enabled, Peekaboo will report when/where those methods are cal
|
|
54
54
|
|
55
55
|
# Peekaboo tracer receives the following message when .first_class_method is called below:
|
56
56
|
# "File:Line ( Example.first_class_method called with [] ==> Returning: 'whatever gets returned' )"
|
57
|
+
|
57
58
|
Example.first_class_method
|
58
59
|
|
59
60
|
# @obj is an instance of Example
|
60
61
|
# Peekaboo tracer receives the following message when #baz is called below:
|
61
62
|
# "File:Line ( Example#an_instance_method called with [:one, 2, "three"] ==> Returning: 'whatever gets returned' )"
|
63
|
+
|
62
64
|
@obj.an_instance_method :one, 2, "three"
|
63
65
|
|
66
|
+
### Disabling Method Tracing
|
67
|
+
|
68
|
+
Because your application may only want to trace certain methods at certain times, you can disable tracing for any method that
|
69
|
+
was previously being traced. The interface arguments are the same as above except that you will pass them to `disable_tracing_for`.
|
70
|
+
|
71
|
+
# Peekaboo is tracing .something and #something_else
|
72
|
+
|
73
|
+
Example.disable_tracing_for :singleton_methods => [:something], :instance_methods => [:something_else]
|
74
|
+
|
75
|
+
# Peekaboo has now restored these methods to an "untraced" state
|
76
|
+
|
64
77
|
### Pre-registration of Methods
|
65
78
|
|
66
79
|
Sometimes, in Ruby, we need to define methods at runtime based on some aspect of our application. Fortunately,
|
@@ -113,12 +126,12 @@ Simply provide a list of classes to the configuration.
|
|
113
126
|
end
|
114
127
|
|
115
128
|
# Then inside your code somewhere
|
116
|
-
Zip.
|
117
|
-
Zap.
|
118
|
-
Boom.
|
129
|
+
Zip.enable_tracing_for # ...
|
130
|
+
Zap.enable_tracing_for # ...
|
131
|
+
Boom.enable_tracing_for # ...
|
119
132
|
|
120
133
|
By configuring auto-inclusion, `Peekaboo` will load itself into your class *dynamically* at runtime.
|
121
|
-
All that's left for you to do is call `
|
134
|
+
All that's left for you to do is call `enable_tracing_for` with a list of methods you want to trace.
|
122
135
|
|
123
136
|
Easy, huh? *It gets better!*
|
124
137
|
|
@@ -140,8 +153,8 @@ it will be enabled for any class that inherits from that class.
|
|
140
153
|
config.autoinclude_with Weapon
|
141
154
|
end
|
142
155
|
|
143
|
-
Pistol.
|
144
|
-
Firearm.
|
156
|
+
Pistol.enable_tracing_for # Peekaboo loaded, Weapon & Firearm still left unchanged
|
157
|
+
Firearm.enable_tracing_for # Peekaboo loaded, Weapon left unchanged
|
145
158
|
|
146
159
|
## Issues
|
147
160
|
|
data/lib/peekaboo.rb
CHANGED
@@ -38,29 +38,11 @@ module Peekaboo
|
|
38
38
|
klass.const_set :PEEKABOO_METHOD_MAP, { :singleton_methods => Set.new, :instance_methods => Set.new }.freeze
|
39
39
|
klass.instance_variable_set :@_hooked_by_peekaboo, true
|
40
40
|
klass.extend SingletonMethods
|
41
|
-
|
42
|
-
def klass.method_added name
|
43
|
-
Peekaboo.wrap self, name, :instance if traced_instance_methods.include? name
|
44
|
-
end
|
45
|
-
|
46
|
-
def klass.singleton_method_added name
|
47
|
-
Peekaboo.wrap self, name, :singleton if traced_singleton_methods.include? name
|
48
|
-
end
|
49
41
|
end
|
50
42
|
|
51
43
|
# @private
|
52
44
|
def setup_autoinclusion klass
|
53
|
-
|
54
|
-
# compatibility with {#enable_tracing_on}. This will become
|
55
|
-
# much simpler when that method is removed.
|
56
|
-
def klass.method_missing(method_name, *args, &block)
|
57
|
-
if method_name.to_s =~ /^enable_tracing_(on|for)$/
|
58
|
-
instance_eval { include Peekaboo }
|
59
|
-
__send__ method_name, *args
|
60
|
-
else
|
61
|
-
super
|
62
|
-
end
|
63
|
-
end
|
45
|
+
klass.extend SingletonMethods::AutoInclusion
|
64
46
|
end
|
65
47
|
|
66
48
|
# @private
|
@@ -81,6 +63,16 @@ module Peekaboo
|
|
81
63
|
end
|
82
64
|
end
|
83
65
|
|
66
|
+
# @private
|
67
|
+
def unwrap klass, method_name, target
|
68
|
+
removal_snippet = "alias_method :#{method_name}, :original_#{method_name}"
|
69
|
+
case target
|
70
|
+
when :singleton then klass.instance_eval "class << self ; #{removal_snippet} ; end"
|
71
|
+
when :instance then klass.class_eval removal_snippet
|
72
|
+
else raise 'Only :class and :instance are valid targets'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
84
76
|
private
|
85
77
|
|
86
78
|
def wrap_instance_method klass, method_name, original_method_name
|
@@ -56,8 +56,35 @@ module Peekaboo
|
|
56
56
|
_register_traceables_ method_map[:singleton_methods], :singleton
|
57
57
|
end
|
58
58
|
|
59
|
+
# Removes singleton and instance method tracing. This can be called in
|
60
|
+
# exactly the same fashion as {#enable_tracing_for enable_tracing_for}.
|
61
|
+
#
|
62
|
+
# @param [Hash] method_map a list of methods to trace
|
63
|
+
# @option method_map [Array<Symbol>] :singleton_methods ([]) singleton method list
|
64
|
+
# @option method_map [Array<Symbol>] :instance_methods ([]) instance method list
|
65
|
+
def disable_tracing_for method_map
|
66
|
+
method_map = { :singleton_methods => [], :instance_methods => [] }.merge method_map
|
67
|
+
|
68
|
+
_unregister_traceables_ method_map[:instance_methods], :instance
|
69
|
+
_unregister_traceables_ method_map[:singleton_methods], :singleton
|
70
|
+
end
|
71
|
+
|
59
72
|
private
|
60
73
|
|
74
|
+
# Hooks tracing for instance methods added after registration.
|
75
|
+
#
|
76
|
+
# @param [Symbol] name method name
|
77
|
+
def method_added name
|
78
|
+
Peekaboo.wrap self, name, :instance if traced_instance_methods.include? name
|
79
|
+
end
|
80
|
+
|
81
|
+
# Hooks tracing for singleton methods added after registration.
|
82
|
+
#
|
83
|
+
# @param [Symbol] name method name
|
84
|
+
def singleton_method_added name
|
85
|
+
Peekaboo.wrap self, name, :singleton if traced_singleton_methods.include? name
|
86
|
+
end
|
87
|
+
|
61
88
|
# Registers a list of method signatures and optionally enables tracing on them.
|
62
89
|
# Tracing will only be "enabled" if the method exists and has not already been registered.
|
63
90
|
#
|
@@ -75,52 +102,37 @@ module Peekaboo
|
|
75
102
|
end
|
76
103
|
end
|
77
104
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
public
|
83
|
-
|
84
|
-
# @return [Array<Symbol>]
|
85
|
-
# a list of instance methods that are being traced inside calling class
|
86
|
-
# @deprecated
|
87
|
-
# this method will be removed in version 0.4.0, use {#traced_method_map} instead
|
88
|
-
def peek_list
|
89
|
-
traced_instance_methods.to_a
|
90
|
-
end
|
91
|
-
|
92
|
-
# Enables instance method tracing on calling class.
|
93
|
-
#
|
94
|
-
# @example Trace a couple of methods
|
95
|
-
# class SomeClass
|
96
|
-
# include Peekaboo
|
97
|
-
#
|
98
|
-
# def method1; end
|
99
|
-
# def method2; end
|
100
|
-
# def method3; end
|
101
|
-
# end
|
102
|
-
#
|
103
|
-
# # Tracing will be performed on method1(), method2(), but NOT method3()
|
104
|
-
# SomeClass.enable_tracing_on :method1, :method2
|
105
|
+
# Unregisters a list of method signatures and optionally disables tracing on them.
|
106
|
+
# Tracing will only be "disabled" if the method exists and was previously being traced.
|
105
107
|
#
|
106
|
-
# @param [
|
107
|
-
#
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
108
|
+
# @param [Array<Symbol>] method_list methods to register
|
109
|
+
# @param [Symbol] target specifies the receiver, either +:singleton+ or +:instance+
|
110
|
+
def _unregister_traceables_ method_list, target
|
111
|
+
method_list.each do |method_name|
|
112
|
+
target_method_list = __send__ :"traced_#{target}_methods"
|
113
|
+
|
114
|
+
if target_method_list.include? method_name
|
115
|
+
target_method_list.delete method_name
|
116
|
+
existing_methods = self.__send__(:"#{target}_methods", false).map(&:to_sym)
|
117
|
+
Peekaboo.unwrap self, method_name, target if existing_methods.include? method_name
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
module AutoInclusion
|
123
|
+
|
124
|
+
private
|
114
125
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
Peekaboo.wrap self, method_name, :instance if method_list.include? method_name
|
126
|
+
def method_missing(method_name, *args, &block)
|
127
|
+
if method_name.to_s =~ /^enable_tracing_for$/
|
128
|
+
instance_eval { include Peekaboo }
|
129
|
+
enable_tracing_for *args
|
120
130
|
else
|
121
|
-
|
131
|
+
super
|
122
132
|
end
|
123
133
|
end
|
134
|
+
|
124
135
|
end
|
136
|
+
|
125
137
|
end
|
126
138
|
end
|
data/lib/peekaboo/version.rb
CHANGED
@@ -50,14 +50,14 @@ describe Peekaboo::Configuration do
|
|
50
50
|
it "should auto-include Peekaboo into any class in its list" do
|
51
51
|
test_class = new_test_class
|
52
52
|
@config.autoinclude_with test_class
|
53
|
-
lambda { test_class.
|
53
|
+
lambda { test_class.enable_tracing_for({}) }.should_not raise_exception
|
54
54
|
end
|
55
55
|
|
56
56
|
it "should auto-include Peekaboo into any class that inherits from a class in its list" do
|
57
57
|
parent_class = new_test_class
|
58
58
|
child_class = Class.new(parent_class)
|
59
59
|
@config.autoinclude_with parent_class
|
60
|
-
lambda { child_class.
|
60
|
+
lambda { child_class.enable_tracing_for({}) }.should_not raise_exception
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
data/spec/peekaboo_spec.rb
CHANGED
@@ -14,7 +14,7 @@ describe Peekaboo do
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
context "
|
17
|
+
context "enabling tracing" do
|
18
18
|
before(:each) do
|
19
19
|
@tracer = Peekaboo.configuration.tracer
|
20
20
|
@test_class = new_test_class.instance_eval { include Peekaboo }
|
@@ -268,148 +268,73 @@ describe Peekaboo do
|
|
268
268
|
end
|
269
269
|
end
|
270
270
|
|
271
|
-
|
272
|
-
### OLD SPECIFICATIONS: Remove when moving to version 0.4.0 ###
|
273
|
-
|
274
|
-
|
275
|
-
context ".enable_tracing_on (old)" do
|
271
|
+
context "disabling tracing" do
|
276
272
|
before(:each) do
|
277
|
-
@test_class = new_test_class
|
278
|
-
@test_class.instance_eval { include Peekaboo }
|
279
|
-
end
|
280
|
-
|
281
|
-
it "should be a singleton method added to any including class" do
|
282
|
-
@test_class.should respond_to :enable_tracing_on
|
283
|
-
end
|
284
|
-
|
285
|
-
it "should store a list of methods to trace on any including class" do
|
286
|
-
methods_to_trace = [:method_no_args, :method_one_arg]
|
287
|
-
@test_class.enable_tracing_on *methods_to_trace
|
288
|
-
@test_class.peek_list.should =~ methods_to_trace
|
289
|
-
end
|
290
|
-
|
291
|
-
it "should raise an exception when trying to add a method that is already being traced" do
|
292
|
-
@test_class.enable_tracing_on :some_method
|
293
|
-
lambda {
|
294
|
-
@test_class.enable_tracing_on :some_method
|
295
|
-
}.should raise_exception "Already tracing `some_method'"
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
context "instance method tracing (old)" do
|
300
|
-
before(:all) do
|
301
|
-
@test_class = new_test_class
|
302
|
-
@test_class.instance_eval do
|
303
|
-
include Peekaboo
|
304
|
-
enable_tracing_on :method_no_args, :method_one_arg, :method_two_args, :method_optional_args, :method_variable_args, :method_raises
|
305
|
-
end
|
306
|
-
|
307
|
-
@test_instance = @test_class.new
|
308
273
|
@tracer = Peekaboo.configuration.tracer
|
274
|
+
@test_class = new_test_class.instance_eval { include Peekaboo }
|
275
|
+
@test_class.enable_tracing_for :singleton_methods => [:say_hello, :hello, :add, :happy?, :comma_list, :kaboom],
|
276
|
+
:instance_methods => [:say_goodbye, :goodbye, :subtract, :sad?, :pipe_list, :crash]
|
309
277
|
end
|
310
278
|
|
311
|
-
it "should not
|
312
|
-
|
313
|
-
@
|
314
|
-
end
|
315
|
-
|
316
|
-
it "should show listed methods with no arguments" do
|
317
|
-
@tracer.should_receive(:info).with trace_message "Invoking: #{@test_class}#method_no_args with [] ==> Returning: nil"
|
318
|
-
@test_instance.method_no_args
|
319
|
-
end
|
320
|
-
|
321
|
-
it "should show listed methods with standard arguments" do
|
322
|
-
@tracer.should_receive(:info).
|
323
|
-
with trace_message %{Invoking: #{@test_class}#method_one_arg with ["one"] ==> Returning: nil}
|
324
|
-
@test_instance.method_one_arg 'one'
|
325
|
-
|
326
|
-
@tracer.should_receive(:info).
|
327
|
-
with trace_message %{Invoking: #{@test_class}#method_two_args with ["one", "two"] ==> Returning: nil}
|
328
|
-
@test_instance.method_two_args 'one', 'two'
|
329
|
-
end
|
330
|
-
|
331
|
-
it "should show methods with optional arguments" do
|
332
|
-
@tracer.should_receive(:info).
|
333
|
-
with trace_message %{Invoking: #{@test_class}#method_optional_args with [] ==> Returning: nil}
|
334
|
-
@test_instance.method_optional_args
|
335
|
-
|
336
|
-
@tracer.should_receive(:info).
|
337
|
-
with trace_message %{Invoking: #{@test_class}#method_optional_args with ["override"] ==> Returning: nil}
|
338
|
-
@test_instance.method_optional_args 'override'
|
279
|
+
it "should not raise an exception when methods do not exist and have not been pre-registered" do
|
280
|
+
methods = { :singleton_methods => [:missing_class_def], :instance_methods => [:missing_instance_def] }
|
281
|
+
lambda { @test_class.disable_tracing_for methods }.should_not raise_exception
|
339
282
|
end
|
340
283
|
|
341
|
-
it "should
|
342
|
-
|
343
|
-
|
344
|
-
@
|
345
|
-
|
346
|
-
@tracer.should_receive(:info).
|
347
|
-
with trace_message %{Invoking: #{@test_class}#method_variable_args with ["one"] ==> Returning: nil}
|
348
|
-
@test_instance.method_variable_args 'one'
|
349
|
-
|
350
|
-
@tracer.should_receive(:info).
|
351
|
-
with trace_message %{Invoking: #{@test_class}#method_variable_args with ["one", "two"] ==> Returning: nil}
|
352
|
-
@test_instance.method_variable_args 'one', 'two'
|
284
|
+
it "should not raise an exception when methods do not exist and have been pre-registered" do
|
285
|
+
methods = { :singleton_methods => [:missing_class_def], :instance_methods => [:missing_instance_def] }
|
286
|
+
@test_class.enable_tracing_for methods
|
287
|
+
lambda { @test_class.disable_tracing_for methods }.should_not raise_exception
|
353
288
|
end
|
354
289
|
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
@
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
context "autoinclusion tracing (old)" do
|
365
|
-
before(:all) do
|
366
|
-
@tracer = Peekaboo.configuration.tracer
|
367
|
-
end
|
368
|
-
|
369
|
-
it "should inject functionality into an auto-included class" do
|
370
|
-
test_class = new_test_class
|
371
|
-
Peekaboo.configure { |config| config.autoinclude_with test_class }
|
372
|
-
test_class.enable_tracing_on :method_no_args
|
373
|
-
|
374
|
-
@tracer.should_receive(:info).with trace_message "Invoking: #{test_class}#method_no_args with [] ==> Returning: nil"
|
375
|
-
test_class.new.method_no_args
|
376
|
-
end
|
377
|
-
|
378
|
-
it "should inject functionality into any class that inherits from an auto-included class" do
|
379
|
-
parent_class = new_test_class
|
380
|
-
child_class = Class.new(parent_class) do
|
381
|
-
def another_method() ; end
|
290
|
+
context "on class methods" do
|
291
|
+
it "should remove the method name for the list of traced methods" do
|
292
|
+
lambda {
|
293
|
+
@test_class.disable_tracing_for :singleton_methods => [:say_hello]
|
294
|
+
}.should change(@test_class.traced_singleton_methods, :size).by(-1)
|
295
|
+
|
296
|
+
lambda {
|
297
|
+
@test_class.disable_tracing_for :singleton_methods => [:hello, :add]
|
298
|
+
}.should change(@test_class.traced_singleton_methods, :size).by(-2)
|
382
299
|
end
|
383
|
-
|
384
|
-
Peekaboo.configure { |config| config.autoinclude_with parent_class }
|
385
|
-
child_class.enable_tracing_on :another_method
|
386
300
|
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
lambda { another_test_class.enable_tracing_on :method_no_args }.should raise_exception NoMethodError
|
301
|
+
it "should properly restore the original method to an untraced state" do
|
302
|
+
@test_class.disable_tracing_for :singleton_methods => [:say_hello]
|
303
|
+
@tracer.should_not_receive :info
|
304
|
+
@test_class.say_hello.should == 'hello'
|
305
|
+
|
306
|
+
@test_class.disable_tracing_for :singleton_methods => [:hello, :add]
|
307
|
+
@tracer.should_not_receive :info
|
308
|
+
@test_class.hello('you').should == 'hello you'
|
309
|
+
@test_class.add(5, 4).should == 9
|
310
|
+
end
|
398
311
|
end
|
399
312
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
def another_method() ; end
|
313
|
+
context "on instance methods" do
|
314
|
+
before(:each) do
|
315
|
+
@test_instance = @test_class.new
|
404
316
|
end
|
405
317
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
318
|
+
it "should remove the method name for the list of traced methods" do
|
319
|
+
lambda {
|
320
|
+
@test_class.disable_tracing_for :instance_methods => [:say_goodbye]
|
321
|
+
}.should change(@test_class.traced_instance_methods, :size).by(-1)
|
322
|
+
|
323
|
+
lambda {
|
324
|
+
@test_class.disable_tracing_for :instance_methods => [:goodbye, :subtract]
|
325
|
+
}.should change(@test_class.traced_instance_methods, :size).by(-2)
|
326
|
+
end
|
327
|
+
|
328
|
+
it "should properly restore the original method to an untraced state" do
|
329
|
+
@test_class.disable_tracing_for :instance_methods => [:say_goodbye]
|
330
|
+
@tracer.should_not_receive :info
|
331
|
+
@test_instance.say_goodbye.should == 'goodbye'
|
332
|
+
|
333
|
+
@test_class.disable_tracing_for :instance_methods => [:goodbye, :subtract]
|
334
|
+
@tracer.should_not_receive :info
|
335
|
+
@test_instance.goodbye('mother').should == 'goodbye mother'
|
336
|
+
@test_instance.subtract(100, 99).should == 1
|
337
|
+
end
|
413
338
|
end
|
414
339
|
end
|
415
340
|
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: peekaboo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
+
- 4
|
8
9
|
- 0
|
9
|
-
version: 0.
|
10
|
+
version: 0.4.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Sonny Ruben Garcia
|
@@ -14,7 +15,7 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-13 00:00:00 -06: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: 17
|
28
30
|
segments:
|
29
31
|
- 1
|
30
32
|
- 0
|
@@ -70,6 +72,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
70
72
|
requirements:
|
71
73
|
- - ">="
|
72
74
|
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
73
76
|
segments:
|
74
77
|
- 0
|
75
78
|
version: "0"
|
@@ -78,6 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
81
|
requirements:
|
79
82
|
- - ">="
|
80
83
|
- !ruby/object:Gem::Version
|
84
|
+
hash: 3
|
81
85
|
segments:
|
82
86
|
- 0
|
83
87
|
version: "0"
|