From 629682aae4d1e69df725c0d6cf01223bac7647d3 Mon Sep 17 00:00:00 2001 From: tannevaled Date: Sun, 11 Oct 2026 18:09:11 +0200 Subject: [PATCH 1/3] playground: a Ruby tab, run in the browser by go-embedded-ruby 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 --- .github/workflows/hugo.yml | 25 +- .github/workflows/playground.yml | 14 +- .gitignore | 1 + layouts/_default/playground.html | 50 +- playground/README.md | 49 +- playground/app.go | 56 +- playground/app_test.go | 83 ++- playground/browser_test.go | 20 +- playground/browsertest/driver.cjs | 67 +- playground/cmd/playground-wasm/main.go | 44 ++ playground/debug.go | 38 + playground/engine/args.go | 34 + playground/engine/engine_test.go | 4 +- playground/engine/inspect.go | 11 + playground/engine/ops.go | 122 +++- playground/engine/ruby_test.go | 213 ++++++ playground/engine/session.go | 34 +- playground/events.go | 2 +- playground/rubywasm/go.mod | 406 +++++++++++ playground/rubywasm/go.sum | 966 +++++++++++++++++++++++++ playground/vm/ruby_test.go | 142 ++++ playground/vm/vm.go | 196 ++++- 22 files changed, 2478 insertions(+), 99 deletions(-) create mode 100644 playground/engine/ruby_test.go create mode 100644 playground/rubywasm/go.mod create mode 100644 playground/rubywasm/go.sum create mode 100644 playground/vm/ruby_test.go diff --git a/.github/workflows/hugo.yml b/.github/workflows/hugo.yml index c02cd1d..8cf4b7f 100644 --- a/.github/workflows/hugo.yml +++ b/.github/workflows/hugo.yml @@ -53,15 +53,18 @@ jobs: id: pages uses: actions/configure-pages@v6 - # The playground's two assets are build artifacts, never committed: the - # wasm compiled from playground/ at this commit, and wasm_exec.js taken - # from the SAME toolchain (the two must match). Built before Hugo, which - # reads the wasm's size for the loader's progress bar. + # The playground's three assets are build artifacts, never committed: the + # wasm compiled from playground/ at this commit, the Ruby tab's + # interpreter (go-embedded-ruby at the version playground/rubywasm/go.mod + # pins), and wasm_exec.js taken from the SAME toolchain (all must match). + # Built before Hugo, which reads the two wasm sizes for the progress bars. - name: Setup Go uses: actions/setup-go@v7 with: go-version: "1.27.2" - cache-dependency-path: playground/go.sum + cache-dependency-path: | + playground/go.sum + playground/rubywasm/go.sum - name: Build the playground working-directory: playground @@ -75,6 +78,18 @@ jobs: -o ../static/playground/playground.wasm ./cmd/playground-wasm cp "$(go env GOROOT)/lib/wasm/wasm_exec.js" ../static/playground/ + # Fetched by the page only when a visitor opens the Ruby tab. + - name: Build go-embedded-ruby for the Ruby tab + working-directory: playground/rubywasm + env: + GOWORK: "off" + GOTOOLCHAIN: local + run: | + GOOS=js GOARCH=wasm go build -trimpath -ldflags "-s -w" \ + -o ../../static/playground/rbgo.wasm github.com/go-embedded-ruby/ruby/cmd/wasm + raw=$(stat -c %s ../../static/playground/rbgo.wasm); gz=$(gzip -9 -c ../../static/playground/rbgo.wasm | wc -c) + echo "rbgo.wasm ($(go list -m -f '{{.Version}}' github.com/go-embedded-ruby/ruby)): $raw bytes, $gz gzipped" | tee -a "$GITHUB_STEP_SUMMARY" + - name: Build env: HUGO_ENVIRONMENT: production diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index 6e9f2b2..e3b2df4 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -12,8 +12,10 @@ # and dark forced, 1x and 2x, plus a phone (390x844 at 3x, # mobile, touch): real clicks and keys, asserted on the app's # state AND on canvas pixels, and the canvas must fit the -# viewport width. A missing browser is a -# failure here, never a skip. +# viewport width. The Ruby tab: go-embedded-ruby is fetched +# only once the tab is opened (requests counted), and the +# README example run in Ruby prints go-ndarray's shape and +# values. A missing browser is a failure here, never a skip. name: playground on: @@ -102,7 +104,9 @@ jobs: - uses: actions/setup-go@v7 with: go-version: "1.27.2" - cache-dependency-path: playground/go.sum + cache-dependency-path: | + playground/go.sum + playground/rubywasm/go.sum - uses: actions/setup-node@v7 with: node-version: "24" @@ -123,7 +127,9 @@ jobs: CHROME: ${{ steps.chrome.outputs.chrome-path }} PLAYGROUND_NODE_PATH: ${{ runner.temp }}/pptr/node_modules PLAYGROUND_CAPTURE_DIR: ${{ runner.temp }}/captures - run: go test -count=1 -v -run TestBrowserProof . + # The proof builds the Ruby wasm too (go-embedded-ruby, about 100 MB) and + # downloads it twice in Chrome: give it more than go test's 10 minutes. + run: go test -count=1 -timeout 30m -v -run TestBrowserProof . - name: keep the screenshots if: always() uses: actions/upload-artifact@v7 diff --git a/.gitignore b/.gitignore index 594d8e6..09e86db 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ resources/ # Built by the pages workflow from playground/ (never committed). static/playground/playground.wasm static/playground/wasm_exec.js +static/playground/rbgo.wasm diff --git a/layouts/_default/playground.html b/layouts/_default/playground.html index 16b95d3..b9cb7e4 100644 --- a/layouts/_default/playground.html +++ b/layouts/_default/playground.html @@ -4,7 +4,7 @@ Playground — {{ .Site.Title }} - + {{ partial "styles.html" . }}