method_call_tracer 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c0a180a16f9d4798139f03dc6cc487632ec0cfbf
4
- data.tar.gz: d7294c63a4bc0e293fa9e883338248aee417c050
3
+ metadata.gz: 5ec122bd2856f55ddd0958f690f667cfac0dd6d0
4
+ data.tar.gz: c517dc70ab2c883d8acc5e8b32e78a833c0565ba
5
5
  SHA512:
6
- metadata.gz: 9f03140a84d526cc297d97c650ae3a55df9e28dbfe2b5d8be5ed832aee97689a73b4eb2402faaca16d5ad1a9b2a2c434fe9f1d4032041b45cabc2e2135e818d8
7
- data.tar.gz: 2e36e0b7bcbb327ffa925f3667f23532238d47956ca70ce6a46e852732aca43b700288473bd45fe82eefcb0854ccab39310fe69849ea68b49448d9fd23601f1b
6
+ metadata.gz: f1f235d6fe985239be47614b1bcfd9a925c157152de974d7dabf071d0cf36a024dbc63f37db9b9bbfc71351faec6cfd0b93d5fef9874916199e456e1b26366a2
7
+ data.tar.gz: 672b73d90ab60177d87b3f0a67ab828800154e077c20cdc51facc2178637ba3ff015731e7bf85a13c53d844827406218c61575799a114f335c7869272af34a01
data/README.md CHANGED
@@ -4,6 +4,8 @@ MethodTracer is a tool for detecting lines in an application that call certain m
4
4
 
5
5
  <sup>1</sup> Designating traced methods by file lets you trace methods defined in the "namespace" of a different gem. For example, if a hypothetical gem `activerecord-extension` defines some methods on the class `ActiveRecord`, we still have the ability to trace only the methods from `activerecord-extension` without capturing the methods from `activerecord`.
6
6
 
7
+ **Note about gem name**: due to a naming collision on rubygems.org, this gem appears there as `method_call_tracer`.
8
+
7
9
  ## Usage
8
10
 
9
11
  To attach tracers to methods, instantiate `MethodTracer::Tracer` objects. For Rails applications, these can be placed in the provided initializer.
@@ -35,7 +37,7 @@ MethodTracer theoretically does not interfere with the original behavior of meth
35
37
  Add this line to your application's Gemfile:
36
38
 
37
39
  ```ruby
38
- gem 'method_tracer'
40
+ gem 'method_call_tracer'
39
41
  ```
40
42
 
41
43
  And then execute:
@@ -44,7 +46,7 @@ And then execute:
44
46
 
45
47
  Or install it yourself as:
46
48
 
47
- $ gem install method_tracer
49
+ $ gem install method_call_tracer
48
50
 
49
51
  If you are using it with Rails, run the installation generator to install an example config initializer:
50
52
 
@@ -1,3 +1,5 @@
1
+ require 'method_tracer'
2
+
1
3
  # Define the prefix for the application code. Only calls matching this pattern
2
4
  # will be recorded.
3
5
  MethodTracer::Config.app_path = Rails.application.paths.path.to_s
@@ -1,37 +1,28 @@
1
+ require 'where_is'
2
+
1
3
  module MethodTracer
2
4
  class Tracer
3
- UNCOOPERATIVE_NAMES = [
4
- # Some classes don't behave well when we try to hook them, at least with
5
- # the methods currently used.
6
- 'CGI', # Waits for input from stdin when opening rails console
7
- 'RSpec' # RSpec doesn't run
8
- ].freeze
9
-
10
5
  def initialize(target)
11
6
  @target_path = target
12
7
 
13
- find_methods!
14
-
15
- add_hooks_to_class_methods
16
- add_hooks_to_instance_methods
8
+ @tracer = TracePoint.trace(:call) do |tp|
9
+ record_call_if_interesting(tp)
10
+ end
17
11
  end
18
12
 
19
- def self.uncooperative_class?(class_name)
20
- !class_name.nil? &&
21
- UNCOOPERATIVE_NAMES.any? { |bad_name| class_name.include?(bad_name) }
22
- end
13
+ def record_call_if_interesting(tp)
14
+ return unless class_is_interesting?(tp.defined_class)
23
15
 
