Permalink
Browse files

Merge branch 'release/1.1.1'

  • Loading branch information...
2 parents ed1301e + dac918c commit dcfb368b2af5cac8dcf29f9188fbb6a22a60566a @amalloy amalloy committed Jul 19, 2011
View
@@ -46,6 +46,7 @@ vaguely like this:
* [David Davis](https://github.com/daviddavis) (daviddavis)
* [Devin Walters](https://github.com/devn) (devn)
* [Michael Kohl](https://github.com/citizen428) (citizen428)
+* [Martin Sander](https://github.com/marvinthepa) (0x89)
Problem sources:
View
@@ -1,4 +1,4 @@
-(defproject foreclojure "1.1.0"
+(defproject foreclojure "1.1.1"
:description "4clojure - a website for lisp beginners"
:dependencies [[clojure "1.2.1"]
[clojure-contrib "1.2.0"]
@@ -60,6 +60,13 @@ function configureDataTables(){
} );
}
+function setIconColor(element, color, timeOut) {
+ timeOut = (typeof timeOut == "undefined") ? 0 : timeOut
+ setTimeout (function() {
+ element.src = "/images/"+color+"light.png";
+ }, timeOut);
+}
+
function configureCodeBox(){
//For no javascript version we have the code-box text area
//If we have javascript on then we remove it and replace it with
@@ -81,41 +88,55 @@ function configureCodeBox(){
images = $(".testcases").find("img"),
cont = true,
high = false,
- time = 800,
+ animationTime = 800,
+ waitTimePerItem = 500,
+ waitTime = waitTimePerItem,
beforeSendCallback = function(data) {
$("#message-text").text("Executing unit tests...");
+ images.each( function(index, element) {
+ setIconColor(element, "blue");
+ });
var anim = function() {
if(cont) {
images.animate({
opacity: high ? 1.0 : 0.1,
- }, time);
+ }, animationTime);
high = !high;
- setTimeout(anim,time);
+ setTimeout(anim,animationTime);
}
};
anim();
},
successCallback = function(data) {
- var failingTest = data.failingTest;
- cont = false;
-
- images.stop(true);
- images.css({ opacity: 1.0, });
- images.each( function(index,element) {
- var color = "blue";
- if (index < failingTest) {
- color = "green";
- } else if (index === failingTest) {
- color = "red";
- }
- element.src = "/images/"+color+"light.png";
- });
-
- $("#message-text").html(data.message);
- $("#golfgraph").html(data.golfChart);
- $("#golfscore").html(data.golfScore);
- configureGolf();
+ var failingTest = data.failingTest
+ getColorFor = function(index) {
+ return index === failingTest ? "red" : "green";
+ },
+ testWasExecuted = function(index) {
+ return index <= failingTest;
+ },
+ setColor = function(index,element) {
+ var color = getColorFor(index);
+ waitTime = waitTimePerItem * (index+1);
+ setIconColor(element, color, waitTime);
+ },
+ setMessages = function() {
+ $("#message-text").html(data.message);
+ $("#golfgraph").html(data.golfChart);
+ $("#golfscore").html(data.golfScore);
+ configureGolf();
+ }
+ stopAnimation = function() {
+ cont = false;
+ images.stop(true);
+ images.css({ opacity: 1.0, });
+ };
+
+ setTimeout(stopAnimation, waitTime);
+ images.filter( testWasExecuted ).
+ each(setColor);
+ setTimeout (setMessages, waitTime);
};
$.ajax({type: "POST",
View
@@ -34,6 +34,7 @@
session/wrap-stateful-session
handler/site
wrap-uri-binding
+ wrap-strip-trailing-slash
wrap-gzip))
(defn run []
@@ -31,17 +31,33 @@
:where criteria
:sort {:_id 1}))))
-(defn next-unsolved-problem [solved-problems]
- (when-let [unsolved (->> (get-problem-list)
- (remove (comp (set solved-problems) :_id))
- (seq))]
- (apply min-key :_id unsolved)))
+(defn next-unsolved-problem [solved-problems just-solved-id]
+ (when-let [unsolved (seq
+ (from-mongo
+ (fetch :problems
+ :only [:_id :title]
+ :where {:_id {:$nin solved-problems}}
+ :sort {:_id 1})))]
+ (let [[skipped not-yet-tried] (split-with #(< (:_id %) just-solved-id)
+ unsolved)]
+ (filter identity [(rand-nth (or (seq skipped)
+ [nil])) ; rand-nth barfs on empty seq
+ (first not-yet-tried)]))))
+
+(letfn [(problem-link [{id :_id title :title}]
+ (str "<a href='/problem/" id "#prob-title'>" title "</a>"))]
+ (defn suggest-problems
+ ([] "You've solved them all! Come back later for more!")
+ ([problem]
+ (str "Now try " (problem-link problem) "!"))
+ ([skipped not-tried]
+ (str "Now move on to " (problem-link not-tried)
+ ", or go back and try " (problem-link skipped) " again!"))))
(defn next-problem-link [completed-problem-id]
(when-let [{:keys [solved]} (get-user (session/session-get :user))]
- (if-let [{:keys [_id title]} (next-unsolved-problem solved)]
- (str "Now try <a href='/problem/" _id "'>" title "</a>!")
- "You've solved them all! Come back later for more!")))
+ (apply suggest-problems
+ (next-unsolved-problem solved completed-problem-id))))
(defn get-recent-problems [n]
(map get-problem (map :_id (take-last n (get-problem-list)))))
@@ -122,7 +138,7 @@
:else (str "You've solved the problem! If you "
(login-link "log in" (str "/problem/" _id)) " we can track your progress."))]
(session/session-put! :code [_id code])
- [(str message " " gist-link) (str "/problem/" _id)] ))
+ {:message (str message " " gist-link), :url (str "/problem/" _id)}))
(def restricted-list '[use require in-ns future agent send send-off pmap pcalls])
@@ -138,30 +154,42 @@
(doall (take-while (complement #{end})
(repeatedly #(read *in* false end))))))))
-(defn run-code [id raw-code]
- (let [code (.trim raw-code)
- {:keys [tests restricted] :as problem} (get-problem id)
- sb-tester (get-tester restricted)]
- (session/flash-put! :code code)
- (try
- (let [user-forms (s/join " " (map pr-str (read-string-safely code)))]
- (if (empty? user-forms)
- ["Empty input is not allowed" *url*]
- (loop [[test & more] tests
- i 0]
- (session/flash-put! :failing-test i)
- (if-not test
- (mark-completed problem code)
- (let [testcase (s/replace test "__" user-forms)]
- (if (sb sb-tester (first (read-string-safely testcase)))
- (recur more (inc i))
- ["You failed the unit tests." *url*]
- ))))))
- (catch Exception e
- [(.getMessage e) *url*]))))
+(defn run-code
+ "Run the specified code-string against the test cases for the problem with the
+specified id.
+
+Return a map, {:message, :url, :num-tests-passed}."
+ [id raw-code]
+ (try
+ (let [code (.trim raw-code)
+ {:keys [tests restricted] :as problem} (get-problem id)
+ sb-tester (get-tester restricted)
+ user-forms (s/join " " (map pr-str (read-string-safely code)))
+ results (if (empty? user-forms)
+ ["Empty input is not allowed."]
+ (for [test tests]
+ (try
+ (when-not (->> user-forms
+ (s/replace test "__")
+ read-string-safely
+ first
+ (sb sb-tester))
+ "You failed the unit tests")
+ (catch Throwable t (.getMessage t)))))
+ [passed [fail-msg]] (split-with nil? results)]
+ (assoc (if fail-msg
+ {:message fail-msg :url *url*}
+ (mark-completed problem code))
+ :num-tests-passed (count passed)))
+ (catch Throwable t {:message (.getMessage t), :url *url*
+ :num-tests-passed 0})))
(defn static-run-code [id raw-code]
- (apply flash-msg (run-code id raw-code)))
+ (let [{:keys [message url num-tests-passed]}
+ (binding [*url* (str *url* "#prob-desc")]
+ (run-code id raw-code))]
+ (session/flash-put! :failing-test num-tests-passed)
+ (flash-msg message url)))
(defn render-test-cases [tests]
[:table {:class "testcases"}
@@ -197,8 +225,8 @@
[:span#graph-link "View Chart"]]])))
(defn rest-run-code [id raw-code]
- (let [[message url] (run-code id raw-code)]
- (json-str {:failingTest (session/flash-get :failing-test)
+ (let [{:keys [message url num-tests-passed]} (run-code id raw-code)]
+ (json-str {:failingTest num-tests-passed
:message message
:golfScore (html (render-golf-score))
:golfChart (html (render-golf-chart))})))
View
@@ -1,7 +1,8 @@
(ns foreclojure.ring
(:use [compojure.core :only [GET]]
[ring.util.response :only [response]])
- (:require [clojure.java.io :as io])
+ (:require [clojure.java.io :as io]
+ [clojure.string :as s])
(:import (java.net URL)))
;; copied from compojure.route, modified to use File instead of Stream
@@ -22,3 +23,7 @@
(= "file" (.getProtocol ^URL body)))
(update-in resp [:body] io/as-file)
resp))))
+
+(defn wrap-strip-trailing-slash [handler]
+ (fn [request]
+ (handler (update-in request [:uri] s/replace #"(?<=.)/$" ""))))
View
@@ -117,10 +117,10 @@
(defn html-doc [& body]
(let [user (session/session-get :user)]
- (html
+ (html
(doctype :html5)
- [:html
- [:head
+ [:html
+ [:head
[:title "4Clojure"]
[:link {:rel "alternate" :type "application/atom+xml" :title "Atom" :href "http://4clojure.com/problems/rss"}]
[:link {:rel "shortcut icon" :href "/favicon.ico"}]
@@ -171,7 +171,10 @@
[:div#content_body body]
[:div#footer
"The content on 4clojure.com is available under the EPL v 1.0 license."
- [:a#contact {:href "mailto:team@4clojure.com"} "Contact us!"]]
+ (let [email "team@4clojure.com"]
+ [:span
+ [:a#contact {:href (str "mailto:" email)} "Contact us"]
+ (str `(~email))])]
(javascript-tag
" var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-22844856-1']);

0 comments on commit dcfb368

Please sign in to comment.