Skip to content

Commit

Permalink
Improve contributing.md and tutorial.md (#240)
Browse files Browse the repository at this point in the history
* Update screenshot in contributing.md

closes #239

* Improve tutorial.md

* Add complete source code to tutorial.md

* Add a link to tutorial project in tutorial.md
  • Loading branch information
flyjwayur authored and viebel committed Mar 8, 2017
1 parent 890adc3 commit ff27ac9
Show file tree
Hide file tree
Showing 2 changed files with 206 additions and 27 deletions.
2 changes: 1 addition & 1 deletion contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ KLIPSE is live [here](http://app.klipse.tech).
And it looks like this:


![KLIPSE screenshot](http://blog.klipse.tech/assets/hello-klipse.png "KLIPSE screenshot")
![KLIPSE screenshot](https://cloud.githubusercontent.com/assets/11784820/23673439/fde9c7da-037a-11e7-889e-6c3e7ea6394d.png "KLIPSE screenshot")

Basically, [KLIPSE](http://app.klipse.tech) is made of 4 rectangles:

Expand Down
231 changes: 205 additions & 26 deletions tutorial.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
## Tutorial
# Tutorial

Tutorial Summary
----------

1. init project
2. figwheel
3. compiler functions
4. om.next
1. Init project
2. Figwheel
3. Compiler functions
4. Om.next

1- Init Project
1- Init project
----------

Create a new project directory, switch into it, add a `project.clj` configuration file to it.
Expand Down Expand Up @@ -77,10 +77,10 @@ lein cljsbuild once dev
Now open the `index.html` file in a chrome browser, open the console, great! you can see our "Hello world!" log.


2- figwheel
2- Figwheel
-----------

We use [figwheel](https://github.com/bhauman/lein-figwheel) to make our devlopment more funny. Add figwheel plugin to your `project.clj` and `:figwheel true` configuration to your dev compilation configuration:
We use [figwheel](https://github.com/bhauman/lein-figwheel) to make our development more fun. Add figwheel plugin to your `project.clj` and `:figwheel true` configuration to your dev compilation configuration:

``` clojure
(defproject cljs-compiler "0.1.0-SNAPSHOT"
Expand All @@ -106,13 +106,14 @@ Launch figwheel from the terminal:
lein figwheel
```

or
The REPL doesn't currently have built-in readline support.
To have a better experience use [rlwrap.](https://github.com/hanslub42/rlwrap)

```
rlwrap lein figwheel
```

Open `http://localhost:3449/` in chrome, open console, there is our "Hello world!" log. Now, update `core.cljs`:
Open [http://localhost:3449/](http://localhost:3449/) in chrome, open console, there is our "Hello world!" log. Now, update `core.cljs`:

``` clojure
(ns cljs_compiler.core)
Expand All @@ -133,10 +134,10 @@ And in the terminal, in the figwheel session:
```


3- compiler functions
3- Compiler functions
----------

Add to dependencies the `cljs.js` namespace.
Require the `cljs.js` namespace in `core` namespace.
Learn more about `cljs.js` [here](https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/js.cljs).

``` clojure
Expand All @@ -145,7 +146,7 @@ Learn more about `cljs.js` [here](https://github.com/clojure/clojurescript/blob/
[cljs.js :as cljs]))
```

We need a callback function as util to handle errors compilation.
We need a callback function as util to handle errors occurred during compilation.

``` clojure
(defn callback [{:keys [value error]}]
Expand All @@ -157,7 +158,7 @@ We need a callback function as util to handle errors compilation.
```

The function `_compilation` will receive a clojurescript source as a string.
Return [:error "reason"] in case of error and [:ok "js-code"] in case of success.
Returns [:error "reason"] in case of error and [:ok "js-code"] in case of success.

``` clojure
(defn _compilation [s]
Expand All @@ -168,7 +169,7 @@ Return [:error "reason"] in case of error and [:ok "js-code"] in case of success
```

The function `_eval` will receive a clojurescript source as a string and evaluate it.
Return [:error "reason"] in case of error and [:ok "js-code"] in case of success.
Returns [:error "reason"] in case of error and [:ok value] in case of success.

``` clojure
(defn _eval [s]
Expand All @@ -180,15 +181,15 @@ Return [:error "reason"] in case of error and [:ok "js-code"] in case of success
callback))
```

The function `_evaluation-js` return the jsonify `_eval` result.
The function `_evaluation-js` returns the jsonify `_eval` result.

``` clojure
(defn _evaluation-js [s]
(let [[status res] (_eval s)]
[status (.stringify js/JSON res nil 4)]))
```

The function `_evaluation-clj` return the stringify `_eval` result.
The function `_evaluation-clj` returns the stringify `_eval` result.

``` clojure
(defn _evaluation-clj [s]
Expand All @@ -200,18 +201,31 @@ In this step you can test the compilation functions using the repl.

``` clojure
(in-ns 'cljs_compiler.core)
(_compilation "(+ 1 2"))
(_compilation "(+ 1 2)")

;; => [:ok "(1 + 2);\n"]

(_eval "(+ 1 2)")

;; => [:ok 3]

(_evaluation-js "(clj->js {:a 5})")

;; => [:ok "{\n \"a\": 5\n}"]

(_evaluation-clj "(+ 1 2)")

;; => [:ok "3"]

;; => [:ok "(2 + 2);\n"]
```


4- om.next
4- Om.next
----------

[Om.next](https://github.com/omcljs/om/wiki/Quick-Start-(om.next)) is a great client framework based on [React.js](https://facebook.github.io/react/). It wasn't necessary to use it for our small app but it was an opportunity to discover it.

Add om.next dependencies to `project.clj`
Add om.next to dependencies in `project.clj`

``` clojure
{
Expand All @@ -223,7 +237,7 @@ Add om.next dependencies to `project.clj`
}
```

and to `core.cljs`
and require it in `core.cljs`

``` clojure
(ns cljs_compiler.core
Expand Down Expand Up @@ -320,8 +334,8 @@ and of course test all that using the repl:
```


OK! now you need UI components:
We build an om component that contains 4 textarea, one for input and one for each compile/eval results.
OK! Now you need UI components:
We build an om component that contains 4 textareas, one for input and one for each compile/eval results.

``` clojure
(defui CompilerUI
Expand All @@ -331,7 +345,6 @@ We build an om component that contains 4 textarea, one for input and one for eac
'[:compilation :evaluation-js :evaluation-clj])

Object

(render [this]
(as->
(om/props this) $
Expand All @@ -342,7 +355,7 @@ We build an om component that contains 4 textarea, one for input and one for eac
(evaluate-js-ui $)))))
```

and our 4 textareas
Then declare 4 types of textareas before CompilerUI.

``` clojure
(defn input-ui [reconciler]
Expand Down Expand Up @@ -371,4 +384,170 @@ and our 4 textareas
:readOnly true}))))
```

Lastly, add a div with ID `app` and add root to that dom element

``` html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Eval clojurescript to javascript!</title>
</head>
<body>
<div id="app"></div>
<script src="js/main.js"></script>
</body>
</html>
```

``` clojure
(om/add-root! reconciler
CompilerUI (gdom/getElement "app"))
```

Go to [http://localhost:3449/](http://localhost:3449/), you have an awesome clojurescript compiler.

Appendix
----------
Below is the complete source code for core namespace in this tutorial.
Or you can download/clone the whole tutorial project from [here.](https://github.com/flyjwayur/simple-cljs-web-compiler)

``` clojure
(ns cljs_compiler.core
(:require
[cljs.js :as cljs]
[goog.dom :as gdom]
[om.next :as om :refer-macros [defui]]
[om.dom :as dom]))

;; -----------------------------------------------------------------------------
;; Compiler functions

(defn callback [{:keys [value error]}]
(let [status (if error :error :ok)
res (if error
(.. error -cause -message)
value)]
[status res]))

(defn _compilation [s]
(cljs/compile-str
(cljs/empty-state)
s
callback))

(defn _eval [s]
(cljs/eval-str
(cljs/empty-state)
s
'test
{:eval cljs/js-eval}
callback))

(defn _evaluation-js [s]
(let [[status res] (_eval s)]
[status (.stringify js/JSON res nil 4)]))

(defn _evaluation-clj [s]
(let [[status res] (_eval s)]
[status (str res)]))

;; -----------------------------------------------------------------------------

(defonce app-state (atom
{:input ""
:compilation ""
:evaluation-js ""
:evaluation-clj ""}))

;; -----------------------------------------------------------------------------
;; Parsing

(defn read [{:keys [state]} key params]
{:value (get @state key "")})

(defmulti mutate om/dispatch)

(defmethod mutate 'input/save [{:keys [state]} _ {:keys [value]}]
{:action (fn []
(swap! state assoc :input value))})

(defmethod mutate 'cljs/compile [{:keys [state]} _ {:keys [value]}]
{:action (fn []
(swap! state update :compilation
(partial _compilation value)))})

(defmethod mutate 'js/eval [{:keys [state]} _ {:keys [value]}]
{:action (fn []
(swap! state update :evaluation-js
(partial _evaluation-js value)))})

(defmethod mutate 'clj/eval [{:keys [state]} _ {:keys [value]}]
{:action (fn []
(swap! state update :evaluation-clj
(partial _evaluation-clj value)))})

(def parser (om/parser {:read read
:mutate mutate}))

(def reconciler
(om/reconciler
{:state app-state
:parser parser}))

(defn process-input [compiler s]
(om/transact! compiler
[(list 'input/save {:value s})
(list 'cljs/compile {:value s})
(list 'js/eval {:value s})
(list 'clj/eval {:value s})]))

;; -----------------------------------------------------------------------------
;; UI Component

(defn input-ui [reconciler]
(dom/section nil
(dom/textarea #js {:autoFocus true
:onChange #(process-input
reconciler
(.. % -target -value))})))

(defn compile-cljs-ui [{:keys [compilation]}]
(let [[status result] compilation]
(dom/section nil
(dom/textarea #js {:value result
:readOnly true}))))

(defn evaluate-clj-ui [{:keys [evaluation-clj]}]
(let [[status result] evaluation-clj]
(dom/section nil
(dom/textarea #js {:value result
:readOnly true}))))

(defn evaluate-js-ui [{:keys [evaluation-js]}]
(let [[status result] evaluation-js]
(dom/section nil
(dom/textarea #js {:value result
:readOnly true}))))

(defui CompilerUI

static om/IQuery
(query [this]
'[:compilation :evaluation-js :evaluation-clj])

Object
(render [this]
(as->
(om/props this) $
(dom/div nil
(input-ui this)
(compile-cljs-ui $)
(evaluate-clj-ui $)
(evaluate-js-ui $)))))

;; -----------------------------------------------------------------------------

(om/add-root! reconciler
CompilerUI (gdom/getElement "app"))
```

0 comments on commit ff27ac9

Please sign in to comment.