peekaboo 0.2.1 → 0.3.0

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