Skip to content

Bind pure-Go actionpack into rbgo (ActionController + ActionDispatch) - #196

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

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

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

Binds github.com/go-ruby-actionpack/actionpack — a pure-Go (CGO=0) port of Rails' Action Pack — into rbgo as a native module set, so require "action_controller" / require "action_dispatch" resolve with no .rb file. Pinned at @main (8ba13fb).

The four subpackages

Subpackage Ruby surface
routing ActionDispatch::Routing::RouteSet + Mapper — the draw DSL (get/post/put/patch/delete/match, resources/resource, root, namespace/scope, member/collection, constraints, all option keys incl. to:/as:/via:/on:/constraints:/defaults:), plus recognize / path / path_args / url_for reverse routing
controller ActionController::Base (over AbstractController::Base + ActionController::Metal) — before_action/after_action/around_action (with only:/except:/if:/unless:), rescue_from, render/redirect_to/head, and PostsController.dispatch(action, env)
parameters ActionController::Parameters — permit/require/[]/to_h/to_unsafe_h/merge strong-parameters, with ParameterMissing/UnpermittedParameters/UnfilteredParameters errors
dispatch ActionDispatch::Request / Response over the bound go-ruby-rack

Seam wiring

Every seam runs inline on the VM goroutine under the GVL:

  • RunAction (primary): the Ruby action method (def index; …; end) is sent to the controller instance; an unmapped action returns AbstractController::ActionNotFound.
  • Filters / rescue_from: wired to Ruby blocks or named instance methods sent to the instance; around filters yield through a native block so the Ruby method's yield runs the rest of the chain.
  • Renderer (view layer): sends a render message to an ActionView-style context object set with view_context — so the consolidated binary dispatches to the bound actionview at the Ruby level; actionpack itself does not import actionview. In this clone (no actionview present) the seam is tested with an injected Ruby renderer stub (a Stub.new responding to #render).

A controller instance is a plain RObject of the user's subclass whose live *controller.Base is reached through an @__ac handle (mirroring the ActionCable channel binding), so a bare render inside def index resolves to the inherited native method that writes into that request's response. The routing/dispatch/params value objects each carry their Ruby class for classOf.

Registration

registerActionPack joins the bootstrap after registerRack/registerActionCable; providedFeatures gains action_controller/action_dispatch/actionpack/abstract_controller; classOf gains the RouteSet/Mapper/Parameters/Request/Response cases.

Verification

  • 100% coverage of all new files (actionpack*.go): routing recognize/resources + reverse-routing error paths, filters + rescue_from (match/miss/inherited/with:), strong-params permit/require raise paths, the RunAction/around/rescue/Renderer seams (string + non-string render), double-render, missing action.
  • Full internal/vm + internal/object suites green; gofmt -l empty; go vet clean.
  • Builds on all 6 64-bit arches: amd64, arm64, riscv64, loong64, ppc64le, s390x.

Deps: go-ruby-activesupport + go-ruby-rack (both already bound). CGO=0, GOWORK=off, go 1.26.4, BSD-3-Clause.

🤖 Generated with Claude Code

Bind github.com/go-ruby-actionpack/actionpack — a pure-Go (CGO=0) port of
Rails' Action Pack — into rbgo as a native module set, so `require
"action_controller"` / `require "action_dispatch"` work with no .rb file.

The four subpackages are wired across five files:

  - routing: ActionDispatch::Routing::RouteSet + Mapper — the routes `draw`
    DSL (verb matchers, resources/resource, root, namespace/scope,
    member/collection, constraints, all option keys) plus recognize / path /
    path_args / url_for reverse routing.
  - controller: ActionController::Base (over AbstractController::Base +
    ActionController::Metal) — before/after/around filters (only/except/if/
    unless), rescue_from, render/redirect_to/head, and PostsController.dispatch.
  - parameters: ActionController::Parameters — permit/require/[]/to_h/merge
    strong-parameters, with the ParameterMissing/UnpermittedParameters/
    UnfilteredParameters errors.
  - dispatch: ActionDispatch::Request / Response over the bound go-ruby-rack.

Every seam runs inline on the VM goroutine under the GVL: the Ruby action
method (RunAction), the filter/rescue bodies (blocks or named methods), and
the view render — the Renderer seam sends a `render` message to an
ActionView-style context set with `view_context`, so the consolidated binary
dispatches to the bound actionview while this clone tests it with an injected
Ruby renderer stub. A controller instance is a plain RObject of the user's
subclass whose live *controller.Base is reached through the @__ac handle
(mirroring the ActionCable channel binding); the routing/dispatch/params value
objects each carry their Ruby class for classOf. actionpack does not import
actionview — rendering is the seam above.

registerActionPack joins the bootstrap after registerRack/registerActionCable;
providedFeatures gains action_controller/action_dispatch/actionpack/
abstract_controller; classOf gains the RouteSet/Mapper/Parameters/Request/
Response cases.

100% coverage of all new files (routing recognize/resources + reverse-routing
error paths, filters/rescue_from, strong-params permit/require raise paths,
the RunAction/around/rescue/Renderer seams, double-render), full internal/vm +
internal/object suites green, gofmt/go vet clean, builds on all 6 64-bit
arches (amd64/arm64/riscv64/loong64/ppc64le/s390x).

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