peekaboo 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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