alainravet/private_please

View on GitHub
lib/private_please/tracking/trace_point_processor.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'private_please/config'
require 'private_please/storage/called_methods_memory_store'
require 'private_please/tracking/debug/trace_point_data_logger'
require 'private_please/tracking/result'
require 'private_please/tracking/trace_point_details'
require 'private_please/utils/two_level_stack'

module PrivatePlease
  module Tracking
    class TracePointProcessor
      def initialize(config)
        @config                   = config

        @latest_tracepoints       = Utils::TwoLevelStack.new
        @encountered_method_calls = Storage::CalledMethodsMemoryStore.new
      end

      def process(tp)
        return if untracked_code?(tp.path)
        remember_trace_point tp
        store_method_call_details if tp.event == :call
      end

      def result
        Result.new(@encountered_method_calls)
      end

      private

      if Debug.enabled?
        def remember_trace_point(tp)
          tpd = TracePointDetails.from(tp)
          @latest_tracepoints.push tpd
          Debug.log_to_trace_file  tpd
        end
      else
        def remember_trace_point(tp)
          @latest_tracepoints.push TracePointDetails.from(tp)
        end
      end

      def untracked_code?(path)
        path.start_with?(*untracked_source_dirs)
      end

      def untracked_source_dirs
        @_untracked_source_dirs ||= begin
          Utils::RubyUtils.gems_paths +
          Array(Utils::RubyUtils.std_lib_home) +
          @config.additional_excluded_dirs
        end
      end

      def tp_curr; @latest_tracepoints.curr end
      def tp_prev; @latest_tracepoints.prev end

      def store_method_call_details
        key = tp_curr.method_full_name
        if private_call?
          @encountered_method_calls.add_private_call(key) unless already_private?
        else
          @encountered_method_calls.add_public_call(key)
        end
      end

      def private_call?
        return unless tp_prev  # fails sometime (ex: rspec-core) # UNTESTED
        curr_event, prev_event = tp_curr.event, tp_prev.event
        (curr_event == :call) &&
          [:line, :return, :c_return].include?(prev_event) &&
          tp_curr.same_object?(tp_prev)
      end

      def already_private?
        tp_curr._self.private_methods.include?(tp_curr.method_id)
      end
    end
  end
end