support exposing clojure functions to rhino

This commit is contained in:
Mariano Guerra 2013-01-09 16:26:14 +01:00
parent 3e8419f935
commit 2fc12781ef
3 changed files with 72 additions and 33 deletions

View file

@ -81,6 +81,23 @@ handy convertions::
user=> (js/from-js (js/eval sc "o = {name: 'spongebob', friends: ['patrick', 'sandy']};")) user=> (js/from-js (js/eval sc "o = {name: 'spongebob', friends: ['patrick', 'sandy']};"))
{:friends ["patrick" "sandy"], :name "spongebob"} {:friends ["patrick" "sandy"], :name "spongebob"}
exposing clojure functions to rhino::
user=> (require '[clj-rhino :as js])
nil
user=> (defn add [ctx scope this [a b]] (+ a b))
#'user/add
user=> (def scope (js/new-safe-scope))
#'user/scope
user=> (js/set! scope "add" (js/make-fn add))
nil
user=> (js/eval scope "add(1, 2)")
3.0
license? license?
-------- --------

View file

@ -1,6 +1,7 @@
(ns clj-rhino (ns clj-rhino
(:refer-clojure :exclude (eval get get-in set!)) (:refer-clojure :exclude (eval get get-in set!))
(:import [org.mozilla.javascript Context UniqueTag NativeArray NativeObject])) (:import [org.mozilla.javascript Context UniqueTag NativeArray NativeObject
BaseFunction]))
(defprotocol RhinoConvertible (defprotocol RhinoConvertible
(-to-rhino [object scope ctx] "convert a value to a rhino compatible type")) (-to-rhino [object scope ctx] "convert a value to a rhino compatible type"))
@ -198,3 +199,13 @@
(.compileFunction ctx scope code (.compileFunction ctx scope code
(or filename "<eval>") (or filename "<eval>")
(or line-number 1) sec-domain)))) (or line-number 1) sec-domain))))
(defn make-fn [fun]
"return an object that can be used as a function in rhino,
fun must receive the following arguments [ctx scope this args]
args will be passed through from-js before calling fun and the result
through to-js"
(proxy [BaseFunction] []
(call [ctx scope this args]
(to-js (fun ctx scope this (from-js args)) scope ctx))))

View file

@ -80,7 +80,8 @@
(is (= (js/get scope "b") false)))) (is (= (js/get scope "b") false))))
(testing "to-js works" (testing "to-js works"
(js/with-context (fn [ctx] (js/with-context
(fn [ctx]
(let [scope (js/new-safe-scope)] (let [scope (js/new-safe-scope)]
(is (= (js/to-js nil scope ctx) nil)) (is (= (js/to-js nil scope ctx) nil))
@ -101,7 +102,8 @@
(is (= (get (js/to-js {:name "mariano" :age 27} scope ctx) "age") 27)))))) (is (= (get (js/to-js {:name "mariano" :age 27} scope ctx) "age") 27))))))
(testing "to-js works on complex nested structures" (testing "to-js works on complex nested structures"
(js/with-context (fn [ctx] (js/with-context
(fn [ctx]
(let [scope (js/new-safe-scope) (let [scope (js/new-safe-scope)
obj {:name "bob" obj {:name "bob"
:age 27 :age 27
@ -117,7 +119,8 @@
(is (= (get-in js-obj ["friends" "sandy"]) "squirrel")))))) (is (= (get-in js-obj ["friends" "sandy"]) "squirrel"))))))
(testing "unknown types throw exception when converting to-js" (testing "unknown types throw exception when converting to-js"
(js/with-context (fn [ctx] (js/with-context
(fn [ctx]
(let [scope (js/new-safe-scope)] (let [scope (js/new-safe-scope)]
(is (thrown? Exception (js/to-js (atom {}) scope ctx))))))) (is (thrown? Exception (js/to-js (atom {}) scope ctx)))))))
@ -154,5 +157,13 @@
(assert-simetric-convertion {:b {"c" {:d [{"e" 4}]}}} scope ctx (assert-simetric-convertion {:b {"c" {:d [{"e" 4}]}}} scope ctx
{:b {:c {:d [{:e 4}]}}}) {:b {:c {:d [{:e 4}]}}})
)))) ))))
)
(testing "native clojure functions can be added"
(js/with-context
(fn [ctx]
(let [scope (js/new-safe-scope)]
(js/set! scope "add" (js/make-fn (fn [ctx scope this [a b]] (+ a b))))
(is (= (js/eval scope "add(1, 2)") 3.0))))))
)