Files
news.gitea.happylizard.me/bin/gems/zeitwerk-2.7.2/lib/zeitwerk/loader/helpers.rb
T
pizza2d1 4cee170d66
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 9s
Add bin and edit workflow
2026-09-16 13:11:16 -06:00

147 lines
4.0 KiB
Ruby

# 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)
if !has_at_least_one_ruby_file?(abspath)
log("directory #{abspath} is ignored because it has no Ruby files") if logger
next
end
ftype = :directory
else
next unless ruby?(abspath)
ftype = :file
end
# We freeze abspath because that saves allocations when passed later to
# File methods. See #125.
yield basename, abspath.freeze, ftype
end
end
# Looks for a Ruby file using breadth-first search. This type of search is
# important to list as less directories as possible and return fast in the
# common case in which there are Ruby files.
#
# @sig (String) -> bool
private def has_at_least_one_ruby_file?(dir)
to_visit = [dir]
while (dir = to_visit.shift)
Dir.each_child(dir) do |basename|
next if hidden?(basename)
abspath = File.join(dir, basename)
next if ignored_path?(abspath)
if dir?(abspath)
to_visit << abspath unless roots.key?(abspath)
else
return true if ruby?(abspath)
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
# --- Inflection --------------------------------------------------------------------------------
CNAME_VALIDATOR = Module.new
private_constant :CNAME_VALIDATOR
# @raise [Zeitwerk::NameError]
# @sig (String, String) -> Symbol
private def cname_for(basename, abspath)
cname = inflector.camelize(basename, abspath)
unless cname.is_a?(String)
raise TypeError, "#{inflector.class}#camelize must return a String, received #{cname.inspect}"
end
if cname.include?("::")
raise Zeitwerk::NameError.new(<<~MESSAGE, cname)
wrong constant name #{cname} inferred by #{inflector.class} from
#{abspath}
#{inflector.class}#camelize should return a simple constant name without "::"
MESSAGE
end
begin
CNAME_VALIDATOR.const_defined?(cname, false)
rescue ::NameError => error
path_type = ruby?(abspath) ? "file" : "directory"
raise Zeitwerk::NameError.new(<<~MESSAGE, error.name)
#{error.message} inferred by #{inflector.class} from #{path_type}
#{abspath}
Possible ways to address this:
* Tell Zeitwerk to ignore this particular #{path_type}.
* Tell Zeitwerk to ignore one of its parent directories.
* Rename the #{path_type} to comply with the naming conventions.
* Modify the inflector to handle this case.
MESSAGE
end
cname.to_sym
end
end