PageRenderTime 53ms CodeModel.GetById 15ms app.highlight 34ms RepoModel.GetById 1ms app.codeStats 0ms

/README.markdown

http://github.com/arohner/scriptjure
Markdown | 238 lines | 169 code | 69 blank | 0 comment | 0 complexity | c9940ed7ecc9d970a2571d9dfe976b60 MD5 | raw file
  1Scriptjure is a Clojure library for generating javascript from Clojure forms. Its primary goal is to make it simple to embed "glue" javascript in Clojure webapps. Generated Scriptjure javascript is intended to be readable.
  2
  3At the moment, Scriptjure is very simple, but is still under active development.
  4
  5Sample Code
  6===========
  7    (use [com.reasonr.scriptjure :only (js)])
  8    (js (fn foo [e]
  9         (var x 42)
 10         (return (+ x e))))
 11
 12results in the string "function foo (e) { x = 42; return (x + e); }"
 13
 14
 15Rules
 16=====
 17
 18`(js)` is a macro that takes one or more sexprs and returns a string that is valid javascript.
 19
 20Numbers
 21-------
 22
 23Clojure numbers are converted as you would expect:
 24    (js 42) 
 25    => "42"
 26
 27Strings
 28------
 29    (js "foo") 
 30    => "\"foo\""
 31
 32Symbols 
 33-------
 34Clojure symbols and keywords are converted to javascript symbols:
 35
 36    (js foo) 
 37    => "foo"
 38    (js :bar) 
 39    => "bar"
 40
 41Since JS is a macro, symbols will not be evaluated, so there is no need to quote them. Actually, (js 'foo) will be interpreted as (js (quote foo)), which is probably not what you want. Scriptjure makes no attempt to verify that a generated symbol is defined in the JS environment.
 42
 43Arrays, Maps
 44----------
 45Clojure arrays and maps are converted to array literals, and JSON:
 46
 47    (js [1 2 3]) 
 48    => "[1, 2, 3]"
 49    (js {:packages "columnchart"}) 
 50    => "{packages: \"columnchart\"}"
 51
 52Note that JSON map keys aren't necessarily converted to strings. If you want the key to be a string rather than a symbol, use a Clojure string. Yes, this doesn't follow the JSON spec, but some JS libraries require this.
 53
 54Lists
 55----
 56Lists where the first element is a symbol are converted to function calls, and "special forms." If the head of the list is not one of the special forms, a list returns a normal function call.
 57
 58Normal Function Calls
 59-----------------
 60 The head of the list is the name of the function. All remaining items in the list are treated as arguments to the call:
 61
 62    (js (alert "hello world")) 
 63    => "alert(\"hello world\")"
 64    (js (foo x y)) 
 65    => "foo(x, y)"
 66
 67Special Forms
 68-----------
 69If the head of the list is a symbol in the special forms list, rather than resulting in a normal function call, something else will happen:
 70
 71**var**
 72    (var symbol value)
 73Var takes two arguments, and defines a new variable
 74
 75    (js (var x 3)) 
 76    => "var x = 3;"
 77
 78**set!**
 79    (set! symbol value)
 80Takes two arguments, assignment.
 81
 82    (js (set! x 5)) 
 83    => "x = 5;"
 84
 85**if**
 86    (if test true-form & false-form)
 87Returns a javascript if statement. Like Clojure, true-form and false-form take one form each. If you want multiple statements in the body, combine with a do statement.
 88
 89    (js (if (== foo 3) (foo x) (bar y)))
 90    => "if ( (foo == 3) ) {
 91       foo(x);
 92       }
 93       else {
 94       bar(y);
 95       }"
 96
 97**try / catch / finally**
 98
 99    (try expr* catch-clause? finally-clause?)
