This means that you do not need to require the classes and modules you write before you use them. Instead, your classes and modules are automatically available across your application.

For example, the class defined in the file app/entities/book.rb can be used in another class by simply using the constant Bookshelf::Entities::Book.

While this is convenient, it does mean you must adhere to Zeitwerk’s expectations around file structure, in which file paths match constant paths.

If class Book was changed to class Novel in the above file, the following error would be raised:

  1. Zeitwerk::NameError: expected file bookshelf/app/entities/book.rb to define constant Bookshelf::Entities::Book, but didnt

Moving the file from app/entities/book.rb to app/entities/novel.rb would address this error.

When namespacing classes and modules in your app/ directory, use a top-level module namespace named after your app.

Assuming an app created via hanami new bookshelf (which would have a top-level module Bookshelf), this means abiding by the following structure:

None of the above classes or modules need a require statement before use.

It’s worth noting that, thanks to Hanami’s , the components you write in app/ don’t commonly need to reference their collaborators using Ruby constants - they instead use the Deps mixin to access their dependencies.

If you are adding a class to the app/ directory that you want to use an autoloaded Ruby constant to reference, it’s very likely that you do not want that class to be registered in your app container. To opt out of registration, use the magic comment # auto_register: false or one of the alternative methods discussed in “Opting out of the container” in the container and components guide.

  1. # auto_register: false
  2. require "dry-struct"
  3. module Bookshelf
  4. module Structs
  5. class Book < Dry::Struct
  6. attribute :title, Types::String
  7. attribute :author, Types::String
  8. end
  9. end

This SlackNotifier class from lib/bookshelf for instance can be used in app components without a require statement:

However, code placed in other directories within lib/ does need a require statement. Using code from these directories is akin to using a Ruby gem, and so a require statement is necessary.

The custom redis client below, for example, needs to be required (via require "custom_redis/client") when being used:

  1. # lib/custom_redis/client.rb
  2. module CustomRedis
  3. class Client
  4. end
  5. end
  1. # config/providers/redis.rb
  2. Hanami.app.register_provider :redis do
  3. start do
  4. require "custom_redis/client"
  5. redis = CustomRedis::Client.new(url: target["settings"].redis_url)
  6. register "redis", redis
  7. end
Constant locationUsage
lib/bookshelf/slack_notifier.rbBookshelf::SlackNotifier
lib/custom_redis/client.rbrequire “custom_redis/client”

CustomRedis::Client

Autoloading does not apply to any Ruby gems you include in your project via its Gemfile. Like in any regular Ruby project, require external gems before using their constants in each file.

  1. require "kramdown"
  2. module Bookshelf
  3. class Markdown
  4. def to_html(markdown)
  5. Kramdown::Document.new(markdown).to_html
  6. end
  7. end
  8. end

If you need to configure acronyms like “DB” or “WNBA”, add them to the infector configuration in the app class:

  1. # config/app.rb
  2. require "hanami"
  3. module Bookshelf
  4. class App < Hanami::App
  5. config.inflections do |inflections|
  6. inflections.acronym "DB", "WNBA"
  7. end
  8. end