Skip to content

Commit

Permalink
Documentation, bugfixes and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mgtlake committed Aug 21, 2016
1 parent 1113534 commit 40fc1ed
Show file tree
Hide file tree
Showing 15 changed files with 258 additions and 39 deletions.
71 changes: 51 additions & 20 deletions src/Juliet.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ function __init__()
Welcome to Juliet, the Julia Interative Educational Tutor.
Type `juliet()` to get started
""")
# Seed the rng to make testing deterministic
srand(1)
end

"""
Expand All @@ -43,8 +45,6 @@ end

courses = Vector{Types.Course}()

storeDir = "$(Pkg.dir("Juliet"))/store"

help = Dict(
"select" => """
HELP:
Expand Down Expand Up @@ -73,7 +73,7 @@ function juliet()
end

"""
Choose a lesson and complete it
Choose a course, and then choose a lesson
"""
function choose_lesson(courses::Vector{Types.Course})
@match courses begin
Expand All @@ -97,6 +97,9 @@ function choose_lesson(courses::Vector{Types.Course})
choose_lesson(courses[parse(Int, input)])
end

"""
Choose a lesson, then complete it
"""
function choose_lesson(course::Types.Course)
@match courses begin
[] => begin println("No lessons in $(course.name) - exiting course"); return end
Expand Down Expand Up @@ -132,6 +135,9 @@ function choose_lesson(course::Types.Course)
end
end

"""
Print a list of options
"""
function print_options(list, message)
if length(list) > 0
println(message)
Expand Down Expand Up @@ -184,6 +190,9 @@ function complete_lesson(lesson::Types.Lesson)
println("Finished ", lesson.name)
end

"""
Get input for a question
"""
function get_input(question)
print("> ")
input = @getInput
Expand All @@ -198,6 +207,9 @@ function get_input(question::Types.InfoQuestion)
return replace(input, r"\e\[([A-Z]|[0-9])", "")
end

"""
Ask a question
"""
function ask(question)
println(question.text)
end
Expand All @@ -214,9 +226,12 @@ end
function ask(question::Types.FunctionQuestion)
println(question.text)
println("`!submit` to submit file and run tests")
setup_function_file(lesson, question)
setup_function_file(question)
end

"""
Validate an answer to a question
"""
function validate(question::Types.InfoQuestion, response)
return true
end
Expand All @@ -227,8 +242,8 @@ end

function validate(question::Types.FunctionQuestion, response)
if strip(response) != "!submit" return false end
dir = normpath("$(homedir())/Juliet/$(question.lessonName)")
file = normpath("$dir/$(question.index).jl")
dir = joinpath(homedir(), "Juliet", "FunctionQuestion")
file = joinpath(dir, filename(question))

try
inputs = [pair[1] for pair in question.tests]
Expand Down Expand Up @@ -284,32 +299,48 @@ end

function show_congrats(question::Types.InfoQuestion) end

"""
Set up the file for a function question
"""
function setup_function_file(question::Types.FunctionQuestion)
dir = normpath("$(homedir())/Juliet")
if !isdir(dir) mkdir(dir) end
dir = normpath("$(homedir())/Juliet/$(question.lessonName)")
if !isdir(dir) mkdir(dir) end
dir = joinpath(homedir(), "Juliet", "FunctionQuestion")
mkpath(dir)

file = normpath("$dir/$(question.index).jl")
file = joinpath(dir, filename(question))
if !isfile(file)
open(file, "w") do f
write(f, question.template)
end
end

@compat @static if is_windows()
Util.run(`explorer.exe $file`; whitelist=[1])
elseif is_linux()
run(`xdg-open $file`)
elseif is_apple()
try
run(`open $file`)
catch
run(`open -a TextEdit $file`)
try
@compat @static if is_windows()
Util.run(`explorer.exe $file`; whitelist=[1])
elseif is_linux()
run(`xdg-open $file`)
elseif is_apple()
try
run(`open $file`)
catch
run(`open -a TextEdit $file`)
end
end
catch
println("Could not open file: please open `$file` manually")
end
end

"""
Generate a filename for a function question
"""
function filename(question::Types.FunctionQuestion)
description = x -> x[1:min(25, length(x))]
return "$(description(question.text))-$(hash(question)).jl"
end

"""
Register a course with the current session of Juliet
"""
function register(course::Types.Course)
if !in(course, courses)
push!(courses, course)
Expand Down
9 changes: 9 additions & 0 deletions src/convert.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ module Convert
using Juliet
using Match

"""
Convert a suitable dictionary to a leson
"""
function to_lesson(dict::Dict)
dict = lowercase(dict)
lesson = Juliet.Util.new_lesson(dict["name"])
Expand All @@ -20,6 +23,9 @@ function to_lesson(dict::Dict)
return lesson
end

"""
Convert a dictionary structure into a question based on `type` field
"""
function match_question(question)
@match Base.lowercase(question["type"]) begin
"infoquestion" => Juliet.Types.InfoQuestion(question["text"])
Expand All @@ -32,6 +38,9 @@ function match_question(question)
end
end

"""
Convert all dictionary keys to lowercase
"""
function lowercase(dict::Dict)
newdict = Dict{AbstractString, Any}()
for pair in dict
Expand Down
2 changes: 0 additions & 2 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ immutable FunctionQuestion <: AbstractQuestion
# use an array for now
tests::Array{Array{AbstractString, 1}, 1}
template::AbstractString
#lessonName::AbstractString
#index::Int
end

immutable MultiQuestion <: AbstractQuestion
Expand Down
4 changes: 4 additions & 0 deletions test/in/1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

a = 1
b = 2a
2
7 changes: 7 additions & 0 deletions test/in/2
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

a = 2
a = 1
b = 3a
b = 2a
1
2
1 change: 1 addition & 0 deletions test/in/3
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!submit
18 changes: 18 additions & 0 deletions test/out/1
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Welcome to Juliet, the Julia Interative Educational Tutor.
Type `juliet()` to get started

Welcome to Juliet, the Julia Interative Educational Tutor.
Selct a lesson or course to get started, or type `!help` for information.

Starting Basic syntax
1 / 4: This lesson will teach you about basic Julia syntax
...2 / 4: Set `a` to be 1
> Keep up the great work!
3 / 4: Assign `b` to be twice `a`
> Keep up the great work!
4 / 4: Is this fun?
Options:
1 - no
2 - yes
> You're doing great!
Finished Basic syntax
21 changes: 21 additions & 0 deletions test/out/2
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Welcome to Juliet, the Julia Interative Educational Tutor.
Type `juliet()` to get started

Welcome to Juliet, the Julia Interative Educational Tutor.
Selct a lesson or course to get started, or type `!help` for information.

Starting Basic syntax
1 / 4: This lesson will teach you about basic Julia syntax
...2 / 4: Set `a` to be 1
> One more try
> Keep up the great work!
3 / 4: Assign `b` to be twice `a`
> Close, but no cigar
> Great job!
4 / 4: Is this fun?
Options:
1 - no
2 - yes
> Hang in there
> Keep up the great work!
Finished Basic syntax
12 changes: 12 additions & 0 deletions test/out/3
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Welcome to Juliet, the Julia Interative Educational Tutor.
Type `juliet()` to get started

Welcome to Juliet, the Julia Interative Educational Tutor.
Selct a lesson or course to get started, or type `!help` for information.

Starting Functions TEST
1 / 1: Return the same number
`!submit` to submit file and run tests
> 1/1 tests passed
Keep up the great work!
Finished Functions TEST
21 changes: 16 additions & 5 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,19 @@ using Base.Test

include("unittest.jl")

f = x -> strip(x) != ""
lesson = Juliet.Util.new_lesson("1234")
Juliet.Util.add_question!(lesson, Juliet.Types.FunctionQuestion("question 1",
["hint 1", "hint 2", "hint 3"], f))
# Juliet.complete_lesson(lesson)
clean = x -> replace(x, "\r\n", "\n")

for i in readdir("in")
input = joinpath("in", i)
script = joinpath("script", "$i.jl")
output = joinpath("out", i)
try
run(pipeline(pipeline(`cat $input`, `julia $script`), stdout="temp"))
run(pipeline(pipeline(`type $input`, `julia $script`), stdout="temp"))
end
open("temp", "r") do f
open("$output", "r") do g
@test clean(readall(f)) == clean(readall(g))
end
end
end
12 changes: 11 additions & 1 deletion test/test.toml → test/script/1.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
using Juliet

text = """
name = "Basic syntax"
description = "Some basic syntax stuff"
authors = ["Matthew Lake"]
Expand All @@ -19,10 +22,17 @@ text = "Assign `b` to be twice `a`"
answer = "b = 2a"
hints = []

[[questions]]
type = "MultiQuestion"
text = "Is this fun?"
options = ["no", "yes"]
answer = 2
hints = []
"""

lesson = Juliet.Convert.to_lesson(TOML.parse(text))

c = Juliet.Types.Course("Basic Syntax Lesson", "", v"1", [], [], [lesson])
Juliet.register(c)

juliet()
38 changes: 38 additions & 0 deletions test/script/2.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Juliet

text = """
name = "Basic syntax"
description = "Some basic syntax stuff"
authors = ["Matthew Lake"]
keywords = ["basic", "syntax"]
[[questions]]
type = "InfoQuestion"
text = "This lesson will teach you about basic Julia syntax"
[[questions]]
type = "SyntaxQuestion"
text = "Set `a` to be 1"
answer = "a = 1"
hints = []
[[questions]]
type = "SyntaxQuestion"
text = "Assign `b` to be twice `a`"
answer = "b = 2a"
hints = []
[[questions]]
type = "MultiQuestion"
text = "Is this fun?"
options = ["no", "yes"]
answer = 2
hints = []
"""

lesson = Juliet.Convert.to_lesson(TOML.parse(text))

c = Juliet.Types.Course("Basic Syntax Lesson", "", v"1", [], [], [lesson])
Juliet.register(c)

juliet()
36 changes: 36 additions & 0 deletions test/script/3.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Juliet
using TOML

text = """
name = "Functions TEST"
description = "All functions all the time"
authors = ["Matthew Lake"]
keywords = ["basic", "functions"]
[[questions]]
type = "FunctionQuestion"
text = "Return the same number"
tests = [["123", "123"]]
template = "# write code here"
hints = ["Just return the number you read in"]
"""

lesson = Juliet.Convert.to_lesson(TOML.parse(text))

# Write a passing file
answer = """
print(readline())
"""
dir = joinpath(homedir(), "Juliet", "FunctionQuestion")
file = joinpath(dir, Juliet.filename(lesson.questions[1]))
open(file, "w") do f
write(f, answer)
end

c = Juliet.Types.Course("Basic Function Lesson", "", v"1", [], [], [lesson])
Juliet.register(c)

juliet()

# rm(file)
Loading

0 comments on commit 40fc1ed

Please sign in to comment.