Documentation
¶
Overview ¶
Package roda is a pure-Go (no cgo) reimplementation of the routing-tree engine at the heart of Ruby's Roda web toolkit, matching the semantics of the MRI `roda` gem (Roda 3.x, tracking the 4.0.5 line) without any Ruby runtime.
Roda's defining feature is its routing tree: a request is dispatched by a single route block that peels path segments off the front of the request as it descends, using matcher methods — RodaRequest.On, RodaRequest.Is, the verb matchers RodaRequest.Get/RodaRequest.Post/… , RodaRequest.Root — each of which consumes the segments it matches and yields any captured segments to the block that handles that branch. This package models that segment-consuming engine exactly.
The route block itself is Ruby (in a rbgo binding) or Go (standalone): it is supplied through the injectable Handler seam. The engine drives the tree and the block re-enters it, so the same RodaRequest flows top-down through nested Handler calls. Matching against the request and consuming the path is fully deterministic and lives here as pure Go; running the block is the host's job.
The HTTP server — the socket accept loop, TLS — is out of scope: like Rack, the host owns it. This package builds on github.com/go-ruby-rack/rack for the Rack environment and header machinery, and produces the Rack `[status, headers, body]` tuple through RodaResponse.Finish.
Index ¶
- Variables
- type Handler
- type Hash
- type IntegerMatcher
- type Roda
- type RodaRequest
- func (r *RodaRequest) Captures() []any
- func (r *RodaRequest) Delete(handler Handler, matchers ...any)
- func (r *RodaRequest) Env() rack.Env
- func (r *RodaRequest) Get(handler Handler, matchers ...any)
- func (r *RodaRequest) Halt()
- func (r *RodaRequest) Is(handler Handler, matchers ...any)
- func (r *RodaRequest) On(handler Handler, matchers ...any)
- func (r *RodaRequest) Post(handler Handler, matchers ...any)
- func (r *RodaRequest) Put(handler Handler, matchers ...any)
- func (r *RodaRequest) Redirect(target string, status ...int)
- func (r *RodaRequest) RemainingPath() string
- func (r *RodaRequest) RequestMethod() string
- func (r *RodaRequest) Response() *RodaResponse
- func (r *RodaRequest) Root(handler Handler)
- type RodaResponse
- func (r *RodaResponse) Body() []string
- func (r *RodaResponse) Empty() bool
- func (r *RodaResponse) Finish() (status int, headers *rack.Headers, body []string)
- func (r *RodaResponse) GetHeader(key string) any
- func (r *RodaResponse) Headers() *rack.Headers
- func (r *RodaResponse) Redirect(target string, status int)
- func (r *RodaResponse) SetHeader(key string, val any)
- func (r *RodaResponse) SetStatus(status int)
- func (r *RodaResponse) Status() int
- func (r *RodaResponse) Write(chunk string)
- type RouteBlock
- type StringMatcher
- type Sym
Constants ¶
This section is empty.
Variables ¶
var ( // String is the Roda `String` class matcher (see [StringMatcher]). String = StringMatcher{} // Integer is the Roda `Integer` class matcher (see [IntegerMatcher]). Integer = IntegerMatcher{} )
Sentinel matcher values, provided so callers can write the class matchers without allocating.
Functions ¶
This section is empty.
Types ¶
type Handler ¶
type Handler func(r *RodaRequest, captures []any) (handled bool, body any)
Handler is the injectable seam for a Roda route block. When a matcher method matches, the engine calls the Handler for that branch with the captures accumulated so far. The Handler may re-enter the tree (call more matcher methods on r) — that is how nested routing works — and returns whether it produced a response body and, if so, the body value.
- handled == true: the returned body (a string, a []string, or nil) becomes the response body.
- handled == false: no body is written by this block.
Either way, a matched branch terminates the request (Roda always throws :halt after a matched `on`), unless the Handler itself re-entered and an inner branch terminated first. In a rbgo binding, the Handler runs the Ruby block.
type Hash ¶
Hash is a keyed matcher (the Roda Hash matcher). The supported keys are:
- "method": a string, or []any of strings — matches when the request method equals any of them (case-insensitive). Consumes nothing.
- "param": a string key — matches when that request parameter is present and non-empty, capturing its value. Consumes nothing.
- "extension": a string extension (e.g. "json") — matches when the next segment ends in "."+ext, capturing the segment's base name and consuming through the extension.
All present keys must match (like Ruby's `all?`), and they are evaluated in a fixed order (method, param, extension) for deterministic path consumption.
type IntegerMatcher ¶
type IntegerMatcher struct{}
IntegerMatcher is the Roda `Integer` class matcher: it matches a single segment made entirely of ASCII digits and captures it as an int.
type Roda ¶
type Roda struct {
// contains filtered or unexported fields
}
Roda is a Roda application: a route block plus the machinery to dispatch a Rack request through it. Construct one with New and serve requests with Roda.Call.
func New ¶
func New(route RouteBlock) *Roda
New returns a Roda application that dispatches every request through route, mirroring `Roda.route { |r| … }`.
func (*Roda) Call ¶
Call dispatches a Rack environment through the routing tree and returns the Rack `[status, headers, body]` triplet, mirroring `Roda#call`. It builds the request and response, runs the route block, catches the terminating :halt, and finishes the response — defaulting to a 404 when nothing matched.
type RodaRequest ¶
type RodaRequest struct {
// contains filtered or unexported fields
}
RodaRequest models Roda's `RodaRequest`: the request as seen by the routing tree. It carries the still-unconsumed remaining path and the captures peeled off it so far, and exposes the matcher methods that consume the path.
func (*RodaRequest) Captures ¶
func (r *RodaRequest) Captures() []any
Captures returns the segments captured so far (RodaRequest#captures).
func (*RodaRequest) Delete ¶
func (r *RodaRequest) Delete(handler Handler, matchers ...any)
Delete matches a DELETE request; see RodaRequest.Get.
func (*RodaRequest) Env ¶
func (r *RodaRequest) Env() rack.Env
Env returns the underlying Rack environment.
func (*RodaRequest) Get ¶
func (r *RodaRequest) Get(handler Handler, matchers ...any)
Get matches a GET request. With no matchers it matches only when the whole path is already consumed; with matchers it matches them terminally (like RodaRequest.Is). Mirrors RodaRequest#get.
func (*RodaRequest) Halt ¶
func (r *RodaRequest) Halt()
Halt terminates the request immediately with the current response, mirroring RodaRequest#halt with no arguments.
func (*RodaRequest) Is ¶
func (r *RodaRequest) Is(handler Handler, matchers ...any)
Is is like RodaRequest.On but only matches when the matchers consume the entire remaining path (a terminal match). Mirrors RodaRequest#is.
func (*RodaRequest) On ¶
func (r *RodaRequest) On(handler Handler, matchers ...any)
On matches the given matchers against the request. If they all match, it consumes the matched segments, yields the captures to the Handler and terminates the request. If they do not all match, the path and captures are restored and On returns so the next branch can be tried. Mirrors RodaRequest#on.
func (*RodaRequest) Post ¶
func (r *RodaRequest) Post(handler Handler, matchers ...any)
Post matches a POST request; see RodaRequest.Get for the matcher semantics.
func (*RodaRequest) Put ¶
func (r *RodaRequest) Put(handler Handler, matchers ...any)
Put matches a PUT request; see RodaRequest.Get.
func (*RodaRequest) Redirect ¶
func (r *RodaRequest) Redirect(target string, status ...int)
Redirect sets a redirect response (default status 302) and terminates the request. Mirrors RodaRequest#redirect.
func (*RodaRequest) RemainingPath ¶
func (r *RodaRequest) RemainingPath() string
RemainingPath returns the still-unconsumed portion of the path (RodaRequest#remaining_path).
func (*RodaRequest) RequestMethod ¶
func (r *RodaRequest) RequestMethod() string
RequestMethod returns the HTTP method (REQUEST_METHOD).
func (*RodaRequest) Response ¶
func (r *RodaRequest) Response() *RodaResponse
Response returns the response being built for this request.
func (*RodaRequest) Root ¶
func (r *RodaRequest) Root(handler Handler)
Root matches a GET request whose remaining path is exactly "/", without consuming it. Mirrors RodaRequest#root.
type RodaResponse ¶
type RodaResponse struct {
// contains filtered or unexported fields
}
RodaResponse models Roda's `RodaResponse` — the mutable response the route block writes into. It buffers a status, an ordered header map (reusing rack.Headers) and a list of body chunks, and assembles the Rack `[status, headers, body]` triplet in RodaResponse.Finish.
It mirrors Roda's defaulting rules: a response whose body is empty defaults to status 404, one with a body defaults to 200, and the Content-Type defaults to text/html — so an app whose routing tree matches nothing yields a 404 without the block doing anything.
func NewResponse ¶
func NewResponse() *RodaResponse
NewResponse returns an empty RodaResponse with no status set.
func (*RodaResponse) Body ¶
func (r *RodaResponse) Body() []string
Body returns the buffered body chunks (RodaResponse#body).
func (*RodaResponse) Empty ¶
func (r *RodaResponse) Empty() bool
Empty reports whether nothing has been written to the body (RodaResponse#empty?).
func (*RodaResponse) Finish ¶
func (r *RodaResponse) Finish() (status int, headers *rack.Headers, body []string)
Finish assembles the Rack `[status, headers, body]` triplet, applying Roda's defaults (RodaResponse#finish): an empty body defaults to 404 and a present body to 200; Content-Type defaults to text/html; Content-Length is set from the buffered length except for statuses that forbid an entity body, whose Content-Type/Length headers are stripped.
func (*RodaResponse) GetHeader ¶
func (r *RodaResponse) GetHeader(key string) any
GetHeader returns a header value (RodaResponse#[]).
func (*RodaResponse) Headers ¶
func (r *RodaResponse) Headers() *rack.Headers
Headers returns the underlying header map (RodaResponse#headers).
func (*RodaResponse) Redirect ¶
func (r *RodaResponse) Redirect(target string, status int)
Redirect sets the status and Location header for a redirect, matching RodaResponse#redirect. A zero status defaults to 302 (Found).
func (*RodaResponse) SetHeader ¶
func (r *RodaResponse) SetHeader(key string, val any)
SetHeader sets a header value (RodaResponse#[]=).
func (*RodaResponse) SetStatus ¶
func (r *RodaResponse) SetStatus(status int)
SetStatus sets the response status (RodaResponse#status=).
func (*RodaResponse) Status ¶
func (r *RodaResponse) Status() int
Status returns the currently set status (0 if the block set none; RodaResponse.Finish applies the default).
func (*RodaResponse) Write ¶
func (r *RodaResponse) Write(chunk string)
Write appends a chunk to the body and tracks its length, matching RodaResponse#write.
type RouteBlock ¶
type RouteBlock func(r *RodaRequest) (handled bool, body any)
RouteBlock is the top-level route block of a Roda application — the single block passed to `route do |r| … end`. It receives the RodaRequest and drives the routing tree by calling matcher methods on it. It is the same shape as a Handler and, like one, is a seam the host supplies (the Ruby route block in a rbgo binding).
type StringMatcher ¶
type StringMatcher struct{}
StringMatcher is the Roda `String` class matcher: like a Sym, it matches and captures any single non-empty segment.
