class TappingDevice::Trackers::MutationTracker

Public Class Methods

new(options, &block) click to toggle source
Calls superclass method TappingDevice::new
# File lib/tapping_device/trackers/mutation_tracker.rb, line 4
def initialize(options, &block)
  options[:hijack_attr_methods] = true
  super
  @snapshot_stack = []
end

Public Instance Methods

stop!() click to toggle source
Calls superclass method TappingDevice#stop!
# File lib/tapping_device/trackers/mutation_tracker.rb, line 16
def stop!
  super
  @ivar_snapshot_trace_point.disable
end
track(object) click to toggle source
Calls superclass method TappingDevice#track
# File lib/tapping_device/trackers/mutation_tracker.rb, line 10
def track(object)
  super
  insert_snapshot_taking_trace_point
  self
end

Private Instance Methods

build_payload(tp:, filepath:, line_number:) click to toggle source
Calls superclass method TappingDevice#build_payload
# File lib/tapping_device/trackers/mutation_tracker.rb, line 46
def build_payload(tp:, filepath:, line_number:)
  payload = super

  if change_capturing_event?(tp)
    payload.ivar_changes = capture_ivar_changes
  end

  payload
end
capture_ivar_changes() click to toggle source
# File lib/tapping_device/trackers/mutation_tracker.rb, line 56
def capture_ivar_changes
  changes = {}
  additional_keys = @latest_instance_variables.keys - @instance_variables_snapshot.keys
  additional_keys.each do |key|
    changes[key] = {before: Output::PayloadWrapper::UNDEFINED, after: @latest_instance_variables[key]}
  end

  removed_keys = @instance_variables_snapshot.keys - @latest_instance_variables.keys
  removed_keys.each do |key|
    changes[key] = {before: @instance_variables_snapshot[key], after: Output::PayloadWrapper::UNDEFINED}
  end

  remained_keys = @latest_instance_variables.keys - additional_keys
  remained_keys.each do |key|
    next if @latest_instance_variables[key] == @instance_variables_snapshot[key]
    changes[key] = {before: @instance_variables_snapshot[key], after: @latest_instance_variables[key]}
  end

  changes
end
change_capturing_event?(tp) click to toggle source
# File lib/tapping_device/trackers/mutation_tracker.rb, line 91
def change_capturing_event?(tp)
  !snapshot_capturing_event?(tp)
end
filter_condition_satisfied?(tp) click to toggle source
# File lib/tapping_device/trackers/mutation_tracker.rb, line 33
def filter_condition_satisfied?(tp)
  return false unless is_from_target?(tp)

  if snapshot_capturing_event?(tp)
    true
  else
    @latest_instance_variables = target_instance_variables
    @instance_variables_snapshot = @snapshot_stack.pop

    @latest_instance_variables != @instance_variables_snapshot
  end
end
insert_snapshot_taking_trace_point() click to toggle source

we need to snapshot instance variables at the beginning of every method call so we can get a correct state for the later comparison

# File lib/tapping_device/trackers/mutation_tracker.rb, line 25
def insert_snapshot_taking_trace_point
  @ivar_snapshot_trace_point = build_minimum_trace_point(event_type: :call) do
    snapshot_instance_variables
  end

  @ivar_snapshot_trace_point.enable unless TappingDevice.suspend_new
end
print_snapshot_stack(tp) click to toggle source

belows are debugging helpers I'll leave them for a while in case there's a bug in the tracker

print_state_comparison() click to toggle source
snapshot_capturing_event?(tp) click to toggle source
# File lib/tapping_device/trackers/mutation_tracker.rb, line 87
def snapshot_capturing_event?(tp)
  tp.event == :call
end
snapshot_instance_variables() click to toggle source
# File lib/tapping_device/trackers/mutation_tracker.rb, line 77
def snapshot_instance_variables
  @snapshot_stack.push(target_instance_variables)
end
target_instance_variables() click to toggle source
# File lib/tapping_device/trackers/mutation_tracker.rb, line 81
def target_instance_variables
  target.instance_variables.each_with_object({}) do |ivar, hash|
    hash[ivar] = target.instance_variable_get(ivar)
  end
end