Progress!
Before:
./data/mentions/3f256ff[...]494.json
./data/mentions/62afe34[...]020.json
...
Hmm, so which file pertains to which post?
{{ $slug := .RelPermalink | sha256 }}
{{ $all_mentions := index site.Data.mentions $slug | default slice }}
{{ $likes := where $all_mentions "wm-property" "like-of" }}
At least the template code to get at it is more or less sane.
During:
./data/mentions/note/8/mentions.json
./data/mentions/note/9/mentions.json
Well, that’s clear as day!
{{ $key := (split path.Dir .RelPermalink) "/" | after 1 | append "mentions" }}
{{ $all_mentions := index site.Data.mentions $key | default slice }}
{{ $likes := where $all_mentions "wm-property" "like-of" }}
What the actual fuck? I want to write {{ index site.Data.mentions .RelPermalink }}
and have done with it. To the data mungery!
Now
./data/mentions/all.json
That’s a tad more opaque, isn’t it? Ah well, there’s always jq
. I can’t see what’s got new mentions from git status any more, but also, I can’t forget to add any new data files either. Call it a win on aggregate.
{{ $all_mentions = index site.Data.mentions.all .RelPermalink | default dict }}
{{ $likes := index $all_mentions "like-of" | default slice }}
Well structured data for the win! And I’m working on eliminating the annoying default dict
and default slice
in that too.
When last we left off we had worked out how to grab all the mentions of this site that Webmentions.io knew about and now we want to write that out to the
data/
directory in a format that’s easy to deal with in Hugo.If you’ve read my earlier note, you’ll know that I’ve been evolving the data schema towards something that’s easy for Hugo to deal with and reasonably comprehensible for me too.
As things currently stand, I’ve settled on dropping all the mentions in a single file,
data/mentions/all.json
I’d rather use
which is structured along these lines:data/mentions.json
, but Hugo’s data system doesn’t seem to pick that up, so I’ll live with the slightly more clunky option.Just imagine that JSON object has a bunch more paths as keys referencing similar objects keyed by mention type.
As it stands,
wm--fetch-all
is returning a flat sequence of webmention objects that we want to process into a more structured object,JSON/Javascript calls them objects, old Perl heads like me think of them as hashes, and they’re “Hash Tables” in Emacs Lisp. I’ll be calling them hashes from now on.
in other words we want to fold (or “reduce” in Emacs Lisp terminology) the sequence into a hash. And I know just the function for that. Let’s see whatdescribe-function
has to say aboutseq-reduce
:So we can write
and that will handle the business of iterating over the sequence of mentions for us, and all we have to do is write
wm--add-mention-to-hash-table
to populate the hash we made with(make-hash-table :test 'equal)
We need to use that
one mention at a time, and return the modified hash (You and I both know that it’s the same old hash mutated, but let’s pretend it isn’t, eh?).:test ’equal
part becausejson-insert
wants a hash with strings as keys and the default hash returned by(make-hash-table)
compares keys usingeql
which might or might not work when comparing strings. Not a problem whichequal
has.What does that function look like? Here’s what I wrote:
We grab the path from the
"wm-target"
key, which is actually a URL rather than a simple pathWe could just use the URL, and that would work fine on this site, but not when I’m running on localhost. The path will always match with
so, rather than writing.RelPermalink
, but the host part of.Permalink
is different in development than in production.we’ll thread
mention
through that series of transformations usingdash.el
’s threading macro,-->
.We use the path to grab
mentions-hash
from theacc
-umulating hash and, if there isn’t already one there, we grab an empty, but structured hash usingwm-new-mentions-hash
, which looks like this:Now we look up
"wm-property"
inmention
, and use that to grab its associated vector of mentions. Well, we would, but there’s a small wrinkle.We’re only currently interested in four kinds of mention, but Webmention.io doesn’t know that. We could throw the extras away, but what if we became interested in
bookmark-of
mentions or whatever somewhere down the road. So let’s collect them under theother
key. Which is where this hacky section of ourlet*
form comes in:What’s going on here then?
First, we make a guess at the
mention-type
we’re going to file the current mention under by grabbing the"wm-property"
and use that value to lookup the mention type inmentions-hash
. If it’s one of the four types we’re interested in, that will be a vector, which is truth-y, otherwise we getnil
, which is false-y so we change the mention type to “other” and grab that vector from the mention hash.We now know the key path we’re going to store our mentions in, and we have the current vector of mentions associated with it. So, if we already know
(seq-contains mentions mention)
about the current mention, we reuse that, otherwise we make a new vector with the current mention added to it.That done, it’s a simple matter of putting the new mentions vector into our mentions hash, putting the mentions hash into our accumulating hash and returning that.
With that done, it’s a simple matter of opening
data/mentions/all.json
, erasing the buffer, calling(json-insert (seq-reduce ...))
to update the data and saving it. Here’s the code which does exactly that.Over in the Hugo partial that renders the bit of the page immediately after this, we can get at the data like this:
I’ll leave the rest as an exercise for the interested reader. However, I will note that the Webmention.io API includes the option to pass in a
since
argument, so it wouldn’t be hard to writewithout having to change our reducing function at all.
Separation of concerns, baby! Separation of concerns!