https://github.com/positiondev/larceny
An HTML5 templating language.
https://github.com/positiondev/larceny
haskell html templating-language
Last synced: 6 months ago
JSON representation
An HTML5 templating language.
- Host: GitHub
- URL: https://github.com/positiondev/larceny
- Owner: positiondev
- License: isc
- Created: 2016-04-23T20:21:16.000Z (almost 10 years ago)
- Default Branch: master
- Last Pushed: 2023-09-21T21:56:33.000Z (over 2 years ago)
- Last Synced: 2025-04-12T10:55:48.669Z (10 months ago)
- Topics: haskell, html, templating-language
- Language: HTML
- Homepage:
- Size: 765 KB
- Stars: 3
- Watchers: 1
- Forks: 4
- Open Issues: 14
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Larceny
Larceny is Haskell HTML templating based on [Heist](heist).
With Larceny, you write templates that look like this:
```
Roller Derby
```
And "substitutions" that look like this:
```
teamPageSubs :: Substitutions ()
teamPageSubs =
subs [ ("name", textFill "Gotham Girls")
, ("skaters", mapSubs
(\(i,n,p,b) ->
subs [ ("id", textFill i)
, ("name", textFill n)
, ("position", textFill p)
, ("longBio", textFill b)])
[ ("1", "Bonnie Thunders", "jammer", longBio)
, ("2", "Donna Matrix", "blocker", longBio)
, ("3", "V-Diva", "jammer", longBio) ] )
, ("bio", useAttrs (a"length" %
a"text")
bioFill))
where longBio = "Some example bio that is really long!"
bioFill maybeNumber fullBio = textFill $
case maybeNumber of
Just numChars -> T.take numChars fullBio <> "..."
Nothing -> fullBio
```
You end up with HTML like this:
```
Gotham Girls Roller Derby
-
Bonnie Thunders
jammer
Some example bio that is rea...
-
Donna Matrix
blocker
Some example bio that is rea...
-
V-Diva
jammer
Some example bio that is rea...
```
## Why another templating language? Why not Heist?
Position Dev loves Heist templates!
But then we needed unescaped HTML in our templates... so we had to
use Compiled Heist. Compiled Heist is really hard to undestand.
We wrote Larceny as an alternative to compiled Heist that is easier to
understand and use (if slower).
## Differences from Heist
The Haskell code you write to fill in your templates is very different
from Heist, but we tried to make the templates themselves as similar
as possible, with a couple notable exceptions:
Larceny is different from Interpreted Heist (but similar to Compiled
Heist) in that, by default, it doesn't escape any text. The `textFill`
helper function which you'll most commonly use does escape t, but
if you write your own more complicated Fills, you'll need to remember
to escape the text yourself.
In Heist, ``s inside of nested template application can be used
in the outer templates. We found that confusing, so Larceny doesn't
allow that.
# Troubleshooting
## Locale/`hGetContents`
If your app lives in an environment like Alpine Linux or other
`locale`-less environment, you may run into this error when templates
are loaded:
```
your_app: some_template.tpl: hGetContents: invalid argument (invalid byte sequence)
```
This probably means that your template has UTF-8 characters in it, but there's no locale set.
You can remedy this by using
[`setLocaleEncoding`](https://hackage.haskell.org/package/base-4.9.0.0/docs/GHC-IO-Encoding.html#v:setLocaleEncoding)
from GHC.IO.Encoding, along with an encoding like
[`utf8`](https://hackage.haskell.org/package/base-4.9.0.0/docs/GHC-IO-Encoding.html#v:utf8).
An example would be:
```
initializeApp :: IO AppCtxt
initializeApp = do
setLocaleEncoding utf8
templates <- loadTemplates "templates" defaultOverrides
...
```
# Development Tips
Use `stack ghci --ghci-options -isrc --ghci-options -itest larceny:test` to
start ghci with the ability to reload tests when you change the library code.
CI runs `stack test --pedantic` on branches, which will fail if there are any
errors. Run `stack test --pedantic` before pushing.