-
-
Save anonymous/dc9f501e8c52b3a7166c to your computer and use it in GitHub Desktop.
Pulsar example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; src/test_pulsar/core.clj | |
(ns test-pulsar.core | |
(:require | |
[co.paralleluniverse.pulsar | |
[core :refer :all] | |
[actors :refer :all]] | |
[clojure | |
[walk :as walk] | |
[zip :as zip]]) | |
(:refer-clojure :exclude [promise await]) | |
(:gen-class)) | |
;; Buggy versions. | |
(defsfn buggy-ping [n buggy-pong] | |
(if (== n 0) | |
(do | |
(! buggy-pong :finished) | |
(println "Buggy ping finished")) | |
(do | |
(! buggy-pong [:ping @self]) | |
(receive | |
:pong (println "Buggy ping received buggy pong")) | |
(recur (dec n) buggy-pong)))) | |
(defsfn buggy-pong | |
[] | |
(receive | |
:finished (println "Buggy pong finished") | |
[:ping buggy-ping] | |
(do | |
(println "Pong received ping") | |
(! buggy-ping :pong) | |
(recur)))) | |
(defn buggy-main [] | |
(let [a1 (spawn buggy-pong) | |
b1 (spawn buggy-ping 3 a1)] | |
(join a1) | |
(join b1) | |
:ok)) | |
(defmacro defsfnp | |
"Walks through a 'defn' macroexpansion and wraps the generated fn* in | |
a 'suspendable!' call." | |
[& expr] | |
(-> (cons 'defn expr) | |
walk/macroexpand-all | |
zip/seq-zip | |
zip/down | |
zip/rightmost | |
(zip/edit (fn [loc] `(suspendable! ~loc))) | |
zip/root)) | |
(defsfnp ping [n pong] | |
(if (== n 0) | |
(do | |
(! pong :finished) | |
(println "ping finished")) | |
(do | |
(! pong [:ping @self]) | |
(receive | |
:pong (println "Ping received pong")) | |
(recur (dec n) pong)))) | |
(defsfnp pong | |
[] | |
(receive | |
:finished (println "Pong finished") | |
[:ping ping] (do | |
(println "Pong received ping") | |
(! ping :pong) | |
(recur)))) | |
(defn main [] | |
(let [a1 (spawn pong) | |
b1 (spawn ping 3 a1)] | |
(join a1) | |
(join b1) | |
:ok)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; test/test_pulsar/core_test.clj | |
(ns test-pulsar.core-test | |
(:require [clojure.test :refer :all] | |
[test-pulsar.core :refer :all])) | |
;; Utilities | |
(defn temp-ns | |
"Create and return a temporary ns, using clojure.core + uses" | |
[& uses] | |
(binding [*ns* *ns*] | |
(in-ns (gensym)) | |
(apply clojure.core/use 'clojure.core uses) | |
*ns*)) | |
(defmacro eval-in-temp-ns [& forms] | |
`(binding [*ns* *ns*] | |
(in-ns (gensym)) | |
(clojure.core/use 'clojure.core) | |
(eval | |
'(do ~@forms)))) | |
(defn causes | |
[^Throwable throwable] | |
(loop [causes [] | |
t throwable] | |
(if t (recur (conj causes t) (.getCause t)) causes))) | |
(defmethod assert-expr 'fails-with-cause? | |
[msg [_ exception-class msg-re & body :as form]] | |
`(try | |
~@body | |
(report {:type :fail, :message ~msg, :expected '~form, :actual nil}) | |
(catch Throwable t# | |
(if (some (fn [cause#] | |
(and | |
(= ~exception-class (class cause#)) | |
(re-find ~msg-re (.getMessage cause#)))) | |
(causes t#)) | |
(report {:type :pass, :message ~msg, | |
:expected '~form, :actual t#}) | |
(report {:type :fail, :message ~msg, | |
:expected '~form, :actual t#}))))) | |
(defmacro with-err-print-writer | |
"Evaluate with err pointing to a temporary PrintWriter, and | |
return err contents as a string." | |
[& body] | |
`(let [s# (java.io.StringWriter.) | |
p# (java.io.PrintWriter. s#)] | |
(binding [*err* p#] | |
~@body | |
(str s#)))) | |
(deftest defn-error-messages | |
(testing "multiarity syntax invalid parameter declaration" | |
(is (fails-with-cause? | |
IllegalArgumentException | |
#"Parameter declaration \"arg1\" should be a vector" | |
(eval-in-temp-ns (test-pulsar.core/defsfnp foo (arg1 arg2)))))) | |
(testing "multiarity syntax invalid signature" | |
(is (fails-with-cause? | |
IllegalArgumentException | |
#"Invalid signature \"\[a b\]\" should be a list" | |
(eval-in-temp-ns (test-pulsar.core/defsfnp foo | |
([a] 1) | |
[a b]))))) | |
(testing "assume single arity syntax" | |
(is (fails-with-cause? | |
IllegalArgumentException | |
#"Parameter declaration \"a\" should be a vector" | |
(eval-in-temp-ns (test-pulsar.core/defsfnp foo a))))) | |
(testing "bad name" | |
(is (fails-with-cause? | |
IllegalArgumentException | |
#"First argument to defn must be a symbol" | |
(eval-in-temp-ns (test-pulsar.core/defsfnp "bad docstring" testname [arg1 arg2]))))) | |
(testing "missing parameter/signature" | |
(is (fails-with-cause? | |
IllegalArgumentException | |
#"Parameter declaration missing" | |
(eval-in-temp-ns (test-pulsar.core/defsfnp testname))))) | |
(testing "allow trailing map" | |
(is (eval-in-temp-ns (test-pulsar.core/defsfnp a "asdf" ([a] 1) {:a :b})))) | |
(testing "don't allow interleaved map" | |
(is (fails-with-cause? | |
IllegalArgumentException | |
#"Invalid signature \"\{:a :b\}\" should be a list" | |
(eval-in-temp-ns (test-pulsar.core/defsfnp a "asdf" ([a] 1) {:a :b} ([] 1))))))) | |
(deftest non-dynamic-warnings | |
(testing "no warning for **" | |
(is (empty? (with-err-print-writer | |
(eval-in-temp-ns (test-pulsar.core/defsfnp ** ([a b] (Math/pow (double a) (double b))))))))) | |
(testing "warning for *hello*" | |
(is (not (empty? (with-err-print-writer | |
(eval-in-temp-ns (test-pulsar.core/defsfnp *hello* [] "hi")))))))) | |
(deftest dynamic-redefinition | |
;; too many contextual things for this kind of caching to work... | |
(testing "classes are never cached, even if their bodies are the same" | |
(is (= :b | |
(eval | |
'(do | |
(defmacro my-macro [] :a) | |
(test-pulsar.core/defsfnp do-macro [] (my-macro)) | |
(defmacro my-macro [] :b) | |
(test-pulsar.core/defsfnp do-macro [] (my-macro)) | |
(do-macro))))))) | |
(deftest nested-dynamic-declaration | |
(testing "vars :dynamic meta data is applied immediately to vars declared anywhere" | |
(is (= 10 | |
(eval | |
'(do | |
(list | |
(declare ^:dynamic p) | |
(test-pulsar.core/defsfnp q [] @p)) | |
(binding [p (atom 10)] | |
(q)))))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defproject test-pulsar "0.1.0-SNAPSHOT" | |
:description "FIXME: write description" | |
:url "http://example.com/FIXME" | |
:license {:name "Eclipse Public License" | |
:url "http://www.eclipse.org/legal/epl-v10.html"} | |
:dependencies [[org.clojure/clojure "1.7.0"] | |
[co.paralleluniverse/pulsar "0.7.3"]] | |
:java-agents [[co.paralleluniverse/quasar-core "0.7.3" :classifier "jdk8"]] | |
:main ^:skip-aot test-pulsar.core | |
:target-path "target/%s" | |
:profiles {:uberjar {:aot :all}}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment