Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[BUG][RUBY-NEXTGEN] Nothing autoloads when moduleName is not the camelized gemName

Open Beginner friendly
#24,997 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
70/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
java, ruby

Research direction

The bug is in the Ruby NextGen generator's gem.mustache template. Start by locating modules/openapi-generator/src/main/resources/ruby-nextgen/gem.mustache in the repository. The issue is that Zeitwerk::Loader.for_gem expects the gem name to match the module name, but when they differ, autoloading fails. The fix is to always use the explicit loader (Zeitwerk::Loader.new + push_dir) instead of conditionally. Test by generating a Ruby gem with mismatched gemName and moduleName, then requiring it and checking if constants load. The provided diff shows the exact change needed.

Written by the indexing model from the issue text.

Description

Bug Report Checklist
  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
Description

When moduleName is not the camelized gemName (e.g. gemName=things_api, moduleName=Things), none of the generated constants load. For a single-level moduleName, gem.mustache sets Zeitwerk up with Zeitwerk::Loader.for_gem, which expects lib/things_api/** to define constants under ThingsApi. The generated files define them under Things, so Things::Client is never autoloaded and eager_load fails on ThingsApi.

gem.mustache already has a loader that works (Zeitwerk::Loader.new + push_dir(..., namespace: self)), but it only emits it when moduleName is nested.

openapi-generator version

master, 7.26.0-SNAPSHOT, 05b61f34d7fb0199330e1d6c57e6159f72427837

OpenAPI declaration file content or url
openapi: 3.0.3
info:
  title: zeitwerk
  version: 1.0.0
paths:
  /things:
    get:
      operationId: listThings
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Thing'
components:
  schemas:
    Thing:
      type: object
      properties:
        name:
          type: string
Generation Details
java -jar openapi-generator-cli.jar generate -g ruby-nextgen -i spec.yaml -o out \
  --additional-properties=gemName=things_api,moduleName=Things

Generated lib/things_api.rb (comments trimmed):

module Things
  class << self
    attr_reader :loader
  end

  @loader = Zeitwerk::Loader.for_gem
  @loader.setup

  def self.eager_load!
    @loader.eager_load
  end
end
Steps to reproduce
$LOAD_PATH.unshift 'out/lib'
require 'things_api'

Things::Client.new(base_url: 'http://localhost')

Actual (ruby 3.3, zeitwerk 2.8.3):

uninitialized constant Things::Client (NameError)

Things.eager_load! raises uninitialized constant ThingsApi (NameError).

Expected: the client loads, as it does with gemName=things.

Related issues/PRs

None found.

Suggest a fix

Always use the explicit loader. push_dir(namespace: self) doesn't depend on gemName matching moduleName. With this change the snippet works for both gemName=things_api and gemName=things, and Things::VERSION still resolves.

--- a/modules/openapi-generator/src/main/resources/ruby-nextgen/gem.mustache
+++ b/modules/openapi-generator/src/main/resources/ruby-nextgen/gem.mustache
@@ -21,10 +21,9 @@
     attr_reader :loader
   end
 
-{{#moduleNameNested}}
-  # Nested moduleName: for_gem can't target a nested namespace, so drive Zeitwerk
-  # explicitly. The parent module(s) above are pre-defined so `module {{moduleName}}`
-  # (here and in every generated file) reopens rather than raising NameError.
+  # for_gem derives the namespace from gemName, which need not match moduleName (and
+  # can't target a nested one), so drive Zeitwerk explicitly. Any parent module(s) above
+  # are pre-defined so `module {{moduleName}}` reopens rather than raising NameError.
   @loader = Zeitwerk::Loader.new
   @loader.push_dir("#{__dir__}/{{gemName}}", namespace: self)
   # version.rb defines VERSION (not a `Version` class). for_gem's GemInflector special-cases
@@ -32,10 +31,6 @@
   # {{moduleName}}::VERSION available.
   @loader.ignore("#{__dir__}/{{gemName}}/version.rb")
   require_relative "{{gemName}}/version"
-{{/moduleNameNested}}
-{{^moduleNameNested}}
-  @loader = Zeitwerk::Loader.for_gem
-{{/moduleNameNested}}
 {{#zeitwerkInflections.0}}
   # Model names keep their acronym casing (e.g. HTTPConfig), but Zeitwerk's default
   # inflector would expect HttpConfig from the file name. Register the exceptions so

Generated with Claude Code

Dominant language
Java
Stars
26.8k
Forks
7.7k
Avg merge
2d 18h
Merged PRs (30d)
103

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from OpenAPITools/openapi-generator

All issues in OpenAPITools/openapi-generator

Similar issues

More Java issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.