File: C:/Ruby27-x64/lib/ruby/gems/2.7.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/helpers.rb
# frozen_string_literal: true
module Zeitwerk::Loader::Helpers
# --- Logging -----------------------------------------------------------------------------------
# @sig (String) -> void
private def log(message)
method_name = logger.respond_to?(:debug) ? :debug : :call
logger.send(method_name, "Zeitwerk@#{tag}: #{message}")
end
# --- Files and directories ---------------------------------------------------------------------
# @sig (String) { (String, String) -> void } -> void
private def ls(dir)
children = Dir.children(dir)
# The order in which a directory is listed depends on the file system.
#
# Since client code may run in different platforms, it seems convenient to
# order directory entries. This provides consistent eager loading across
# platforms, for example.
children.sort!
children.each do |basename|
next if hidden?(basename)
abspath = File.join(dir, basename)
next if ignored_path?(abspath)
if dir?(abspath)
next if roots.key?(abspath)
next if !has_at_least_one_ruby_file?(abspath)
else
next unless ruby?(abspath)
end
# We freeze abspath because that saves allocations when passed later to
# File methods. See #125.
yield basename, abspath.freeze
end
end
# @sig (String) -> bool
private def has_at_least_one_ruby_file?(dir)
to_visit = [dir]
while dir = to_visit.shift
ls(dir) do |_basename, abspath|
if dir?(abspath)
to_visit << abspath
else
return true
end
end
end
false
end
# @sig (String) -> bool
private def ruby?(path)
path.end_with?(".rb")
end
# @sig (String) -> bool
private def dir?(path)
File.directory?(path)
end
# @sig (String) -> bool
private def hidden?(basename)
basename.start_with?(".")
end
# @sig (String) { (String) -> void } -> void
private def walk_up(abspath)
loop do
yield abspath
abspath, basename = File.split(abspath)
break if basename == "/"
end
end
# --- Constants ---------------------------------------------------------------------------------
# The autoload? predicate takes into account the ancestor chain of the
# receiver, like const_defined? and other methods in the constants API do.
#
# For example, given
#
# class A
# autoload :X, "x.rb"
# end
#
# class B < A
# end
#
# B.autoload?(:X) returns "x.rb".
#
# We need a way to strictly check in parent ignoring ancestors.
#
# @sig (Module, Symbol) -> String?
if method(:autoload?).arity == 1
private def strict_autoload_path(parent, cname)
parent.autoload?(cname) if cdef?(parent, cname)
end
else
private def strict_autoload_path(parent, cname)
parent.autoload?(cname, false)
end
end
# @sig (Module, Symbol) -> String
if Symbol.method_defined?(:name)
# Symbol#name was introduced in Ruby 3.0. It returns always the same
# frozen object, so we may save a few string allocations.
private def cpath(parent, cname)
Object == parent ? cname.name : "#{real_mod_name(parent)}::#{cname.name}"
end
else
private def cpath(parent, cname)
Object == parent ? cname.to_s : "#{real_mod_name(parent)}::#{cname}"
end
end
# @sig (Module, Symbol) -> bool
private def cdef?(parent, cname)
parent.const_defined?(cname, false)
end
# @raise [NameError]
# @sig (Module, Symbol) -> Object
private def cget(parent, cname)
parent.const_get(cname, false)
end
# @raise [NameError]
# @sig (Module, Symbol) -> Object
private def crem(parent, cname)
parent.__send__(:remove_const, cname)
end
end