[BUG][RUBY-NEXTGEN] Nothing autoloads when moduleName is not the camelized gemName
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
- Domain
- backend-api-design, devtools
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
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from OpenAPITools/openapi-generator
-
Issue: Bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
OpenAPITools/openapi-generator#25021 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
OpenAPITools/openapi-generator#25014 ·
Maintainers usually reply within 1 day
-
Issue: Bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
OpenAPITools/openapi-generator#24859 ·
Maintainers usually reply within 1 day
-
[BUG][KOTLIN] Fails to compile after updating to 7.25.0 with useJackson3=false useSpringBoot4=trueOpenIssue: Bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
OpenAPITools/openapi-generator#24842 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
OpenAPITools/openapi-generator#24830 ·
Maintainers usually reply within 1 day
All issues in OpenAPITools/openapi-generator
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
refinedmods/refinedstorage2#1414 · 1 comment ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
In Java's `LongBoundedSum`, setting `lower` to `Long.MIN_VALUE` under-estimates the sensitivityOpen
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
google/differential-privacy#489 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
link-check link-check:manual
Difficulty 2/5 1-3 hours Newbie friendliness 85/100