Home > Raku > Low profile quoting

Low profile quoting

I wrote a program that got exactly one user that is not me and is used once a week. Hence, I can proudly claim to be 520% efficient. The result can be found at the bottom of each Raku Weekly News. While casting my Raku spells I once again had felt the urge for a simply but convenient way to inline fragments of html in code. The language leans itself to the task with colon pairs and slurpy arrays.

sub a(*@a, *%_) { ... }

a(:href<www.somewhere.tld>, child(...), 'bare string');

I don’t want o pull in lots of names into the local namespace and avoiding a module would be nice. For a simple shellish script unusual dependencies are best avoided. At first I tried to abuse packages but those are compile time creatures and I don’t fancy to pre-define all possible html tags. But a package in the end is just a Stash is a Map is a Hash. Building a simple dynamic Hash-like is quite easy.

constant term:<␣> = ' ';
constant term:<¶> = $?NL;

constant html = class :: does Associative {
    sub qh($s) {
        $s.trans([ '<'   , '>'   , '&' ] =>
                 [ '&lt;', '&gt;', '&amp;' ])
    }

    role NON-QUOTE {}

    method AT-KEY($key) {
        sub (*@a, *%_) {
            ('<' ~ $key ~ (+%_ ?? ␣ !! '') ~ %_.map({ .key ~ '="' ~ .value ~ '"'  }).join(' ') ~ '>' ~
            @a.map( -> \e { e ~~ NON-QUOTE ?? e !! e.&qh }).join('') ~
            '</' ~ $key ~ '>') does NON-QUOTE
        }
    }
}

put html<a>(:href<www.foo.bar>, html<em>('<person@domain.top>'), 'M&M');

Here we got a singleton of a class that does Associative and as such will react nicely to <> and {} subscripts. It will quote bare strings because the anonymous sub will mark its output with the empty role NON-QUOTE. Anything returned from that sub is HTML and as such doesn’t need quoting. Bare string will not be returned by that sub, resulting in them being quoted.

This snippet is short enough to be covered by fair use — even by German standards — so please feel free to use it.

UPDATE:

HTML-entities must not be quoted too and never have arguments. Since we can tell them apart by the & at the beginning, we can return something different from the hash-like.

constant html = class :: does Associative {
    sub qh($s) {
        $s.trans([ '<'   , '>'   , '&' ] =>
                 [ '&lt;', '&gt;', '&amp;' ])
    }

    role NON-QUOTE {}

    method AT-KEY($key) {
        when $key ~~ /^ '&' / {
            $key does NON-QUOTE
        }
        when $key ~~ /\w+/ {
            sub (*@a, *%_) {
                dd @a;
                ('<' ~ $key ~ (+%_ ?? ␣ !! '') ~ %_.map({ .key ~ '="' ~ .value ~ '"'  }).join(' ') ~ '>' ~
                @a.map( -> \e { e ~~ NON-QUOTE ?? e !! e.&qh }).join('') ~
                '</' ~ $key ~ '>') does NON-QUOTE
            }
        }
    }
}

put html<a>(:href<www.foo.bar>, html<em>('<person@domain.top>'), html<&nbsp;>, 'M&M');
put html<&nbsp;>;
Categories: Raku
  1. June 4, 2021 at 13:16

    Great idea – I love it so much that I plan to wrote a blog with this in the examples … one impression I get from using this for several lines of HTML is that the ‘html’ constant you use is a bit repetitive and obscures the readability – so I propose the line “`constant term: = class :: does Associative {“`

  2. June 4, 2021 at 13:17

    hmmm that’s term < § >

  1. June 4, 2021 at 13:45
  2. June 7, 2021 at 19:12
  3. June 10, 2021 at 00:03

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: