class DEBUGGER__::MethodBreakpoint

def enable

def enable
  try_enable
end

def eval_class_name

def eval_class_name
  return @klass if @klass
  @klass = @klass_eval_binding.eval(@sig_klass_name)
  @klass_eval_binding = nil
  @klass
end

def initialize b, klass_name, op, method_name, cond: nil, command: nil, path: nil

def initialize b, klass_name, op, method_name, cond: nil, command: nil, path: nil
  @sig_klass_name = klass_name
  @sig_op = op
  @sig_method_name = method_name
  @klass_eval_binding = b
  @override_method = false
  @klass = nil
  @method = nil
  @cond_class = nil
  @key = "#{klass_name}#{op}#{method_name}".freeze
  super(cond, command, path, do_enable: false)
end

def override klass

def override klass
  sig_method_name = @sig_method_name
  klass.prepend Module.new{
    define_method(sig_method_name) do |*args, &block|
      super(*args, &block)
    end
  }
end

def override klass

def override klass
  sig_method_name = @sig_method_name
  klass.prepend Module.new{
    define_method(sig_method_name) do |*args, **kw, &block|
      super(*args, **kw, &block)
    end
  }
end

def search_method

def search_method
  case @sig_op
  when '.'
    @method = @klass.method(@sig_method_name)
  when '#'
    @method = @klass.instance_method(@sig_method_name)
  else
    raise "Unknown op: #{@sig_op}"
  end
end

def setup

def setup
  @tp = TracePoint.new(:call){|tp|
    next if !safe_eval(tp.binding, @cond) if @cond
    next if @cond_class && !tp.self.kind_of?(@cond_class)
    caller_location = caller_locations(2, 1).first.to_s
    next if skip_path?(caller_location)
    suspend
  }
end

def sig

def sig
  @key
end

def to_s

def to_s
  if @method
    loc = @method.source_location || []
    "#{generate_label("Method")} #{sig} at #{loc.join(':')}"
  else
    "#{generate_label("Method (pending)")} #{sig}"
  end + super
end

def try_enable added: false

def try_enable added: false
  eval_class_name
  search_method
  begin
    retried = false
    @tp.enable(target: @method)
    DEBUGGER__.info "#{self} is activated." if added
    if @sig_op == '#'
      @cond_class = @klass if @method.owner != @klass
    else # '.'
      begin
        @cond_class = @klass.singleton_class if @method.owner != @klass.singleton_class
      rescue TypeError
      end
    end
  rescue ArgumentError
    raise if retried
    retried = true
    # maybe C method
    case @sig_op
    when '.'
      begin
        override @klass.singleton_class
      rescue TypeError
        override @klass.class
      end
    when '#'
      override @klass
    end
    # re-collect the method object after the above patch
    search_method
    @override_method = true if @method
    retry
  end
rescue Exception
  raise unless added
end