peekaboo 0.1.2 → 0.2.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.
@@ -1,3 +1,9 @@
1
+ ## 0.2.0 (October 28, 2010)
2
+
3
+ Features:
4
+
5
+ - Adds support for auto-inclusion
6
+
1
7
  ## 0.1.0 (October 25, 2010)
2
8
 
3
9
  Features:
data/README.md CHANGED
@@ -25,11 +25,11 @@ When creating a new class, include Peekaboo and then call `enable_tracing_on`, p
25
25
  enable_tracing_on :foo, :bar
26
26
 
27
27
  def foo
28
- ...
28
+ #...
29
29
  end
30
30
 
31
31
  def bar
32
- ...
32
+ #...
33
33
  end
34
34
  end
35
35
 
@@ -51,6 +51,15 @@ Now, with tracing enabled, Peekaboo will report when/where those methods are cal
51
51
 
52
52
  @obj.baz :one, 2, "three"
53
53
 
54
+ **NOTE:** Once a class has already included `Peekaboo`, you can call `enable_tracing_on` directly on the class.
55
+
56
+ class SomeClass
57
+ include Peekaboo
58
+ # methods n' such
59
+ end
60
+
61
+ SomeClass.enable_tracing_on :this, :that, :the_other
62
+
54
63
  ## Configuration
55
64
 
56
65
  The default tracer for Peekaboo is an instance of `Logger` streaming to `STDOUT`.
@@ -67,6 +76,46 @@ If this doesn't suit your needs, it is a trivial task to set the tracer to anoth
67
76
  config.trace_with @custom_logger_object
68
77
  end
69
78
 
79
+ ### Auto-inclusion ( Exciting NEW FEATURE )
80
+
81
+ Want to use tracing in classes without having to open up their definitions?
82
+ Simply provide a list of classes to the configuration.
83
+
84
+ Peekaboo.configure do |config|
85
+ config.autoinclude_with Zip, Zap, Boom
86
+ end
87
+
88
+ # Then inside your code somewhere
89
+ Zip.enable_tracing_on # ...
90
+ Zap.enable_tracing_on # ...
91
+ Boom.enable_tracing_on # ...
92
+
93
+ By configuring auto-inclusion, `Peekaboo` will load itself into your class *dynamically* at runtime.
94
+ All that's left for you to do is call `enable_tracing_on` with a list of methods you want to trace.
95
+
96
+ Easy, huh? *It gets better!*
97
+
98
+ This feature also works with class hierarchies, meaning that, if you setup auto-inclusion on a given class,
99
+ it will be enabled for any class that inherits from that class.
100
+
101
+ **This does NOT mean that Peekaboo gets loaded into every subclass, but only that it's available for dynamic inclusion.**
102
+
103
+ class Weapon
104
+ end
105
+
106
+ class Firearm < Weapon
107
+ end
108
+
109
+ class Pistol < Firearm
110
+ end
111
+
112
+ Peeakboo.configure do |config|
113
+ config.autoinclude_with Weapon
114
+ end
115
+
116
+ Pistol.enable_tracing_one # Peekaboo loaded, Weapon & Firearm still left unchanged
117
+ Firearm.enable_tracing_on # Peekaboo loaded, Weapon left unchanged
118
+
70
119
  ## Issues
71
120
 
