Repository navigation
feat(ruby): Ruby language bindings - #5178
omarqureshi wants to merge 7 commits into
Conversation
0ea38eb to
d2c88dd
Compare
7295d63 to
e7e2ca2
Compare
Additive schema only: `ruby { gem, module, acronyms? }` joins the existing
per-language target blocks. The `.jsii` assembly format is unchanged —
AssemblyTargets already carries an index signature, so existing assemblies
and every other language are unaffected.
toRubyVersionRange converts semver ranges to RubyGems requirement syntax (throwing on `||` OR-ranges, which Gem::Requirement cannot express), and toReleaseVersion gains a RUBY case with a strict prerelease-label grammar. Shared file, self-contained change, fully covered in version-utils.test.ts including the error paths.
Pure addition. The Ruby guest runtime: a Monitor-serialized kernel driving the standard Node sidecar over line-delimited JSON (all twelve wire verbs), a type-driven serializer for every value envelope, override discovery from generated metadata tables, hash-to-struct and Proc-to-interface (SAM) coercion, lazy type registration/hydration, and an error taxonomy that separates kernel faults from remote JS exceptions. Hand-written RBS signatures under sig/. No dependencies beyond stdlib + base64 (a Ruby 3.4+ default-gem unbundling requirement).
0dc40de to
f4a25f4
Compare
The generator (lib/targets/ruby.ts, new file): classes with flattened member re-emission so `super` works in guest overrides, interfaces as modules, structs with keyword constructors, enums, per-assembly acronym config read from targets.ruby (no built-in lists), lazy loading via paired autoload registration, RBS signature emission, YARD docs with rosetta-translated examples, reserved-word escaping synced with the runtime, and injection-safe string escaping at every interpolation site. Cross-cutting surface is two lines in lib/targets/index.ts (target registration) and a one-line generalization of package-ruby.bin's gemspec glob. Coverage: the target-ruby snapshot corpus over jsii-calc plus focused naming/casing tests.
packages/@jsii/ruby-runtime-test (new): 14 compliance spec files tagged case-for-case against tools/jsii-compliance/suite.ts, plus unit specs for the riskiest machinery (autoload, callbacks, serializer, SAM coercion, concurrency, RBS validation with a negative control). generate.sh regenerates the jsii-calc bindings unconditionally so specs can never run against stale generated code. Enablement edits outside the new package: targets.ruby declarations on the four jsii-calc fixture assemblies, matching ruby naming expectations in @jsii/kernel's kernel.test.ts, and a bash shebang on update-all.sh.
…nestly suite.ts registers the ruby binding's report path. report.ts previously iterated the report files present on disk; it now iterates the declared bindings, which surfaces a latent presentation bug: a language whose report file is absent in a given checkout would render as a false 0.00%. Absent reports now render as "n/a" cells with an (n/a) header — languages with report files are computed exactly as before, and the regenerated gh-pages report reflects both changes.
Ruby 3.3 joins every job's setup and the OS matrix gains Ruby 3.4 and 4.0 rows (Linux/macOS/Windows). yarn.lock carries the ruby-runtime test package's dependency graph. tsconfig-base.json gains ignoreDeprecations "6.0": the shared compiler options include settings TypeScript 6 flags as deprecated, and the Ruby target was developed against a TS 6 toolchain. This is repo-wide and deliberately surfaced here for review — it can be dropped if the mainline toolchain does not need it.
f4a25f4 to
0514baf
Compare
|
Hi, and thank you for the large amount of work on this. This is my first time engaging with this repository, but I'm looking forward to Ruby support, so I tried the PR locally and wanted to share what I found. What I triedI rebased the branch onto the latest main (ddc88f3) and ran the tests locally:
The rebase conflicts were limited to 6-compliance-report.md and .github/workflows/main.yml (the Go 1.25 entry that main has since removed). QuestionsI may be missing context, so please take these as questions rather than suggestions:
I'd be glad to help with any of this if it's useful. Please feel free to disregard anything that misses the mark. |
|
Hi @yuuu - work on this has been scrapped in favour of a language plugin system due to maintenance concerns with an official Ruby language, I will have something to share on this in the next week. Unfortunately work commitments have been very hectic I would have a read of https://github.com/omarqureshi/aws-cdk-rfcs/blob/4721527e92fc7cd582671cde7d3837102a200ab8/text/0000-jsii-language-plugins.md with https://github.com/omarqureshi/jsii-target-ruby as an implementation |
|
Another thing you can try is have a read of https://rubygems.omarqureshi.net/ - these gems are by no means up to date but they are a usable CDK implementation in Ruby |
|
This is superseded by the plugin approach in RFC aws/aws-cdk-rfcs#1005 (RFC text), which follows the discussion that closed aws/aws-cdk-rfcs#935. Rather than adding Ruby to this repository, the RFC opens the seams an out-of-tree language target needs, and Ruby becomes the first plugin (omarqureshi/jsii-target-ruby). In this repository, the plugin work is the I'm leaving this open as a reference until the RFC has a decision, and will close it then. |
Objective
Introduces comprehensive Ruby language bindings for the jsii ecosystem, enabling AWS CDK (and other jsii-based libraries) to be packaged as gems and consumed idiomatically from Ruby. It adds the code-generation target (
jsii-pacmak) and the core Ruby runtime (@jsii/ruby-runtime), with strict type-safety, careful object lifecycle management, and thread-safe IPC with the jsii Node kernel.Implements RFC 0935: Ruby language bindings. The change is strictly additive — no breaking changes to existing languages and no assembly-format change beyond an additive
targets.rubyschema extension.Warning
CI is expected to be red on this branch, by design. Ruby code generation requires a jsii-compiler release with Ruby target support, which is not yet published. Until it is, the following failures are expected and are not indicative of broken work:
jsii-pacmaktarget-rubysnapshot test — this branch builds with the stock compiler (no Ruby support), so the committed assemblies carry notargets.rubyand generated names won't match the snapshot.@jsii/ruby-runtime-test(generate.sh+ rspec) — cannot generate the Rubylib/without the Ruby-capable compiler.Once the Ruby-capable compiler is released, the committed fixtures (assemblies with
targets.ruby+ the Ruby snapshot) are regenerated against it and CI goes green. End-to-end regeneration + publish has already been validated against the fork compiler.Key Components
1. Code Generation (
jsii-pacmak)RubyTarget&RubyGenerator(packages/jsii-pacmak/lib/targets/ruby.ts): translate jsii types into idiomatic Ruby —class < Jsii::Object, behavioral interfaces as mixinmodules, datatype structs as kwargs value-classes (< Jsii::Struct), enums asJsii::Enumwrapper constants, async + sync methods, and property/method overrides..rbs; output validates clean underrbs validateacrossjsii-calcand its dependency closure.next→_next). Root namespaceAWSCDKwith AWS-prefix de-duplication (aws-s3→AWSCDK::S3::Bucket).module X; end) in dependency order to preventNameErrorduring nested type generation.Jsii::Type.check_typefor runtime enforcement, and embeds type metadata as Base64-encoded JSON literals so no jsii-supplied identifier or docstring can inject into generated source via string interpolation.version-utils.tstranslates npm semver (incl. pre-release.alpha.1/.dev.1) to RubyGems ranges.2. Ruby Runtime Core (
@jsii/ruby-runtime)Monitormakes the bidirectional JSON-RPC stdio pipe safe under concurrency and re-entrant callbacks; an isolated stderr-draining thread prevents pipe deadlocks.supercrossing back to the JS implementation), with user subclasses detected at construction time..allocate, mapped by$jsii.byref; deliberately never issues a guest-initiateddel(matching the Python/Go runtimes) — cleanup is wholesale on kernel shutdown, which suits short-livedsynthworkloads.Jsii::Serializer(rather than monkey-patching core types) handles by-value structs vs by-reference objects, avoiding leakage of host application state.3. Compliance & Testing (
@jsii/ruby-runtime-test)rbs validate. No skipped/pending tests.4. CI / Build
buildspec.yamlCodeBuild runtime added.tools/jsii-compliance).Compatibility & Known Limitations
required_ruby_version >= 3.3.0(3.1/3.2 are EOL). JRuby/TruffleRuby are out of scope for the initial release.beginAPI only accepts object references — a limitation shared by all bindings).Notes & Next Steps
jsii-rosettatranslation backend for Ruby is not included here and will follow in a subsequent PR.mainand do not yet carrytargets.ruby(it's compiler-generated). They — and thetarget-rubysnapshot — will be regenerated against the released Ruby-capable compiler before merge. See the warning above.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
How to review this PR
The branch history is organized into seven self-contained review units, ordered so the
cross-cutting surface comes first and the large pure-addition trees are isolated. Total
shared-file footprint outside new
ruby-*trees: 8 files (spec configuration,version-utils + its test, pacmak target registration, kernel.test.ts naming expectations,
compliance suite/report, CI matrix, tsconfig-base, one build-tools glob).
feat(spec)targets.rubyschema — the only assembly-facing changefeat(pacmak)feat(ruby)@jsii/ruby-runtime— the runtime gem (pure addition)feat(pacmak)test(ruby)targets.rubydeclarationstest(compliance)ciignoreDeprecations(called out for review in the commit message)Suggested reading order: 1 → 2 → 7 → 6 (the entire cross-cutting surface, ~15 minutes) —
then 3 (the runtime) and 5 (its tests) as one unit, and 4 last (of its +26.6k, ~24k is the
committed generated-code snapshot; the generator itself is
lib/targets/ruby.ts, ~2.4k lines).Checks on this PR stay red until aws/jsii-compiler#2663
merges and releases (the branch builds against that schema); green full-matrix runs exist on
the branch and the daily preview pipeline smoke-tests the published output — sequencing in
the RFC's Upstreaming sequence section (aws/aws-cdk-rfcs#939).