24
- def self.record_and_call_original(unbound_m, receiver, *args, &block)
25
- outfile.write "#{receiver}.#{unbound_m.name} called from:\n"
26
- caller_locations.select { |loc| loc.path.start_with?(Config.app_path) }
27
- .each do |loc|
28
- outfile.write "#{loc.path}:#{loc.lineno}\n"
29
- end
16
+ locations = caller_locations.select { |loc| loc.path.start_with?(Config.app_path) }
17
+ return if locations.empty?
30
18
 
31
- unbound_m.bind(receiver).call(*args, &block)
19
+ outfile.write "#{@target_path} :#{tp.method_id}\n"
20
+ locations.each do |loc|
21
+ outfile.write "#{loc.path}:#{loc.lineno}\n"
22
+ end
32
23
  end
33
24
 
34
- def self.outfile
25
+ def outfile
35
26
  @outfile ||= begin
36
27
  output_file = Config.output_file
37
28
  if output_file.instance_of?(IO) || output_file.instance_of?(StringIO)
@@ -44,58 +35,13 @@ module MethodTracer
44
35
  end
45
36
  end
46
37
 
47
- private
48
-
49
- def add_hooks_to_class_methods
50
- methods_of_interest(@all_class_methods).each do |m|
51
- unbound_m = m.unbind
52
- receiver = m.receiver
53
-
54
- receiver.send(:define_singleton_method, unbound_m.name) do |*args, &block|
55
- Tracer.record_and_call_original(unbound_m, receiver, *args, &block)
56
- end
57
- end
58
- end
59
-
60
- def add_hooks_to_instance_methods
61
- methods_of_interest(@all_instance_methods).each do |m|
62
- unbound_m = m.unbind
63
- receiver = m.receiver
64
-
65
- receiver.class.send(:define_method, m.name) do |*args, &block|
66
- Tracer.record_and_call_original(unbound_m, receiver, *args, &block)
67
- end
68
- end
69
- end
70
-
71
- def find_methods!
72
- @all_class_methods = []
73
- @all_instance_methods = []
74
- ObjectSpace.each_object(Class) do |defined_class|
75
- next if Tracer.uncooperative_class?(defined_class.name)
76
-
77
- defined_class.methods(false).each do |method_sym|
78
- @all_class_methods << defined_class.method(method_sym)
79
- end
80
-
81
- begin
82
- instance = defined_class.new
83
- defined_class.instance_methods(false).each do |method_sym|
84
- @all_instance_methods << instance.method(method_sym)
85
- end
86
- rescue StandardError, NotImplementedError, LoadError
87
- # If the class isn't instantiable, skip it
88
- next
89
- end
90
- end
91
- end
92
-
93
- def methods_of_interest(methods)
94
- methods.select do |m|
95
- m.instance_of?(Method) &&
96
- !m.source_location.nil? &&
97
- m.source_location[0].start_with?(@target_path)
38
+ def class_is_interesting?(candidate_class)
39
+ begin
40
+ location = Where.is(candidate_class)
41
+ rescue NameError
42
+ return false
98
43
  end
44
+ location[:file].start_with?(@target_path)
99
45
  end
100
46
  end
101
47
  end
@@ -1,3 +1,3 @@
1
1
  module MethodTracer
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
@@ -21,5 +21,7 @@ Gem::Specification.new do |spec|
21
21
  end
22
22
  spec.require_paths = ['lib']
23
23
 
24
- spec.add_development_dependency 'minitest', '~> 0'
24
+ spec.add_dependency 'where_is', '~> 0'
25
+
26
+ spec.add_development_dependency 'minitest', '~> 5'
25
27
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: method_call_tracer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eddie Lebow
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-24 00:00:00.000000000 Z
11
+ date: 2018-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: minitest
14
+ name: where_is
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
- type: :development
20
+ type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5'
27
41
  description: This tool wraps every specified method with some logging statements that
28
42
  record the call stack, allowing you to see exactly which lines in your application
29
43
  make calls to methods in question. The specified methods can constitute all methods