peekaboo 0.2.1 → 0.3.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/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  .yardoc/*
2
2
  doc/*
3
3
  coverage/*
4
+ Gemfile.lock
5
+ .bundle/*
@@ -0,0 +1,3 @@
1
+ --no-private
2
+ lib/**/*.rb -
3
+ CHANGELOG.md
@@ -1,3 +1,16 @@
1
+ # Changelog
2
+
3
+ ## 0.3.0 (November 8, 2010)
4
+
5
+ Features:
6
+
7
+ - Adds support for class & instance method tracing via `.enable_tracing_for`
8
+ - Adds convenience methods for inspecting traced methods within a class
9
+ - `.traced_method_map`
10
+ - `.traced_instance_methods`
11
+ - `.traced_singleton_methods`
12
+ - Deprecates `.enable_tracing_on` & `.peek_list`
13
+
1
14
  ## 0.2.1 (November 4, 2010)
2
15
 
3
16
  Bugfix:
@@ -16,4 +29,3 @@ Features:
16
29
 
17
30
  - Adds support for instance method tracing
18
31
  - Configurable tracer via `Peekaboo.configure`
19
-
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :gemcutter
2
+
3
+ gem "rake"
4
+ gem "rspec", "1.3.1"
5
+ gem "rcov", "0.9.9"
6
+ gem "yard", "0.6.1"
7
+ gem "bluecloth", "2.0.9"
8
+ gem (RUBY_VERSION =~ /^1\.9/ ? "ruby-debug19" : "ruby-debug")
data/README.md CHANGED
@@ -1,67 +1,94 @@
1
- # Peekaboo: Unobtrusive method tracing for Ruby classes
1
+ # Peekaboo - Unobtrusive method tracing for Ruby classes
2
2
 
3
3
  Do you find yourself constantly adding log statements to a lot of the methods in your project?
4
4
  Does it lead to a lot of duplication and make your code feel less "elegant"?
5
5
  Peekaboo offers an alternative approach to tracing method calls, their provided arguments, and their return values.
6
6
  Simply specify which methods you want to trace inside a class and let peekaboo take care of the rest.
7
7
 
8
- ## Installation and usage
8
+ **( Compatible with Ruby versions 1.8.7 and 1.9.2 )**
9
9
 
10
- Gem:
10
+ ## Usage
11
+
12
+ ### Installation
13
+
14
+ Install via Rubygems:
11
15
 
12
16
  $ gem install peekaboo
13
17
 
14
- ### How it works:
18
+ ### Concept
15
19
 
16
- Peekaboo uses method wrapping and an internal tracer to capture the data you want to know about your methods.
20
+ Peekaboo uses method wrapping and an internal tracer to capture data about method calls.
17
21
  Its tracer adheres to the API established by the Logger class ( i.e. debug, info, warn, etc... ).
18
22
  For now, the only trace level supported is "info", but there are plans to support all trace levels in the future.
19
- Also, this first cut only provides tracing for _instance_ methods.
20
23
 
21
- When creating a new class, include Peekaboo and then call `enable_tracing_on`, passing it a list of method names to trace.
24
+ Including Peekaboo into your class definition initializes the system within the context of that class and adds
25
+ a number of class methods that can be used to create and inspect traced methods.
22
26
 
27
+ require 'peekaboo'
28
+
23
29
  class Example
24
30
  include Peekaboo
25
- enable_tracing_on :foo, :bar
26
-
27
- def foo
28
- #...
29
- end
30
-
31
- def bar
32
- #...
33
- end
31
+ # ...
34
32
  end
35
33
 
