Functional
Air::Functional
This raku module is one of the core libraries of the raku Air distribution.
It exports HTML tags as raku subs that can be composed as functional code within a raku program.
It replaces the HTML::Functional module by the same author.
SYNOPSIS
Here's a regular HTML page:
<div class="jumbotron">
<h1>Welcome to Dunder Mifflin!</h1>
<p>
Dunder Mifflin Inc. (stock symbol <strong>DMI</strong>) is
a micro-cap regional paper and office supply distributor with
an emphasis on servicing small-business clients.
</p>
</div>And here is the same page using Air::Functional:
use Air::Functional;
div :class<jumbotron>, [
h1 "Welcome to Dunder Mifflin!";
p [
"Dunder Mifflin Inc. (stock symbol "; strong 'DMI'; ") ";
q:to/END/;
is a micro-cap regional paper and office
supply distributor with an emphasis on servicing
small-business clients.
END
];
];DESCRIPTION
Key features shown are:
HTML tags are implemented as raku functions:
div, h1, pand so onparens
()are optional in raku function callsHTML tag attributes are passed as raku named arguments
HTML tag inners (e.g. the Str in
h1) are passed as raku positional argumentsthe raku Pair syntax is used for each attribute i.e.
:name<value>multiple
@innersare passed as a literal Array[]ā div contains h1 and pthe raku parser looks at functions from the inside out, so
strongis evaluated beforep, beforedivand so onsemicolon
;is used as the Array literal separator to suppress nesting of tags
Normally the items in a raku literal Array are comma , separated. Raku precedence considers that div [h1 x, p y]; is equivalent to div( h1(x, p(y) ) ); ⦠so the p tag is embedded within the h1 tag unless parens are used to clarify. But replace the comma , with a semi colon ; and predisposition to nest is reversed. So div [h1 x; p y]; is equivalent to div( h1(x), p(y) ). Boy that Larry Wall was smart!
The raku example also shows the power of the raku Q-lang at work:
double quotes
""interpolate their contentscurlies denote an embedded code block
"{fn x}"tilde
~is for Str concatenationthe heredoc form
q:to/END/;can be used for verbatim text blocks
This module generally returns Str values to be string concatenated and included in an HTML content/text response.
It also defines a programmatic API for the use of HTML tags for raku functional coding and so is offered as a basis for sister modules that preserve the API, but have a different technical implementation such as a MemoizedDOM.
Declare Constants
All of the HTML tags listed at https://www.w3schools.com/tags/default.asp are covered ...
... of which empty (Singular) tags from https://www.tutsinsider.com/html/html-empty-elements/
HTML Escape
sub escape
sub escape(
Str:D(Any):D $s
) returns StrExplicitly HTML::Escape inner text
multi sub prefix:<^>
multi sub prefix:<^>(
Str:D(Any):D $s
) returns Stralso a shortcut ^ prefix
Tag Rendering
role Attr is Str {} - type for Attribute values, use Attr() for coercion
subset Inner where Str | Tag | Taggable | Markup - type union for Inner elements
role Tag [TagType Singular|Regular] {} - basis for Air functions
has Str $.name
tag name is the unqualified (ie the last) part of the class name in lower case
has Associative[Air::Functional::Attr] %.attrs
can be provided with attrs
has Positional[Air::Functional::Inner] @.inners
can be provided with inners
method new
method new(
*@inners,
*%attrs
) returns Muok to call .new with @inners as Positional
method HTML
method HTML() returns Muprovides default .HTML method used by tag render
Custom Elements
Use eg. el "simple-greeting", :name<John>, @inners to issue HTML custom element simple-greeting name="John">@inners</simple-greeting
sub el
sub el(
Str $element-name,
*@inners,
*%attrs
) returns Muissue an HTML custom-element tag
Low Level API
This level is where users want to mess around with the parts of a tag for customizations
sub attrs
sub attrs(
%h
) returns Strconvert from raku Pair syntax to HTML tag attributes
sub merge
sub merge(
%a,
%b
) returns Hashmerge two attr hashes so that two styles are Str concatenated
sub opener
sub opener(
$tag,
*%h
) returns Stropen a custom tag
sub inner
sub inner(
@inners
) returns Str(Any)convert from an inner list to HTML tag inner string
sub closer
sub closer(
$tag,
:$nl
) returns Strclose a custom tag (unset :!nl to suppress the newline)
High Level API
This level is for general use from custom tags that behave like regular/singular tags
sub do-regular-tag
sub do-regular-tag(
Str $tag,
*@inners,
*%h
) returns Air::Functional::Markup(Any)do a regular tag (ie a tag with @inners)
sub do-singular-tag
sub do-singular-tag(
Str $tag,
*%h
) returns Air::Functional::Markup(Any)do a singular tag (ie a tag without @inners)
Tag Export Options
Exports all the tags programmatically
sub h
sub h(
Int $level where { ... },
*@inners,
*%h
) returns Air::Functional::Markup(Any)head dispatcher h(2, "Title") calls h2("Title") etc.
package Air::Functional::EXPORT::DEFAULT
export all HTML tags viz. https://docs.raku.org/language/modules#Exporting_and_selective_importing
package Air::Functional::EXPORT::CRO
use :CRO as package to avoid collisions with Cro::Router names
package Air::Functional::EXPORT::BASE
use :BASE as package to avoid collisions with Cro::Router, Air::Base & Air::Component names NB the HTML description list tags are also excluded to avoid conflict with the raku dd command
AUTHOR
Steve Roe [email protected]
COPYRIGHT AND LICENSE
Copyright(c) 2025 Henley Cloud Consulting Ltd.
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.