Skip to content

Commit

Permalink
Code and test case for javascript functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
marick committed Sep 21, 2012
1 parent 641854e commit 692d303
Show file tree
Hide file tree
Showing 9 changed files with 344 additions and 0 deletions.
16 changes: 16 additions & 0 deletions solutions/javascript.clj
@@ -0,0 +1,16 @@
(load-file "sources/javascript.clj")

;;; Exercise 1
(def js-apply
(fn [javascript-function object arguments]
(binding [this object]
(apply (:__function__ javascript-function) arguments))))


;;; Exercise 2
(def Function
(make-function (fn [fn-value & property-pairs]
(merge this
{:__function__ fn-value}
(apply hash-map property-pairs)))))

1 change: 1 addition & 0 deletions sources/build
@@ -1 +1,2 @@

cat pieces/javascript-*.clj > javascript.clj
100 changes: 100 additions & 0 deletions sources/javascript.clj
@@ -0,0 +1,100 @@
(def dot get)

(def ^:dynamic this {:shift (fn [x y] "the default version of `shift`")})

(def default-this
(fn [] (.getRawRoot #'this)))

(def js-apply
(fn [javascript-function object arguments]
(binding [this object]
(apply javascript-function arguments))))

(def js-call
(fn [javascript-function object & args]
(js-apply javascript-function object args)))

(def send-to
(fn [object message & arguments]
(js-apply (get object message) object arguments)))

(def plain-call
(fn [message & arguments]
(apply send-to (default-this) message arguments)))

(def js-new
(fn [constructor & arguments]
(js-apply constructor {} arguments)))



;;; Here are some test cases. With the following definition of
;;; `make-function`, they work even the exercise code changes.
;;; Your job is to make them work after.

(def make-function identity)

;; js-apply
(println (js-apply (make-function (fn [x] [this x]))
{:an :object}
[1]))

;; js-call
(println (js-call (make-function (fn [x] [this x]))
{:an :object}
1))

;; send-to
(def object {:some-property 5,
:some-method
(make-function
(fn [x] (+ x (dot this :some-property))))})
(println (send-to object :some-method 3))

;; plain-call
(def ^:dynamic this {:some-property -3838383838
:value-returner
(make-function
(fn [] (dot this :some-property)))})
(def object {:value-returner
(make-function
(fn [] "SHOULD NOT BE CALLED"))
:some-method
(make-function
(fn [] (plain-call :value-returner)))})

(println (send-to object :some-method))

;; js-new
(def Point
(make-function
(fn [x y]
(assoc this
:x x, :y y,
:get-x (make-function (fn [] (dot this :x)))))))
(def point (js-new Point 1 2))

(println (send-to point :get-x))



;;; For Exercise 1
;;; This function will be used to bootstrap the replacement
;;; of Clojure functions with Javascript Functions:

(def make-function
(fn [fn-value & property-pairs]
(merge {:__function__ fn-value}
(apply hash-map property-pairs))))



;;; For Exercise 2

;;; This is a Function constructor that doesn't work.

(def Function
(fn [fn-value & property-pairs]
(merge this
{:__function__ fn-value}
(apply hash-map property-pairs))))
30 changes: 30 additions & 0 deletions sources/pieces/javascript-1.clj
@@ -0,0 +1,30 @@
(def dot get)

(def ^:dynamic this {:shift (fn [x y] "the default version of `shift`")})

(def default-this
(fn [] (.getRawRoot #'this)))

(def js-apply
(fn [javascript-function object arguments]
(binding [this object]
(apply javascript-function arguments))))

(def js-call
(fn [javascript-function object & args]
(js-apply javascript-function object args)))

(def send-to
(fn [object message & arguments]
(js-apply (get object message) object arguments)))

(def plain-call
(fn [message & arguments]
(apply send-to (default-this) message arguments)))

(def js-new
(fn [constructor & arguments]
(js-apply constructor {} arguments)))



50 changes: 50 additions & 0 deletions sources/pieces/javascript-2.clj
@@ -0,0 +1,50 @@
;;; Here are some test cases. With the following definition of
;;; `make-function`, they work even the exercise code changes.
;;; Your job is to make them work after.

(def make-function identity)

;; js-apply
(println (js-apply (make-function (fn [x] [this x]))
{:an :object}
[1]))

;; js-call
(println (js-call (make-function (fn [x] [this x]))
{:an :object}
1))

;; send-to
(def object {:some-property 5,
:some-method
(make-function
(fn [x] (+ x (dot this :some-property))))})
(println (send-to object :some-method 3))

;; plain-call
(def ^:dynamic this {:some-property -3838383838
:value-returner
(make-function
(fn [] (dot this :some-property)))})
(def object {:value-returner
(make-function
(fn [] "SHOULD NOT BE CALLED"))
:some-method
(make-function
(fn [] (plain-call :value-returner)))})

(println (send-to object :some-method))

;; js-new
(def Point
(make-function
(fn [x y]
(assoc this
:x x, :y y,
:get-x (make-function (fn [] (dot this :x)))))))
(def point (js-new Point 1 2))

(println (send-to point :get-x))



10 changes: 10 additions & 0 deletions sources/pieces/javascript-3.clj
@@ -0,0 +1,10 @@
;;; For Exercise 1
;;; This function will be used to bootstrap the replacement
;;; of Clojure functions with Javascript Functions:

(def make-function
(fn [fn-value & property-pairs]
(merge {:__function__ fn-value}
(apply hash-map property-pairs))))


10 changes: 10 additions & 0 deletions sources/pieces/javascript-4.clj
@@ -0,0 +1,10 @@

;;; For Exercise 2

;;; This is a Function constructor that doesn't work.

(def Function
(fn [fn-value & property-pairs]
(merge this
{:__function__ fn-value}
(apply hash-map property-pairs))))
64 changes: 64 additions & 0 deletions test/solutions/ts_javascript.clj
@@ -0,0 +1,64 @@
(ns solutions.ts-javascript
(:use midje.sweet))

(load-file "solutions/javascript.clj")



(fact "js-apply"
(js-apply (make-function (fn [x] [this x]))
{:an :object}
[1]) => [{:an :object} 1])


(fact "js-call"
(js-call (make-function (fn [x] [this x]))
{:an :object}
1) => [{:an :object} 1])

;; send-to
(def object {:some-property 5,
:some-method
(make-function
(fn [x] (+ x (dot this :some-property))))})

(fact (send-to object :some-method 3) => 8)

;; plain-call
(def ^:dynamic this {:some-property -3838383838
:value-returner
(make-function
(fn [] (dot this :some-property)))})

(def object {:value-returner
(make-function
(fn [] "SHOULD NOT BE CALLED"))
:some-method
(make-function
(fn [] (plain-call :value-returner)))})

(fact (send-to object :some-method) => -3838383838)

;; js-new
(def Point
(make-function
(fn [x y]
(assoc this
:x x, :y y,
:get-x (make-function (fn [] (dot this :x)))))))
(def point (js-new Point 1 2))

(fact (send-to point :get-x) => 1)

(load-file "sources/pieces/javascript-3.clj")

(fact "make-function"
(make-function identity) => {:__function__ identity }
(make-function identity :key :value) => {:__function__ identity, :key :value})

(load-file "sources/pieces/javascript-4.clj")


(def this {})
(fact "Function constructor"
(Function identity :key :value) => (make-function identity :key :value))
63 changes: 63 additions & 0 deletions test/sources/t_javascript.clj
@@ -0,0 +1,63 @@
(ns sources.t-javascript
(:use midje.sweet))

(load-file "sources/pieces/javascript-1.clj")
(load-file "sources/pieces/javascript-2.clj")

(fact "js-apply"
(js-apply (make-function (fn [x] [this x]))
{:an :object}
[1]) => [{:an :object} 1])


(fact "js-call"
(js-call (make-function (fn [x] [this x]))
{:an :object}
1) => [{:an :object} 1])

;; send-to
(def object {:some-property 5,
:some-method
(make-function
(fn [x] (+ x (dot this :some-property))))})

(fact (send-to object :some-method 3) => 8)

;; plain-call
(def ^:dynamic this {:some-property -3838383838
:value-returner
(make-function
(fn [] (dot this :some-property)))})

(def object {:value-returner
(make-function
(fn [] "SHOULD NOT BE CALLED"))
:some-method
(make-function
(fn [] (plain-call :value-returner)))})

(fact (send-to object :some-method) => -3838383838)

;; js-new
(def Point
(make-function
(fn [x y]
(assoc this
:x x, :y y,
:get-x (make-function (fn [] (dot this :x)))))))
(def point (js-new Point 1 2))

(fact (send-to point :get-x) => 1)

(load-file "sources/pieces/javascript-3.clj")

(fact "make-function"
(make-function identity) => {:__function__ identity }
(make-function identity :key :value) => {:__function__ identity, :key :value})

(load-file "sources/pieces/javascript-4.clj")


(def this {})
(fact "Function constructor"
(Function identity :key :value) => (make-function identity :key :value))

0 comments on commit 692d303

Please sign in to comment.