72
121
  Please report any bugs or issues to the [Issue Tracking System](http://github.com/sgarcia/peekaboo/issues/).
data/Rakefile CHANGED
@@ -6,12 +6,12 @@ require 'yard'
6
6
 
7
7
  Spec::Rake::SpecTask.new(:spec) do |t|
8
8
  t.spec_files = FileList['spec/**/*_spec.rb']
9
- t.warning = true
10
9
  t.verbose = true
11
10
  end
12
11
 
13
12
  Rcov::RcovTask.new(:rcov) do |t|
14
13
  t.test_files = FileList['spec/**/*_spec.rb']
14
+ t.rcov_opts = ['--exclude', '/gems/,spec'] # /gems/,/Library/,spec,.bundle,config
15
15
  t.verbose = true
16
16
  end
17
17
 
@@ -1,18 +1,31 @@
1
1
  require 'peekaboo/configuration'
2
2
 
3
+ # The workhorse of this "Unobtrusive Tracing System".
3
4
  module Peekaboo
4
-
5
5
  class << self
6
+ # @return [Configuration] the current configuration
6
7
  def configuration
7
8
  @configuration ||= Configuration.new
8
9
  end
9
10
 
11
+ # Convenience method added to assist in configuring the system
12
+ # ( see {Configuration} for details on all options ).
13
+ #
14
+ # @example Configuring the system inside your project
15
+ # Peekaboo.configure do |config|
16
+ # config.trace_with MyCustomerLogger.new
17
+ # config.autoinclude_with SomeBaseClass, AnotherSoloClass
18
+ # end
10
19
  def configure
11
20
  yield configuration
12
21
  end
13
22
 
23
+ # Callback used to hook tracing system into any class.
24
+ #
25
+ # @param [Class] klass including class
14
26
  def included klass
15
27
  klass.const_set :PEEKABOO_METHOD_LIST, []
28
+ klass.instance_variable_set :@_hooked_by_peekaboo, true
16
29
  klass.extend SingletonMethods
17
30
 
18
31
  def klass.method_added name
@@ -20,7 +33,28 @@ module Peekaboo
20
33
  end
21
34
  end
22
35
 
23
- # @note Should I add execution time to logs?
36
+ # Modifies a class, and its child classes, to dynamically include module
37
+ # at runtime. This method is used by {Configuration#autoinclude_with}.
38
+ #
39
+ # @param [Class] klass class to modify
40
+ def setup_autoinclusion klass
41
+ def klass.method_missing(method_name, *args, &block)
42
+ if method_name.to_s =~ /^enable_tracing_on$/
43
+ instance_eval { include Peekaboo }
44
+ enable_tracing_on *args
45
+ else
46
+ super
47
+ end
48
+ end
49
+ end
50
+
51
+ # Takes a class object and method name, aliases the original method,
52
+ # and redefines the method with injected tracing.
53
+ #
54
+ # @note Should I add execution time to tracing? Configurable?
55
+ #
56
+ # @param [Class] klass method owner
57
+ # @param [Symbol] name method to trace
24
58
  def wrap_method klass, name
25
59
  return if @_adding_a_method
26
60
  @_adding_a_method = true
@@ -48,21 +82,44 @@ module Peekaboo
48
82
  end
49
83
  end
50
84
 
85
+ # Contains methods added to every class that includes the *Peekaboo* module,
86
+ # either through _direct_ or _auto_ inclusion.
51
87
  module SingletonMethods
88
+ # @return [Array<Symbol>]
89
+ # a list of instance methods that are being traced inside calling class
52
90
  def peek_list
53
91
  self::PEEKABOO_METHOD_LIST
54
92
  end
55
93
 
94
+ # Enables instance method tracing on calling class.
95
+ #
96
+ # @example Trace a couple of methods
97
+ # class SomeClass
98
+ # include Peekaboo
99
+ #
100
+ # def method1; end
101
+ # def method2; end
102
+ # def method3; end
103
+ # end
104
+ #
105
+ # # Tracing will be performed on method1(), method2(), but NOT method3()
106
+ # SomeClass.enable_tracing_on :method1, :method2
107
+ #
108
+ # @param [*Symbol] method_names
109
+ # the list of methods that you want to trace
110
+ # @raise [RuntimeError]
111
+ # when attempting to add a method that is already being traced
56
112
  def enable_tracing_on *method_names
113
+ include Peekaboo unless @_hooked_by_peekaboo
114
+
57
115
  method_names.each do |method_name|
58
116
  unless peek_list.include? method_name
59
117
  peek_list << method_name
60
- Peekaboo.wrap_method(self, method_name) if self.instance_methods(false).include? method_name.to_s
118
+ Peekaboo.wrap_method self, method_name if self.instance_methods(false).include? method_name.to_s
61
119
  else
62
120
  raise "Already tracing `#{method_name}'"
63
121
  end
64
122
  end
65
123
  end
66
124
  end
67
-
68
125
  end
@@ -1,10 +1,34 @@
1
1
  require 'logger'
2
+ require 'set'
2
3
 
3
4
  module Peekaboo
5
+ # Rome wasn't built in a day...
6
+ # Documentation soon to come.
4
7
  class Configuration
5
8
 
6
9
  TRACE_LEVELS = [ :debug, :info, :warn, :error, :fatal, :unknown ]
7
10
 
11
+ def initialize
12
+ @autoincluded = Set.new
13
+ end
14
+
15
+ def autoincluded
16
+ @autoincluded.to_a
17
+ end
18
+
19
+ def autoinclude_with *klasses
20
+ if klasses.all? { |klass| klass.instance_of? Class }
21
+ @autoincluded.merge klasses
22
+
23
+ autoincluded.each do |klass|
24
+ next if klass.included_modules.include? Peekaboo.to_s
25
+ Peekaboo.setup_autoinclusion klass
26
+ end
27
+ else
28
+ raise 'Auto-inclusion can only be used with classes'
29
+ end
30
+ end
31
+
8
32
  def tracer
9
33
  @tracer ||= Logger.new STDOUT
10
34
  end
@@ -1,8 +1,9 @@
1
1
  module Peekaboo
2
+ # If you cannot figure this one out, you're on your own!
2
3
  module Version
3
4
  MAJOR = 0
4
- MINOR = 1
5
- PATCH = 2
5
+ MINOR = 2
6
+ PATCH = 0
6
7
 
7
8
  STRING = [MAJOR, MINOR, PATCH].join('.')
8
9
  end
@@ -6,29 +6,96 @@ describe Peekaboo::Configuration do
6
6
  @config = Peekaboo::Configuration.new
7
7
  end
8
8
 
9
- context "#tracer (default)" do
10
- it "should initialize tracing" do
9
+ context "autoinclusion" do
10
+ it "should not reference any class by default" do
11
+ @config.autoincluded.should be_empty
12
+ end
13
+
14
+ it "should raise an exception when trying to add a non-class objects" do
15
+ lambda {
16
+ [ [Object.new], ["", Hash] ].each { |object_list| @config.autoinclude_with *object_list }
17
+ }.should raise_exception("Auto-inclusion can only be used with classes")
18
+ end
19
+
20
+ it "should allow class objects to be added" do
21
+ test_class1 = new_test_class
22
+ test_class2 = new_test_class
23
+ test_class3 = new_test_class
24
+
25
+ lambda {
26
+ [ [test_class1],
27
+ [test_class1, test_class2],
28
+ [test_class1, test_class2, test_class3]
29
+ ].each { |klass_list| @config.autoinclude_with *klass_list }
30
+ }.should_not raise_exception
31
+ end
32
+
33
+ it "should maintain a list of classes to use" do
34
+ test_class1 = new_test_class
35
+ test_class2 = new_test_class
36
+ test_class3 = new_test_class
37
+
38
+ @config.autoinclude_with test_class1, test_class2, test_class3
39
+ @config.autoincluded.should =~ [ test_class1, test_class2, test_class3 ]
40
+ end
41
+
42
+ it "should ensure its list of classes is unique" do
43
+ test_class1 = new_test_class
44
+ test_class2 = new_test_class
45
+
46
+ @config.autoinclude_with test_class1, test_class2, test_class1, test_class2
47
+ @config.autoincluded.should =~ [ test_class1, test_class2 ]
48
+ end
49
+
50
+ it "should auto-include Peekaboo into any class in its list" do
51
+ test_class = new_test_class
52
+ @config.autoinclude_with test_class
53
+ lambda { test_class.enable_tracing_on }.should_not raise_exception
54
+ end
55
+
56
+ it "should auto-include Peekaboo into any class that inherits from a class in its list" do
57
+ parent_class = new_test_class
58
+ child_class = Class.new(parent_class)
59
+ @config.autoinclude_with parent_class
60
+ lambda { child_class.enable_tracing_on }.should_not raise_exception
61
+ end
62
+ end
63
+
64
+ context "tracing" do
65
+ it "should have a default implementation" do
11
66
  @config.tracer.should_not be_nil
12
67
  end
13
68
 
14
- it "should adhere to the standard 'Logger' interface" do
69
+ it "should maintain the 'Logger' interface by default" do
15
70
  [ :debug, :info, :warn, :error, :fatal, :unknown ].each { |logger_msg|
16
71
  @config.tracer.should respond_to(logger_msg)
17
72
  }
18
73
  end
19
- end
20
74
 
21
- context "#trace_with" do
22
- it "should set a new tracer for use" do
23
- new_tracer = Logger.new STDOUT
75
+ it "should use any tracer that maintains the 'Logger' interface" do
76
+ tmp_file = Tempfile.new 'some-log.txt'
77
+ some_logger_obj = MyLogger = Class.new do
78
+ def debug(msg) ; end
79
+ def info(msg) ; end
80
+ def warn(msg) ; end
81
+ def error(msg) ; end
82
+ def fatal(msg) ; end
83
+ def unknown(msg) ; end
84
+ end.new
85
+
86
+ tracers = [ Logger.new(tmp_file.path), some_logger_obj ]
87
+
88
+ tracers.each do |some_tracer|
89
+ @config.trace_with some_tracer
90
+ @config.tracer.should == some_tracer
91
+ end
24
92
 
25
- @config.trace_with new_tracer
26
- @config.tracer.should == new_tracer
93
+ tmp_file.close!
27
94
  end
28
95
 
29
- it "should enforce that new tracer adheres to the standard 'Logger' interface" do
96
+ it "should raise an exception when attempting to use an object that does not maintaint the 'Logger' interface" do
30
97
  lambda {
31
- @config.trace_with 'garbage value'
98
+ @config.trace_with 'garbage object'
32
99
  }.should raise_exception('Tracer must respond to debug(), info(), warn(), error(), fatal(), and unknown()')
33
100
  end
34
101
  end
@@ -4,7 +4,7 @@ describe Peekaboo do
4
4
 
5
5
  context ".configuration" do
6
6
  it "should hold a reference to the current configuration" do
7
- Peekaboo.configuration.should be_an_instance_of(Peekaboo::Configuration)
7
+ Peekaboo.configuration.should be_an_instance_of Peekaboo::Configuration
8
8
  end
9
9
  end
10
10
 
@@ -23,7 +23,7 @@ describe Peekaboo do
23
23
  end
24
24
 
25
25
  it "should be a singleton method added to any including class" do
26
- @test_class.should respond_to(:enable_tracing_on)
26
+ @test_class.should respond_to :enable_tracing_on
27
27
  end
28
28
 
29
29
  it "should store a list of methods to trace on any including class" do
@@ -36,7 +36,7 @@ describe Peekaboo do
36
36
  @test_class.enable_tracing_on :some_method
37
37
  lambda {
38
38
  @test_class.enable_tracing_on :some_method
39
- }.should raise_exception("Already tracing `some_method'")
39
+ }.should raise_exception "Already tracing `some_method'"
40
40
  end
