Skip to content

Commit 7c3ad9a

Browse files
omarqureshiclaude
andcommitted
feat(ruby): emit submodule READMEs as module docstrings
Mirror the Python target's emitModuleDocumentation: for the assembly and each submodule that has a README, translate its TypeScript samples to Ruby via Rosetta (translateSnippetsInMarkdown, same tablet path as @example) and emit the result as the module's YARD docstring in a doc-only `_readme.rb` inside the module's directory, so YARD renders it on the module page. This surfaces CDK's real usage docs — which live in module READMEs, not per-type @example tags — in the Ruby API reference. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent d2c88dd commit 7c3ad9a

1 file changed

Lines changed: 59 additions & 0 deletions

File tree

  • packages/jsii-pacmak/lib/targets

packages/jsii-pacmak/lib/targets/ruby.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,22 @@ export class RubyGenerator extends Generator {
244244
return translated.source;
245245
}
246246

247+
/**
248+
* Translate the TypeScript code samples embedded in a Markdown document (a
249+
* module README) into Ruby via Rosetta, leaving the prose untouched. Mirror
250+
* of `convertExample` but for whole documents, matching the Python target's
251+
* `convertMarkdown`.
252+
*/
253+
private convertMarkdown(markdown: string, apiLocation: ApiLocation): string {
254+
assertSpecIsRosettaCompatible(this.assembly);
255+
return this.rosetta.translateSnippetsInMarkdown(
256+
apiLocation,
257+
markdown,
258+
TargetLanguage.RUBY,
259+
enforcesStrictMode(this.assembly),
260+
);
261+
}
262+
247263
/**
248264
* Normalize a type reference to its raw `spec.TypeReference` shape.
249265
* Call sites hold two shapes: jsii-reflect `TypeReference` instances
@@ -653,6 +669,10 @@ export class RubyGenerator extends Generator {
653669
this.code.closeFile(typeFile);
654670
}
655671

672+
// Emit each submodule's README as its module docstring (samples translated
673+
// to Ruby), so YARD renders it on the module page.
674+
this.emitModuleReadmes();
675+
656676
// Generate the gemspec manifest file for package management
657677
await this.generateGemspec(outdir);
658678

@@ -663,6 +683,45 @@ export class RubyGenerator extends Generator {
663683
return super.save(outdir, tarball, legalese);
664684
}
665685

686+
/**
687+
* Emit each submodule's (and the assembly's own) README as a Ruby module
688+
* docstring, its TypeScript samples translated to Ruby — mirroring the Python
689+
* target's `emitModuleDocumentation`. Each README goes in a doc-only
690+
* `_readme.rb` inside the module's directory (alongside its type files) so a
691+
* per-directory YARD run picks it up and renders it on the module page. The
692+
* file is never `require`d at runtime.
693+
*/
694+
private emitModuleReadmes(): void {
695+
const emit = (moduleFqn: string, markdown: string | undefined): void => {
696+
if (!markdown) {
697+
return;
698+
}
699+
const rubyModule = this.rubyFullTypeName(moduleFqn);
700+
const translated = this.convertMarkdown(markdown, {
701+
api: 'moduleReadme',
702+
moduleFqn,
703+
});
704+
const docFile = path.join(
705+
'lib',
706+
this.rubyRequirePath(moduleFqn),
707+
'_readme.rb',
708+
);
709+
this.code.openFile(docFile);
710+
for (const line of translated.split('\n')) {
711+
this.code.line(line.length > 0 ? `# ${line}` : '#');
712+
}
713+
this.code.line(`module ${rubyModule}; end`);
714+
this.code.closeFile(docFile);
715+
};
716+
717+
emit(this.assembly.name, this.assembly.readme?.markdown);
718+
for (const [fqn, submodule] of Object.entries(
719+
this.assembly.submodules ?? {},
720+
)) {
721+
emit(fqn, submodule.readme?.markdown);
722+
}
723+
}
724+
666725
private emitHeader(): void {
667726
this.code.line("require 'jsii'");
668727
this.code.line("require 'json'");

0 commit comments

Comments
 (0)