arichiardi / replumb

ClojureScript plumbing for your self-hosted REPLs.
http://clojurescript.io
Eclipse Public License 1.0
209 stars 16 forks source link

Build Status

Replumb Logo

Replumb ('rɛplʌm) is a plumbing library for your self-hosted ClojureScript Read-Eval-Print-Loops. Live demo available at clojurescript.io.

This library tries to ease the burden of talking directly to ClojureScript cljs.js and puts together pieces of work contributed by the ClojureScript community at disparate points in time on the cljs-in-cljs subject. It aspires to be a common starting point for custom REPLs and/or REPL-ish apps (educational interactive environments for instance).

Thanks

As current maintainer of the project I would like to thank each and every present and future contributor, Scalac for actively supporting the (Clojure) open source community and Mikes Fikes for having answered to my incessant questions on Slack, for having aided in brainstorming the project name and of course for the symbiosis with planck.

Usage

Versions higher than 0.2.0 break two replumb.core APIs:

via Clojars

There is one entry namespace, replumb.core, whose functions you should call directly:

(ns ...
  (:require ...
            [replumb.core :as replumb]
            [your.io.impl :as io]))

(defn handle-result!
  [console result]
  (let [write-fn (if (replumb/success? result) console/write-return! console/write-exception!)]
    (write-fn console (replumb/unwrap-result result))))

(defn cljs-read-eval-print!
  [console repl-opts user-input]
  (replumb/read-eval-call repl-opts
                          (partial handle-result! console)
                          user-input))

(defn cljs-console-did-mount
  [console-opts]
  (js/$
   (fn []
     (let [repl-opts (merge (replumb/options :browser
                                             ["/src/cljs" "/js/compiled/out"]
                                             io/fetch-file!)
                            {:warning-as-error true
                             :verbose true})
           jqconsole (console/new-jqconsole "#cljs-console" console-opts)]
       (cljs-console-prompt! jqconsole repl-opts)))))

Note that replumb, like ClojureScript, abstracts over IO details. You will need to provide your own read/write functions for it to work. There are examples of this in both replumb.browser.io and replumb.nodejs.io that you can freely copy over.

Read-eval-call options

The core of it all is read-eval-call, which reads, evaluates and calls back with the evaluation result.

The first parameter is a map of configuration options, currently supporting:

The second parameter, callback, should be a 1-arity function which receives the result map, whose result keys will be:

{:success?  a boolean indicating if everything went alright
 :value     (if (:success? result)), this key contains the yielded value as
            string, unless :no-pr-str-on-value is true, in which case it
            returns the bare value.
 :error     (if-not (:success? result)) will contain a js/Error
 :warning   in case a warning was thrown and :warning-as-error is falsey
 :form      the evaluated form as data structure (not string)}

The third parameter is the source string to be read and evaluated.

See the browser-repl for an actual implementation using jq-console.

Node.js

Support is provided, but only :optimizations :none works fine at the moment:

(replumb/read-eval-call
  (replumb/options :node src-paths node-read-file!)
  (fn [res]
    (-> res
        replumb/result->string true
        println)
    (.setPrompt rl (replumb/get-prompt))
    (.prompt rl))
  cmd)

Where node-read-file! is the user-provided node implementation for :read-file-fn!.

See replumb.core/options documentation and feel free to reuse code in src/node/replumb/nodejs/io.cljs. Moreover repl-demo/node contains a working example that can be built and executed with lein node-repl.

You can also watch Mike Fikes' demo or peek under the crook of his elbow.

Design

The implementation was designed not to conceal ClojureScript's cljs.js/eval quirks and idiosyncrasies. Therefore tricks like Mike Fikes' "Messing with macros at the REPL" are still part of the game and actually implemented as tests.

This will in the long run be useful for both replumb and the ClojureScript community as it will help in finding and fix issues.

Another challenge faced during the development was about the asynchronous evaluation response: we were torn between keeping the callback model as per cljs.js or adopting the novel and cutting-edge channel model of core.async. We did not see any strong evidence for adding channels here, therefore avoiding inflating the artifact size and delegating the choice to client code.

This project adheres to the SemVer specification.

Documentation

The documentation referring to the latest version (SNAPSHOT or release) can always be found in the doc folder of this repo or generated through lein codox.

The wiki is also good (growing) source of info.

Hacking

Contributions are welcome, of any kind. Have a look at CONTRIBUTING.md for details.

The project uses lein-figwheel and needs a simple lein repl to bootstrap, after which the following customary three commands needs to be executed in the resulting repl:

(require 'figwheel-sidecar.repl-api)
(figwheel-sidecar.repl-api/start-figwheel!)
(figwheel-sidecar.repl-api/cljs-repl)

Now you point your browser to http://localhost:3449 and you'll be thrown in the Clojurescript-in-clojurescript parallel world. Enjoy!

Community

Tell us about your amazing Replumb project!

Author Link Repo
@viebel, @RaphaelBoukara KLIPSE: a simple and elegant online cljs compiler and evaluator klipse
@joakin Web repl + notebook cljs-browser-repl
@jaredly Repl w/ autocomplete, parinfer, and more Reepl
@milt Simple Emacs-flavored web repl re-pl

License

Distributed under the Eclipse Public License, the same as Clojure.

Copyright (C) 2015-16 Scalac Sp. z o.o.

LambdaX lambdax.io is a Clojure-centric software house: functional experts dedicated to Clojure and ClojureScript.

On our blog we share our knowledge with the community. Put (defn) back into programming!