36
- Sometimes you may want to trace methods in a class that has already been created.
37
- In that case, simply reopen the class definition and follow the same steps listed above.
34
+ It is also possible to enable tracing without explicitly including Peekaboo. See the ["Auto-inclusion"](#Auto-inclusion) for details.
38
35
 
39
- # Example class already exists with instance methods #baz and #bif defined
40
-
36
+ ### Method Tracing
37
+
38
+ Once Peekaboo has been enabled within a class you can call `enable_tracing_for`, inside the class definition or
39
+ directly on the class object, passing it a structured hash of method names. The hash should contain 1 or 2 keys,
40
+ `:singleton_methods` and `:instance_methods`, each pointing to an array of symbolized method names.
41
+
42
+ # Calling inside class definition
41
43
  class Example
42
- include Peekaboo
43
- enable_tracing_on :baz, :bif
44
+ enable_tracing_for :singleton_methods => [:first_class_method, :second_class_method],
45
+ :instance_methods => [:an_instance_method]
46
+
47
+ # method n' such...
44
48
  end
49
+
50
+ # Calling on class object
51
+ Example.enable_tracing_for # same arguments as above
45
52
 
46
53
  Now, with tracing enabled, Peekaboo will report when/where those methods are called along with their input and output values.
47
54
 
55
+ # Peekaboo tracer receives the following message when .first_class_method is called below:
56
+ # "File:Line ( Example.first_class_method called with [] ==> Returning: 'whatever gets returned' )"
57
+ Example.first_class_method
58
+
48
59
  # @obj is an instance of Example
49
60
  # Peekaboo tracer receives the following message when #baz is called below:
50
- # "File:Line ( Example#baz called with [:one, 2, "three"] ==> Returning: 'whatever gets returned' )"
51
-
52
- @obj.baz :one, 2, "three"
61
+ # "File:Line ( Example#an_instance_method called with [:one, 2, "three"] ==> Returning: 'whatever gets returned' )"
62
+ @obj.an_instance_method :one, 2, "three"
53
63
 
54
- **NOTE:** Once a class has already included `Peekaboo`, you can call `enable_tracing_on` directly on the class.
64
+ ### Pre-registration of Methods
55
65
 
56
- class SomeClass
57
- include Peekaboo
58
- # methods n' such
66
+ Sometimes, in Ruby, we need to define methods at runtime based on some aspect of our application. Fortunately,
67
+ Peekaboo allows you to _register_ a method signature for tracing without enforcing that the method actually exists.
68
+ If any methods that you register get added to your type during program execution, Peekaboo will trace calls to
69
+ those methods in exactly the same fashion as before.
70
+
71
+ class DynamicEntity
72
+ # #might_need_it is not yet defined
73
+ enable_tracing_for :instance_methods => [:might_need_it]
59
74
  end
60
75
 
61
- SomeClass.enable_tracing_on :this, :that, :the_other
76
+ # somewhere else in the codebase the pre-registered method gets defined
77
+ DynamicEntity.class_eval do
78
+ def might_need_it
79
+ # ...
80
+ end
81
+ end
82
+
83
+ DynamicEntity.new.might_need_it # calls out to the Peekaboo tracer
62
84
 
63
85
  ## Configuration
64
86
 
87
+ There are a number of ways to configure Peekaboo for your project. Please read each section below for information
88
+ on a particular configuration option.
89
+
90
+ ### Method Tracer
91
+
65
92
  The default tracer for Peekaboo is an instance of `Logger` streaming to `STDOUT`.
66
93
  If this doesn't suit your needs, it is a trivial task to set the tracer to another object using the Peekaboo configuration.
67
94
 
@@ -76,7 +103,7 @@ If this doesn't suit your needs, it is a trivial task to set the tracer to anoth
76
103
  config.trace_with @custom_logger_object
77
104
  end
78
105
 
79
- ### Auto-inclusion ( Exciting NEW FEATURE )
106
+ ### Auto-inclusion
80
107
 
81
108
  Want to use tracing in classes without having to open up their definitions?
82
109
  Simply provide a list of classes to the configuration.
@@ -127,7 +154,7 @@ If you're looking to contribute please read the contribution guidelines before s
127
154
 
128
155
  ## License
129
156
 
130
- Copyright (c) 2009 Sonny Ruben Garcia
157
+ Copyright (c) 2010 Sonny Ruben Garcia
131
158
 
132
159
  Permission is hereby granted, free of charge, to any person obtaining
133
160
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
- require 'rake'
2
+ require 'bundler/setup'
3
+
3
4
  require 'spec/rake/spectask'
4
5
  require 'rcov/rcovtask'
5
6
  require 'yard'
@@ -11,10 +12,8 @@ end
11
12
 
12
13
  Rcov::RcovTask.new(:rcov) do |t|
13
14
  t.test_files = FileList['spec/**/*_spec.rb']
14
- t.rcov_opts = ['--exclude', '/gems/,spec'] # /gems/,/Library/,spec,.bundle,config
15
+ t.rcov_opts = ['--exclude', '/gems/,spec']
15
16
  t.verbose = true
16
17
  end
17
18
 
18
- YARD::Rake::YardocTask.new(:yard) do |t|
19
- t.files = ["lib/**/*.rb", "-", "CHANGELOG.md"]
20
- end
19
+ YARD::Rake::YardocTask.new(:yard)
@@ -1,71 +1,95 @@
1
1
  require 'peekaboo/configuration'
2
+ require 'peekaboo/singleton_methods'
2
3
 
3
- # The workhorse of this "Unobtrusive Tracing System".
4
+ # This system has been designed to provide you with an easy and unobtrusive way to trace:
5
+ # * _When_ certain methods are being called
6
+ # * _What_ values they are being supplied
7
+ # * _What_ values they return
8
+ # * _If_ they raise an exception
9
+ #
10
+ # Its API supports both class and instance method tracing inside any of your custom types.
11
+ # You can enable tracing for existing methods and/or pre-register method signatures for any of your types.
12
+ # The latter option gives you the ability to trace any methods that are defined _dynamically_ at runtime.
13
+ #
14
+ # ( see {SingletonMethods#enable_tracing_for} for details )
15
+ #
16
+ # You can also setup *auto-inclusion*, which will allow you _dynamically_ include this module into any of
17
+ # your types at runtime. This alleviates the hassle of having to "+include Peekaboo+" inside all of the
18
+ # classes that you intend use it.
19
+ #
20
+ # ( see {Configuration#autoinclude_with} for details )
4
21
  module Peekaboo
5
22
  class << self
6
- # @return [Configuration] the current configuration
23
+ # @private
7
24
  def configuration
8
25
  @configuration ||= Configuration.new
9
26
  end
10
27
 
11
- # Convenience method added to assist in configuring the system
12
- # ( see {Configuration} for details on all options ).
28
+ # Use this to configure various aspects of tracing in your application.
13
29
  #
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
30
+ # See {Configuration} for option details.
31
+ # @yieldparam [Configuration] config current configuration
19
32
  def configure
20
33
  yield configuration
21
34
  end
22
35
 
23
- # Callback used to hook tracing system into any class.
24
- #
25
- # @param [Class] klass including class
36
+ # @private
26
37
  def included klass
27
- klass.const_set :PEEKABOO_METHOD_LIST, []
38
+ klass.const_set :PEEKABOO_METHOD_MAP, { :singleton_methods => Set.new, :instance_methods => Set.new }.freeze
28
39
  klass.instance_variable_set :@_hooked_by_peekaboo, true
29
40
  klass.extend SingletonMethods
30
41
 
31
42
  def klass.method_added name
32
- Peekaboo.wrap_method self, name if peek_list.include? 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
33
48
  end
34
49
  end
35
50
 
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
51
+ # @private
40
52
  def setup_autoinclusion klass
53
+ # @note changes made to this methods to support backwards
54
+ # compatibility with {#enable_tracing_on}. This will become
55
+ # much simpler when that method is removed.
41
56
  def klass.method_missing(method_name, *args, &block)
42
- if method_name.to_s =~ /^enable_tracing_on$/
57
+ if method_name.to_s =~ /^enable_tracing_(on|for)$/
43
58
  instance_eval { include Peekaboo }
44
- enable_tracing_on *args
59
+ __send__ method_name, *args
45
60
  else
46
61
  super
47
62
  end
48
63
  end
49
64
  end
50
65
 
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
58
- def wrap_method klass, name
66
+ # @private
67
+ def wrap klass, method_name, target
59
68
  return if @_adding_a_method
60
- @_adding_a_method = true
61
-
62
- original_method = "original_#{name}"
69
+ begin
70
+ @_adding_a_method = true
71
+ original_method = "original_#{method_name}"
72
+ case target
73
+ when :singleton then wrap_singleton_method klass, method_name, original_method
74
+ when :instance then wrap_instance_method klass, method_name, original_method
75
+ else raise 'Only :class and :instance are valid targets'
76
+ end
77
+ rescue => exe
78
+ raise exe
79
+ ensure
80
+ @_adding_a_method = false
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def wrap_instance_method klass, method_name, original_method_name
63
87
  method_wrapping = %{
64
- alias_method :#{original_method}, :#{name}
65
- def #{name} *args, &block
66
- trace = "\#{caller(1)[0]}\n\t( Invoking: #{klass}\##{name} with \#{args.inspect} "
88
+ alias_method :#{original_method_name}, :#{method_name}
89
+ def #{method_name} *args, &block
90
+ trace = "\#{caller(1)[0]}\n\t( Invoking: #{klass}\##{method_name} with \#{args.inspect} "
67
91
  begin
68
- result = #{original_method} *args, &block
92
+ result = #{original_method_name} *args, &block
69
93
  trace << "==> Returning: \#{result.inspect} )"
70
94
  result
71
95
  rescue Exception => exe
@@ -77,50 +101,28 @@ module Peekaboo
77
101
  end
78
102
  }
79
103
  klass.class_eval method_wrapping
80
-
81
- @_adding_a_method = false
82
- end
83
- end
84
-
85
- # Contains methods added to every class that includes the *Peekaboo* module,
86
- # either through _direct_ or _auto_ inclusion.
87
- module SingletonMethods
88
- # @return [Array<Symbol>]
89
- # a list of instance methods that are being traced inside calling class
90
- def peek_list
91
- self::PEEKABOO_METHOD_LIST
92
104
  end
93
105
 
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
112
- def enable_tracing_on *method_names
113
- include Peekaboo unless @_hooked_by_peekaboo
114
-
115
- method_names.each do |method_name|
116
- unless peek_list.include? method_name
117
- peek_list << method_name
118
- method_list = self.instance_methods(false).map(&:to_sym)
119
- Peekaboo.wrap_method self, method_name if method_list.include? method_name
120
- else
121
- raise "Already tracing `#{method_name}'"
106
+ def wrap_singleton_method klass, method_name, original_method_name
107
+ method_wrapping = %{
108
+ class << self
109
+ alias_method :#{original_method_name}, :#{method_name}
110
+ def #{method_name} *args, &block
111
+ trace = "\#{caller(1)[0]}\n\t( Invoking: #{klass}.#{method_name} with \#{args.inspect} "
112
+ begin
113
+ result = #{original_method_name} *args, &block
114
+ trace << "==> Returning: \#{result.inspect} )"
115
+ result
116
+ rescue Exception => exe
117
+ trace << "!!! Raising: \#{exe.message.inspect} )"
118
+ raise exe
119
+ ensure
120
+ Peekaboo.configuration.tracer.info trace
121
+ end
122
+ end
122
123
  end
123
- end
124
+ }
125
+ klass.instance_eval method_wrapping
124
126
  end
125
127
  end
126
128
  end
@@ -0,0 +1,126 @@
1
+ module Peekaboo
2
+ # Contains methods added to every class that includes the
3
+ # {Peekaboo} module, either by _direct_ or _auto_ inclusion.
4
+ module SingletonMethods
5
+ # Provides access to traced methods.
6
+ #
7
+ # @example
8
+ # CustomType.traced_method_map # => {:instance_methods=>#<Set: {:foo}>, :singleton_methods=>#<Set: {:bar}>}
9
+ #
10
+ # @return [Hash] all methods registered for tracing
11
+ def traced_method_map
12
+ self::PEEKABOO_METHOD_MAP
13
+ end
14
+
15
+ # Provides convenient access to traced instance methods.
16
+ #
17
+ # @example
18
+ # CustomType.traced_instance_methods # => #<Set: {:foo}>
19
+ #
20
+ # @return [Set<Symbol>] all instance methods registered for tracing
21
+ def traced_instance_methods
22
+ traced_method_map[:instance_methods]
23
+ end
24
+
25
+ # Provides convenient access to traced singleton methods.
26
+ #
27
+ # @example
28
+ # CustomType.traced_singleton_methods # => #<Set: {:bar}>
29
+ #
30
+ # @return [Set<Symbol>] all singleton methods registered for tracing
31
+ def traced_singleton_methods
32
+ traced_method_map[:singleton_methods]
33
+ end
34
+
35
+ # Enables singleton and instance method tracing. If the _method-to-trace_
36
+ # is not currently defined in the calling class, *Peekaboo* will register
37
+ # that signature so that tracing is enabled at the time it is added.
38
+ #
39
+ # @example Tracing singleton methods
40
+ # CustomType.enable_tracing_for :singleton_methods => [:a, :b, :c]
41
+ # @example Tracing instance methods
42
+ # CustomType.enable_tracing_for :instance_methods => [:one, :two, :three]
43
+ # @example Tracing a mix of methods
44
+ # CustomType.enable_tracing_for :singleton_methods => [:this, :that],
45
+ # :instance_methods => [:the_other]
46
+ #
47
+ # @param [Hash] method_map a list of methods to trace
48
+ # @option method_map [Array<Symbol>] :singleton_methods ([]) singleton method list
49
+ # @option method_map [Array<Symbol>] :instance_methods ([]) instance method list
50
+ def enable_tracing_for method_map
51
+ include Peekaboo unless @_hooked_by_peekaboo
52
+
53
+ method_map = { :singleton_methods => [], :instance_methods => [] }.merge method_map
54
+
55
+ _register_traceables_ method_map[:instance_methods], :instance
56
+ _register_traceables_ method_map[:singleton_methods], :singleton
57
+ end
58
+
59
+ private
60
+
61
+ # Registers a list of method signatures and optionally enables tracing on them.
62
+ # Tracing will only be "enabled" if the method exists and has not already been registered.
63
+ #
64
+ # @param [Array<Symbol>] method_list methods to register
65
+ # @param [Symbol] target specifies the receiver, either +:singleton+ or +:instance+
66
+ def _register_traceables_ method_list, target
67
+ method_list.each do |method_name|
68
+ target_method_list = __send__ :"traced_#{target}_methods"
69
+
70
+ unless target_method_list.include? method_name
71
+ target_method_list << method_name
72
+ existing_methods = self.__send__(:"#{target}_methods", false).map(&:to_sym)
73
+ Peekaboo.wrap self, method_name, target if existing_methods.include? method_name
74
+ end
75
+ end
76
+ end
77
+
78
+
79
+ #################### DEPRECATED ####################
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
+ #
106
+ # @param [*Symbol] method_names
107
+ # the list of methods that you want to trace
108
+ # @raise [RuntimeError]
109
+ # when attempting to add a method that is already being traced
110
+ # @deprecated
111
+ # this method will be removed in version 0.4.0, use {#enable_tracing_for} instead
112
+ def enable_tracing_on *method_names
113
+ include Peekaboo unless @_hooked_by_peekaboo
114
+
115
+ method_names.each do |method_name|
116
+ unless peek_list.include? method_name
117
+ traced_instance_methods << method_name
118
+ method_list = self.instance_methods(false).map(&:to_sym)
119
+ Peekaboo.wrap self, method_name, :instance if method_list.include? method_name
120
+ else
121
+ raise "Already tracing `#{method_name}'"
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -1,9 +1,9 @@
1
1
  module Peekaboo
2
- # If you cannot figure this one out, you're on your own!
2
+ # Pretty self-explanatory
3
3
  module Version
4
4
  MAJOR = 0
5
- MINOR = 2
6
- PATCH = 1
5
+ MINOR = 3
6
+ PATCH = 0
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH].join('.')
9
9
  end
