Skip to content

playground: a Ruby tab, run in the browser by go-embedded-ruby - #39

Merged
tannevaled merged 3 commits into
mainfrom
playground-ruby-tab
Oct 11, 2026
Merged

tannevaled merged 3 commits into
mainfrom
playground-ruby-tab

Conversation

@tannevaled

@tannevaled tannevaled commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

The code panel gains a Ruby program between Go and NumPy (tabs Go | Ruby | NumPy), and Run executes it in the page with go-embedded-ruby compiled to WebAssembly.

What changes

  • engine: every operation in Ops gets a Ruby spelling (plan.rb, Step.Rb, Session.RbProgram(sel)), written against go-embedded-ruby's NDArray API: NDArray.arange/linspace/zeros/ones/full/eye/from, a.reshape(3, -1), a.transpose, a.dup, NumPy slices as Ranges and ArithmeticSequences (b[true, (1..) % 2], b[(-1..) % -1]), a.sum(1, keepdims: true), NDArray.maximum(a, b), a.matmul(b), NDArray.concatenate([a, b], axis: 0), ... engine/ruby_test.go checks each spelling and that it calls nothing outside that API. The program prints every step, then the selected step's shape and to_a.
  • vm: LangRuby, a RunRuby command, RubyStatus/RubyProgress/RubyOutput observables, and two host hooks (RubyLoad, RubyEval). The interpreter is requested the first time the Ruby tab is opened; Run pressed during the download runs after it; a failed download can be retried.
  • View: Run beside Copy, the program beside its output (below it on a phone), a status line and a progress bar for the download, and a Ruby detail line.
  • Page: ndarrayRubyLoad(onProgress) fetches /playground/rbgo.wasm (byte-counted progress, size read at build time) and starts it in a second new Go().
  • Build: playground/rubywasm/ is a module of its own that pins github.com/go-embedded-ruby/ruby through a tool directive (Renovate bumps it). The deploy builds cmd/wasm from it with -trimpath -ldflags="-s -w", with the same toolchain as the playground, so one wasm_exec.js serves both modules.

Size

The go-embedded-ruby wasm is about 99 MB stripped (21 MB gzipped) against 13.9 MB for the playground, so the page never loads it up front: only when the Ruby tab is opened.

Proof

TestBrowserProof counts requests for rbgo.wasm: none through the Go and NumPy tabs, one when the Ruby tab opens, still one after two runs. It runs the README example in Ruby and requires the printed shape and to_a to equal go-ndarray's result for the same step (desktop light@1x and the phone). Negative control, run locally: making the page fetch the Ruby wasm at start-up fails the proof at "the Ruby module was not downloaded before the Ruby tab was opened".

go-embedded-ruby v0.5.0

rubywasm/go.mod pins v0.5.0 (3c86317, the merge of go-embedded-ruby#813, which implements the NDArray API), on go-ndarray v0.11.0 like the playground. v0.3.0 and v0.4.0 lack the binding. Stripped wasm: 99,921,220 bytes, 21,396,357 gzipped (102,598,409 unstripped).

TestRubyAgreesWithGo (engine) runs the Ruby program of every operation case and of every preset step, 111 programs, on the interpreter under node, and compares the printed shape and values with go-ndarray's numerically. Against v0.3.0 it reports 98 failures. With a deliberate off-by-one in the Ruby spelling of 1:, it fails on Slice(1:, ::-1).

🤖 Generated with Claude Code

tannevaled and others added 3 commits October 11, 2026 18:09
The code panel gains a Ruby program between Go and NumPy (Go | Ruby | NumPy).
Every operation has a Ruby spelling written against go-embedded-ruby's
NDArray API (ruby-ndarray-contract): NDArray.arange, a.reshape, NumPy slices
as Ranges and ArithmeticSequences (b[true, (1..) % 2]), b.sum(0, keepdims:
true), NDArray.concatenate([a, b], axis: 0), ... engine/ruby_test.go checks
each spelling and that it calls nothing outside that API.

Run executes the program in the page: go-embedded-ruby's cmd/wasm, pinned in
the new playground/rubywasm module (a tool directive, so Renovate bumps it),
is built by the deploy with the same toolchain as the playground, so one
wasm_exec.js serves both Go runtimes. It is ~99 MB (21 MB gzipped), so the
page fetches it only when the visitor opens the Ruby tab, with a progress
line and bar counting the bytes; the ViewModel drives the download and the
run (RunRuby command, RubyStatus/RubyProgress/RubyOutput observables).

The browser proof counts requests for rbgo.wasm: none through the Go and
NumPy tabs, one when the Ruby tab opens, still one after two runs. It runs
the README example in Ruby and requires the printed shape and to_a to equal
go-ndarray's result for the same step, on the desktop and on a phone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d one, refit on tab change

TestRubyAgreesWithGo runs the Ruby program of every operation case and of
every preset step on go-embedded-ruby under node and compares the printed
shape and values with go-ndarray's (CI builds the interpreter once for it and
the browser proof). Calls go through the page's ndarrayRubyEval, which
reports a stopped Go runtime instead of throwing into the playground's. The
canvas is refitted when the code tab changes, so the stacked Ruby output
does not run under the status line on a phone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… binding

v0.5.0 (3c86317, the merge of go-embedded-ruby#813) implements the NDArray
API the Ruby tab emits, on go-ndarray v0.11.0 like the playground. All 111
Ruby programs of TestRubyAgreesWithGo print go-ndarray's shapes and values;
the stripped wasm is 99,921,220 bytes, 21,396,357 gzipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tannevaled
tannevaled marked this pull request as ready for review October 11, 2026 17:30
@tannevaled
tannevaled merged commit 2a0d65a into main Oct 11, 2026
7 checks passed
@tannevaled
tannevaled deleted the playground-ruby-tab branch October 11, 2026 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant