class DEBUGGER__::ThreadClient

def get_consts expr = nil, only_self: false, &block

def get_consts expr = nil, only_self: false, &block
  if expr && !expr.empty?
    begin
      _self = frame_eval(expr, re_raise: true)
    rescue Exception
      # ignore
    else
      if M_KIND_OF_P.bind_call(_self, Module)
        iter_consts _self, &block
        return
      else
        puts "#{_self.inspect} (by #{expr}) is not a Module."
      end
    end
  elsif _self = current_frame&.self
    cs = {}
    if M_KIND_OF_P.bind_call(_self, Module)
      cs[_self] = :self
    else
      _self = M_CLASS.bind_call(_self)
      cs[_self] = :self unless only_self
    end
    unless only_self
      _self.ancestors.each{|c| break if c == Object; cs[c] = :ancestors}
      if b = current_frame&.binding
        b.eval('::Module.nesting').each{|c| cs[c] = :nesting unless cs.has_key? c}
      end
    end
    names = {}
    cs.each{|c, _|
      iter_consts c, names, &block
    }
  end
end