ruby_tracer 0.1.0 → 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.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +7 -1
- data/README.md +94 -13
- data/lib/ruby_tracer/base.rb +2 -1
- data/lib/ruby_tracer/call_tracer.rb +11 -3
- data/lib/ruby_tracer/exception_tracer.rb +3 -1
- data/lib/ruby_tracer/helper.rb +3 -0
- data/lib/ruby_tracer/irb.rb +90 -0
- data/lib/ruby_tracer/object_tracer.rb +4 -4
- data/lib/ruby_tracer/version.rb +1 -1
- data/lib/ruby_tracer.rb +25 -0
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ac708e995302930fed59fa3b9396dc5b3c45ab76d4306c8bbac65fe69c49377
|
4
|
+
data.tar.gz: 99f23f4e5fb2d5f8ae694ff1203524707c757fd5a91cd29131ac61e79c5cb15f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd1e5c1aef7115227db143c95939ad7ce180c65924334f30540dbed8f9d2f5cd468f0e3e989af1e7d6dd4e49e023798d5a1133c26cf49ccef54080eceb6f925c
|
7
|
+
data.tar.gz: 0dd0e49cf41d3e9fe4fd880b68364f1727d4d29bb4fb8c35b76e37ed97549979130d2678f2f2a0c720282ad17bd0abb15b0694478dea24b40dc57baf452b434b
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,15 +1,20 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
ruby_tracer (0.
|
4
|
+
ruby_tracer (0.3.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
+
io-console (0.6.0)
|
10
|
+
irb (1.6.2)
|
11
|
+
reline (>= 0.3.0)
|
9
12
|
language_server-protocol (3.17.0.3)
|
10
13
|
power_assert (2.0.2)
|
11
14
|
prettier_print (1.2.0)
|
12
15
|
rake (13.0.6)
|
16
|
+
reline (0.3.2)
|
17
|
+
io-console (~> 0.5)
|
13
18
|
ruby-lsp (0.3.8)
|
14
19
|
language_server-protocol (~> 3.17.0)
|
15
20
|
sorbet-runtime
|
@@ -25,6 +30,7 @@ PLATFORMS
|
|
25
30
|
x86_64-linux
|
26
31
|
|
27
32
|
DEPENDENCIES
|
33
|
+
irb
|
28
34
|
rake (~> 13.0)
|
29
35
|
ruby-lsp
|
30
36
|
ruby_tracer!
|
data/README.md
CHANGED
@@ -1,14 +1,6 @@
|
|
1
1
|
# ruby_tracer
|
2
2
|
|
3
|
-
ruby_tracer is an extraction of [`ruby/debug`](https://github.com/ruby/debug)'s [powerful tracers](https://github.com/ruby/debug/blob/master/lib/debug/tracer.rb), with user-facing APIs and
|
4
|
-
|
5
|
-
Its goal is to help users understand their Ruby programss activities by emitting useful trace information, such us:
|
6
|
-
|
7
|
-
- How and where is the target object is being used (`ObjectTracer`)
|
8
|
-
- What exceptions are raised during the execution (`ExceptionTracer`)
|
9
|
-
- When method calls are being performed (`CallTracer`)
|
10
|
-
- Line execution (`LineTracer`)
|
11
|
-
|
3
|
+
ruby_tracer is an extraction of [`ruby/debug`](https://github.com/ruby/debug)'s [powerful tracers](https://github.com/ruby/debug/blob/master/lib/debug/tracer.rb), with user-facing APIs, IRB-integration, and improvements on accuracy.
|
12
4
|
|
13
5
|
## Installation
|
14
6
|
|
@@ -24,7 +16,92 @@ $ gem install ruby_tracer
|
|
24
16
|
|
25
17
|
## Usage
|
26
18
|
|
27
|
-
|
19
|
+
```rb
|
20
|
+
Tracer.trace(object) { ... } # trace object's activities in the given block
|
21
|
+
Tracer.trace_call { ... } # trace method calls in the given block
|
22
|
+
Tracer.trace_exception { ... } # trace exceptions in the given block
|
23
|
+
```
|
24
|
+
|
25
|
+
**Example**
|
26
|
+
|
27
|
+
```rb
|
28
|
+
require "ruby_tracer"
|
29
|
+
|
30
|
+
obj = Object.new
|
31
|
+
|
32
|
+
def obj.foo
|
33
|
+
100
|
34
|
+
end
|
35
|
+
|
36
|
+
def bar(obj)
|
37
|
+
obj.foo
|
38
|
+
end
|
39
|
+
|
40
|
+
Tracer.trace(obj) { bar(obj) }
|
41
|
+
#depth:1 #<Object:0x000000010903c190> is used as a parameter obj of Object#bar at test.rb:13:in `block in <main>'
|
42
|
+
#depth:2 #<Object:0x000000010903c190> receives .foo at test.rb:10:in `bar'
|
43
|
+
```
|
44
|
+
|
45
|
+
### `ruby_tracer/helper`
|
46
|
+
|
47
|
+
If you want to avoid the `Tracer` namespace, you can do `require "ruby_tracer/helper"` instead:
|
48
|
+
|
49
|
+
```rb
|
50
|
+
require "ruby_tracer/helper"
|
51
|
+
|
52
|
+
trace(object) { ... } # trace object's activities in the given block
|
53
|
+
trace_call { ... } # trace method calls in the given block
|
54
|
+
trace_exception { ... } # trace exceptions in the given block
|
55
|
+
```
|
56
|
+
|
57
|
+
### IRB-integration
|
58
|
+
|
59
|
+
Once required, `ruby_tracer` registers a few IRB commands to help you trace Ruby expressions:
|
60
|
+
|
61
|
+
```
|
62
|
+
trace Trace the target object (or self) in the given expression. Usage: `trace [target,] <expression>`
|
63
|
+
trace_call Trace method calls in the given expression. Usage: `trace_call <expression>`
|
64
|
+
trace_exception Trace exceptions in the given expression. Usage: `trace_exception <expression>`
|
65
|
+
```
|
66
|
+
|
67
|
+
**Example**
|
68
|
+
|
69
|
+
```rb
|
70
|
+
# test.rb
|
71
|
+
require "ruby_tracer"
|
72
|
+
|
73
|
+
obj = Object.new
|
74
|
+
|
75
|
+
def obj.foo
|
76
|
+
100
|
77
|
+
end
|
78
|
+
|
79
|
+
def bar(obj)
|
80
|
+
obj.foo
|
81
|
+
end
|
82
|
+
|
83
|
+
binding.irb
|
84
|
+
```
|
85
|
+
|
86
|
+
|
87
|
+
```
|
88
|
+
irb(main):001:0> trace obj, bar(obj)
|
89
|
+
#depth:23 #<Object:0x0000000107a86648> is used as a parameter obj of Object#bar at (eval):1:in `<main>'
|
90
|
+
#depth:24 #<Object:0x0000000107a86648> receives .foo at test.rb:10:in `bar'
|
91
|
+
=> 100
|
92
|
+
irb(main):002:0> trace_call bar(obj)
|
93
|
+
#depth:23> Object#bar at (eval):1:in `<main>'
|
94
|
+
#depth:24> #<Object:0x0000000107a86648>.foo at test.rb:10:in `bar'
|
95
|
+
#depth:24< #<Object:0x0000000107a86648>.foo #=> 100 at test.rb:10:in `bar'
|
96
|
+
#depth:23< Object#bar #=> 100 at (eval):1:in `<main>'
|
97
|
+
=> 100
|
98
|
+
```
|
99
|
+
|
100
|
+
### Tracer Classes
|
101
|
+
|
102
|
+
If you want to have more control over individual traces, you can use individual tracer classes:
|
103
|
+
|
104
|
+
#### ObjectTracer
|
28
105
|
|
29
106
|
```rb
|
30
107
|
class User
|
@@ -49,7 +126,7 @@ end
|
|
49
126
|
#depth:4 #<User:0x000000010696cad8 @name="John"> receives #name (User#name) at test.rb:8:in `authorized?'
|
50
127
|
```
|
51
128
|
|
52
|
-
|
129
|
+
#### ExceptionTracer
|
53
130
|
|
54
131
|
```rb
|
55
132
|
ExceptionTracer.new.start
|
@@ -63,7 +140,7 @@ end
|
|
63
140
|
#depth:1 #<RuntimeError: boom> at test.rb:4
|
64
141
|
```
|
65
142
|
|
66
|
-
|
143
|
+
#### CallTracer
|
67
144
|
|
68
145
|
```rb
|
69
146
|
class User
|
@@ -95,7 +172,7 @@ end
|
|
95
172
|
#depth:4 < block #=> true at test.rb:16
|
96
173
|
```
|
97
174
|
|
98
|
-
|
175
|
+
#### LineTracer
|
99
176
|
|
100
177
|
```rb
|
101
178
|
class User
|
@@ -120,6 +197,10 @@ end
|
|
120
197
|
#depth:5 at test.rb:8
|
121
198
|
```
|
122
199
|
|
200
|
+
## Customization
|
201
|
+
|
202
|
+
TBD
|
203
|
+
|
123
204
|
## Acknowledgement
|
124
205
|
|
125
206
|
[@ko1](https://github.com/ko1) (Koichi Sasada) implemented the majority of [`ruby/debug`](https://github.com/ruby/debug), including its tracers. So this project wouldn't exist without his amazing work there.
|
data/lib/ruby_tracer/base.rb
CHANGED
@@ -70,10 +70,11 @@ module Tracer
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
def initialize(output: STDOUT, pattern: nil, colorize: nil)
|
73
|
+
def initialize(output: STDOUT, pattern: nil, colorize: nil, depth_offset: 0)
|
74
74
|
@name = self.class.name
|
75
75
|
@type = @name.sub(/Tracer\z/, "")
|
76
76
|
@output = output
|
77
|
+
@depth_offset = depth_offset
|
77
78
|
@colorize = colorize || colorizable?
|
78
79
|
|
79
80
|
if pattern
|
@@ -7,22 +7,30 @@ class CallTracer < Tracer::Base
|
|
7
7
|
TracePoint.new(:a_call, :a_return) do |tp|
|
8
8
|
next if skip?(tp)
|
9
9
|
|
10
|
+
location = caller_locations(2, 1).first.to_s
|
11
|
+
next if location.match?(DIR) || location.match?(/<internal:/)
|
12
|
+
|
10
13
|
depth = caller.size
|
11
14
|
|
12
15
|
call_identifier_str = (tp.defined_class ? minfo(tp) : "block")
|
13
|
-
|
14
16
|
call_identifier_str = colorize_blue(call_identifier_str)
|
15
17
|
|
16
18
|
case tp.event
|
17
19
|
when :call, :c_call, :b_call
|
18
20
|
depth += 1 if tp.event == :c_call
|
19
21
|
sp = " " * depth
|
20
|
-
out tp,
|
22
|
+
out tp,
|
23
|
+
">#{sp}#{call_identifier_str}",
|
24
|
+
depth: depth - 2 - @depth_offset,
|
25
|
+
location: location
|
21
26
|
when :return, :c_return, :b_return
|
22
27
|
depth += 1 if tp.event == :c_return
|
23
28
|
sp = " " * depth
|
24
29
|
return_str = colorize_magenta(safe_inspect(tp.return_value))
|
25
|
-
out tp,
|
30
|
+
out tp,
|
31
|
+
"<#{sp}#{call_identifier_str} #=> #{return_str}",
|
32
|
+
depth: depth - 2 - @depth_offset,
|
33
|
+
location: location
|
26
34
|
end
|
27
35
|
end
|
28
36
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "irb/cmd/nop"
|
2
|
+
require "irb"
|
3
|
+
|
4
|
+
module Tracer
|
5
|
+
def self.register_irb_commands
|
6
|
+
ec = IRB::ExtendCommandBundle.instance_variable_get(:@EXTEND_COMMANDS)
|
7
|
+
|
8
|
+
[
|
9
|
+
[:trace, :Trace, nil, [:trace, IRB::ExtendCommandBundle::OVERRIDE_ALL]],
|
10
|
+
[
|
11
|
+
:trace_call,
|
12
|
+
:TraceCall,
|
13
|
+
nil,
|
14
|
+
[:trace_call, IRB::ExtendCommandBundle::OVERRIDE_ALL]
|
15
|
+
],
|
16
|
+
[
|
17
|
+
:trace_exception,
|
18
|
+
:TraceException,
|
19
|
+
nil,
|
20
|
+
[:trace_exception, IRB::ExtendCommandBundle::OVERRIDE_ALL]
|
21
|
+
]
|
22
|
+
].each do |ecconfig|
|
23
|
+
ec.push(ecconfig)
|
24
|
+
IRB::ExtendCommandBundle.def_extend_command(*ecconfig)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module IRB
|
30
|
+
module ExtendCommand
|
31
|
+
class TraceCommand < Nop
|
32
|
+
class << self
|
33
|
+
def transform_args(args)
|
34
|
+
# Return a string literal as is for backward compatibility
|
35
|
+
if args.empty? || string_literal?(args)
|
36
|
+
args
|
37
|
+
else # Otherwise, consider the input as a String for convenience
|
38
|
+
args.strip.dump
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Trace < TraceCommand
|
45
|
+
category "Tracing"
|
46
|
+
description "Trace the target object (or self) in the given expression. Usage: `trace [target,] <expression>`"
|
47
|
+
|
48
|
+
def execute(*args)
|
49
|
+
args = args.first.split(/,/, 2)
|
50
|
+
|
51
|
+
case args.size
|
52
|
+
when 1
|
53
|
+
target = irb_context.workspace.main
|
54
|
+
expression = args.first
|
55
|
+
when 2
|
56
|
+
target = eval(args.first, irb_context.workspace.binding)
|
57
|
+
expression = args.last
|
58
|
+
else
|
59
|
+
raise ArgumentError,
|
60
|
+
"wrong number of arguments (given #{args.size}, expected 1..2)"
|
61
|
+
end
|
62
|
+
|
63
|
+
b = irb_context.workspace.binding
|
64
|
+
Tracer.trace(target) { eval(expression, b) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class TraceCall < TraceCommand
|
69
|
+
category "Tracing"
|
70
|
+
description "Trace method calls in the given expression. Usage: `trace_call <expression>`"
|
71
|
+
|
72
|
+
def execute(expression)
|
73
|
+
b = irb_context.workspace.binding
|
74
|
+
Tracer.trace_call { eval(expression, b) }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class TraceException < TraceCommand
|
79
|
+
category "Tracing"
|
80
|
+
description "Trace exceptions in the given expression. Usage: `trace_exception <expression>`"
|
81
|
+
|
82
|
+
def execute(expression)
|
83
|
+
b = irb_context.workspace.binding
|
84
|
+
Tracer.trace_exception { eval(expression, b) }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Tracer.register_irb_commands
|
@@ -65,7 +65,7 @@ class ObjectTracer < Tracer::Base
|
|
65
65
|
out tp,
|
66
66
|
" #{colorized_target_label} receives #{colorize_blue(method_info)}",
|
67
67
|
location: caller_locations(internal_depth, 1).first,
|
68
|
-
depth: caller.size - internal_depth
|
68
|
+
depth: caller.size - internal_depth - @depth_offset
|
69
69
|
elsif !tp.parameters.empty?
|
70
70
|
b = tp.binding
|
71
71
|
method_info = colorize_blue(minfo(tp))
|
@@ -82,7 +82,7 @@ class ObjectTracer < Tracer::Base
|
|
82
82
|
out tp,
|
83
83
|
" #{colorized_target_label} is used as a parameter #{colorized_name} of #{method_info}",
|
84
84
|
location: caller_locations(internal_depth, 1).first,
|
85
|
-
depth: caller.size - internal_depth
|
85
|
+
depth: caller.size - internal_depth - @depth_offset
|
86
86
|
end
|
87
87
|
when :rest
|
88
88
|
next if name == :"*"
|
@@ -94,7 +94,7 @@ class ObjectTracer < Tracer::Base
|
|
94
94
|
out tp,
|
95
95
|
" #{colorized_target_label} is used as a parameter in #{colorized_name} of #{method_info}",
|
96
96
|
location: caller_locations(internal_depth, 1).first,
|
97
|
-
depth: caller.size - internal_depth
|
97
|
+
depth: caller.size - internal_depth - @depth_offset
|
98
98
|
end
|
99
99
|
end
|
100
100
|
when :keyrest
|
@@ -106,7 +106,7 @@ class ObjectTracer < Tracer::Base
|
|
106
106
|
out tp,
|
107
107
|
" #{colorized_target_label} is used as a parameter in #{colorized_name} of #{method_info}",
|
108
108
|
location: caller_locations(internal_depth, 1).first,
|
109
|
-
depth: caller.size - internal_depth
|
109
|
+
depth: caller.size - internal_depth - @depth_offset
|
110
110
|
end
|
111
111
|
end
|
112
112
|
end
|
data/lib/ruby_tracer/version.rb
CHANGED
data/lib/ruby_tracer.rb
CHANGED
@@ -5,3 +5,28 @@ require_relative "ruby_tracer/line_tracer"
|
|
5
5
|
require_relative "ruby_tracer/call_tracer"
|
6
6
|
require_relative "ruby_tracer/exception_tracer"
|
7
7
|
require_relative "ruby_tracer/object_tracer"
|
8
|
+
|
9
|
+
module Tracer
|
10
|
+
module Helper
|
11
|
+
DEPTH_OFFSET = 3
|
12
|
+
|
13
|
+
def trace_exception(&block)
|
14
|
+
tracer = ExceptionTracer.new(depth_offset: DEPTH_OFFSET)
|
15
|
+
tracer.start(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def trace_call(&block)
|
19
|
+
tracer = CallTracer.new(depth_offset: DEPTH_OFFSET)
|
20
|
+
tracer.start(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def trace(target, &block)
|
24
|
+
tracer = ObjectTracer.new(target, depth_offset: DEPTH_OFFSET)
|
25
|
+
tracer.start(&block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
extend Helper
|
30
|
+
end
|
31
|
+
|
32
|
+
require_relative "ruby_tracer/irb"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_tracer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stan Lo
|
@@ -29,6 +29,8 @@ files:
|
|
29
29
|
- lib/ruby_tracer/call_tracer.rb
|
30
30
|
- lib/ruby_tracer/color.rb
|
31
31
|
- lib/ruby_tracer/exception_tracer.rb
|
32
|
+
- lib/ruby_tracer/helper.rb
|
33
|
+
- lib/ruby_tracer/irb.rb
|
32
34
|
- lib/ruby_tracer/line_tracer.rb
|
33
35
|
- lib/ruby_tracer/object_tracer.rb
|
34
36
|
- lib/ruby_tracer/version.rb
|