tracer 0.1.0 → 0.2.1
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/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +10 -3
- data/Gemfile.lock +41 -0
- data/README.md +189 -49
- data/Rakefile +5 -3
- data/lib/tracer/base.rb +172 -0
- data/lib/tracer/call_tracer.rb +41 -0
- data/lib/tracer/color.rb +43 -0
- data/lib/tracer/exception_tracer.rb +23 -0
- data/lib/tracer/helper.rb +3 -0
- data/lib/tracer/irb.rb +115 -0
- data/lib/tracer/line_tracer.rb +13 -0
- data/lib/tracer/object_tracer.rb +117 -0
- data/lib/tracer/version.rb +2 -2
- data/lib/tracer.rb +20 -275
- data/tracer.gemspec +36 -19
- metadata +28 -43
- data/.gitignore +0 -8
- data/.travis.yml +0 -6
- data/bin/console +0 -14
- data/bin/setup +0 -8
data/lib/tracer/color.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tracer
|
4
|
+
module Color
|
5
|
+
CLEAR = 0
|
6
|
+
BOLD = 1
|
7
|
+
UNDERLINE = 4
|
8
|
+
REVERSE = 7
|
9
|
+
RED = 31
|
10
|
+
GREEN = 32
|
11
|
+
YELLOW = 33
|
12
|
+
BLUE = 34
|
13
|
+
MAGENTA = 35
|
14
|
+
CYAN = 36
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def colorize(text, seq)
|
18
|
+
seq = seq.map { |s| "\e[#{const_get(s)}m" }.join("")
|
19
|
+
"#{seq}#{text}#{clear}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def clear
|
23
|
+
"\e[#{CLEAR}m"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def colorize(str, seq, colorize: @colorize)
|
28
|
+
!colorize ? str : Color.colorize(str, seq)
|
29
|
+
end
|
30
|
+
|
31
|
+
def colorize_cyan(str)
|
32
|
+
colorize(str, %i[CYAN BOLD])
|
33
|
+
end
|
34
|
+
|
35
|
+
def colorize_blue(str)
|
36
|
+
colorize(str, %i[BLUE BOLD])
|
37
|
+
end
|
38
|
+
|
39
|
+
def colorize_magenta(str)
|
40
|
+
colorize(str, %i[MAGENTA BOLD])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
class ExceptionTracer < Tracer::Base
|
6
|
+
def setup_tp
|
7
|
+
TracePoint.new(:raise) do |tp|
|
8
|
+
next if skip?(tp)
|
9
|
+
|
10
|
+
exc = tp.raised_exception
|
11
|
+
|
12
|
+
out tp,
|
13
|
+
" #{colorize_magenta(exc.inspect)}",
|
14
|
+
depth: caller.size - (1 + @depth_offset)
|
15
|
+
rescue Exception => e
|
16
|
+
p e
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def skip_with_pattern?(tp)
|
21
|
+
super && !tp.raised_exception.inspect.match?(@pattern)
|
22
|
+
end
|
23
|
+
end
|
data/lib/tracer/irb.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require_relative "../tracer"
|
2
|
+
require "irb/cmd/nop"
|
3
|
+
require "irb"
|
4
|
+
|
5
|
+
module Tracer
|
6
|
+
def self.register_irb_commands
|
7
|
+
ec = IRB::ExtendCommandBundle.instance_variable_get(:@EXTEND_COMMANDS)
|
8
|
+
|
9
|
+
[
|
10
|
+
[:trace, :Trace, nil, [:trace, IRB::ExtendCommandBundle::OVERRIDE_ALL]],
|
11
|
+
[
|
12
|
+
:trace_call,
|
13
|
+
:TraceCall,
|
14
|
+
nil,
|
15
|
+
[:trace_call, IRB::ExtendCommandBundle::OVERRIDE_ALL]
|
16
|
+
],
|
17
|
+
[
|
18
|
+
:trace_exception,
|
19
|
+
:TraceException,
|
20
|
+
nil,
|
21
|
+
[:trace_exception, IRB::ExtendCommandBundle::OVERRIDE_ALL]
|
22
|
+
]
|
23
|
+
].each do |ecconfig|
|
24
|
+
ec.push(ecconfig)
|
25
|
+
IRB::ExtendCommandBundle.def_extend_command(*ecconfig)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module IRB
|
31
|
+
module ExtendCommand
|
32
|
+
class TraceCommand < Nop
|
33
|
+
class << self
|
34
|
+
def transform_args(args)
|
35
|
+
# Return a string literal as is for backward compatibility
|
36
|
+
if args.empty? || string_literal?(args)
|
37
|
+
args
|
38
|
+
else # Otherwise, consider the input as a String for convenience
|
39
|
+
args.strip.dump
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Trace < TraceCommand
|
46
|
+
category "Tracing"
|
47
|
+
description "Trace the target object (or self) in the given expression. Usage: `trace [target,] <expression>`"
|
48
|
+
|
49
|
+
def execute(*args)
|
50
|
+
if args.empty?
|
51
|
+
puts "Please provide the expression to trace. Usage: `trace [target,] <expression>`"
|
52
|
+
return
|
53
|
+
end
|
54
|
+
|
55
|
+
args = args.first.split(/,/, 2)
|
56
|
+
|
57
|
+
case args.size
|
58
|
+
when 1
|
59
|
+
target = irb_context.workspace.main
|
60
|
+
expression = args.first
|
61
|
+
when 2
|
62
|
+
target = eval(args.first, irb_context.workspace.binding)
|
63
|
+
expression = args.last
|
64
|
+
else
|
65
|
+
puts "Please provide the expression to trace. Usage: `trace [target,] <expression>`"
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
69
|
+
unless expression
|
70
|
+
puts "Please provide the expression to trace. Usage: `trace [target,] <expression>`"
|
71
|
+
return
|
72
|
+
end
|
73
|
+
|
74
|
+
b = irb_context.workspace.binding
|
75
|
+
Tracer.trace(target) { eval(expression, b) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class TraceCall < TraceCommand
|
80
|
+
category "Tracing"
|
81
|
+
description "Trace method calls in the given expression. Usage: `trace_call <expression>`"
|
82
|
+
|
83
|
+
def execute(*args)
|
84
|
+
expression = args.first
|
85
|
+
|
86
|
+
unless expression
|
87
|
+
puts "Please provide the expression to trace. Usage: `trace_call <expression>`"
|
88
|
+
return
|
89
|
+
end
|
90
|
+
|
91
|
+
b = irb_context.workspace.binding
|
92
|
+
Tracer.trace_call { eval(expression, b) }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class TraceException < TraceCommand
|
97
|
+
category "Tracing"
|
98
|
+
description "Trace exceptions in the given expression. Usage: `trace_exception <expression>`"
|
99
|
+
|
100
|
+
def execute(*args)
|
101
|
+
expression = args.first
|
102
|
+
|
103
|
+
unless expression
|
104
|
+
puts "Please provide the expression to trace. Usage: `trace_exception <expression>`"
|
105
|
+
return
|
106
|
+
end
|
107
|
+
|
108
|
+
b = irb_context.workspace.binding
|
109
|
+
Tracer.trace_exception { eval(expression, b) }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
Tracer.register_irb_commands
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
class ObjectTracer < Tracer::Base
|
6
|
+
attr_reader :target_id, :target_label
|
7
|
+
|
8
|
+
def initialize(target = nil, target_id: nil, target_label: nil, **kw)
|
9
|
+
unless target || target_id
|
10
|
+
raise ArgumentError, "target or target_id is required"
|
11
|
+
end
|
12
|
+
|
13
|
+
@target_id = target_id || M_OBJECT_ID.bind_call(target)
|
14
|
+
@target_label =
|
15
|
+
(target ? safe_inspect(target) : target_label || "<unlabelled>")
|
16
|
+
super(**kw)
|
17
|
+
end
|
18
|
+
|
19
|
+
def key
|
20
|
+
[@type, @target_id, @pattern, @into].freeze
|
21
|
+
end
|
22
|
+
|
23
|
+
def description
|
24
|
+
"for #{@target_label} #{super}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def colorized_target_label
|
28
|
+
colorize_magenta(@target_label)
|
29
|
+
end
|
30
|
+
|
31
|
+
PRIMITIVE_METHOD_SOURCES = [Module, Class, Object, Kernel]
|
32
|
+
|
33
|
+
def setup_tp
|
34
|
+
TracePoint.new(:a_call) do |tp|
|
35
|
+
next if skip?(tp)
|
36
|
+
|
37
|
+
if M_OBJECT_ID.bind_call(tp.self) == @target_id
|
38
|
+
if PRIMITIVE_METHOD_SOURCES.any? { |klass| klass == tp.defined_class }
|
39
|
+
next
|
40
|
+
end
|
41
|
+
|
42
|
+
internal_depth = 2
|
43
|
+
klass = tp.defined_class
|
44
|
+
method = tp.method_id
|
45
|
+
method_info =
|
46
|
+
method_info =
|
47
|
+
if klass
|
48
|
+
if klass.singleton_class?
|
49
|
+
if M_IS_A.bind_call(tp.self, Class)
|
50
|
+
".#{method} (#{klass}.#{method})"
|
51
|
+
else
|
52
|
+
".#{method}"
|
53
|
+
end
|
54
|
+
else
|
55
|
+
"##{method} (#{klass}##{method})"
|
56
|
+
end
|
57
|
+
else
|
58
|
+
if method
|
59
|
+
"##{method} (<unknown>##{method})"
|
60
|
+
else
|
61
|
+
"<eval or exec with &block>"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
out tp,
|
66
|
+
" #{colorized_target_label} receives #{colorize_blue(method_info)}",
|
67
|
+
location: caller_locations(internal_depth, 1).first,
|
68
|
+
depth: caller.size - internal_depth - @depth_offset
|
69
|
+
elsif !tp.parameters.empty?
|
70
|
+
b = tp.binding
|
71
|
+
method_info = colorize_blue(minfo(tp))
|
72
|
+
|
73
|
+
tp.parameters.each do |type, name|
|
74
|
+
next unless name
|
75
|
+
|
76
|
+
colorized_name = colorize_cyan(name)
|
77
|
+
|
78
|
+
case type
|
79
|
+
when :req, :opt, :key, :keyreq
|
80
|
+
if M_OBJECT_ID.bind_call(b.local_variable_get(name)) == @target_id
|
81
|
+
internal_depth = 4
|
82
|
+
out tp,
|
83
|
+
" #{colorized_target_label} is used as a parameter #{colorized_name} of #{method_info}",
|
84
|
+
location: caller_locations(internal_depth, 1).first,
|
85
|
+
depth: caller.size - internal_depth - @depth_offset
|
86
|
+
end
|
87
|
+
when :rest
|
88
|
+
next if name == :"*"
|
89
|
+
|
90
|
+
internal_depth = 6
|
91
|
+
ary = b.local_variable_get(name)
|
92
|
+
ary.each do |e|
|
93
|
+
if M_OBJECT_ID.bind_call(e) == @target_id
|
94
|
+
out tp,
|
95
|
+
" #{colorized_target_label} is used as a parameter in #{colorized_name} of #{method_info}",
|
96
|
+
location: caller_locations(internal_depth, 1).first,
|
97
|
+
depth: caller.size - internal_depth - @depth_offset
|
98
|
+
end
|
99
|
+
end
|
100
|
+
when :keyrest
|
101
|
+
next if name == :"**"
|
102
|
+
internal_depth = 6
|
103
|
+
h = b.local_variable_get(name)
|
104
|
+
h.each do |k, e|
|
105
|
+
if M_OBJECT_ID.bind_call(e) == @target_id
|
106
|
+
out tp,
|
107
|
+
" #{colorized_target_label} is used as a parameter in #{colorized_name} of #{method_info}",
|
108
|
+
location: caller_locations(internal_depth, 1).first,
|
109
|
+
depth: caller.size - internal_depth - @depth_offset
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/lib/tracer/version.rb
CHANGED
data/lib/tracer.rb
CHANGED
@@ -1,287 +1,32 @@
|
|
1
|
-
# frozen_string_literal:
|
2
|
-
#--
|
3
|
-
# $Release Version: 0.3$
|
4
|
-
# $Revision: 1.12 $
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
# trace output (see Tracer.add_filter, Tracer.on, and Tracer.off).
|
12
|
-
#
|
13
|
-
# == Example
|
14
|
-
#
|
15
|
-
# Consider the following Ruby script
|
16
|
-
#
|
17
|
-
# class A
|
18
|
-
# def square(a)
|
19
|
-
# return a*a
|
20
|
-
# end
|
21
|
-
# end
|
22
|
-
#
|
23
|
-
# a = A.new
|
24
|
-
# a.square(5)
|
25
|
-
#
|
26
|
-
# Running the above script using <code>ruby -r tracer example.rb</code> will
|
27
|
-
# output the following trace to STDOUT (Note you can also explicitly
|
28
|
-
# <code>require 'tracer'</code>)
|
29
|
-
#
|
30
|
-
# #0:<internal:lib/rubygems/custom_require>:38:Kernel:<: -
|
31
|
-
# #0:example.rb:3::-: class A
|
32
|
-
# #0:example.rb:3::C: class A
|
33
|
-
# #0:example.rb:4::-: def square(a)
|
34
|
-
# #0:example.rb:7::E: end
|
35
|
-
# #0:example.rb:9::-: a = A.new
|
36
|
-
# #0:example.rb:10::-: a.square(5)
|
37
|
-
# #0:example.rb:4:A:>: def square(a)
|
38
|
-
# #0:example.rb:5:A:-: return a*a
|
39
|
-
# #0:example.rb:6:A:<: end
|
40
|
-
# | | | | |
|
41
|
-
# | | | | ---------------------+ event
|
42
|
-
# | | | ------------------------+ class
|
43
|
-
# | | --------------------------+ line
|
44
|
-
# | ------------------------------------+ filename
|
45
|
-
# ---------------------------------------+ thread
|
46
|
-
#
|
47
|
-
# Symbol table used for displaying incoming events:
|
48
|
-
#
|
49
|
-
# +}+:: call a C-language routine
|
50
|
-
# +{+:: return from a C-language routine
|
51
|
-
# +>+:: call a Ruby method
|
52
|
-
# +C+:: start a class or module definition
|
53
|
-
# +E+:: finish a class or module definition
|
54
|
-
# +-+:: execute code on a new line
|
55
|
-
# +^+:: raise an exception
|
56
|
-
# +<+:: return from a Ruby method
|
57
|
-
#
|
58
|
-
# == Copyright
|
59
|
-
#
|
60
|
-
# by Keiju ISHITSUKA(keiju@ishitsuka.com)
|
61
|
-
#
|
62
|
-
class Tracer
|
3
|
+
require_relative "tracer/version"
|
4
|
+
require_relative "tracer/line_tracer"
|
5
|
+
require_relative "tracer/call_tracer"
|
6
|
+
require_relative "tracer/exception_tracer"
|
7
|
+
require_relative "tracer/object_tracer"
|
63
8
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
alias verbose? verbose
|
9
|
+
module Tracer
|
10
|
+
module Helper
|
11
|
+
DEPTH_OFFSET = 3
|
68
12
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
# mutex lock used by tracer for displaying trace output
|
73
|
-
attr_reader :stdout_mutex
|
74
|
-
|
75
|
-
# display process id in trace output (defaults to false)
|
76
|
-
attr_accessor :display_process_id
|
77
|
-
alias display_process_id? display_process_id
|
78
|
-
|
79
|
-
# display thread id in trace output (defaults to true)
|
80
|
-
attr_accessor :display_thread_id
|
81
|
-
alias display_thread_id? display_thread_id
|
82
|
-
|
83
|
-
# display C-routine calls in trace output (defaults to false)
|
84
|
-
attr_accessor :display_c_call
|
85
|
-
alias display_c_call? display_c_call
|
86
|
-
end
|
87
|
-
|
88
|
-
Tracer::stdout = STDOUT
|
89
|
-
Tracer::verbose = false
|
90
|
-
Tracer::display_process_id = false
|
91
|
-
Tracer::display_thread_id = true
|
92
|
-
Tracer::display_c_call = false
|
93
|
-
|
94
|
-
@stdout_mutex = Thread::Mutex.new
|
95
|
-
|
96
|
-
# Symbol table used for displaying trace information
|
97
|
-
EVENT_SYMBOL = {
|
98
|
-
"line" => "-",
|
99
|
-
"call" => ">",
|
100
|
-
"return" => "<",
|
101
|
-
"class" => "C",
|
102
|
-
"end" => "E",
|
103
|
-
"raise" => "^",
|
104
|
-
"c-call" => "}",
|
105
|
-
"c-return" => "{",
|
106
|
-
"unknown" => "?"
|
107
|
-
}
|
108
|
-
|
109
|
-
def initialize # :nodoc:
|
110
|
-
@threads = Hash.new
|
111
|
-
if defined? Thread.main
|
112
|
-
@threads[Thread.main.object_id] = 0
|
113
|
-
else
|
114
|
-
@threads[Thread.current.object_id] = 0
|
13
|
+
def trace_exception(&block)
|
14
|
+
tracer = ExceptionTracer.new(depth_offset: DEPTH_OFFSET)
|
15
|
+
tracer.start(&block)
|
115
16
|
end
|
116
17
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
121
|
-
|
122
|
-
def stdout # :nodoc:
|
123
|
-
Tracer.stdout
|
124
|
-
end
|
125
|
-
|
126
|
-
def on # :nodoc:
|
127
|
-
if block_given?
|
128
|
-
on
|
129
|
-
begin
|
130
|
-
yield
|
131
|
-
ensure
|
132
|
-
off
|
133
|
-
end
|
134
|
-
else
|
135
|
-
set_trace_func method(:trace_func).to_proc
|
136
|
-
stdout.print "Trace on\n" if Tracer.verbose?
|
18
|
+
def trace_call(&block)
|
19
|
+
tracer = CallTracer.new(depth_offset: DEPTH_OFFSET)
|
20
|
+
tracer.start(&block)
|
137
21
|
end
|
138
|
-
end
|
139
|
-
|
140
|
-
def off # :nodoc:
|
141
|
-
set_trace_func nil
|
142
|
-
stdout.print "Trace off\n" if Tracer.verbose?
|
143
|
-
end
|
144
|
-
|
145
|
-
def add_filter(p = proc) # :nodoc:
|
146
|
-
@filters.push p
|
147
|
-
end
|
148
|
-
|
149
|
-
def set_get_line_procs(file, p = proc) # :nodoc:
|
150
|
-
@get_line_procs[file] = p
|
151
|
-
end
|
152
22
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
end
|
157
|
-
|
158
|
-
unless list = SCRIPT_LINES__[file]
|
159
|
-
list = File.readlines(file) rescue []
|
160
|
-
SCRIPT_LINES__[file] = list
|
161
|
-
end
|
162
|
-
|
163
|
-
if l = list[line - 1]
|
164
|
-
l
|
165
|
-
else
|
166
|
-
"-\n"
|
23
|
+
def trace(target, &block)
|
24
|
+
tracer = ObjectTracer.new(target, depth_offset: DEPTH_OFFSET)
|
25
|
+
tracer.start(&block)
|
167
26
|
end
|
168
27
|
end
|
169
28
|
|
170
|
-
|
171
|
-
if no = @threads[Thread.current.object_id]
|
172
|
-
no
|
173
|
-
else
|
174
|
-
@threads[Thread.current.object_id] = @threads.size
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def trace_func(event, file, line, id, binding, klass, *) # :nodoc:
|
179
|
-
return if file == __FILE__
|
180
|
-
|
181
|
-
for p in @filters
|
182
|
-
return unless p.call event, file, line, id, binding, klass
|
183
|
-
end
|
184
|
-
|
185
|
-
return unless Tracer::display_c_call? or
|
186
|
-
event != "c-call" && event != "c-return"
|
187
|
-
|
188
|
-
Tracer::stdout_mutex.synchronize do
|
189
|
-
if EVENT_SYMBOL[event]
|
190
|
-
stdout.printf("<%d>", $$) if Tracer::display_process_id?
|
191
|
-
stdout.printf("#%d:", get_thread_no) if Tracer::display_thread_id?
|
192
|
-
if line == 0
|
193
|
-
source = "?\n"
|
194
|
-
else
|
195
|
-
source = get_line(file, line)
|
196
|
-
end
|
197
|
-
stdout.printf("%s:%d:%s:%s: %s",
|
198
|
-
file,
|
199
|
-
line,
|
200
|
-
klass || '',
|
201
|
-
EVENT_SYMBOL[event],
|
202
|
-
source)
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
end
|
207
|
-
|
208
|
-
# Reference to singleton instance of Tracer
|
209
|
-
Single = new
|
210
|
-
|
211
|
-
##
|
212
|
-
# Start tracing
|
213
|
-
#
|
214
|
-
# === Example
|
215
|
-
#
|
216
|
-
# Tracer.on
|
217
|
-
# # code to trace here
|
218
|
-
# Tracer.off
|
219
|
-
#
|
220
|
-
# You can also pass a block:
|
221
|
-
#
|
222
|
-
# Tracer.on {
|
223
|
-
# # trace everything in this block
|
224
|
-
# }
|
225
|
-
|
226
|
-
def Tracer.on
|
227
|
-
if block_given?
|
228
|
-
Single.on{yield}
|
229
|
-
else
|
230
|
-
Single.on
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
##
|
235
|
-
# Disable tracing
|
236
|
-
|
237
|
-
def Tracer.off
|
238
|
-
Single.off
|
239
|
-
end
|
240
|
-
|
241
|
-
##
|
242
|
-
# Register an event handler <code>p</code> which is called everytime a line
|
243
|
-
# in +file_name+ is executed.
|
244
|
-
#
|
245
|
-
# Example:
|
246
|
-
#
|
247
|
-
# Tracer.set_get_line_procs("example.rb", lambda { |line|
|
248
|
-
# puts "line number executed is #{line}"
|
249
|
-
# })
|
250
|
-
|
251
|
-
def Tracer.set_get_line_procs(file_name, p = proc)
|
252
|
-
Single.set_get_line_procs(file_name, p)
|
253
|
-
end
|
254
|
-
|
255
|
-
##
|
256
|
-
# Used to filter unwanted trace output
|
257
|
-
#
|
258
|
-
# Example which only outputs lines of code executed within the Kernel class:
|
259
|
-
#
|
260
|
-
# Tracer.add_filter do |event, file, line, id, binding, klass, *rest|
|
261
|
-
# "Kernel" == klass.to_s
|
262
|
-
# end
|
263
|
-
|
264
|
-
def Tracer.add_filter(p = proc)
|
265
|
-
Single.add_filter(p)
|
266
|
-
end
|
29
|
+
extend Helper
|
267
30
|
end
|
268
31
|
|
269
|
-
|
270
|
-
SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
|
271
|
-
|
272
|
-
if $0 == __FILE__
|
273
|
-
# direct call
|
274
|
-
|
275
|
-
$0 = ARGV[0]
|
276
|
-
ARGV.shift
|
277
|
-
Tracer.on
|
278
|
-
require $0
|
279
|
-
else
|
280
|
-
# call Tracer.on only if required by -r command-line option
|
281
|
-
count = caller.count {|bt| %r%/rubygems/core_ext/kernel_require\.rb:% !~ bt}
|
282
|
-
if (defined?(Gem) and count == 0) or
|
283
|
-
(!defined?(Gem) and count <= 1)
|
284
|
-
Tracer.on
|
285
|
-
end
|
286
|
-
end
|
287
|
-
# :startdoc:
|
32
|
+
require_relative "tracer/irb"
|
data/tracer.gemspec
CHANGED
@@ -1,26 +1,43 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
# for Ruby core repository
|
5
|
-
require_relative "version"
|
6
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/tracer/version"
|
7
4
|
|
8
5
|
Gem::Specification.new do |spec|
|
9
|
-
spec.name
|
10
|
-
spec.version
|
11
|
-
spec.authors
|
12
|
-
spec.email
|
6
|
+
spec.name = "tracer"
|
7
|
+
spec.version = Tracer::VERSION
|
8
|
+
spec.authors = ["Stan Lo", "Keiju ISHITSUKA"]
|
9
|
+
spec.email = %w[stan001212@gmail.com keiju@ruby-lang.org]
|
13
10
|
|
14
|
-
spec.summary
|
15
|
-
spec.description
|
16
|
-
spec.homepage
|
17
|
-
spec.
|
11
|
+
spec.summary = "A Ruby tracer"
|
12
|
+
spec.description = "A Ruby tracer"
|
13
|
+
spec.homepage = "https://github.com/ruby/tracer"
|
14
|
+
spec.licenses = %w[Ruby BSD-2-Clause]
|
15
|
+
spec.required_ruby_version = ">= 2.7.0"
|
18
16
|
|
19
|
-
spec.
|
20
|
-
spec.
|
21
|
-
spec.
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/ruby/tracer"
|
19
|
+
spec.metadata[
|
20
|
+
"changelog_uri"
|
21
|
+
] = "https://github.com/ruby/tracer/blob/main/CHANGELOG.md"
|
22
|
+
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
+
spec.files =
|
26
|
+
Dir.chdir(__dir__) do
|
27
|
+
`git ls-files -z`.split("\x0")
|
28
|
+
.reject do |f|
|
29
|
+
(f == __FILE__) ||
|
30
|
+
f.match(
|
31
|
+
%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)}
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
spec.bindir = "exe"
|
36
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
22
37
|
spec.require_paths = ["lib"]
|
23
38
|
|
24
|
-
|
25
|
-
|
39
|
+
# Uncomment to register a new dependency of your gem
|
40
|
+
|
41
|
+
# For more information and examples about making a new gem, check out our
|
42
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
26
43
|
end
|