go-ruby-widgets is three pure-Go, Ruby-runtime-independent adapters โ widgets,
tui and mvvm โ shaped so that
go-embedded-ruby (rbgo) can bind each as
require "widgets", require "tui" and require "mvvm". Each is a
thin adapter over its go-widgets counterpart, exposed
through Ruby-facing handles whose methods return Ruby-shaped values โ a Hash
(map[string]any), an Array ([]any) or a scalar. A single dynamic entry
point, Call, dispatches a snake_case method name to the matching handle method, which
is exactly what an rbgo binding drives from method_missing. No cgo, no Ruby
runtime dependency anywhere in the stack โ CI-green across amd64, arm64, riscv64, loong64,
ppc64le, s390x and (for widgets) js/wasm.
widgets ready
A live pixel widget UI toolkit over go-widgets/toolkit + go-widgets/painter: buttons, labels, entries, lists, menus and the container/layout system (box/border/card/grid/dock) that arranges them. Every widget and container is an integer handle; Render paints a tree to an RGBA buffer, Dispatch routes input events by hit-testing bounds.
require "widgets"
root = Widgets.v_box
ok = Widgets.button("OK", "on_ok")
Widgets.add_widget(root, ok)
Widgets.layout(root, 200, 80)
img = Widgets.render(root, 200, 80) # => { "pixels"=>, "stride"=>800, "w"=>200, "h"=>80 }
fired = Widgets.dispatch(ok, { "kind" => "click" }) # => { "fired" => ["on_ok"], ... }
https://github.com/go-ruby-widgets/widgets โ
tui ready
A terminal-cell UI toolkit over go-widgets/tui: label/button/entry/check_button/list_box/progress_bar widgets, a border layout container (header/footer bands + overlays), draggable h_split/v_split panes and a card layout notebook (tab strip). render emits a self-contained ANSI stream; render_cells/decode_cells return the decoded grid at cell precision for tests.
require "tui"
button = Tui.button("OK")
button.on_click("ok")
root = Tui.container
root.set_header_height(1)
root.set_header(Tui.label("Title"))
root.set_body(button)
Tui.set_size(root, 40, 10)
puts Tui.render(root, 40, 10) # => ANSI String
fired = Tui.dispatch(button, {"kind" => "click"}) # => {"fired"=>["ok"], "repaint"=>true}
https://github.com/go-ruby-widgets/tui โ
mvvm ready
The data-binding layer over go-widgets/mvvm: a bindable Observable property, a Command action and an ObservableList collection. A hosted Go library can’t call a Ruby block synchronously, so every change queues a callback-id-tagged event Hash; the rbgo binding polls it once per tick with drain_events โ the id + drain seam.
require "mvvm"
name = Mvvm.observable("")
name.subscribe(:on_name)
name.set("Ada") # queues {callback_id: :on_name, kind: "changed", value: "Ada"}
Mvvm.drain_events.each do |ev| # => Array<Hash>, once per UI tick
dispatch(ev[:callback_id], ev) # Ruby runs the actual block
end
https://github.com/go-ruby-widgets/mvvm โ
rbgo binding planned
require "widgets" / "tui" / "mvvm" โ the thin method_missing shim over each adapter’s Call that exposes it inside github.com/go-embedded-ruby/ruby (rbgo). Pending in that repo; nothing in the three adapters above depends on the Ruby runtime.
https://github.com/go-embedded-ruby/ruby โ
- ready shipped and covered
- active in progress
- planned not started yet
Three siblings, one shape: an object graph addressed by integer
handles, a uniform Call/Methods dynamic-dispatch surface driven by
reflection, and Ruby-shaped results throughout. widgets owns a live pixel object graph and
renders to an RGBA buffer; tui owns a live terminal-cell object graph and renders to ANSI
(decodable at cell precision via DecodeANSI); mvvm has no live UI tree at all โ
just an Observable property, a Command action and an ObservableList collection,
notifying Ruby through a queued, callback-id-tagged event Hash that drain_events pulls
once per tick. All three sit over the go-widgets
toolkits (toolkit,
tui,
mvvm) and are bound into
rbgo by a thin
method_missing shim โ a sibling pattern to
go-ruby-opentype,
go-ruby-regexp and
go-ruby-erb in the go-ruby-* family.