[ruby-nextgen] fix: autoload broken when moduleName differs from camelized gemName

IN
8h ago
+146-50

Fixes #24997.

ruby-nextgen used Zeitwerk::Loader.for_gem when moduleName is a single level (not nested). for_gem derives its root namespace from the gem name, so with gemName=things_api, moduleName=Things it targeted ThingsApi while the generated files define constants under Things — nothing autoloaded, require 'things_api' then Things::Client raised NameError, and Things.eager_load! failed on uninitialized constant ThingsApi.

What changed

  • ruby-nextgen/gem.mustache: always drive Zeitwerk explicitly (Zeitwerk::Loader.new + push_dir(..., namespace: self)), removing the moduleNameNested branch that fell back to for_gem. The explicit loader never depended on gemName matching moduleName, and the nested case already used it — so this only changes behavior for the previously broken single-level case. Suggested in the issue by the reporter.

Verification

  • New unit test testZeitwerkLoaderWhenModuleNameDiffersFromGemName generates with gemName=things_api, moduleName=Things and asserts the explicit push_dir(namespace: self) loader is emitted and for_gem is not. RubyNextgenClientCodegenTest: 24 tests, 0 failures.
  • Regenerated both ruby-nextgen sample configs (matching gemName/moduleName, so only the loader lines change); ruby -c syntax check passes on the regenerated gems.
  • The issue reporter verified the same change restores require 'things_api' + Things::Client.new(...) for the mismatching pair while gemName=things keeps working.

PR checklist

  • Read the contribution guidelines.
  • Regenerated the affected samples via ./bin/generate-samples.sh (both ruby-nextgen configs); no files deleted.
  • Pull request is created against the master branch.

Summary by cubic

Fixes ruby-nextgen autoloading when moduleName differs from the camelized gemName, URI-encodes Dart-dio path parameters, and pins source_helper below 1.4.0 to fix the freezed variant's build_runner builds.

Bug Fixes

  • ruby-nextgen now always drives Zeitwerk explicitly with push_dir(namespace: self) instead of Zeitwerk::Loader.for_gem, which derived the namespace from gemName and autoloaded nothing when it didn't match moduleName.
  • Dart-dio path parameters are now wrapped in Uri.encodeComponent via a new api/path_param partial for all three serialization libraries, so values containing /, spaces, or reserved characters no longer break the request path.
  • The freezed variant pins source_helper at >=1.3.8 <1.4.0: 1.4.0's extension members clash with json_serializable 6.x and break build_runner builds, and the 1.3.8 lower bound keeps 1.3.9+ (which requires Dart 3.9) resolvable for the variant's 3.8 baseline.