Day 18 – Happy™ Xmas

Christmas was fast approaching and Santa was starting to worry about all the presents being wrapped in time. Ensuring that he could quickly find the Elfmail address for all of the team was important to whip them into shape.

Luckily, Rudolph [for it was he] had been learning raku and cro for some years now and he was ready to help. This year he had read about the wonderful HTMX framework and thought “If only I can combine HTMX and Cro and Raku in a cool way, I can make site build and maintenance a breeze.”

Now, since Rudolph was lazy, he didn’t really care about functional or object oriented coding style purity – he just wanted to get the job done fast and get back to his gin-sodden hay. And so he proceeded to dismay the other purile (should that be purist? -ed) elven coding communities such as Elflang and O-camel-ye-faithful and C++istmas by using the tool that worked best for the job.

Object Oriented

First, he knew that websites – especially those with HTMX – were written largely in HTML, so he wanted to write some HTML, but not too much.

To get some optional HTML, the Cro template <?.thead>...</?> tag; and some interpolated data, the <@results>...</@> and variable <.email> tags are great. Cro Template language is very nice for this – best tool for the job!

Here is a section of MyLib.rakumod

class ActiveTable is export {
    has THead() $.thead;

    method RENDER {
        q:to/END/
         <table class="striped">
             <?.thead>
                 <&THead(.thead)>
             </?>
             <tbody id="search-results">
             </tbody>
         </table>
     END
    }   
}

class Results is export {
    has @.results;

    method RENDER {
        q:to/END/
         <@results>
         <tr>
             <td><.firstName></td>
             <td><.lastName></td>
             <td><.email></td>
         </tr>
         </@>
     END
    }   
}

He wanted this HTML to be reusable, so he asked his friend to make a Cromponent prototype so he could make a library of reusable components – raku OO classes with attributes and (optionally) methods.

Functional

Then he thought – I am bored with HTML and OO. What other coding styles are there? Ah, yes I remember HTML::Functional – that looks like a cool new toy.

use Cromponent;
use Cromponent::MyLib;

my $cromponent = Cromponent.new;
my ($index, $topic);

{  #block to avoid namespace collision

    use HTML::Functional;

    $index =
        div [
            h3 [
                'Search Elves',
                span :class<htmx-indicator>, [ img :src</img/bars.svg>; '  Searching...' ]
            ];  

            input :class<form-control>, :type<search>, :name<search>,
                :placeholder<Begin typing to search elvesis>,
                :hx-post</happy_tm_xmas/search>,
                :hx-trigger<keyup changed delay:500ms, search>,
                :hx-target<#search-results>,
                :hx-indicator<.htmx-indicator>;

            activetable :thead<Given Elven Elfmail>, :$topic;
        ];      
}

Of course he had not forgotten the cool dynamic capabilities of HTMX – in this case the Active Search example. But he loved the way that he could compose HTML tags and Cromponents directly as raku source just like Elmlang – but on the server side!

Procedural

Rudolph was exhausted with all that heavy OO and Functional coding – so he just finished off with some plain old Procedural – phew!

use Cro::HTTP::Router;
use Cro::WebApp::Template;

sub happy_tm_xmas-routes() is export {

    route {

        $cromponent.add: Results, ActiveTable, THead, HCell, Row, Cell;

        get -> {
            template-with-components $cromponent, $index, $topic;
        }

        post -> 'search' {
            my $needle;

            request-body -> %fields {
                $needle = %fields<search>;
            }

            template-with-components $cromponent, results( results => search($needle), :$topic), $topic;
        }
    }
}

sub search($needle) {

    sub check($str) { $str.contains($needle, :i) };

    data.grep: (
        *.<firstName>.&check,
        *.<lastName>.&check,
        *.<email>.&check,
    ).any;
}

use JSON::Fast;

sub data() {

    from-json q:to/END/;
    [
        {"firstName": "Venus", "lastName": "Grimes", "email": "lectus.rutrum@Duisa.edu", "city": "Ankara"},
        {"firstName": "Fletcher", "lastName": "Owen", "email": "metus@Aenean.org", "city": "Niort"},
        {"firstName": "William", "lastName": "Hale", "email": "eu.dolor@risusodio.edu", "city": "Te Awamutu"},
        {"firstName": "TaShya", "lastName": "Cash", "email": "tincidunt.orci.quis@nuncnullavulputate.co.uk", "city": "Titagarh"},
       ...
    ]
    END
}

And, so that was it – a couple of Cro routes, serving the new template-with-components function to serve up the Cromponents. Some data and a search function to serve the results on the HTMX keyup trigger.

Happy™ Xmas

The proof of the pudding is in the viewing – so here is the finished result. If you would like to try this yourself, the code is available here: https://github.com/librasteve/raku-Cro-Website-Basic/tree/02-sharc1 … note that the branch is called 02-sharc1 for sass, htmx, raku, cro.

Credits

On a serious note, while it seems odd to apply three styles of coding in a few lines, a practical coder who wants to use the best tool for the job will appreciate that all these styles are there according to what works best.

Massive kudos to smokemachine for making an experiment with Cromponents – this post is just scraping the surface of what can be done. A better way would be to use Red for our data model and to have that inside the Cromponent – and to get the search results via a method on class ActiveTable {...}

These ideas will hopefully coalesce over on my Raku::Journey blog in 2025…

~librasteve (aka Rudolph)

2 thoughts on “Day 18 – Happy™ Xmas

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.