git.m455.casa

m455.casa

clone url: git://git.m455.casa/m455.casa


html/archive/2020/generating-a-list-of-posts-for-my-blog.html

1 <!DOCTYPE html>
2 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
3 <head>
4 <meta charset="utf-8" />
5 <meta name="generator" content="pandoc" />
6 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
7 <title>Generating a list of posts for my blog</title>
8 <style>
9 code{white-space: pre-wrap;}
10 span.smallcaps{font-variant: small-caps;}
11 span.underline{text-decoration: underline;}
12 div.column{display: inline-block; vertical-align: top; width: 50%;}
13 div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
14 ul.task-list{list-style: none;}
15 </style>
16 <style>
17 body {
18 line-height: 1.5;
19 font-family: sans-serif;
20 font-size: 18px;
21 margin: 20px auto;
22 max-width: 630px;
23 }
24
25 a {
26 color: blue;
27 }
28
29 code, pre {
30 background-color: #fddee3;
31 font-size: 14px;
32 }
33
34 pre {
35 padding: 25px 25px;
36 overflow: auto;
37 }
38
39 pre code {
40 white-space: pre;
41 }
42
43 img {
44 max-width: 100%;
45 }
46
47 table {
48 border-collapse: collapse;
49 }
50
51 table caption {
52 font-weight: bold;
53 margin: 10px 0px;
54 text-align: left;
55 }
56
57 th, td {
58 border: 1px solid #000;
59 padding: 4px;
60 }
61
62 blockquote {
63 border-left: 3px solid #000;
64 padding-left: 10px;
65 }
66
67 .border {
68 border: 1px solid #000;
69 margin: 25px 0px;
70 padding: 5px 25px;
71 }
72
73 @media only screen and (max-width: 700px) {
74 body {
75 margin: 10px;
76 }
77 }
78
79 @media (prefers-color-scheme: dark) {
80 body {
81 background-color: #111;
82 color: #eee;
83 }
84 a {
85 color: #009fff;
86 }
87 code, pre {
88 background-color: #111;
89 color: #fd6363;
90 }
91 pre {
92 padding: 15px 25px;
93 }
94 blockquote {
95 border-left: 3px solid #666;
96 }
97 .border, th, td {
98 border: 1px solid #666;
99 }
100 }
101 </style>
102 </head>
103 <body>
104 <main>
105 <h2 id="generating-a-list-of-posts-for-my-blog">Generating a list of posts for my blog</h2>
106 <p>2020-11-17 00:00</p>
107 <h3 id="post-overview">Post overview</h3>
108 <!-- vim-markdown-toc GFM -->
109 <ul>
110 <li><a href="#about-the-script">About the script</a></li>
111 <li><a href="#retrieving-necessary-data-from-markdown-files">Retrieving necessary data from Markdown files</a></li>
112 <li><a href="#plopping-it-all-into-a-data-format">Plopping it all into a data format</a></li>
113 <li><a href="#sorting-the-data">Sorting the data</a></li>
114 <li><a href="#thou-shalt-order-thy-file-writing">Thou shalt order thy file writing</a></li>
115 <li><a href="#back-to-rss-generator-programming">Back to RSS-generator programming…</a></li>
116 <li><a href="#getting-meta">Getting meta</a></li>
117 </ul>
118 <!-- vim-markdown-toc -->
119 <p>I just finished something that past-me would have had a really hard time with. It felt like some kind of programming koan for me, as I’m just a hobbyist programmer, but regardless, these little victories make me happy.</p>
120 <p>I wrote a little script to generate a list of blog posts, which I used to
121 write by hand. You can see the result by viewing <a href="/archive/">my posts page</a>, which is underwhelming, but that all used to be written by hand, and now it’s automated!</p>
122 <p>I figured, when my blog posts end up getting to a number that is unmanageable by hand, I should make my computer do the work!</p>
123 <p>Okay, that’s not the reason why. I just wanted a little programming project, and writing short programming projects is totally what I love doing.</p>
124 <h3 id="about-the-script">About the script</h3>
125 <p>The script just recursively goes through my <code>convert/posts/</code> directory, and looks for files that end with an <code>.md</code> suffix that aren’t <code>index.md</code>, because that’s the file to be generated or an old version of a previously generated file, or in this case, it was my original hand-written file.</p>
126 <h3 id="retrieving-necessary-data-from-markdown-files">Retrieving necessary data from Markdown files</h3>
127 <p>The script has a function that opens up files to find the title, date, and link. The title is retrieved from the first line, which looks something like <code># Hey, I'm a title</code>. The date is retrieved from the third line, which looks something like <code>Date published: 2020-11-21</code>. The link to the file is retrieved from the recursively constructed path, which looks something like <code>convert/posts/2020/hey-im-a-blog-post.md</code>.</p>
128 <p>The title, date, and link are then stripped as follows:</p>
129 <ul>
130 <li>The <code>#</code> is stripped from the <code># Hey, I'm a title</code>.</li>
131 <li>The <code>Date published:</code> is stripped from the <code>Date published: 2020-11-21</code>.</li>
132 <li>The <code>convert</code> is stripped from the <code>convert/posts/2020/hey-im-a-blog-post.md</code>.</li>
133 </ul>
134 <aside class="border">
135 <p>
136 <strong>Notice</strong>: Since this blog post, you may have noticed that I’ve changed my date format from <code>Date published: yyyy-mm-dd</code> to just <code>yyyy-mm-dd</code>.
137 </p>
138 </aside>
139 <h3 id="plopping-it-all-into-a-data-format">Plopping it all into a data format</h3>
140 <p>All of this is then mushed into a key-value table that looks similar to the one below:</p>
141 <pre><code>{:date &quot;2020-11-20&quot;
142 :title &quot;Title of the post&quot;
143 :link &quot;/posts/2020/some-blog-post.md&quot;}</code></pre>
144 <p>Another function, uses the function above to construct another table using a loop. It recursively finds all files, scoops up the title, date, and link using the function above, and then creates an unordered list of date keys and Markdown link values, which look something like the following table:</p>
145 <pre><code>{:2020-11-21 &quot;[Title of the post](/posts/2020/title-of-the-post.md)&quot;
146 :2017-11-20 &quot;[Another title](/posts/2017/another-title.md)&quot;
147 :2017-11-21 &quot;[And yet another one](/posts/2017/and-yet-another-one.md)&quot;
148 :2018-11-20 &quot;[Running out of ideas](/posts/2018/running-out-of-ideas.md)&quot;
149 :2019-11-20 &quot;[Um](/posts/2019/um.md)&quot;
150 :2020-11-22 &quot;[Yep](/posts/2020/yep.md)&quot;
151 :2020-11-23 &quot;[Some title](/posts/2020/some-title.md)&quot;}</code></pre>
152 <h3 id="sorting-the-data">Sorting the data</h3>
153 <p>A sorting function takes this table, reverse sorts it by keys to create a table that looks something like the following table:</p>
154 <pre><code>{:2020-11-23 &quot;[Some title](/posts/2020/some-title.md)&quot;
155 :2020-11-22 &quot;[Yep](/posts/2020/yep.md)&quot;
156 :2020-11-21 &quot;[Title of the post](/posts/2020/title-of-the-post.md)&quot;
157 :2019-11-20 &quot;[Um](/posts/2019/um.md)&quot;
158 :2018-11-20 &quot;[Running out of ideas](/posts/2018/running-out-of-ideas.md)&quot;
159 :2017-11-21 &quot;[And yet another one](/posts/2017/and-yet-another-one.md)&quot;
160 :2017-11-20 &quot;[Another title](/posts/2017/another-title.md)&quot;}</code></pre>
161 <p>The sorting function then uses the ordered keys from this table as keys for the originally unsorted table, so it calls them in order. I had to use keys from the sorted table as keys for the unsorted table just because I couldn’t figure out how to do this any other way. It might be a Lua thing? Haha. Well, I’m working in Fennel, but same same, they are interoperable haha.</p>
162 <p>The fancy (awful?) sorting function looks like the one below:</p>
163 <pre><code>(fn write-sorted-posts [tbl]
164 (let [key-seq []]
165 ;; Create a seq of keys from tbl
166 (each [k _ (pairs tbl)]
167 (table.insert key-seq k))
168
169 ;; Sort the keys from small to big
170 (table.sort key-seq)
171
172 ;; Start from the end (length of) seq-of-keys
173 ;; End on 1 (Starting of index)
174 ;; Step by -1
175 (for [i (# key-seq) 1 -1]
176 (let [date (. key-seq i)
177 post (. tbl date)]
178 (file-write destination post :a)))))</code></pre>
179 <h3 id="thou-shalt-order-thy-file-writing">Thou shalt order thy file writing</h3>
180 <p>To create a header for this file, I just write to the file first, before any of that fancy parsing, and then use an append mode when writing the posts to the file. The initial writing of the title for the <code>index.md</code> wipes outdated <code>index.md</code> and starts over.</p>
181 <h3 id="back-to-rss-generator-programming">Back to RSS-generator programming…</h3>
182 <p>Before, I was recursively doing the same thing to generate an RSS feed, but the feed wasn’t ordered, because, I figured “Hey, RSS feed readers will order this all for me! I’m not gonna bother ordering it!”, but then I figured (I say figured a lot, don’t I?) I should just use the same sorting trick to reverse sort my RSS feed as well, so that happened!</p>
183 <h3 id="getting-meta">Getting meta</h3>
184 <p>Okay, so, the ultimate test! Let’s see if this post is picked up and added to my <a href="/posts/">posts page</a>. I’ll add a line below this to let you know if it did the first time!</p>
185 <p>Edit: It worked!</p>
186 </main>
187 </body>
188 </html>