Skip to content

Instantly share code, notes, and snippets.

@rubysolo
Created July 24, 2014 17:15
Show Gist options
  • Save rubysolo/d0c03cc4d5d62cfb0070 to your computer and use it in GitHub Desktop.
Save rubysolo/d0c03cc4d5d62cfb0070 to your computer and use it in GitHub Desktop.
package main
import "errors"
import "fmt"
import "io"
import "io/ioutil"
import "log"
import "os"
import "path/filepath"
import "strings"
func main() {
testFile, err := detectExercism()
if (err != nil) {
log.Fatal(err)
}
fmt.Println("Found " + testFile + ", let the leinifying commence!")
exerciseName := strings.Replace(testFile, "_test.clj", "", -1)
fmt.Println("Exercise name: " + exerciseName)
transformTestFile(testFile, exerciseName)
createProjectFile(exerciseName)
createSrcFile(exerciseName)
}
func detectExercism() (f string, err error) {
files, _ := filepath.Glob("*_test.clj")
if len(files) == 0 {
return "", errors.New("Could not find an exercism clojure test (*_test.clj) in current directory.")
}
return files[0], nil
}
func transformTestFile(fileName string, exerciseName string) {
bytes, err := ioutil.ReadFile(fileName)
if (err != nil) {
log.Fatal(err)
}
content := string(bytes[:])
// extract ns form boundaries
_, nsBoundEnd := formBounds(content, 0)
// extract load file form boundaries
_, lfBoundEnd := formBounds(content, nsBoundEnd+1)
// remove ns and load-file forms
content = content[lfBoundEnd+1:]
// insert new ns form
nsForm := "(ns " + exerciseName + "-test\n" +
" (:require [clojure.test :refer :all]\n" +
" [" + exerciseName + " :refer :all]))\n\n"
content = nsForm + strings.Replace(content, "(run-tests)", "", -1)
if os.MkdirAll("test", 0777) != nil {
log.Fatal("could not create 'test' directory!")
}
fileOut, err := os.Create(strings.Join([]string{"test", fileName}, "/"))
if (err != nil) {
log.Fatal("could not create 'test/" + fileName + "'!")
}
defer fileOut.Close()
fmt.Println("writing 'test/" + fileName + "'...")
io.WriteString(fileOut, content)
}
// find the start and end character index of the next lisp form in string
// at or after index, handling nested forms
func formBounds(s string, index int) (startIndex int, endIndex int) {
stack := 0
startIndex = -1
endIndex = -1
for i,c := range s {
if i >= index {
switch c {
case '(':
if (startIndex == -1) {
startIndex = i
}
stack++
case ')':
stack--
if (stack == 0) {
endIndex = i
break
}
}
}
if (endIndex > 0) {
break
}
}
return startIndex, endIndex+1
}
func createProjectFile(exerciseName string) {
fileOut, err := os.Create("project.clj")
if (err != nil) {
log.Fatal("could not create 'project.clj'!")
}
defer fileOut.Close()
clojureVersion := os.Getenv("CLOJURE_VERSION")
if (clojureVersion == "") {
message := "*** It looks like you haven't specified your clojure version.\n" +
" I'll default it to 1.6.0; if you want something different,\n" +
" set the CLOJURE_VERSION environment variable"
fmt.Println(message)
clojureVersion = "1.6.0"
}
content := "(defproject " + exerciseName + " \"1.0.0\"\n" +
" :dependencies [[org.clojure/clojure \"" + clojureVersion + "\"]])\n"
fmt.Println("writing 'project.clj'...")
io.WriteString(fileOut, content)
}
func createSrcFile(exerciseName string) {
if os.MkdirAll("src", 0777) != nil {
log.Fatal("could not create 'src' directory!")
}
fileName := exerciseName + ".clj"
fileOut, err := os.Create(strings.Join([]string{"src", fileName}, "/"))
if (err != nil) {
log.Fatal("could not create 'src/" + fileName + "'!")
}
defer fileOut.Close()
fmt.Println("writing 'src/" + fileName + "'...")
io.WriteString(fileOut, "(ns " + exerciseName + ")")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment