I have built a Ruby project and I want to switch from using a ton of require_relative statements to a smarter autoloader like Zeitwerk.
There are a lot of files/folders in the project, hence I will only present some of them in order to not make my question too bloated with unnecessary details. You can find the whole project on Github.
The structure of the repo is the following
chess/
bin/
chess
lib/
chess.rb
chess/
board.rb
serialize.rb
coordinates.rb
pieces/
(other files and folders)
(other files)
bin/chess is the executable file and contains
#!/usr/bin/env ruby
require "zeitwerk"
loader = Zeitwerk::Loader.for_gem
loader.setup
Chess.new.start # method that starts the whole game
lib/chess.rb contains the class Chess, which runs the logic of the game.
All the other files inside of lib/ follow the Zeitwerk file structure.
Therefore, lib/chess/serialize.rb contains
class Chess
module Serialize
...
end
end
and lib/chess/pieces/piece.rb contains
class Chess
module Pieces
module Piece
...
end
end
end
When I try to run the script, with bin/chess (or cding into the bin/ folder and running ./chess), the terminal returns
uninitialized constant Chess (NameError)
It seems like the files are not loaded by Zeitwerk. I read all of their documentation but I was not able to discover what's the problem.
edit:
As one of the answers pointed out, I removed the for_gem call in bin/chess with
loader = Zeitwerk::Loader.new
loader.tag = File.basename(__FILE__, ".rb")
loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
loader.push_dir("#{__dir__}/../lib")
loader.setup
However, now all the classes/modules inside of the Chess namespace are loaded, while all the ones located in deeper directories, like lib/chess/display/chess_display.rb (which is Chess::Display::ChessDisplay) don't get loaded.
According to the Readme,
for_gemcorresponds to:note the
push_dir(__dir__)and that it's expected to be called from thelib/directory. You're calling it from a file in thebin/directory.I have not used zeitwork like this, but I think you might want to either:
lib/chess.rband perform theZeitwork::Loader.for_gemin that filefor_gemand use the snippet above, but adjust__dir__ to be../lib.