Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
82 additions
and
70 deletions.
There are no files selected for viewing
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
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,15 @@ | |||
(ns foreclojure-downloader.api | |||
(:require [clj-http.client :as client]) | |||
(:use [slingshot.slingshot :only [try+]])) | |||
|
|||
(defn- problem-url | |||
"Return the 4clojure URL for a given problem number." | |||
[n] | |||
(str "http://www.4clojure.com/api/problem/" n)) | |||
|
|||
(defn problem | |||
"Returns a numbered problem from 4clojure as a map." | |||
[n] | |||
(try+ (assoc (:body (client/get (problem-url n) {:as :json})) :number n) | |||
(catch [:status 404] _))) | |||
|
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -1,73 +1,13 @@ | |||
(ns foreclojure-downloader.core | (ns foreclojure-downloader.core | ||
(:require [clojure.string :as string]) | (:require [foreclojure-downloader.api :as api] | ||
(:require [clojure.core.reducers :as reducers]) | [foreclojure-downloader.writer :as writer])) | ||
(:require [clj-http.client :as client]) | |||
(:require [cheshire.core :as cheshire])) | |||
|
|
||
(defn download-problem [n] | (defn- problems | ||
"Download the given problem number from 4clojure." | [] | ||
(let [url (str "http://www.4clojure.com/api/problem/" n) | (pmap api/problem (range 1 200))) | ||
response (client/get url {:throw-exceptions false})] | |||
(when (= 200 (:status response)) | |||
(cheshire/parse-string (:body response) true)))) | |||
|
|||
(defn convert-newlines [string] | |||
(string/replace string "\r\n" "\n")) | |||
|
|||
(defn parse-test [test] | |||
"Take a String test and parse out the equality operator and two sides. | |||
Do this with a regular expression rather than read-string in an attempt | |||
to preserve the original test code: e.g. reading #(* % 2) with | |||
read-string produces (fn* [pn_1234#] (* pn_1234# 2))." | |||
(if-let [matches (re-find #"^(?s)\((==?)\s+(#?\".+\"|'?\(.+\)|\[.+\]|#?\{.+\}|\S+)\s+(#?\".+\"|'?\(.+\)|\[.+\]|#?\{.+\}|\S+)\)$" | |||
(convert-newlines test))] | |||
matches | |||
["" "=" (convert-newlines test) true])) | |||
|
|||
(defn arrow [test] | |||
"Return the appropriate checker for the given test." | |||
(let [equals (second (parse-test test))] | |||
(str equals ">"))) | |||
|
|||
(defn lhs [test] | |||
"Return the left-hand side of the given test." | |||
(nth (parse-test test) 2)) | |||
|
|||
(defn rhs [test] | |||
"Return the left-hand side of the given test." | |||
(last (parse-test test))) | |||
|
|||
(defn checker [test] | |||
"Return the full checker for the given test." | |||
(str " " (lhs test) " " (arrow test) " " (rhs test))) | |||
|
|||
(defn checkers [problem] | |||
"Return all checkers for the given problem." | |||
(str (string/join "\n" (map checker (:tests problem))) ")")) | |||
|
|||
(defn fact [problem] | |||
"Return a full fact block for a given problem including all checkers." | |||
(str "(future-fact \"" (:title problem) "\"\n" (checkers problem) "\n")) | |||
|
|||
(defn problem-file-content [n problem] | |||
"Return the full test file content for a given problem." | |||
(str "(ns foreclojure-solutions.p" n "\n" | |||
" (:use midje.sweet))\n" | |||
"\n" | |||
"(defn __ []\n" | |||
" \"Implement me!\")\n" | |||
"\n" | |||
(fact problem))) | |||
|
|||
(defn problem-file-name [n] | |||
(str "src/foreclojure_solutions/p" n ".clj")) | |||
|
|||
(defn write-problem [n] | |||
(when-let [problem (download-problem n)] | |||
(.mkdirs (java.io.File. "src/foreclojure_solutions")) | |||
(spit (problem-file-name n) (problem-file-content n problem))) | |||
n) | |||
|
|
||
(defn -main [] | (defn -main [] | ||
(into [] (reducers/map write-problem (range 1 200)))) | (do | ||
(println "Downloading problems...") | |||
(pmap writer/write-problem (problems)) | |||
nil)) |
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,41 @@ | |||
(ns foreclojure-downloader.translator | |||
(:require [clojure.string :as string])) | |||
|
|||
(defn- parse-simple-test | |||
"Parse simple tests of the form (= x y) where possible." | |||
[test] | |||
(next (re-find #"^(?s)\((==?)\s+(#?\".+\"|'?\(.+\)|\[.+\]|#?\{.+\}|\S+)\s+(#?\".+\"|'?\(.+\)|\[.+\]|#?\{.+\}|\S+)\)$" | |||
test))) | |||
|
|||
(defn- test->checker | |||
"Translate a test into a Midje checker. | |||
Tests of the form (= x y) will be translated to x => y but more complex tests | |||
will be preserved and checked to be true, e.g. (and (= x y) (= z a)) => true" | |||
[test] | |||
(let [normalized-test (string/replace test "\r\n" "\n")] | |||
(if-let [[equals left right] (parse-simple-test normalized-test)] | |||
(str " " left " " equals "> " right) | |||
(str normalized-test " => true")))) | |||
|
|||
(defn- checkers | |||
"Return all checkers for the given problem." | |||
[problem] | |||
(str (string/join "\n" (map test->checker (:tests problem))) ")")) | |||
|
|||
(defn- fact | |||
"Return a full fact block for a given problem including all checkers." | |||
[problem] | |||
(str "(future-fact \"" (:title problem) "\"\n" | |||
(checkers problem) "\n")) | |||
|
|||
(defn problem-test | |||
"Return the full test for a given problem as a String." | |||
[problem] | |||
(str "(ns foreclojure-solutions.p" (:number problem) "\n" | |||
" (:use midje.sweet))\n" | |||
"\n" | |||
"(defn __ []\n" | |||
" \"Implement me!\")\n" | |||
"\n" | |||
(fact problem))) |
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,16 @@ | |||
(ns foreclojure-downloader.writer | |||
(:require [foreclojure-downloader.translator :as translator])) | |||
|
|||
(defn- file-name | |||
"Return the file name for the given problem." | |||
[problem] | |||
(str "src/foreclojure_solutions/p" (:number problem) ".clj")) | |||
|
|||
(defn write-problem | |||
"Write the given problem to disk." | |||
[problem] | |||
(do | |||
(.mkdirs (java.io.File. "src/foreclojure_solutions")) | |||
(spit (file-name problem) (translator/problem-test problem))) | |||
problem) | |||
|