/$$
| $$
/$$$$$$$ | $$ /$$ /$$ /$$
/$$_____/ | $$ |__/ | $$ /$$/
| $$ | $$ /$$ \ $$$$/
| $$ | $$ | $$ >$$ $$
| $$$$$$$ | $$ | $$ /$$/\ $$
\_______/ |__/ | $$ |__/ \__/
/$$ | $$
| $$$$$$/ Your code is, like, data, bro.
\______/
Cljx is a Lein plugin that emits Clojure and ClojureScript code from a single metadata-annotated codebase.
To use it, add it to your project.clj
:
:plugins [[com.keminglabs/cljx "0.2.0"]]
:cljx {:builds [{:source-paths ["src/cljx"]
:output-path ".generated/clj"
:rules cljx.rules/clj-rules}
{:source-paths ["src/cljx"]
:output-path ".generated/cljs"
:extension "cljs"
:include-meta true
:rules cljx.rules/cljs-rules}]}
Can be run "once" or "auto", in which case it will watch all source-paths for changes to .cljx files. Defaults to "once".
Add
:hooks [cljx.hooks]
to automatically run cljx before cutting a JAR.
The included clj and cljs rule sets will remove forms marked with platform-specific metadata and rename protocols as appropriate.
E.g., the .cljx
source containing
^:clj (ns c2.maths
(:use [c2.macros :only [combine-with]]))
^:cljs (ns c2.maths
(:use-macros [c2.macros :only [combine-with]]))
(defn ^:clj sin [x] (Math/sin x))
(defn ^:cljs sin [x] (.sin js/Math x))
(reify
clojure.lang.IFn
(invoke [_ x] (inc x)))
will, when run through cljx.rules/cljs-rules
, yield:
(ns c2.maths
(:use-macros [c2.macros :only [combine-with]]))
(defn sin [x] (.sin js/Math x))
(reify
IFn
(invoke [_ x] (inc x)))
The value associated with :rules
should be a symbol naming a var containing
the rules to use for that build. cljx.rules/cljs-rules
and cljx.rules/clj-rules
are provided as a convenience, but you can extend those (or replace them entirely).
For example, a namespace on your classpath like this defines some rules:
(ns my.rules
(:require [kibit.rules.util :refer (compile-rule defrules)]))
(defrules rules
[(+ ?x 1) (inc ?x)]
[(- ?x 1) (dec ?x)])
Now you can use those rules in a cljx build like so:
:rules my.rules/rules
The var's namespace will be automatically loaded by cljx (i.e. no need to do so
manually via the :injections
key in your project.clj
).
Forms that are converted into :cljx.core/exclude
will be excluded from the output.
See Kibit for more info on writing rules, and
C2 for a project that uses .cljx
heavily.
Cljx does not try to hide implementation differences between host platforms. Clojure has ints, floats, longs, &c., ClojureScript has number; Clojure regular expressions act differently than ClojureScript regular expressions, because they are different.
Cljx only tries to unify Clojure/ClojureScript abstractions when it makes sense.
E.g., converting clojure.lang.IFn
into IFn
when generating ClojureScript.
Emacs users, want syntax highlighting?
Add to your emacs config: (add-to-list 'auto-mode-alist '("\\.cljx\\'" . clojure-mode))
.
- CLJS: Remove docstrings from namespaces.
@jonase & @ohpauleez for kibit @swannodette for core.logic