How to handle path with case sensitivity?
ejstembler opened this issue · 9 comments
I have a gem with a path like mygem/lib/mygem/IO/csv_writer.rb
for Mygem::IO::CsvWriter
where the IO
path is case sensitive on the deployed container. And the module name is too.
However, Zeitwerk fails with this error:
/Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/helpers.rb:135:in 'const_get': uninitialized constant Mygem::Io::CsvWriter (NameError)
parent.const_get(cname, false)
^^^^^^^^^^
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/helpers.rb:135:in cget'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/eager_load.rb:169:in 'block in actual_eager_load_dir'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/helpers.rb:40:in 'block in ls'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/helpers.rb:25:in 'each'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/helpers.rb:25:in 'ls'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/eager_load.rb:164:in 'actual_eager_load_dir'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/eager_load.rb:17:in 'block (2 levels) in eager_load'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/eager_load.rb:16:in 'each'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/eager_load.rb:16:in 'block in eager_load'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/eager_load.rb:10:in 'synchronize'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader/eager_load.rb:10:in 'eager_load'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader.rb:297:in 'block in eager_load_all'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader.rb:295:in 'each'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.7/lib/zeitwerk/loader.rb:295:in 'eager_load_all'
Any way around this?
@fxn Thanks for the reply. I did try this:
require 'zeitwerk'
# Setup auto-loading
loader = Zeitwerk::Loader.new
loader.push_dir(Rails.root.join('lib', 'mygem', 'lib'))
loader.inflector.inflect(
'Mygem::Io::CsvWriter' => 'Mygem::IO::CsvWriter'
)
loader.setup
Though the error still persists. Did I use it correctly?
Should be
loader.inflector.inflect('io' => 'IO')
In this simple API you inflect only the basename, I realize this is not clear enough in the docs, will improve them.
@fxn I appreciate your guidance. Unfortunately, neither of these worked:
loader.inflector.inflect('io' => 'IO')
or
loader.inflector.inflect('Io' => 'IO')
Still that same error:
uninitialized constant Mygem::Io::CsvWriter
Same stacktrace as before.
Incidentally, if I try putting the code in the gem module and use .for_gem
and later loader.eager_load
after the module, it returns a similar but different error:
/Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/callbacks.rb:25:in 'on_file_autoloaded': expected file /Users/myuser/Projects/mygem/lib/mygem/IO/csv_writer.rb to define constant mygem::Io::CsvWriter, but didn't (Zeitwerk::NameError)
raise Zeitwerk::NameError.new(msg, cref.last)
^^^^^
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/kernel.rb:31:in 'require'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/helpers.rb:135:in 'const_get'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/helpers.rb:135:in 'cget'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:169:in 'block in actual_eager_load_dir'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/helpers.rb:40:in 'block in ls'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/helpers.rb:25:in 'each'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/helpers.rb:25:in 'ls'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:164:in 'actual_eager_load_dir'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:17:in 'block (2 levels) in eager_load'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:16:in 'each'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:16:in 'block in eager_load'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:10:in 'synchronize'
from /Users/myuser/.asdf/installs/ruby/3.2.0/lib/ruby/gems/3.2.0/gems/zeitwerk-2.6.8/lib/zeitwerk/loader/eager_load.rb:10:in 'eager_load'
Ahhhh, sorry, I totally missed the name of the directory is "IO", all in capital letters! Please try instead
loader.inflector.inflect('IO' => 'IO')
Let me say that directory name is not conventional, you have csv_writer.rb
, and by the same convention you normally have io
. In Ruby, file and directory names are normally snake case.
But, if you want it that way, you can with the configuration above.
@fxn Thanks, that worked! loader.inflector.inflect('IO' => 'IO')
I originally had the lower-case path, with upper-case sub-module. That was fine while developing on macOS. Though when deploying to a GCP server, case sensitivity was enforced.. So, I changed to path to upper-case too.
@ejstembler awesome.
I see the documentation could be better in this regard too, the default inflector assumes snake case (and is based on String#capitalize!
), but this is not explictly said.