Class: Zeitwerk::Loader::FileSystem
- Inherits:
-
Object
- Object
- Zeitwerk::Loader::FileSystem
- Defined in:
- lib/zeitwerk/loader/file_system.rb
Overview
This private class encapsulates interactions with the file system.
It is used to list directories and check file types, and it encodes the conventions documented in the README.
Instance Method Summary collapse
-
#dir?(path) ⇒ Boolean
: (String) -> bool.
-
#has_exactly_one_nsfile?(cref, dir) ⇒ Boolean
Returns the absolute path to an nsfile in ‘dir`, if there is exactly one.
-
#hidden?(basename) ⇒ Boolean
: (String) -> bool.
-
#initialize(loader) ⇒ FileSystem
constructor
: (Zeitwerk::Loader) -> void.
-
#ls(dir, collapse: true, &block) ⇒ Object
This method lists directories, filtering out the following:.
-
#rb_extension?(path) ⇒ Boolean
: (String) -> bool.
-
#supported_ftype?(abspath) ⇒ Boolean
Encodes the documented conventions.
-
#walk_up(abspath) ⇒ Object
: (String) { (String) -> void } -> void.
Constructor Details
#initialize(loader) ⇒ FileSystem
: (Zeitwerk::Loader) -> void
11 12 13 |
# File 'lib/zeitwerk/loader/file_system.rb', line 11 def initialize(loader) @loader = loader end |
Instance Method Details
#dir?(path) ⇒ Boolean
: (String) -> bool
120 121 122 |
# File 'lib/zeitwerk/loader/file_system.rb', line 120 def dir?(path) File.directory?(path) end |
#has_exactly_one_nsfile?(cref, dir) ⇒ Boolean
Returns the absolute path to an nsfile in ‘dir`, if there is exactly one. If there is none, it returns `nil`.
This method accounts for collapsed directories, which conceptually allow for multiple nsfiles. If two are found, Zeitwerk::ConflictingNamespaceDefinitionError is raised.
: (Zeitwerk::Cref, String) -> String? ! Zeitwerk::ConflictingNamespaceDefinitionError
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/zeitwerk/loader/file_system.rb', line 71 def has_exactly_one_nsfile?(cref, dir) return unless @loader.nsfile # When `dir` does not have any collapsed directories a simple lookup # suffices. This is a common case worth optimizing. unless @loader.__collapse_parent?(dir) nsfile_abspath = File.join(dir, @loader.nsfile) if File.exist?(nsfile_abspath) && !@loader.__ignored_path?(nsfile_abspath) return nsfile_abspath end return end nsfile = nil to_visit = [dir] while (dir = to_visit.shift) relevant_dir_entries(dir) do |basename, abspath, ftype| if ftype == :file && basename == @loader.nsfile if nsfile raise Zeitwerk::ConflictingNamespaceDefinitionError.new(cref.path, location: nsfile, conflicting_file: abspath) end nsfile = abspath elsif ftype == :directory && @loader.__collapse?(abspath) to_visit << abspath end end end nsfile end |
#hidden?(basename) ⇒ Boolean
: (String) -> bool
125 126 127 |
# File 'lib/zeitwerk/loader/file_system.rb', line 125 def hidden?(basename) basename.start_with?('.') end |
#ls(dir, collapse: true, &block) ⇒ Object
This method lists directories, filtering out the following:
-
Hidden entries.
-
Ignored entries.
-
Files whose extension is not ‘.rb`.
-
Nested root directories, since they represent separate trees.
-
Subdirectories that (recursively) contain no Ruby files.
If ‘collapse` is true, collapsed directories are not yielded, instead, the method recurses so that the caller gets a conceptually flat listing.
For every entry that is not excluded, ‘ls` yields its basename, absolute path, and file type, which can only be :file or :directory.
: (String) { (String, String, Symbol) -> void } -> void
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/zeitwerk/loader/file_system.rb', line 30 def ls(dir, collapse: true, &block) children = relevant_dir_entries(dir) # The order in which a directory is listed depends on the file system. # # Since client code may run on different platforms, it seems convenient to # sort directory entries. This provides more deterministic behavior, with # consistent eager loading in particular. children.sort_by!(&:first) children.each do |basename, abspath, ftype| if ftype == :directory if !has_at_least_one_ruby_file?(abspath) @loader.__log { "directory #{abspath} is ignored because it has no Ruby files" } next elsif collapse && @loader.__collapse?(abspath) ls(abspath, collapse: collapse, &block) next end end yield basename, abspath, ftype end end |
#rb_extension?(path) ⇒ Boolean
: (String) -> bool
115 116 117 |
# File 'lib/zeitwerk/loader/file_system.rb', line 115 def rb_extension?(path) path.end_with?('.rb') end |
#supported_ftype?(abspath) ⇒ Boolean
Encodes the documented conventions.
: (String) -> Symbol?
106 107 108 109 110 111 112 |
# File 'lib/zeitwerk/loader/file_system.rb', line 106 def supported_ftype?(abspath) if rb_extension?(abspath) :file # By convention, we can avoid a syscall here. elsif dir?(abspath) :directory end end |
#walk_up(abspath) ⇒ Object
: (String) { (String) -> void } -> void
56 57 58 59 60 61 62 |
# File 'lib/zeitwerk/loader/file_system.rb', line 56 def walk_up(abspath) loop do yield abspath abspath, basename = File.split(abspath) break if basename == '/' end end |