Class: Dontbugme::VariableTracker

Inherits:
Object
  • Object
show all
Defined in:
lib/dontbugme/variable_tracker.rb

Overview

Automatically captures local variable changes between lines using TracePoint. Emits observe-style spans when variables change, so you can inspect value transformations without manual Dontbugme.observe calls.

Constant Summary collapse

THREAD_KEY =
:dontbugme_variable_tracker_state
THREAD_PATH_KEY =
:dontbugme_variable_tracker_path
IN_TRACKER_KEY =
:dontbugme_variable_tracker_in_callback
SKIP_VARS =
%w[_ result trace e ex].freeze
TRACKABLE_CLASSES =
[String, Integer, Float, Symbol, TrueClass, FalseClass, NilClass].freeze

Class Method Summary collapse

Class Method Details

.clear_state!Object



60
61
62
63
# File 'lib/dontbugme/variable_tracker.rb', line 60

def clear_state!
  Thread.current[THREAD_KEY] = nil
  Thread.current[THREAD_PATH_KEY] = nil
end

.handle_line(tp) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/dontbugme/variable_tracker.rb', line 31

def handle_line(tp)
  return if Thread.current[IN_TRACKER_KEY]
  return unless Dontbugme.config.recording?
  return unless Dontbugme.config.capture_variable_changes
  return unless Context.active?

  path = tp.path.to_s
  return if path.include?('dontbugme') || path.include?('/gems/') || path.include?('bundler')
  return unless Dontbugme.config.source_filter.any? { |f| path.include?(f) }

  binding = tp.binding
  return unless binding

  Thread.current[IN_TRACKER_KEY] = true
  begin
    current = extract_locals(binding)
    prev = Thread.current[THREAD_KEY]
    prev_path = Thread.current[THREAD_PATH_KEY]
    # Only diff when we're in the same file (avoid cross-scope false positives)
    if prev && prev_path == path
      diff_and_emit(prev, current, tp)
    end
    Thread.current[THREAD_KEY] = current
    Thread.current[THREAD_PATH_KEY] = path
  ensure
    Thread.current[IN_TRACKER_KEY] = false
  end
end

.subscribeObject



15
16
17
18
19
20
21
# File 'lib/dontbugme/variable_tracker.rb', line 15

def subscribe
  return if @subscribed

  @trace_point = TracePoint.new(:line) { |tp| handle_line(tp) }
  @trace_point.enable
  @subscribed = true
end

.unsubscribeObject



23
24
25
26
27
28
29
# File 'lib/dontbugme/variable_tracker.rb', line 23

def unsubscribe
  return unless @subscribed

  @trace_point&.disable
  @trace_point = nil
  @subscribed = false
end