Repository navigation
playground: a Ruby tab, run in the browser by go-embedded-ruby - #39
Merged
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
Opsgets a Ruby spelling (plan.rb,Step.Rb,Session.RbProgram(sel)), written against go-embedded-ruby'sNDArrayAPI: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.gochecks each spelling and that it calls nothing outside that API. The program prints every step, then the selected step'sshapeandto_a.LangRuby, aRunRubycommand,RubyStatus/RubyProgress/RubyOutputobservables, 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.Rubydetail line.ndarrayRubyLoad(onProgress)fetches/playground/rbgo.wasm(byte-counted progress, size read at build time) and starts it in a secondnew Go().playground/rubywasm/is a module of its own that pinsgithub.com/go-embedded-ruby/rubythrough atooldirective (Renovate bumps it). The deploy buildscmd/wasmfrom it with-trimpath -ldflags="-s -w", with the same toolchain as the playground, so onewasm_exec.jsserves 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
TestBrowserProofcounts requests forrbgo.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 printedshapeandto_ato 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.modpins v0.5.0 (3c86317, the merge of go-embedded-ruby#813, which implements theNDArrayAPI), 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 of1:, it fails onSlice(1:, ::-1).🤖 Generated with Claude Code