lib/ivar/check_all_manager.rb



# frozen_string_literal: true

require "pathname"

module Ivar
  # Manages automatic inclusion of Ivar::Checked in classes and modules
  class CheckAllManager
    def initialize
      @trace_point = nil
      @mutex = Mutex.new
    end

    # Enables automatic inclusion of Ivar::Checked in all classes and modules
    # defined within the project root.
    #
    # @param project_root [String] The project root directory path
    # @param block [Proc] Optional block. If provided, auto-checking is only active
    #   for the duration of the block. Otherwise, it remains active indefinitely.
    # @return [void]
    def enable(project_root, &block)
      disable if @trace_point
      root_pathname = Pathname.new(project_root)
      @mutex.synchronize do
        # :end means "end of module or class definition" in TracePoint
        @trace_point = TracePoint.new(:end) do |tp|
          next unless tp.path
          file_path = Pathname.new(File.expand_path(tp.path))
          if file_path.to_s.start_with?(root_pathname.to_s)
            klass = tp.self
            next if klass.included_modules.include?(Ivar::Checked)
            klass.include(Ivar::Checked)
          end
        end

        @trace_point.enable
      end

      if block
        begin
          yield
        ensure
          disable
        end
      end

      nil
    end

    # Disables automatic inclusion of Ivar::Checked in classes and modules.
    # @return [void]
    def disable
      @mutex.synchronize do
        if @trace_point
          @trace_point.disable
          @trace_point = nil
        end
      end
    end

    # Returns whether check_all is currently enabled
    # @return [Boolean] true if check_all is enabled, false otherwise
    def enabled?
      @mutex.synchronize { !@trace_point.nil? && @trace_point.enabled? }
    end

    # Returns the current trace point (mainly for testing)
    # @return [TracePoint, nil] The current trace point or nil if not enabled
    def trace_point
      @mutex.synchronize { @trace_point }
    end
  end
end