Compare commits

...

6 Commits

  1. 6
      Makefile
  2. 9
      engine/img-to-webp.lua
  3. 22
      engine/metas.lua
  4. 8
      engine/mk-html.sh
  5. 12
      engine/optim-img.sh
  6. 1
      shell.nix
  7. 2
      src/posts/0002-troll-2/index.org
  8. 2
      src/posts/0019-utopia-tv-show/index.org
  9. 118
      src/posts/0021-elegant-functional-programming-application-architecture/index.org
  10. 2
      templates/index.html
  11. 4
      templates/post.html

6
Makefile

@ -47,9 +47,11 @@ DST_PANDOC_FILES ?= $(patsubst %$(EXT),%.html, \
$(SRC_PANDOC_FILES)))
PANDOC_TEMPLATE ?= templates/post.html
PANDOC_LUA_FILTER ?= engine/links-to-html.lua
PANDOC_LUA_FILTER_IMG ?= engine/img-to-webp.lua
PANDOC_LUA_METAS ?= engine/metas.lua
MK_HTML := engine/mk-html.sh
PANDOC := $(MK_HTML) $(PANDOC_TEMPLATE) $(PANDOC_LUA_FILTER)
$(DST_DIR)/%.html: $(SRC_DIR)/%.org $(PANDOC_TEMPLATE) $(PANDOC_LUA_FILTER) $(MK_HTML) $(ENV_VARS)
PANDOC := $(MK_HTML) $(PANDOC_TEMPLATE) $(PANDOC_LUA_FILTER) $(PANDOC_LUA_FILTER_IMG) $(PANDOC_LUA_METAS)
$(DST_DIR)/%.html: $(SRC_DIR)/%.org $(PANDOC_TEMPLATE) $(PANDOC_LUA_FILTER) $(PANDOC_LUA_FILTER_IMG) $(PANDOC_LUA_METAS) $(MK_HTML) $(ENV_VARS)
@mkdir -p "$(dir $@)"
$(PANDOC) "$<" "$@.tmp"
minify --mime text/html "$@.tmp" > "$@"

9
engine/img-to-webp.lua

@ -0,0 +1,9 @@
-- img-to-webp.lua
function Image(el)
local fileext = el.src:match("%.[^%.]+$");
-- DEBUG -- print("LUA IMG: ", fileext);
if ( fileext == ".jpg" or fileext == ".png" or fileext == ".jpeg" ) then
el.src = el.src .. ".webp"
end
return el
end

22
engine/metas.lua

@ -0,0 +1,22 @@
-- intermediate store for variables and their values
local variables = {}
--- Function called for each raw block element.
function RawBlock (raw)
-- Don't do anything unless the block contains *org* markup.
if raw.format ~= 'org' then return nil end
-- extract variable name and value
local name, value = raw.text:match '#%+(%w+):%s*(.+)$'
if name and value then
variables[name] = value
end
end
-- Add the extracted variables to the document's metadata.
function Meta (meta)
for name, value in pairs(variables) do
meta[name] = value
end
return meta
end

8
engine/mk-html.sh

@ -4,8 +4,10 @@ set -eu
cd "$(git rev-parse --show-toplevel)" || exit 1
template="$1"
luafilter="$2"
orgfile="$3"
htmlfile="$4"
luafilterimg="$3"
luametas="$4"
orgfile="$5"
htmlfile="$6"
tocoption=""
if grep -ie '^#+options:' "$orgfile" | grep 'toc:t'>/dev/null; then
@ -16,6 +18,8 @@ set -x
pandoc $tocoption \
--template="$template" \
--lua-filter="$luafilter" \
--lua-filter="$luafilterimg" \
--lua-filter="$luametas" \
--mathml \
--from org \
--to html5 \

12
engine/optim-img.sh

@ -7,10 +7,18 @@ sizeof() {
stat --format="%s" "$*"
}
convert "$src" -resize 800x800\> -quality 50 "$dst"
convert "$src" -resize 800x800\> "$dst"
before=$(sizeof $src)
after=$(sizeof $dst)
if [[ "${src:e}" == "gif" ]]; then
after=$(sizeof $dst)
else
cwebp "$dst" -quiet -o "$dst.webp"
after=$(sizeof $dst.webp)
fi
if (( before <= after )); then
cp -f "$src" "$dst"

1
shell.nix

