the fact that process.clj is only about 250 lines is pretty damn impressive to me
@brdloush Ran some benchmarks against the main babashka script which returns the headers, HTML, and CSS
For context this is running within a docker container on my local
Also stored https://github.com/eccentric-j/clj-cgi-example#benchmarks
Good morning old guy (noticed that you @borkdude turned 40)! We will probably rework https://github.com/polyfy/polylith #polylith a bit and decouple it from #tools-deps (the migration to the new version will be automated) but still use tools.deps as the default target "platform". I have used https://freemarker.apache.org before for code generation, which has worked out really well. The only problem is that it doesn't support opening files for writing within the templates themselves. Now I got an idea, and that is to use babashka for that. My idea is to make it mandatory in the next version of Polylith (it's an idea so far, nothing decided yet). Then people could write their own templates and produce whatever output they want, like support for Leingingen, Boot, producing diagrams (like https://www.yworks.com/products/yed), documentation, and so on. Some of these outputs will probably be supported out of the box anyway, but users of Polylith would be able to write their own artefacts also. One option would be that babashka added templating support out of the box (more integrated) or we could put the templating related code in its own library that could be used to script things. Basically you need to read a template into memory (which will be represented as a hash map and then in the script, loop any of the data structures in there and write the output to a file. I have most of the code already, because I did something similar recently in another project. The difference now is that I realized that babashka could do it much more elegant.
@tengstrand welcome! You can re-use your templating logic in babashka if you load it as a library perhaps?
If you could show some examples, that could be helpful.
Another possibility would be that you would make your own custom polylith binary CLI with all the specific libs you need for polylith and use sci for glue code. Basically a spin-off from bb. But let's see if it can be done with bb proper first.
I will experiment a bit, and come back to you! Thanks.
Welcome again poly @teng
Thanks! Thought I joint the channel already. I think I really need support for https://freemarker.apache.org because I need a really powerful template engine, and that’s the best I have seen so far. The use case is to be able to transform the data structure you get when you read a Polylith workspace into files. I will post two templatefiles that I use in another project to give you an idea.
marcos.ftl:
<#macro playerLink player dir>
<#local profile = "">
<#list players as p>
<#if p.profile?? && p.name == player>
<#local profile = p.profile>
</#if>
</#list>
<#if profile == "">
${player}
<#else>
<a href="${dir}/Spelarprofiler/${profile}">${player}</a></#if></#macro>
<#macro playerLinkAlias alias>
<#local profile = "">
<#list players as p>
<#if p.profile?? && p.alias == alias>
<#local profile = p.profile>
</#if>
</#list>
<#if profile == "">
${alias}
<#else>
<a href="Spelarprofiler/${profile}">${alias}</a></#if></#macro>
<#macro round x>
<#local result = "">
<#if x < 0>
<#local value = -x>
<#local sign = "-">
<#local color = "#A00000">
<#else>
<#local value = x>
<#local sign = "+">
<#local color = "#008000">
</#if>
<#if x != 0>
<font color="${color}">${sign}${value?string["0.#"]}</font></#if></#macro>
<#macro arrow x>
<#if x lt 0>
<#local arrow = "&#10138;">
<#local color = "#008000">
<#elseif x == 0>
<#local arrow = "&nbsp;&nbsp;&nbsp;">
<#local color = "#000000">
<#else>
<#local arrow = "&#10136;">
<#local color = "#A00000">
</#if>
<font color="${color}">${arrow}</font></#macro>
<#function videolink url>
<#if url = "">
<#return "">
<#else>
<#local str = "<a href='">
<#local str += url>
<#local str += "' target='_blank'>Stream</a>">
<#return str>
</#if>
</#function>
<#function firstRed poangjakt>
<#local index = 12>
<#local length = poangjakt.rankinglista?size - 1>
<#list length..11 as i>
<#if poangjakt.rankinglista[i].points != poangjakt.rankinglista[11].points>
<#local index = i>
</#if>
</#list>
<#return index>
</#function>
<#function percentclass percent>
<#if percent gte 80>
<#return "percent80">
<#elseif percent gte 70>
<#return "percent70">
<#elseif percent gte 60>
<#return "percent60">
<#elseif percent gte 50>
<#return "percent50">
<#elseif percent gte 40>
<#return "percent40">
<#elseif percent gte 30>
<#return "percent30">
<#elseif percent gte 20>
<#return "percent20">
<#elseif percent gte 10>
<#return "percent10">
<#else>
<#return "percent0">
</#if>
</#function>
ranking.ftl:
<#include "macros.ftl">
<html>
<head>
<title>Uppsalarankingen</title>
<meta http-equiv="Content-Type" content= "text/html; charset=UTF-8">
</head>
<body bgcolor="#FFFFFF" text="#000000" link="#000000" alink="#000000" vlink="#000000">
<p><font color="#CCCCCC"><b><font size="5" color="#000000">Uppsalarankingen<font size="3"> (per ${lastTournamentDate})</font></font></b></font></p>
<table>
<tr>
<td>&nbsp;&nbsp;</td>
<td><a href="rankinghistorik.html">Ratinghistorik</a>&nbsp;&nbsp;</td>
<td><a href="diagram-1599/ratingdiagram.html">Diagram < 1600</a>&nbsp;&nbsp;</td>
<td><a href="diagram-1600/ratingdiagram.html">Diagram >= 1600</a>&nbsp;&nbsp;</td>
</tr>
</table>
<br>
<table width="70%" border="0">
<tr>
<td width="24%" align="center"><font color="#000000"><b>Placering</b></font></td>
<td width="40%"><font color="#000000"><b>Namn</b></font></td>
<td width="30%"><font color="#000000"><b>Rating</b></font></td>
</tr>
<#list ratings as player>
<tr>
<td width="24%" height="25" align="center"><font color="#000000">${player.rank} <@arrow player.rankchange /></font></td>
<td width="40%" height="25"><p><@playerLink player.name "."/></p></td>
<td width="30%" height="25">${player.rating?floor?string["0"]} &nbsp;<@round player.change /></td>
</tr>
<#if player.rank == 8>
</table>
<p><font color="#000000">Gräns för deltagande i Uppsalamästerskapen.</font></p>
<table width="70%" border="0">
</#if>
</#list>
</table>
<#assign now = .now>
<p><font color="#666666">Uppdaterad ${now?string["EEEE yyyy-MM-dd HH:mm"]}</font></p>
</body>
</html>
Then I have written some Clojure code that uses the template and produces files. Maybe you have some good examples of how code generation is solved in babashka today? Or any ideas what the best way to go would be (you suggested two ways already in the other thread).
@tengstrand @teng I'm not so familiar with freemarker, although I've heard about it. It looks similar to selmer.
So is there a clojure library wrapping this somewhere that you are using currently?
@teng This templating lib works with babashka from source: https://github.com/weavejester/comb You can use it like this:
(require '[babashka.deps :as deps])
(deps/add-deps '{:deps {comb/comb {:mvn/version "0.1.1"}}})
(require '[comb.template :as template])
(template/eval "<% (dotimes [x 3] %>foo<% ) %>") ;;=> "foofoofoo"
If freemarker is a high requirement, then babashka will currently not work since it doesn't have this library and babashka can not run this from source since it's a Java project. Then you will probably will have to make a JVM-based tool which you can then optionally compile to native using GraalVM native-image for fast startup.
If you need eval
in that binary, you can use sci:
https://github.com/borkdude/sci
That is the same interpreter that is used in babashka.
Okay, interesting. Looks like Comb doesn’t meet my requirements, like support for macros. Thanks for the tip anyway. It would be really cool if babashka could support Freemarker though, but in the meantime, I will try out the things you have suggested. Thanks!
I have the feeling that selmer is more well known / popular in the clojure community than freemarker. That said, babashka does support ways to extend with non-default stuff. 1) feature flags. https://github.com/borkdude/babashka/blob/master/doc/build.md a feature flag for freemarker is welcome. You will have to compile and distribute bb with freemarker yourself as it won't be in the default distribution (until it's clear that this is a thing many people want) 2) pods. these are extra CLIs to which babashka shells out for additional features. See https://github.com/babashka/pod-registry. I'm not sure if pods fit well here since they have data in / data out semantics. I would have to see the clojure API for freemarker to see if this works.
Okay cool, now I have plenty of things to look into! :-)
Released bb 0.2.10... there was a stupid error in if
: (if false 10 20)
returned nil
. This only happened on literally false
and nil
and was due to an optimization that I blindly applied from the 2-arity to the 3-arity version of if
. 🤦
Probably age 😋