Skip to content

Bind Action Mailer (go-ruby-actionmailer) as a native module - #194

Closed
tannevaled wants to merge 1 commit into
mainfrom
feat/bind-actionmailer
Closed

tannevaled wants to merge 1 commit into
mainfrom
feat/bind-actionmailer

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Adds require "action_mailer" support backed by
go-ruby-actionmailer/actionmailer
(pinned @main, f116fa6), so mailer classes compose and deliver mail with no
.rb file — mirroring the existing Mail and ActiveJob bindings.

Surface (ActionMailer::Base subclass model)

  • Class DSL: default, delivery_method= / delivery_method,
    perform_deliveries=, raise_delivery_errors=, register_interceptor,
    register_observer, the shared deliveries sink, and the renderer= /
    enqueuer= injection points.
  • Each mailer action method (def welcome) becomes callable as a class
    method
    via the method_added hook, returning an
    ActionMailer::MessageDelivery (deliver_now / deliver / deliver_later /
    message).
  • The mailer instance surface a def welcome body runs against:
    mail(...), attachments (regular + attachments.inline), headers(hash).

Four Ruby-dispatch seams (all INLINE under the GVL)

Seam Wiring
Action the mailer method body is sent to a freshly allocated instance bound to the library *Mailer; a raise maps to an error the delivery proxy re-raises faithfully
RenderBody → Action View sends #render to the configured Ruby renderer (renderer=, wired to the bound go-ruby-actionview in the consolidated binary; a stub in tests); a nil renderer / nil result skips the format
DeliveryMethod = test default appends to ActionMailer::Base.deliveries; a #deliver object plugs in a custom transport
EnqueueJob → Active Job deliver_later sends #enqueue to the configured Ruby enqueuer (enqueuer=, wired to the bound go-ruby-activejob in the consolidated binary; a stub in tests), else runs inline

Verification

  • go build ./internal/vm/ → 0; classOf cases end in return (orphan scan clean).
  • 100% coverage of the new files (actionmailer.go, actionmailer_bind.go):
    compose (single / alternative / related / mixed / empty), attachments
    (regular + inline), interceptors/observers, deliver_now / deliver_later
    (inline + enqueuer stub), the RenderBody + EnqueueJob seams via injected stubs,
    and the delivery-error raise paths.
  • Full suite go test ./internal/vm/ ./internal/object/ → both ok.
  • gofmt -l clean; go vet ./internal/vm/ → 0.
  • Cross-compiles on all six 64-bit arches (amd64, arm64, riscv64, loong64, ppc64le, s390x).

🤖 Generated with Claude Code

Add `require "action_mailer"` support backed by
github.com/go-ruby-actionmailer/actionmailer, so mailer classes compose and
deliver mail with no .rb file, mirroring the existing Mail / ActiveJob bindings.

Surface (ActionMailer::Base subclass model):
- class DSL: `default`, `delivery_method=`/`delivery_method`,
  `perform_deliveries=`, `raise_delivery_errors=`, `register_interceptor`,
  `register_observer`, the shared `deliveries` sink and the `renderer=`/
  `enqueuer=` injection points;
- each mailer action method (`def welcome`) becomes a class method via the
  method_added hook, returning an ActionMailer::MessageDelivery
  (`deliver_now` / `deliver` / `deliver_later` / `message`);
- the mailer instance surface a `def welcome` body runs against: `mail(...)`,
  `attachments` (regular + `attachments.inline`) and `headers(hash)`.

Four Ruby-dispatch seams, all run INLINE under the GVL:
- Action: the mailer method body is sent to a freshly allocated mailer instance
  bound to the library *Mailer; a raise maps to an error the delivery proxy
  re-raises faithfully;
- RenderBody: body rendering sends #render to the configured Ruby renderer
  (Action View in the consolidated binary; a stub in tests); a nil renderer or
  nil result skips the format;
- DeliveryMethod: defaults to the :test method (append to
  ActionMailer::Base.deliveries); a #deliver object plugs in a custom transport;
- EnqueueJob: deliver_later sends #enqueue to the configured Ruby enqueuer
  (Active Job in the consolidated binary; a stub in tests), else runs inline.

100% coverage of the new files (compose/alternative/related/mixed, attachments,
interceptors/observers, deliver_now/later, delivery-error raise paths, all seams
via injected stubs). gofmt + go vet clean; builds on all six 64-bit arches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tannevaled

Copy link
Copy Markdown
Contributor Author

Superseded by the wave-2 consolidation PR (single merge onto main; shared builtins/require/object_model/vm/arith/digest_bind). Work preserved verbatim; branch kept for reference.

@tannevaled tannevaled closed this Jul 6, 2026
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