@@ -12,10 +12,9 @@ Gem::Specification.new do |gem|
12
12
  gem.homepage = "http://github.com/sgarcia/peekaboo"
13
13
  gem.authors = ["Sonny Ruben Garcia"]
14
14
 
15
- gem.add_development_dependency "rspec", "1.3.0"
16
- gem.add_development_dependency "rcov", "0.9.9"
17
- gem.add_development_dependency "yard", "0.6.1"
15
+ gem.add_development_dependency "bundler", "1.0.3"
18
16
 
19
17
  gem.files = `git ls-files`.split("\n")
20
18
  gem.test_files = `git ls-files -- spec/*`.split("\n")
19
+ gem.extra_rdoc_files = ["CHANGELOG.md"]
21
20
  end
@@ -1,22 +1,278 @@
1
1
  require File.expand_path('../spec_helper', __FILE__)
2
2
 
3
3
  describe Peekaboo do
4
-
5
- context ".configuration" do
6
- it "should hold a reference to the current configuration" do
4
+
5
+ context "configuration" do
6
+ it "should be properly referenced" do
7
7
  Peekaboo.configuration.should be_an_instance_of Peekaboo::Configuration
8
8
  end
9
- end
10
-
11
- context ".configure" do
12
- it "should yield the current configuration" do
9
+
10
+ it "should yield itself" do
13
11
  yielded_object = nil
