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([ '<' , '>' , '&' ] =>
[ '<', '>', '&' ])
}
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([ '<' , '>' , '&' ] =>
[ '<', '>', '&' ])
}
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< >, 'M&M');
put html< >;
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 {“`
hmmm that’s term < § >