Giter Club home page Giter Club logo

cljx's Introduction

            /$$                
           | $$                
  /$$$$$$$ | $$    /$$   /$$   /$$
 /$$_____/ | $$   |__/  |  $$ /$$/
| $$       | $$    /$$   \  $$$$/ 
| $$       | $$   | $$    >$$  $$ 
|  $$$$$$$ | $$   | $$   /$$/\  $$
 \_______/ |__/   | $$  |__/  \__/
             /$$  | $$          
            |  $$$$$$/  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.2"]]
: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 starting a REPL, cutting a JAR, etc.

Available options include:

  • :nested-exclusions — When true, ^:clj and ^:cljs metadata (used to indicate target-specific inclusions/exclusions) may be used on "nested" (non-top-level) forms (defaults false)
  • :maintain-form-position – When true, the line positions of transformed cljx forms are maintained, which aligns error and debug info (e.g. line numbers in stack traces, ClojureScript source maps, etc) in the generated files with those in the source cljx files (defaults false)
  • :include-meta — pass code-level metadata along to generated Clojure and ClojureScript (defaults false)
  • :extension — a string indicating the target of a given "build" (defaults "clj")
  • :rules — a fully-qualified symbol that names a var containing the rules to be used

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.

Clojure is a hosted language

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.

Also, note that cljx has no effect on code produced by macros. Macroexpansion occurs long after cljx touches your code.

REPL Integration

Cljx provides an nREPL middleware that allows you to work with .cljx files in the same way you work with regular .clj files from any toolchain with good nREPL support, like nrepl.el, Counterclockwise, etc.

In your project, in addition to adding cljx as a plugin, just add its middleware in your :dev profile (along with Piggieback's, assuming you're going to be interacting with ClojureScript REPLs as well):

:profiles {:dev {:dependencies [[com.keminglabs/cljx "0.2.2"]]
                 :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl
                                                   cljx.repl-middleware/wrap-cljx]}}}

Now all REPL evaluations and load-file operations will be processed by cljx appropriately before they reach the Clojure or ClojureScript compiler. Whether cljx code is processed for Clojure or ClojureScript is determined by the existence [or not] of a Piggieback ClojureScript environment in your current nREPL session's environment; this is entirely automatic.

Currently, only cljx's default rulesets are used in this case (though you can work around this by making your own higher-order cljx nREPL middleware that uses whatever rulesets you want).

Misc

Emacs users, want syntax highlighting? Add to your emacs config: (add-to-list 'auto-mode-alist '("\\.cljx\\'" . clojure-mode)).

Todo

  • CLJS: Remove docstrings from namespaces.
  • Explore providing an API that macros can easily use to transform their results

Thanks

@jonase & @ohpauleez for kibit @swannodette for core.logic

cljx's People

Contributors

cemerick avatar lynaghk avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.