41
41
  end
42
42
 
@@ -53,7 +53,7 @@ describe Peekaboo do
53
53
  end
54
54
 
55
55
  it "should not take place on unlisted methods" do
56
- @tracer.should_not_receive(:info)
56
+ @tracer.should_not_receive :info
57
57
  @test_instance.method_no_tracing
58
58
  end
59
59
 
@@ -103,4 +103,56 @@ describe Peekaboo do
103
103
  end
104
104
  end
105
105
 
106
+ context "autoinclusion tracing" do
107
+ before(:all) do
108
+ @tracer = Peekaboo.configuration.tracer
109
+ end
110
+
111
+ it "should inject functionality into an auto-included class" do
112
+ test_class = new_test_class
113
+ Peekaboo.configure { |config| config.autoinclude_with test_class }
114
+ test_class.enable_tracing_on :method_no_args
115
+
116
+ @tracer.should_receive(:info).with trace_message "Invoking: #{test_class}#method_no_args with [] ==> Returning: nil"
117
+ test_class.new.method_no_args
118
+ end
119
+
120
+ it "should inject functionality into any class that inherits from an auto-included class" do
121
+ parent_class = new_test_class
122
+ child_class = Class.new(parent_class) do
123
+ def another_method() ; end
124
+ end
125
+
126
+ Peekaboo.configure { |config| config.autoinclude_with parent_class }
127
+ child_class.enable_tracing_on :another_method
128
+
129
+ @tracer.should_receive(:info).with trace_message "Invoking: #{child_class}#another_method with [] ==> Returning: nil"
130
+ child_class.new.another_method
131
+ end
132
+
133
+ it "should not inject functionality into classes that are not auto-included" do
134
+ test_class = new_test_class
135
+ another_test_class = new_test_class
136
+
137
+ Peekaboo.configure { |config| config.autoinclude_with test_class }
138
+
139
+ lambda { another_test_class.enable_tracing_on :method_no_args }.should raise_exception NoMethodError
140
+ end
141
+
142
+ it "should maintain unique tracing method lists across an inheritance chain" do
143
+ parent_class = new_test_class
144
+ child_class = Class.new(parent_class) do
145
+ def another_method() ; end
146
+ end
147
+
148
+ Peekaboo.configure { |config| config.autoinclude_with parent_class }
149
+
150
+ parent_class.enable_tracing_on :method_no_args
151
+ child_class.enable_tracing_on :another_method
152
+
153
+ parent_class.peek_list.should =~ [:method_no_args]
154
+ child_class.peek_list.should =~ [:another_method]
155
+ end
156
+ end
157
+
106
158
  end
@@ -1,11 +1,13 @@
1
1
  $:.unshift File.expand_path('../../lib', __FILE__)
2
2
 
3
3
  require 'rubygems'
4
- require 'peekaboo'
5
4
  require 'ruby-debug'
5
+ require 'tempfile'
6
6
  require 'spec'
7
7
  require 'spec/autorun'
8
8
 
9
+ require 'peekaboo'
10
+
9
11
  Spec::Runner.configure do |config|
10
12
  def new_test_class
11
13
  Class.new do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: peekaboo
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
8
  - 2
10
- version: 0.1.2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sonny Ruben Garcia
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-26 00:00:00 -05:00
18
+ date: 2010-10-28 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency