a shitty config file parser in fennel
2023-04-28 21:51
i'm working on rewriting my blog enging again (lol) in fennel (again), and made this simple config file parser for the following config file format:
name = someone's name domain = verycoolwebsite.com email = awsick@cool.com
it turned out to be pretty easy too! i made use of fennel's threader macro,
->
, which just takes an initial value and an arbitrary amount of functions,
and passes the initial value as the first argument to the next function, and
then passes the return value of the first function as the first argument to the
next functions, and repeats for every function that was provided.
i think the main reason i like this function is that it makes me clearly see the
steps a value goes through as it gets passed from one function to another. it
has a nice top-to-bottom visual, for me at least. in scheme, i would usually do
a series of let*
statements, which became a little noisy for me. i could have
always imported the clojurian egg
in chicken scheme to get this, or use compose, but, alas, i am in the mood to
rewrite shit.
anyway, here's what it looks like, along with a couple of helper functions i
wrote, and some help from the adored lua library,
lume, assuming you have a modules
directory in
the same directory as this source code, and the lume.lua
file in the modules
directory:
(local lume (require "modules/lume")) ;; converts a file to a sequence of lines (fn file->lines [path] (with-open [f (io.open path :r)] (icollect [i (f:lines)] i))) ;; changes "key = val" to ["key" "val"] (fn split-trim [str del] (-> (lume.split str del) (lume.map lume.trim))) (fn config-file->table [file] (-> (file->lines file) (lume.map #(split-trim $1 "=")) (lume.map #(let [[k v] $1] {k v})) (table.unpack) (lume.merge)))
you can kinda see how it works if i toss some comments in there:
(fn config-file->table [file] (-> (file->lines file) ;; => ["key1 = val" "key2 = val"] (lume.map #(split-trim $1 "=")) ;; => [["key1" "val"] ["key2" "val"]] (lume.map #(let [[k v] $1] {k v})) ;; => [{:key1 "val"} {:key2 "val"}] (table.unpack) ;; => {:key1 "val"} {:key2 "val"} (lume.merge))) ;; {:key1 "val" :key2 "val"}
then all you gotta do is just assign the config-file->table
function's return
value to a variable, and then reference the values in the table using the keys,
like you normally would when interacting with a table.
for example, if we have the following config file format in a file called
config.txt
:
name = someone's name domain = verycoolwebsite.com email = awsick@cool.com
then we can assign the config-file->table
function's return value to a local
variable, config
, and reference that variable as a table using one of the
following approaches:
;; approach 1 (let [config (config-file->table "config.txt")] (. config :name)) ;; approach 2 (let [config (config-file->table "config.txt")] config.name)