14
12
  Peekaboo.configure { |x| yielded_object = x }
15
13
  Peekaboo.configuration.should == yielded_object
16
14
  end
17
15
  end
18
16
 
19
- context ".enable_tracing_on" do
17
+ context "standard tracing" do
18
+ before(:each) do
19
+ @tracer = Peekaboo.configuration.tracer
20
+ @test_class = new_test_class.instance_eval { include Peekaboo }
21
+ @test_class.enable_tracing_for :singleton_methods => [:say_hello, :hello, :add, :happy?, :comma_list, :kaboom],
22
+ :instance_methods => [:say_goodbye, :goodbye, :subtract, :sad?, :pipe_list, :crash]
23
+ end
24
+
25
+ it "should guard its map of traced methods" do
26
+ lambda {
27
+ @test_class.traced_method_map[:something] = 'unwanted'
28
+ }.should raise_exception
29
+ end
30
+
31
+ it "should store a list of traced methods" do
32
+ @test_class.traced_singleton_methods.should include :say_hello, :hello, :add, :happy?, :comma_list, :kaboom
33
+ @test_class.traced_instance_methods.should include :say_goodbye, :goodbye, :subtract, :sad?, :pipe_list, :crash
34
+ end
35
+
36
+ it "should ensure that traced methods are uniquely stored" do
37
+ lambda {
38
+ @test_class.enable_tracing_for :singleton_methods => [:say_hello]
39
+ }.should_not change(@test_class.traced_singleton_methods, :size).from(6)
40
+
41
+ lambda {
42
+ @test_class.enable_tracing_for :singleton_methods => [:object_id]
43
+ }.should change(@test_class.traced_singleton_methods, :size).from(6).to(7)
44
+
45
+ lambda {
46
+ @test_class.enable_tracing_for :instance_methods => [:say_goodbye]
47
+ }.should_not change(@test_class.traced_instance_methods, :size).from(6)
48
+
49
+ lambda {
50
+ @test_class.enable_tracing_for :instance_methods => [:object_id]
51
+ }.should change(@test_class.traced_instance_methods, :size).from(6).to(7)
52
+ end
53
+
54
+ context "on class methods" do
55
+ it "should not take place on unlisted methods" do
56
+ @tracer.should_not_receive :info
57
+ @test_class.object_id
58
+ end
59
+
60
+ it "should show listed methods with no arguments" do
61
+ @tracer.should_receive(:info).
62
+ with trace_message %{Invoking: #{@test_class}.say_hello with [] ==> Returning: "hello"}
63
+ @test_class.say_hello
64
+ end
65
+
66
+ it "should show listed methods with required arguments" do
67
+ @tracer.should_receive(:info).
68
+ with trace_message %{Invoking: #{@test_class}.hello with ["developer"] ==> Returning: "hello developer"}
69
+ @test_class.hello 'developer'
70
+
71
+ @tracer.should_receive(:info).
72
+ with trace_message %{Invoking: #{@test_class}.add with [1, 2] ==> Returning: 3}
73
+ @test_class.add 1, 2
74
+ end
75
+
76
+ it "should show methods with optional arguments" do
77
+ @tracer.should_receive(:info).
78
+ with trace_message %{Invoking: #{@test_class}.happy? with [] ==> Returning: true}
79
+ @test_class.happy?
80
+
81
+ @tracer.should_receive(:info).
82
+ with trace_message %{Invoking: #{@test_class}.happy? with [false] ==> Returning: false}
83
+ @test_class.happy? false
84
+ end
85
+
86
+ it "should show methods with variable arguments" do
87
+ @tracer.should_receive(:info).
88
+ with trace_message %{Invoking: #{@test_class}.comma_list with [] ==> Returning: ""}
89
+ @test_class.comma_list
90
+
91
+ @tracer.should_receive(:info).
92
+ with trace_message %{Invoking: #{@test_class}.comma_list with [:too, "cool"] ==> Returning: "too,cool"}
93
+ @test_class.comma_list :too, 'cool'
94
+
95
+ @tracer.should_receive(:info).
96
+ with trace_message %{Invoking: #{@test_class}.comma_list with [1, "to", 5] ==> Returning: "1,to,5"}
97
+ @test_class.comma_list 1, 'to', 5
98
+ end
99
+
100
+ it "should show methods that raise an exception" do
101
+ lambda do
102
+ @tracer.should_receive(:info).
103
+ with trace_message %{Invoking: #{@test_class}.kaboom with [] !!! Raising: "fire, fire"}
104
+ @test_class.kaboom
105
+ end.should raise_exception
106
+ end
107
+
108
+ it "should work when methods are added after the fact" do
109
+ @test_class.enable_tracing_for :singleton_methods => [:dog]
110
+ def @test_class.dog
111
+ 'woof'
112
+ end
113
+
114
+ @tracer.should_receive(:info).
115
+ with trace_message %{Invoking: #{@test_class}.dog with [] ==> Returning: "woof"}
116
+ @test_class.dog
117
+ end
118
+ end
119
+
120
+ context "on instance methods" do
121
+ before(:each) do
122
+ @test_instance = @test_class.new
123
+ end
124
+
125
+ it "should not take place on unlisted methods" do
126
+ @tracer.should_not_receive :info
127
+ @test_instance.object_id
128
+ end
129
+
130
+ it "should show listed methods with no arguments" do
131
+ @tracer.should_receive(:info).
132
+ with trace_message %{Invoking: #{@test_class}#say_goodbye with [] ==> Returning: "goodbye"}
133
+ @test_instance.say_goodbye
134
+ end
135
+
136
+ it "should show listed methods with required arguments" do
137
+ @tracer.should_receive(:info).
138
+ with trace_message %{Invoking: #{@test_class}#goodbye with ["bugs"] ==> Returning: "goodbye bugs"}
139
+ @test_instance.goodbye 'bugs'
140
+
141
+ @tracer.should_receive(:info).
142
+ with trace_message %{Invoking: #{@test_class}#subtract with [5, 4] ==> Returning: 1}
143
+ @test_instance.subtract 5, 4
144
+ end
145
+
146
+ it "should show methods with optional arguments" do
147
+ @tracer.should_receive(:info).
148
+ with trace_message %{Invoking: #{@test_class}#sad? with [] ==> Returning: false}
149
+ @test_instance.sad?
150
+
151
+ @tracer.should_receive(:info).
152
+ with trace_message %{Invoking: #{@test_class}#sad? with [true] ==> Returning: true}
153
+ @test_instance.sad? true
154
+ end
155
+
156
+ it "should show methods with variable arguments" do
157
+ @tracer.should_receive(:info).
158
+ with trace_message %{Invoking: #{@test_class}#pipe_list with [] ==> Returning: ""}
159
+ @test_instance.pipe_list
160
+
161
+ @tracer.should_receive(:info).
162
+ with trace_message %{Invoking: #{@test_class}#pipe_list with [:alf, "is"] ==> Returning: "alf|is"}
163
+ @test_instance.pipe_list :alf, "is"
164
+
165
+ @tracer.should_receive(:info).
166
+ with trace_message %{Invoking: #{@test_class}#pipe_list with [:alf, "is", 0] ==> Returning: "alf|is|0"}
167
+ @test_instance.pipe_list :alf, "is", 0
168
+ end
169
+
170
+ it "should show methods that raise an exception" do
171
+ lambda do
172
+ @tracer.should_receive(:info).
173
+ with trace_message %{Invoking: #{@test_class}#crash with [] !!! Raising: "twisted code"}
174
+ @test_instance.crash
175
+ end.should raise_exception
176
+ end
177
+
178
+ it "should work when methods are added after the fact" do
179
+ @test_class.enable_tracing_for :instance_methods => [:frog]
180
+ @test_class.class_eval do
181
+ def frog
182
+ 'ribbit'
183
+ end
184
+ end
185
+
186
+ @tracer.should_receive(:info).
187
+ with trace_message %{Invoking: #{@test_class}#frog with [] ==> Returning: "ribbit"}
188
+ @test_instance.frog
189
+ end
190
+ end
191
+ end
192
+
193
+ context "autoinclusion tracing" do
194
+ before(:each) do
195
+ @tracer = Peekaboo.configuration.tracer
196
+ @base_class = new_test_class
197
+ Peekaboo.configure { |config| config.autoinclude_with @base_class }
198
+ end
199
+
200
+ context "on class methods" do
201
+ it "should inject functionality into an auto-included class" do
202
+ @base_class.enable_tracing_for :singleton_methods => [:say_hello]
203
+
204
+ @tracer.should_receive(:info).
205
+ with trace_message %{Invoking: #{@base_class}.say_hello with [] ==> Returning: "hello"}
206
+ @base_class.say_hello
207
+ end
208
+
209
+ it "should inject functionality into any class that inherits from an auto-included class" do
210
+ child_class = Class.new(@base_class) { def self.say_hola; 'hola'; end }
211
+ child_class.enable_tracing_for :singleton_methods => [:say_hola]
212
+
213
+ @tracer.should_receive(:info).
214
+ with trace_message %{Invoking: #{child_class}.say_hola with [] ==> Returning: "hola"}
215
+ child_class.say_hola
216
+ end
217
+
218
+ it "should not inject functionality into classes that are not auto-included" do
219
+ not_a_child_class = new_test_class
220
+ lambda {
221
+ not_a_child_class.enable_tracing_for :singleton_methods => [:say_hello]
222
+ }.should raise_exception NoMethodError
223
+ end
224
+
225
+ it "should maintain unique tracing method lists across an inheritance chain" do
226
+ child_class = Class.new(@base_class) { def self.say_hola; 'hola'; end }
227
+ @base_class.enable_tracing_for :singleton_methods => [:say_hello]
228
+ child_class.enable_tracing_for :singleton_methods => [:say_hola]
229
+
230
+ @base_class.traced_singleton_methods.to_a.should =~ [:say_hello]
231
+ child_class.traced_singleton_methods.to_a.should =~ [:say_hola]
232
+ end
233
+ end
234
+
235
+ context "on instance methods" do
236
+ it "should inject functionality into an auto-included class" do
237
+ @base_class.enable_tracing_for :instance_methods => [:say_goodbye]
238
+
239
+ @tracer.should_receive(:info).
240
+ with trace_message %{Invoking: #{@base_class}#say_goodbye with [] ==> Returning: "goodbye"}
241
+ @base_class.new.say_goodbye
242
+ end
243
+
244
+ it "should inject functionality into any class that inherits from an auto-included class" do
245
+ child_class = Class.new(@base_class) { def say_adios; 'adios'; end }
246
+ child_class.enable_tracing_for :instance_methods => [:say_adios]
247
+
248
+ @tracer.should_receive(:info).
249
+ with trace_message %{Invoking: #{child_class}#say_adios with [] ==> Returning: "adios"}
250
+ child_class.new.say_adios
251
+ end
252
+
253
+ it "should not inject functionality into classes that are not auto-included" do
254
+ not_a_child_class = new_test_class
255
+ lambda {
256
+ not_a_child_class.enable_tracing_for :instance_methods => [:say_goodbye]
257
+ }.should raise_exception NoMethodError
258
+ end
259
+
260
+ it "should maintain unique tracing method lists across an inheritance chain" do
261
+ child_class = Class.new(@base_class) { def say_adios; 'adios'; end }
262
+ @base_class.enable_tracing_for :instance_methods => [:say_goodbye]
263
+ child_class.enable_tracing_for :instance_methods => [:say_adios]
264
+
265
+ @base_class.traced_instance_methods.to_a.should =~ [:say_goodbye]
266
+ child_class.traced_instance_methods.to_a.should =~ [:say_adios]
267
+ end
268
+ end
269
+ end
270
+
271
+
272
+ ### OLD SPECIFICATIONS: Remove when moving to version 0.4.0 ###
273
+
274
+
275
+ context ".enable_tracing_on (old)" do
20
276
  before(:each) do
21
277
  @test_class = new_test_class
22
278
  @test_class.instance_eval { include Peekaboo }
@@ -29,7 +285,7 @@ describe Peekaboo do
29
285
  it "should store a list of methods to trace on any including class" do
30
286
  methods_to_trace = [:method_no_args, :method_one_arg]
31
287
  @test_class.enable_tracing_on *methods_to_trace
32
- @test_class::PEEKABOO_METHOD_LIST.should == methods_to_trace
288
+ @test_class.peek_list.should =~ methods_to_trace
33
289
  end
34
290
 
35
291
  it "should raise an exception when trying to add a method that is already being traced" do
@@ -40,7 +296,7 @@ describe Peekaboo do
40
296
  end
41
297
  end
42
298
 
43
- context "instance method tracing" do
299
+ context "instance method tracing (old)" do
44
300
  before(:all) do
45
301
  @test_class = new_test_class
46
302
  @test_class.instance_eval do
@@ -105,7 +361,7 @@ describe Peekaboo do
105
361
  end
106
362
  end
107
363
 
108
- context "autoinclusion tracing" do
364
+ context "autoinclusion tracing (old)" do
109
365
  before(:all) do
110
366
  @tracer = Peekaboo.configuration.tracer
111
367
  end
@@ -11,27 +11,55 @@ require 'peekaboo'
11
11
  Spec::Runner.configure do |config|
12
12
  def new_test_class
13
13
  Class.new do
14
- def method_no_tracing
14
+ class << self
15
+ def say_hello
16
+ 'hello'
17
+ end
18
+ def hello name
19
+ "hello #{name}"
20
+ end
21
+ def add a, b
22
+ a + b
23
+ end
24
+ def happy? option = true
25
+ option
26
+ end
27
+ def comma_list *args
28
+ args.join ','
29
+ end
30
+ def kaboom
31
+ raise 'fire, fire'
32
+ end
15
33
  end
16
-
17
- def method_no_args
34
+
35
+ def say_goodbye
36
+ 'goodbye'
18
37
  end
19
-
20
- def method_one_arg arg1
38
+ def goodbye name
39
+ "goodbye #{name}"
21
40
  end
22
-
23
- def method_two_args arg1, arg2
41
+ def subtract a, b
42
+ a - b
24
43
  end
25
-
26
- def method_optional_args optional = 'default'
44
+ def sad? option = false
45
+ option
27
46
  end
28
-
29
- def method_variable_args *args
47
+ def pipe_list *args
48
+ args.join '|'
30
49
  end
31
-
32
- def method_raises
33
- raise 'something went wrong'
50
+ def crash
51
+ raise 'twisted code'
34
52
  end
53
+
54
+ ### OLD TEST METHODS ###
55
+
56
+ def method_no_tracing;end
57
+ def method_no_args;end
58
+ def method_one_arg arg1;end
59
+ def method_two_args arg1, arg2;end
60
+ def method_optional_args optional = 'default';end
61
+ def method_variable_args *args;end
62
+ def method_raises;raise 'something went wrong';end
35
63
  end
36
64
  end
37
65
 
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 2
8
- - 1
9
- version: 0.2.1
7
+ - 3
8
+ - 0
9
+ version: 0.3.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Sonny Ruben Garcia
@@ -14,11 +14,11 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-11-04 00:00:00 -05:00
17
+ date: 2010-11-08 00:00:00 -06:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: rspec
21
+ name: bundler
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  none: false
@@ -27,56 +27,29 @@ dependencies:
27
27
  - !ruby/object:Gem::Version
28
28
  segments:
29
29
  - 1
30
- - 3
31
30
  - 0
32
- version: 1.3.0
31
+ - 3
32
+ version: 1.0.3
33
33
  type: :development
34
34
  version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: rcov
37
- prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
39
- none: false
40
- requirements:
41
- - - "="
42
- - !ruby/object:Gem::Version
43
- segments:
44
- - 0
45
- - 9
46
- - 9
47
- version: 0.9.9
48
- type: :development
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
51
- name: yard
52
- prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
54
- none: false
55
- requirements:
56
- - - "="
57
- - !ruby/object:Gem::Version
58
- segments:
59
- - 0
60
- - 6
61
- - 1
62
- version: 0.6.1
63
- type: :development
64
- version_requirements: *id003
65
35
  description: Allows you to log method call information ( input arguments, class/method name, and return value ) without being overly intrusive.
66
36
  email: sonny.ruben@gmail.com
67
37
  executables: []
68
38
 
69
39
  extensions: []
70
40
 
71
- extra_rdoc_files: []
72
-
41
+ extra_rdoc_files:
42
+ - CHANGELOG.md
73
43
  files:
74
44
  - .gitignore
45
+ - .yardopts
75
46
  - CHANGELOG.md
47
+ - Gemfile
76
48
  - README.md
77
49
  - Rakefile
78
50
  - lib/peekaboo.rb
79
51
  - lib/peekaboo/configuration.rb
52
+ - lib/peekaboo/singleton_methods.rb
80
53
  - lib/peekaboo/version.rb
81
54
  - peekaboo.gemspec
82
55
  - spec/peekaboo/configuration_spec.rb