Skip to content

erb: back ERB with the go-ruby-erb library - #41

Merged
tannevaled merged 1 commit into
mainfrom
erb-bind-library
Jun 29, 2026
Merged

tannevaled merged 1 commit into
mainfrom
erb-bind-library

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

What

Rewire rbgo's ERB so its template scan/trim/compile is performed by the standalone pure-Go github.com/go-ruby-erb/erb library — which mirrors MRI's real ERB::Compiler byte for byte — instead of the hand-written compiler that lived in the prelude. This is the same pattern rbgo already uses to back regexps with go-ruby-regexp.

Changes

  • internal/vm/erb.go (new native binding):
    • An ERB class skeleton with a private __compile(template, trim_mode, eoutvar) hook over erb.Compile, returning the compiled Ruby src (which already carries the #coding:UTF-8\n magic prefix). A Compile error is surfaced as a Ruby ArgumentError.
    • An ERB::Util module whose html_escape / url_encode (and the h / u aliases) bind directly to erb.HTMLEscape / erb.URLEncode, so the pure escaping functions come from the library too. Non-string args are coerced with #to_s (MRI semantics).
  • internal/vm/prelude.rb: class ERB is now a thin shim — initialize calls __compile to fill @src; result / result_with_hash / run keep the interpreter-bound binding+eval logic that must stay in rbgo. The inner class Compiler (scan / trim / expand_percent_lines / quote) and the Ruby Util / HTML_ESCAPE table are deleted — net 224 fewer lines of prelude Ruby (236 removed / 12 added).
  • Re-froze the embedded prelude (cmd/freeze-prelude); drift test passes.
  • Added github.com/go-ruby-erb/erb v0.0.0-20260629074717-0999ae4dd529.

Behavior

Byte-for-byte unchanged vs MRI 4.0.5. All existing ERB tests and the conformance sweep pass without any test edits — the library reproduces MRI's <%% / %%>-in-body handling identically, so no rbgo test asserted incorrect behavior. Confirmed against ruby -rerb: the three tag kinds, every trim mode (- / > / <> / %), the <%% / %%> literals, unterminated tags, ERB::Util escaping, and Puppet's ERB.new(content, trim_mode: '-') templatewrapper path all match.

Quality gates

  • Cross-package coverage: 100.0% (the new binding's Compile-error branch is covered via the erbCompile fault-injection seam in an internal test).
  • gofmt clean, go vet ./internal/... clean, go build ./cmd/rbgo succeeds, full ./internal/... suite green.

🤖 Generated with Claude Code

Rewire rbgo's ERB so the template scan/trim/compile is done by the pure-Go
github.com/go-ruby-erb/erb library (which mirrors MRI's ERB::Compiler byte
for byte) instead of a hand-written compiler in the prelude — the same way
rbgo already binds go-ruby-regexp for regexps.

- Add internal/vm/erb.go: a native ERB class skeleton with a private
  __compile(template, trim_mode, eoutvar) hook over erb.Compile, plus an
  ERB::Util module whose html_escape/url_encode (and h/u aliases) bind to
  erb.HTMLEscape/erb.URLEncode. The Compile-error branch is reached through
  the erbCompile seam (the library never fails on a well-formed template).
- Prelude class ERB is now a thin shim: initialize calls __compile to get
  @src; result/result_with_hash/run keep the interpreter-bound binding+eval
  logic. The inner Compiler (scan/trim/expand_percent_lines/quote) and the
  Ruby Util/HTML_ESCAPE table are deleted (net 224 fewer Ruby lines).
- Re-froze the embedded prelude.

Behavior is byte-for-byte unchanged vs MRI 4.0.5: all existing ERB tests,
the conformance sweep, and Puppet's trim_mode '-' templatewrapper path pass
without changes. Cross-package coverage stays at 100.0%.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled
tannevaled merged commit 88ae131 into main Jun 29, 2026
9 checks passed
@tannevaled
tannevaled deleted the erb-bind-library branch June 29, 2026 08:09
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