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, p and so on

  • parens () are optional in raku function calls

  • HTML tag attributes are passed as raku named arguments

  • HTML tag inners (e.g. the Str in h1) are passed as raku positional arguments

  • the raku Pair syntax is used for each attribute i.e. :name<value>

  • multiple @inners are passed as a literal Array [] – div contains h1 and p

  • the raku parser looks at functions from the inside out, so strong is evaluated before p, before div and so on

  • semicolon ; 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 contents

  • curlies denote an embedded code block "{fn x}"

  • tilde ~ is for Str concatenation

  • the 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 Str

Explicitly HTML::Escape inner text

multi sub prefix:<^>

multi sub prefix:<^>(
    Str:D(Any):D $s
) returns Str

also 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 Mu

ok to call .new with @inners as Positional

method HTML

method HTML() returns Mu

provides 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 Mu

issue 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 Str

convert from raku Pair syntax to HTML tag attributes

sub merge

sub merge(
    %a,
    %b
) returns Hash

merge two attr hashes so that two styles are Str concatenated

sub opener

sub opener(
    $tag,
    *%h
) returns Str

open 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 Str

close 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.

Air v0.1.32

Just build websites the right way.

Authors

  • librasteve

License

Artistic-2.0

Dependencies

UUID::V4:ver<1.0.0>:auth<zef:masukomi>:api<1>CSS::Writer:ver<0.3.3>:auth<zef:dwarring>DateTime::Format:ver<0.1.5>:auth<zef:raku-community-modules>:api<1.0>HTML::Escape:ver<0.0.1>Cro::HTTP:ver<0.8.13>:auth<zef:cro>:api<0>Cro::WebApp:ver<0.10.1>:auth<zef:cro>:api<0>Cromponent:ver<0.0.13>:auth<zef:FCO>Text::Markdown:ver<1.1.1>:auth<zef:JJMERELO>YAMLish:ver<0.1.2>:auth<zef:leont>

Test Dependencies

Provides

  • Air
  • Air::Base
  • Air::Base::Elements
  • Air::Base::Tags
  • Air::Base::Tools
  • Air::Base::Widgets
  • Air::Component
  • Air::Form
  • Air::Functional

The Camelia image is copyright 2009 by Larry Wall. "Raku" is trademark of the Yet Another Society. All rights reserved.