@ -24,6 +24,7 @@ pkgs.mkShell {
direnv
ghc
tmux
libwebp
# for emacs dev
ripgrep
nodePackages.http-server

2
src/posts/0002-troll-2/index.org

@ -9,6 +9,8 @@
#+LANG: en
#+OPTIONS: H:5 auto-id:t
#+STARTUP: showeverything
#+lightbk: #0f0
#+darkbk: #080
#+html_head_extra: <style>img,svg {filter: brightness(0.8) sepia(100%) hue-rotate(80deg) saturate(10); } body { font-family: "Comic Sans MS", Chalkboard, sans-serif; } </style>
#+begin_notes

2
src/posts/0019-utopia-tv-show/index.org

@ -14,6 +14,8 @@
#+lang: en
#+options: auto-id:t
#+startup: showeverything
#+lightbk: #ff0
#+darkbk: #880
#+html_head_extra: <style>
#+html_head_extra: :root { --bg: #ff0; --fg: #000; }
#+html_head_extra: img,svg {filter: contrast(0.5)sepia(100%)hue-rotate(20deg)saturate(15); }

118
src/posts/0021-elegant-functional-programming-application-architecture/index.org

@ -0,0 +1,118 @@
#+title: Elegant Functional Programming Application Architecture
#+description: An elegant and working code architecture
#+keywords: blog static
#+author: Yann Esposito
#+email: yann@esposito.host
#+date: [2021-09-26 Sun]
#+lang: en
#+options: auto-id:t
#+startup: showeverything
In this article I will expose you about how to architect your application
using function programming paradigm.
It is not tied to any programming language.
The principles in this article could probably be used by most programming
languages.
* Pre
:PROPERTIES:
:CUSTOM_ID: pre
:END:
First note that many /functional programming languages/ are not functional.
They all provide holes in order to trick the system to be faster.
Also for internal use, some advanced feature might be provided.
1. Type-classes ; this is not something I consider belongs to functional programming.
2. Clojure Protocols, ~defmulti~ ; are not something I would consider belongs
to functional programming.
And many other languages features.
Let be radical functional programmer.
Radical, means going back to the roots.
So here we go.
Functional programming is about manipulating functions with the meaning of
*mathematical functions* not what most programming language call functions.
A "function" in C, Clojure, Python, Java, Javascript is *not* a function in
the functional programming sense.
OTOH in Haskell it is /often/ a real function, but not always.
So a mathematical function is something that takes a bunch of parameters
and return a value (or not, we should allow partial functions unfortunately).
And if you provide the same parameter twice the result will always be the same.
Also, it should not have any side effect, for example, it should log, emit
sounds, ... nothing.
Whoa whoa... Give me a minute here. Why would we want to ... do nothing at
all?
Isn't writing an application about doing things?
Yes, it is.
Let just say, that, you generally, don't need more than plunging a
pure function graph into a context where an interpreter will be able to use
and this big pile of pure functions will be used to have side effect.
A big ball of pure functions are reproducible, easy to test, easy to
analyze and reason about.
Easy to expose business logic out of technical detail to access data,
etc...
So I will provide a system as radical, and simple as possible that will
have a lot of good properties that advanced functional programming methods
(like Monad, Monads transformers, Free Monads, Effect systems) are trying
to achieve.
* The Architecture
:PROPERTIES:
:CUSTOM_ID: the-architecture
:END:
The main architecture is based on the /Service/ paradigm.
A service will be a sub-application living at runtime, it will depends on
other services, and have an internal state.
So in the end your application should look like an acyclic graph of services.
Every service has an init phase, then a living phase, then a stop phase.
Every service declare a set of methods to be used and every service will
keep an internal implicit state.
Even if this look a lot like Object oriented programming.
It is in fact a quite radical functional programming architecture.
#+begin_src clojure
(def Interface
(function-1 [arg-1 arg-2] "a function"))
;; Main implementation of /my-service/
(defservice my-service
Interface
[sub-service-1
sub-service-2
,,,
sub-service-n]
(init [initial-ctx]
(let [service-state
(core/init {:sub-service-1 sub-service-1 ,,,})]
(into initial-ctx service-state)))
(function-1 [ctx arg-1 arg-2]
(core/function-1 ctx arg-1 arg-2)))
;; A test implementation of /my-service/
(defservice my-test-service
Interface
[sub-service-1
sub-service-2
,,,
sub-service-n]
(init [initial-ctx]
(let [service-state
(test/init {:sub-service-1 sub-service-1 ,,,})]
(into initial-ctx service-state)))
(function-1 [ctx arg-1 arg-2]
(test/function-1 ctx arg-1 arg-2)))
#+end_src

2
templates/index.html

@ -10,6 +10,8 @@
<link rel="stylesheet" href="/css/y.css"/>
<link rel="alternate" type="application/rss+xml" href="/rss.xml" />
<link rel="icon" href="/favicon.ico">
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#d84100">
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#2E3440">
$header-includes$
</head>
<body>

4
templates/post.html

@ -10,6 +10,10 @@
<link rel="stylesheet" href="/css/y.css"/>
<link rel="alternate" type="application/rss+xml" href="/rss.xml" />
<link rel="icon" href="/favicon.ico">
<meta name="theme-color" media="(prefers-color-scheme: light)"
content=$if(lightbk)$"$lightbk$"$else$"#d84100"$endif$>
<meta name="theme-color" media="(prefers-color-scheme: dark)"
content=$if(darkbk)$"$darkbk$"$else$"#2E3440"$endif$>
$header-includes$
</head>
<body>

Loading…
Cancel
Save