Skip to content
This repository
tree: e99706fd92
Fetching contributors…

Cannot retrieve contributors at this time

file 169 lines (147 sloc) 5.969 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
(ns tryclojure.core
  (:use [hiccup form-helpers page-helpers]
ring.middleware.file
        noir.core
        [noir.response :only [json]]
[clojure.stacktrace :only [root-cause]]
        [clojail.core :only [sandbox eagerly-consume]]
        [clojail.testers :only [secure-tester-without-def]])
  (:require [noir.server :as server]
            [noir.session :as session])
  (:import java.io.StringWriter
java.util.concurrent.TimeoutException))

(defpartial links []
  (unordered-list
   [(link-to "http://clojure.org" "The official Clojure website")
    (link-to "http://dev.clojure.org/display/doc/Getting+Started" "Getting started with Clojure")
    (link-to "http://groups.google.com/group/clojure" "Clojure mailing list")
    (link-to "http://java.ociweb.com/mark/clojure/article.html" "A comprehensive Clojure tutorial")
    (link-to "http://joyofclojure.com/" "The Joy of Clojure: a book by Michael Fogus and Chris Houser")
    (link-to "http://disclojure.org" "Disclojure")
    (link-to "http://planet.clojure.in" "Planet Clojure")]))

(def github-link (link-to "http://github.com/Raynes/tryclojure" "github"))

(defpartial about-html []
  [:p.bottom
   "Please note that this REPL is sandboxed, so you wont be able to do everything in it "
   "that you would in a local unsandboxed REPL. Keep in mind that this site is designed for "
   "beginners to try out Clojure and not necessarily as a general-purpose server-side REPL."]
  [:p.bottom
   "One quirk you might run into is that things you bind with def can sometimes disappear. "
   "The sandbox wipes defs if you def too many things, so don't be surprised. Furthermore, "
   "The sandbox will automatically be wiped after 15 minutes and if you evaluate more after that,"
   "It'll be in an entirely new namespace/sandbox."]
  [:p.bottom
   "You can find the site's source and such on its "
   github-link
   " page."]
  [:p.bottom
   "TryClojure is written in Clojure and JavaScript (JQuery), powered by "
   (link-to "https://github.com/flatland/clojail" "clojail")
   " and Chris Done's "
   (link-to "https://github.com/chrisdone/jquery-console" "jquery-console")]
  [:p.bottom "Design by " (link-to "http://apgwoz.com" "Andrew Gwozdziewycz")])

(defpartial home-html []
  [:p.bottom
   "Welcome to Try Clojure. See that little box up there? That's a Clojure repl. You can type "
   "expressions and see their results right here in your browser. We also have a brief tutorial to "
   "give you a taste of Clojure. Try it out by typing " [:code.expr "tutorial"] " in the console!"]
  [:p.bottom
   "Check out the site's source on "
   (link-to "http://github.com/Raynes/tryclojure" "github")
   "!"])

(defpartial root-html []
  (html4
   [:head
    (include-css "/resources/public/css/tryclojure.css")
    (include-js "/resources/public/javascript/jquery-1.4.2.min.js"
                "/resources/public/javascript/jquery.console.js"
                "/resources/public/javascript/tryclojure.js")
    [:title "Try Clojure"]]
   [:body
    [:div#wrapper
     [:div#content
      [:div#header
       [:h1
        [:span.logo-try "Try"] " "
        [:span.logo-clojure "Clo" [:em "j"] "ure"]]]
      [:div#container
       [:div#console.console]
       [:div#buttons
        [:a#home.buttons "home"]
        [:a#links.buttons "links"]
        [:a#about.buttons.last "about"]]
       [:div#changer (home-html)]]
      [:div.footer
       [:p.bottom "©2011 Anthony Grimes and numerous contributors"]
       [:p.bottom
        "Built with "
        (link-to "http://webnoir.org" "Noir")
        "."]]
      (javascript-tag
       "var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-27340918-1']);
_gaq.push(['_trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();")]]]))

(defpage "/" []
  (root-html))

(defpage "/home" []
  (home-html))

(defpage "/about" []
  (about-html))

(defpage "/links" []
  (links))

(defpage [:post "/tutorial"] {n :n}
  (slurp (str "resources/public/tutorial/page" n ".html")))

(defn eval-form [form sbox]
  (with-open [out (java.io.StringWriter.)]
    (let [result (sbox form {#'*out* out})]
      {:expr form
       :result [out result]})))

(defn eval-string [expr sbox]
  (let [form (binding [*read-eval* false] (read-string expr))]
    (eval-form form sbox)))

(def try-clojure-tester
  (into secure-tester-without-def
        #{'tryclojure.core}))

(defn make-sandbox []
  (sandbox try-clojure-tester
           :timeout 2000
           :init '(do (use '[clojure.repl :only [doc]])
                      (future (Thread/sleep 600000)
                              (-> *ns* .getName remove-ns)))))

(defn find-sb [old]
  (if-let [sb (get old "sb")]
    old
    (assoc old "sb" (make-sandbox))))

(defn eval-request [expr]
  (try
    (eval-string expr (get (session/swap! find-sb) "sb"))
    (catch TimeoutException _
      {:error true :message "Execution Timed Out!"})
    (catch Exception e
      {:error true :message (str (root-cause e))})))

(defpage "/eval.json" {:keys [expr jsonp]}
  (update-in
   (json
    (let [{:keys [expr result error message] :as res} (eval-request expr)]
      (if error
        res
        (let [[out res] result]
          {:expr (pr-str expr)
           :result (str out (pr-str res))}))))
   [:body]
   #(if jsonp (str jsonp "(" % ")") %)))

(server/add-middleware wrap-file (System/getProperty "user.dir"))

(defn to-port [s]
  (when-let [port s] (Long. port)))

(defn tryclj [& [port]]
  (server/start
   (or (to-port port)
       (to-port (System/getenv "PORT")) ;; For deploying to Heroku
       8801)
   {:session-cookie-attrs {:max-age 600}}))

(defn -main [& args] (tryclj (first args)))
Something went wrong with that request. Please try again.