For a Roda app, I'd like to include a single file for autoloading by Zeitwerk while ignoring all the others in that directory. The simplified layout looks like this:
config
application.rb
puma.rb
(...)
lib
my_class.rb
(...)
To setup Zeitwerk, this would be perfect but not possible:
loader = Zeitwerk::Loader.new
loader.push_dir('lib')
loader.push_file('config/application.rb') # <--- no such thing as push_file
if ENV['RACK_ENV'] == 'development'
loader.enable_reloading
loader.setup
run ->(env) do
loader.reload # <--- full reload on every request
Application.call(env)
end
else
Zeitwerk::Loader.eager_load_all
loader.setup
run Application.freeze.app
end
Excluding all but application.rb
using loader.ignore
won't cut it neither, Ruby glob patterns don't implement negation it appears.
I could of course move application.rb
into lib/
(and I might have to), but I'd rather have it in config/
. Any way to make this fly?
First, to answer the question, there is no way to push one single file. I might consider adding that feature, but need to think about it.
Then, in Roda, you could argue that the application class is not configuration. That class dispatches and has application logic. I'd consider moving that file out of the config
directory for conceptual reasons, regardless.
If you totally want to keep it in that directory, you can "reload" manually in development (untested, written on the spot):
loader.reload
load "#{__dir__}/config/application.rb"
Application.call(env)
Point is that load
, unlike require
, executes always the file.
I am not familiar with Roda and it could be the case that running the file multiple times messes with internal state. If that was the case, you could remove the constant before the load
call:
Object.send(:remove_const, :Application) if defined?(Application)
I've seen Roda has an inherited
hook, but does not seem to cache subclasses in internal state.
Additionally, for production, you normally want to run loader.setup
before eager_load_all
, so that your application is eager loaded too.