support exposing clojure functions to rhino
This commit is contained in:
parent
3e8419f935
commit
2fc12781ef
17
README.rest
17
README.rest
|
@ -81,6 +81,23 @@ handy convertions::
|
|||
user=> (js/from-js (js/eval sc "o = {name: 'spongebob', friends: ['patrick', 'sandy']};"))
|
||||
{: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?
|
||||
--------
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(ns clj-rhino
|
||||
(: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
|
||||
(-to-rhino [object scope ctx] "convert a value to a rhino compatible type"))
|
||||
|
@ -198,3 +199,13 @@
|
|||
(.compileFunction ctx scope code
|
||||
(or filename "<eval>")
|
||||
(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))))
|
||||
|
|
|
@ -80,46 +80,49 @@
|
|||
(is (= (js/get scope "b") false))))
|
||||
|
||||
(testing "to-js works"
|
||||
(js/with-context (fn [ctx]
|
||||
(let [scope (js/new-safe-scope)]
|
||||
(js/with-context
|
||||
(fn [ctx]
|
||||
(let [scope (js/new-safe-scope)]
|
||||
|
||||
(is (= (js/to-js nil scope ctx) nil))
|
||||
(is (= (js/to-js 1 scope ctx) 1))
|
||||
(is (= (js/to-js 1/2 scope ctx) 0.5))
|
||||
(is (= (js/to-js true scope ctx) true))
|
||||
(is (= (js/to-js "foo" scope ctx) "foo"))
|
||||
(is (= (js/to-js :foo scope ctx) "foo"))
|
||||
(is (= (js/to-js nil scope ctx) nil))
|
||||
(is (= (js/to-js 1 scope ctx) 1))
|
||||
(is (= (js/to-js 1/2 scope ctx) 0.5))
|
||||
(is (= (js/to-js true scope ctx) true))
|
||||
(is (= (js/to-js "foo" scope ctx) "foo"))
|
||||
(is (= (js/to-js :foo scope ctx) "foo"))
|
||||
|
||||
(check-array-to-js [] scope ctx)
|
||||
(check-array-to-js [nil 1 1/2 true "foo" :foo] scope ctx)
|
||||
(check-array-to-js '(nil 1 1/2 true "foo" :foo) scope ctx)
|
||||
(check-array-to-js [] scope ctx)
|
||||
(check-array-to-js [nil 1 1/2 true "foo" :foo] scope ctx)
|
||||
(check-array-to-js '(nil 1 1/2 true "foo" :foo) scope ctx)
|
||||
|
||||
; check to-js-generic
|
||||
(check-array-to-js (to-array [nil 1 1/2 true "foo" :foo]) scope ctx)
|
||||
; check to-js-generic
|
||||
(check-array-to-js (to-array [nil 1 1/2 true "foo" :foo]) scope ctx)
|
||||
|
||||
(is (= (get (js/to-js {:name "mariano"} scope ctx) "name") "mariano"))
|
||||
(is (= (get (js/to-js {:name "mariano" :age 27} scope ctx) "age") 27))))))
|
||||
(is (= (get (js/to-js {:name "mariano"} scope ctx) "name") "mariano"))
|
||||
(is (= (get (js/to-js {:name "mariano" :age 27} scope ctx) "age") 27))))))
|
||||
|
||||
(testing "to-js works on complex nested structures"
|
||||
(js/with-context (fn [ctx]
|
||||
(let [scope (js/new-safe-scope)
|
||||
obj {:name "bob"
|
||||
:age 27
|
||||
:tags ["yellow" :sponge ["a" :b 3.2]]
|
||||
:friends {:sandy "squirrel"
|
||||
:patrick "star"}}
|
||||
js-obj (js/to-js obj scope ctx)]
|
||||
(js/with-context
|
||||
(fn [ctx]
|
||||
(let [scope (js/new-safe-scope)
|
||||
obj {:name "bob"
|
||||
:age 27
|
||||
:tags ["yellow" :sponge ["a" :b 3.2]]
|
||||
:friends {:sandy "squirrel"
|
||||
:patrick "star"}}
|
||||
js-obj (js/to-js obj scope ctx)]
|
||||
|
||||
(is (= (get js-obj "name") "bob"))
|
||||
(is (= (get js-obj "age") 27))
|
||||
(is (= (.get (get js-obj "tags") 1) "sponge"))
|
||||
(is (= (.get (.get (get js-obj "tags") 2) 1) "b"))
|
||||
(is (= (get-in js-obj ["friends" "sandy"]) "squirrel"))))))
|
||||
(is (= (get js-obj "name") "bob"))
|
||||
(is (= (get js-obj "age") 27))
|
||||
(is (= (.get (get js-obj "tags") 1) "sponge"))
|
||||
(is (= (.get (.get (get js-obj "tags") 2) 1) "b"))
|
||||
(is (= (get-in js-obj ["friends" "sandy"]) "squirrel"))))))
|
||||
|
||||
(testing "unknown types throw exception when converting to-js"
|
||||
(js/with-context (fn [ctx]
|
||||
(let [scope (js/new-safe-scope)]
|
||||
(is (thrown? Exception (js/to-js (atom {}) scope ctx)))))))
|
||||
(js/with-context
|
||||
(fn [ctx]
|
||||
(let [scope (js/new-safe-scope)]
|
||||
(is (thrown? Exception (js/to-js (atom {}) scope ctx)))))))
|
||||
|
||||
(testing "from-js works"
|
||||
(is-identity nil)
|
||||
|
@ -154,5 +157,13 @@
|
|||
(assert-simetric-convertion {:b {"c" {:d [{"e" 4}]}}} scope ctx
|
||||
{: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))))))
|
||||
|
||||
)
|
||||
|
||||
|
|
Reference in a new issue