- Add RSS generation - Code enhancement - Escaping ~ which were problematic - cl-yag - Common Lisp Yet Another website Generator HTML git clone git://bitreich.org/cl-yag/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/cl-yag/ DIR Log DIR Files DIR Refs DIR Tags DIR README DIR LICENSE --- DIR commit a6f07ecaad846e608500efa5cb5b3913a43db7e0 DIR parent e0a4614444c18e9840e4fa30d832da9fafedfa5e HTML Author: Solene Rapenne <solene@dataswamp.org> Date: Sun, 1 May 2016 00:43:31 +0200 - Add RSS generation - Code enhancement - Escaping ~ which were problematic Diffstat: M README.md | 8 ++++++-- M data/articles.lisp | 11 ++++++++++- M generator.lisp | 80 ++++++++++++++++++++++--------- A template/rss-item.tpl | 5 +++++ A template/rss.tpl | 10 ++++++++++ 5 files changed, 88 insertions(+), 26 deletions(-) --- DIR diff --git a/README.md b/README.md @@ -39,7 +39,7 @@ I tried to make it "hacking friendly" so it's very extensible. Here is an example code if you want to add something like a panel on the layout. + Add a string for the replacement to occure, like %%Panel%% in **template/layout.tpl** (because we want the panel on every page) -+ In **generator.lisp** modify the function *generate-layout* to add "**(template "%%Panel%%" (slurp-file "template/panel.tpl"))**" after one template function call ++ In **generator.lisp** modify the function *generate-layout* to add "**(template "%%Panel%%" (load-file "template/panel.tpl"))**" after one template function call + Create **template/panel.tpl** with the html (note : you can also directly add your text inside the layout template file instead of including another file) @@ -50,7 +50,7 @@ You may want to have some dedicated page for some reason, reusing the website la In **generate-site** function we can load a file, apply the template and save it in the output. It may look like this - (generate "somepage.html" (slurp-file "data/mypage.html")) + (generate "somepage.html" (load-file "data/mypage.html")) This will produce the file somepage.html in the output folder @@ -66,3 +66,7 @@ Here is a tip to produce html files from markdown using emacs 4. run *make* to update your site The generator don't do it natively because I didn't want it to have dependencies. You can use what you want to produces the html files. + +# Known limitation + +The application will crash if you use a single "**~**" caracter inside one data structure in **articles.lisp** files. This is due to the format function trying to interpret the ~ symbol while we just one a ~ symbol. This symbol in the others files are automatically replaced by ~~ which produce a single ~. So, if you want to have a "~" as a title/url/author/description/short/date you have to double it. It may be interestind to sanitize it in the tool maybe. DIR diff --git a/data/articles.lisp b/data/articles.lisp @@ -1,15 +1,24 @@ +;; WARNING caracter "~" must be escaped when used in this file +;; you have to type ~~ for one ~ to escape it + + +;; define informations about your blog +;; used for the RSS generation and some variables replacements in the layout (defvar *config* (list :webmaster "Your author name here" :title "Your blog title here" + :description "Yet another website on the net" + :url "https://my.website/~~user/" )) -;; describes articles (ordered) +;; describes articles (ordered on the website as they are displayed here, the first in list is the top of the website) ;; exemple => (list :id "4" :date "2015-05-04" :title "The article title" :author "Me" :tiny "Short description for home page") ;; :author can be omitted and will be replaced by webmaster value ;; :tiny can be omitted and will be replaced by the full article text (defvar *articles* (list + (list :id "2" :date "30 April 2016" :title "Another message" :short "New version available") (list :id "1" :date "29 April 2016" :title "My first message" :short "This is my first message" :author "Solène") )) DIR diff --git a/generator.lisp b/generator.lisp @@ -13,12 +13,16 @@ :end (or pos (length string))) when pos do (write-string replacement out) while pos))) -;; load a file and return it as a string -(defun slurp-file(path) - (with-open-file (stream path) - (let ((data (make-string (file-length stream)))) - (read-sequence data stream) - data))) + +;; load a file as a string +;; we escape ~ to avoid failures with format +(defun load-file(path) + (replace-all + (with-open-file (stream path) + (let ((data (make-string (file-length stream)))) + (read-sequence data stream) + data)) + "~" "~~")) ;; save a string in a file (defun save-file(path data) @@ -33,54 +37,84 @@ ;; simplify the declaration of a new page type (defmacro prepare(template &body code) `(progn - (let ((output (slurp-file ,template))) + (let ((output (load-file ,template))) ,@code output))) +;; simplify the file saving by using the layout +(defmacro generate(name &body data) + `(progn + (save-file ,name + (generate-layout ,@data)))) + + ;; generates the html of one only article ;; this is called in a loop to produce the homepage (defun create-article(article &optional &key (tiny t)) (prepare "template/article.tpl" - (template "%%Author%%" (if (member :author article) (getf article :author) (getf *config* :webmaster))) + (template "%%Author%%" (getf article :author (getf *config* :webmaster))) (template "%%Date%%" (getf article :date)) (template "%%Title%%" (getf article :title)) (template "%%Id%%" (getf article :id)) (template "%%Text%%" (if (and tiny (member :tiny article)) - (getf article :tiny) (slurp-file (format nil "data/~d.txt" (getf article :id))))))) + (getf article :tiny) (load-file (format nil "data/~d.txt" (getf article :id))))))) ;; return a html string ;; produce the code of a whole page with title+layout with the parameter as the content (defun generate-layout(body) - (let ((output (slurp-file "template/layout.tpl"))) - (template "%%Title%%" (getf *config* :title)) - (template "%%Body%%" body) - output)) + (prepare "template/layout.tpl" + (template "%%Title%%" (getf *config* :title)) + (template "%%Body%%" body) + output)) ;; Homepage generation -;; generate each article and concatenate the whole (defun generate-mainpage() + (prepare "template/layout.tpl" + (template "%%Body%%" + (format nil "~{~d~}" + (loop for article in *articles* collect + (create-article article :tiny t)))) + (template "%%Title%%" (getf *config* :title)))) + + +;; Generate the items for the xml +(defun generate-rss-item() (format nil "~{~d~}" (loop for article in *articles* collect - (create-article article :tiny t)))) + (prepare "template/rss-item.tpl" + (template "%%Title%%" (getf article :title)) + (template "%%Description%%" (getf article :short "")) + (template "%%Url%%" + (format nil "~d/article-~d.html" + (getf *config* :url) + (getf article :id))))))) + +;; Generate the rss xml data +(defun generate-rss() + (prepare "template/rss.tpl" + (template "%%Description%%" (getf *config* :description)) + (template "%%Title%%" (getf *config* :title)) + (template "%%Url%%" (getf *config* :url)) + (template "%%Items%%" (generate-rss-item)))) ;; ENGINE START ! ;; This is function called when running the tool (defun generate-site() - ; produce index.html - (generate "index.html" - (generate-mainpage)) - - ; produce each article file + ;; produce index.html + (save-file "index.html" + (generate-mainpage)) + + ;; produce each article file (dolist (article *articles*) (generate (format nil "article-~d.html" (getf article :id)) (create-article article :tiny nil))) - + ;;(generate-file-rss) - ;;not done yet + (save-file "rss.xml" + (generate-rss)) ) - (generate-site) DIR diff --git a/template/rss-item.tpl b/template/rss-item.tpl @@ -0,0 +1,5 @@ +<item> + <title>%%Title%%</title> + <description>%%Description%%</description> + <link>%%Url%%</link> +</item> DIR diff --git a/template/rss.tpl b/template/rss.tpl @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rss version="2.0"> + <channel> + <title>%%Title%%</title> + <description>%%Description%%</description> + <link>%%Url%%</link> + + %%Items%% + </channel> +</rss>