100    catch-clause -> (catch e expr*)
101    finally-clause -> (finally expr*)
102
103Returns a JavaScript `try` / `catch` / `finally` block.  All non-`catch` and non-`finally` forms within a `try` form are executed in an implicit `do` statement.  The `catch` clause (if present) generates an unconditional `catch` block (multiple conditional `catch` blocks are not supported at this time), with `e` bound to the exception object. The `finally` clause (if present) is used to generate a `finally` block.  All expressions in the `catch` and `finally` clauses are executed in implicit `do` statements.
104
105    (js (try
106          (set! x 5)
107        (catch e
108          (print (+ "BOOM: " e)))
109        (finally
110          (print "saved!"))))
111    => "try{
112        x = 5;
113        }
114        catch(e){
115        print((\"BOOM: \" + e));
116        }
117        finally{
118        print(\"saved!\");
119        }"
120
121An Exception will be thrown if there are no `catch` or `finally` clauses, or if there are more than one of either.
122
123**return**
124    (return value)
125
126Takes one argument, results in a return statement
127
128    (js (return x)) 
129    => "return x;"
130
131**delete**
132    (delete value)
133
134Takes one argument, results in a delete statement
135
136    (js (delete x)) 
137    => "delete x;"
138
139**new**
140    (new Obj & args)
141
142Results in a new statement. The first argument is the object. All remaining items in the list are treated as arguments to the contructor.
143
144    (js (new google.visualization.Query url)) 
145    => "new google.visualization.Query(url)"
146
147**aget**
148    (aget obj & indexes)
149
150    (js (aget foo 42))
151    => "foo[42]"
152
153Array access can also be chained.  This is helpful not only for multidimensional arrays, but for reaching deep into objects using a series of keys (similar to `clojure.core/get-in`)
154
155    (js (aget foo bar "baz"))
156    => "foo[bar][\"baz\"]"
157
158To set an array, combine with set!
159 
160    (js (set! (aget foo 42) 13))
161
162**do**
163   (do & exprs)
164
165Returns the series of expressions, separated by semicolons
166  
167    (js (do
168             (var x 3)
169             (var y 4)))
170    => "var x = 3;
171        var y = 4;"
172
173**dot Method calls**
174    (. method Obj & args)
175
176Works like the dot form in Clojure. If the first item in the list is a dot, calls method on Obj. All remaining items are arguments to the method call
177    (js (. google.chart bar :a :b))
178    => "google.chart.bar(a,b)"
179
180   .method also works:
181
182    (js (.bar google.chart :a :b)) 
183    => "google.chart.bar(a,b)"
184
185**fn**
186    (fn [args] & body)
187    (fn name [args] & body)
188
189Results in a function expression or statement. Forms in body are separated by semicolons
190
191    (js (fn [e]
192       (var x 42)
193       (return (+ x e)))) 
194    => "function (e) { var x = 42; return (x + e); }"
195
196**infix operators**
197    (infix x y)
198If the head of the list is a symbol in the infix operator list, the list results in infix math. The current list is [+ - / * == === < > <= >= !=]. All infix operatations currently only support two operands. All infix expressions are parenthesized to avoid precedence issues.
199
200    (js (> x y)) 
201    => "(x > y)"
202
203** Getting data into JS **
204  
205To get the value of a clojure expression into javascript, use (clj)
206
207    (let [foo 42]
208        (js (+ 3 (clj foo)))) 
209    => (js (+ 3 42)) => "(3 + 42)"
210
211`clj` is a "marker" in the js macro. The `clj` can contain arbitrary normal Clojure, and the result is passed into `(js)`. The `clj` form is allowed to return anything that scriptjure knows how to handle. Since `clj` is not a var, it never needs to be qualified. The clj form is only valid inside a `(js)` form. 
212
213`clj` can be use anywhere in a `js` form:
214
215    (js (fn (clj foo) [x] (return x))) 
216
217This will return a javascript function, with the name being whatever Clojure value foo resolves to.
218
219** Composing JS in Clojure **
220
221If you want to pass a js form from one clojure function to another, use js*
222
223    (let [extra-js (js* (do (baz x) (var y 4)))]
224         (defn gen-js [extra-js]
225             (js (fn foo [x]
226                      (bar x)
227                      (clj extra-js)))))
228    => "function foo(x) {
229              bar(x);
230              baz(x);
231              var y = 4;
232         }"
233
234`cljs` and `cljs*` are shortcuts for `(js (clj ...))` and `(js* (clj ..))` respectively. Note that both only take one form. 
235
236License
237=======
238Scriptjure is licensed under the EPL, the same as Clojure core. See epl-v10.html in the root directory for more information.