Hbs
clojure templating by handlebars.java
Install / Use
/learn @sunng87/HbsREADME
hbs
Real-world Clojure templating, seriously. Don't talk about enlive or hiccup on a clojure web development book any more.
- Never ruin your Clojure code with HTML
- Never ruin your HTML code with Clojure
- Templating without reuse mechanism is shit
- Templating without customization is nothing but shit
What handlebars has?
- Separate your Clojure and HTML, calm down both
- Reuse your handlebars template with include, partial and block
- Create your own helpers for your infinite customization needs
This library is based on handlebars.java.
Usage
Leiningen
Using hbs.core
(require '[hbs.core :as hbs])
;; render template string
(render "Hello {{person.name}}" {:person {:name "World"}})
;; render template file with a registry
(def reg (registry (classpath-loader "/templates" ".tpl")))
(render-file reg "hello" {:name "World"})
Using hbs in Ring application
hbs library provides a default ring middleware
hbs.core/wrap-handlebars-template to generate pages from standard
response: {:hbs {:template ... :context ...}}
;; ring handler function that generate handlebars response
(defn some-handler [req]
;;...
{:hbs {:template "index"
:context {:a "A" :b "B"}}})
By default, hbs middleware use text/html; charset=utf-8 as content
type. You can override it by setting {:headers {"Content-Type" ...}}
explicitly in your response.
Extending hbs.helper
Handlebars is nothing without helpers.
(use '[hbs core helper])
;; def a helper
(defhelper mytag [ctx options]
(safe-str "HelloWorld, " (clojure.string/upper ctx)))
(def reg (registry (classpath-loader "/templates" ".tpl")))
;; register the helper into registry
(register-helper! registry "mytag" mytag)
(render "{{mytag foo}}" {:foo "bar"})
Using javascript helpers
Helpers can also be defined using javascript. Javascript helpers are registered using register-js-helpers!-function
(register-js-helpers! registry "path/to/file.js")
Helpers defined by me
I have some predefined helpers used in my projects. And I decide to ship it in the release.
To use these helpers, be sure eval hbs.ext. You can
just add a (:require [hbs.ext]) on you core namespace.
Available helpers:
- ifequals
- ifgreater
- ifless
- ifcontains
- uppercase
- lowercase
- or
- count
- format-date
- format
- ifempty
- max
- min
You can find usage examples of these helpers in the test case test/hbs/ext_test.clj.
Accessing clojure values
By default, hbs library provides a clj-value-resolver that accepts both keywords and strings
(hbs/render "{{ person.name }}" {:person {"name" "World"}})
=> "World"
Between strings and keywords, it will prefer strings
(hbs/render "{{ person.name }}" {:person {:name "from kw"
"name" "from str"}})
=> "from str"
you can also extend and implement your own value resolver
(hbs/render "{{ person_name }}"
(-> {:person/name "world"}
Context/newBuilder
(.push (into-array ValueResolver [;; if you want, you use the standard hbs first. And just "complement" it.
hbs/clj-value-resolver
(reify ValueResolver
(resolve [_ context ident]
(get context (some-> ident
(string/replace #"_" "/")
keyword)
ValueResolver/UNRESOLVED)))]))
.build))
=> "world"
Checkout ValueResolver
See also
Handlebars implemented for Rust language: handlebars-rust.
License
Copyright © 2013-2018 Sun Ning
Distributed under the Eclipse Public License, the same as Clojure.
Related Skills
node-connect
343.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
90.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
343.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
343.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
