Refactoring to cleaner API. Added WeaveDoc type.

Reading and running chunks now return WeaveDoc's.
Cleaned weave function significantly.
pull/29/head
Matti Pastell 2015-01-07 00:01:25 +02:00
parent e76e823a3d
commit 5d1f5ab4d7
5 changed files with 163 additions and 154 deletions

View File

@ -6,21 +6,18 @@ using Docile
#Contains report global properties
type Report <: Display
source::String
documentationmode::Bool
cwd::String
basename::String
formatdict
formatdict::Dict{Symbol,Any}
pending_code::String
cur_result::String
fignum::Int
figures::Array
figures::Array{String}
term_state::Symbol
cur_chunk
function Report()
new("", false, "", "", Any[], "", "", 1, Any[], :text, @compat Dict{Symbol, Any}() )
function Report(cwd, basename, formatdict)
new(cwd, basename, formatdict, "", "", 1, String[], :text, nothing)
end
end
@ -63,22 +60,12 @@ tangle(source ; out_path=:doc, informat="noweb")
`"somepath"`: Path as a string e.g `"/home/mpastell/weaveout"`
"""->
function tangle(source ; out_path=:doc, informat="noweb")
cwd, fname = splitdir(abspath(source))
basename = splitext(fname)[1]
doc = read_doc(source, informat)
cwd = get_cwd(doc, out_path)
#Set the output directory
if out_path == :doc
cwd = cwd
elseif out_path == :pwd
cwd = pwd()
else
cwd = out_path
end
outname = "$(cwd)/$(basename).jl"
outname = "$(cwd)/$(doc.basename).jl"
open(outname, "w") do io
for chunk in read_doc(source, informat)
for chunk in doc.chunks
if typeof(chunk) == CodeChunk
write(io, chunk.content*"\n")
end
@ -107,140 +94,24 @@ weave(source ; doctype = "pandoc", plotlib="Gadfly",
**Note:** Run Weave from terminal and not using IJulia, Juno or ESS, they tend to mess with capturing output.
""" ->
function weave(source ; doctype = "pandoc", plotlib="Gadfly", informat="noweb", out_path=:doc, fig_path = "figures", fig_ext = nothing)
function weave(source ; doctype = "pandoc", plotlib="Gadfly",
informat="noweb", out_path=:doc, fig_path = "figures", fig_ext = nothing)
report = Report()
cwd, fname = splitdir(abspath(source))
basename = splitext(fname)[1]
formatdict = formats[doctype].formatdict
if fig_ext == nothing
rcParams[:chunk_defaults][:fig_ext] = formatdict[:fig_ext]
else
rcParams[:chunk_defaults][:fig_ext] = fig_ext
end
doc = read_doc(source, informat) #Reader toimii, muuten kesken...
doc = run(doc, doctype = doctype, plotlib=plotlib,
informat = informat, out_path=out_path, fig_path = fig_path, fig_ext = fig_ext)
formatted = format(doc)
#Set the output directory
if out_path == :doc
report.cwd = cwd
elseif out_path == :pwd
report.cwd = pwd()
else
report.cwd = out_path
end
report.source = source
report.basename = basename
rcParams[:chunk_defaults][:fig_path] = fig_path
report.formatdict = formatdict
if plotlib == nothing
rcParams[:chunk_defaults][:fig] = false
else
l_plotlib = lowercase(plotlib)
rcParams[:chunk_defaults][:fig] = true
if l_plotlib == "winston"
eval(parse("""include(Pkg.dir("Weave","src","winston.jl"))"""))
rcParams[:plotlib] = "Winston"
elseif l_plotlib == "pyplot"
eval(Expr(:using, :PyPlot))
rcParams[:plotlib] = "PyPlot"
elseif l_plotlib == "gadfly"
eval(parse("""include(Pkg.dir("Weave","src","gadfly.jl"))"""))
rcParams[:plotlib] = "Gadfly"
end
end
pushdisplay(report)
parsed = read_doc(source, informat)
executed = run(parsed, report)
popdisplay(report)
formatted = format(executed, doctype)
outname = "$(report.cwd)/$(report.basename).$(formatdict[:extension])"
outname = "$(doc.cwd)/$(doc.basename).$(doc.format.formatdict[:extension])"
open(outname, "w") do io
write(io, join(formatted, "\n"))
end
info("Report weaved to $(report.basename).$(formatdict[:extension])")
info("Report weaved to $(doc.basename).$(doc.format.formatdict[:extension])")
end
function run_block(code_str, report::Report)
oldSTDOUT = STDOUT
result = ""
rw, wr = redirect_stdout()
#If there is nothing to read code will hang
println()
try
n = length(code_str)
pos = 1 #The first character is extra line end
while pos < n
oldpos = pos
code, pos = parse(code_str, pos)
s = eval(ReportSandBox, code)
if rcParams[:plotlib] == "Gadfly"
s != nothing && display(s)
end
end
finally
redirect_stdout(oldSTDOUT)
close(wr)
result = readall(rw)
close(rw)
end
return string("\n", result)
end
function run_term(code_str, report::Report)
prompt = "\njulia> "
codestart = "\n\n"*report.formatdict[:codestart]
if haskey(report.formatdict, :indent)
prompt = indent(prompt, report.formatdict[:indent])
end
#Emulate terminal
n = length(code_str)
pos = 2 #The first character is extra line end
while pos < n
oldpos = pos
code, pos = parse(code_str, pos)
report.term_state == :fig && (report.cur_result*= codestart)
prompts = string(prompt, rstrip(code_str[oldpos:(pos-1)]), "\n")
report.cur_result *= prompts
report.term_state = :text
s = eval(ReportSandBox, code)
s != nothing && display(s)
end
return string(report.cur_result)
end
function run(parsed, report::Report)
#Clear sandbox for each document
#Raises a warning, couldn't find a "cleaner"
#way to do it.
eval(parse("module ReportSandBox\nend"))
executed = Any[]
for chunk in copy(parsed)
result_chunk = eval_chunk(chunk, report::Report)
push!(executed, result_chunk)
end
executed
end
function savefigs(chunk, report::Report)
l_plotlib = lowercase(rcParams[:plotlib])
if l_plotlib == "pyplot"

View File

@ -1,4 +1,19 @@
type WeaveDoc
source::String
basename::String
path::String
chunks::Array
cwd::String
format
function WeaveDoc(source, chunks)
path, fname = splitdir(abspath(source))
basename = splitext(fname)[1]
new(source, basename, path, chunks, "", nothing)
end
end
type CodeChunk
content::String
number::Int

View File

@ -1,8 +1,7 @@
#Format the executed document
function format(executed, doctype)
function format(doc::WeaveDoc)
formatted = String[]
docformat = formats[doctype]
docformat = doc.format
#@show docformat
#Complete format dictionaries with defaults
@ -15,7 +14,7 @@ function format(executed, doctype)
get!(formatdict, :fig_env, nothing)
for chunk in copy(executed)
for chunk in copy(doc.chunks)
result = format_chunk(chunk, formatdict, docformat)
push!(formatted, result)
end

View File

@ -14,14 +14,15 @@ const input_formats = @compat Dict{String, Any}(
@doc "Read and parse input document" ->
function read_doc(document::String, format="noweb"::String)
document = bytestring(open(document) do io
mmap_array(Uint8,(filesize(document),),io)
function read_doc(source::String, format="noweb"::String)
document = bytestring(open(source) do io
mmap_array(Uint8,(filesize(source),),io)
end)
return parse_doc(document, format)
parsed = parse_doc(document, format)
doc = WeaveDoc(source, parsed)
end
@doc "Parse document from string" ->
@doc "Parse chunks from string" ->
function parse_doc(document::String, format="noweb"::String)
#doctext = readall(open(document))
lines = split(document, "\n")

View File

@ -1,3 +1,83 @@
function run(doc::WeaveDoc; doctype = "pandoc", plotlib="Gadfly", informat="noweb", out_path=:doc, fig_path = "figures", fig_ext = nothing)
doc.cwd = get_cwd(doc, out_path)
doc.format = formats[doctype]
set_rc_params(doc.format.formatdict, fig_path, fig_ext)
#Clear sandbox for each document
#Raises a warning, couldn't find a "cleaner"
#way to do it.
eval(parse("module ReportSandBox\nend"))
init_plotting(plotlib)
report = Report(doc.cwd, doc.basename, doc.format.formatdict)
pushdisplay(report)
executed = Any[]
for chunk in copy(doc.chunks)
result_chunk = eval_chunk(chunk, report::Report)
push!(executed, result_chunk)
end
popdisplay(report)
doc.chunks = executed
return doc
end
function run_block(code_str, report::Report)
oldSTDOUT = STDOUT
result = ""
rw, wr = redirect_stdout()
#If there is nothing to read code will hang
println()
try
n = length(code_str)
pos = 1 #The first character is extra line end
while pos < n
oldpos = pos
code, pos = parse(code_str, pos)
s = eval(ReportSandBox, code)
if rcParams[:plotlib] == "Gadfly"
s != nothing && display(s)
end
end
finally
redirect_stdout(oldSTDOUT)
close(wr)
result = readall(rw)
close(rw)
end
return string("\n", result)
end
function run_term(code_str, report::Report)
prompt = "\njulia> "
codestart = "\n\n"*report.formatdict[:codestart]
if haskey(report.formatdict, :indent)
prompt = indent(prompt, report.formatdict[:indent])
end
#Emulate terminal
n = length(code_str)
pos = 2 #The first character is extra line end
while pos < n
oldpos = pos
code, pos = parse(code_str, pos)
report.term_state == :fig && (report.cur_result*= codestart)
prompts = string(prompt, rstrip(code_str[oldpos:(pos-1)]), "\n")
report.cur_result *= prompts
report.term_state = :text
s = eval(ReportSandBox, code)
s != nothing && display(s)
end
return string(report.cur_result)
end
function eval_chunk(chunk::CodeChunk, report::Report)
info("Weaving chunk $(chunk.number) from line $(chunk.start_line)")
@ -47,3 +127,46 @@ end
function eval_chunk(chunk::DocChunk, report::Report)
chunk
end
function init_plotting(plotlib)
if plotlib == nothing
rcParams[:chunk_defaults][:fig] = false
else
l_plotlib = lowercase(plotlib)
rcParams[:chunk_defaults][:fig] = true
if l_plotlib == "winston"
eval(parse("""include(Pkg.dir("Weave","src","winston.jl"))"""))
rcParams[:plotlib] = "Winston"
elseif l_plotlib == "pyplot"
eval(Expr(:using, :PyPlot))
rcParams[:plotlib] = "PyPlot"
elseif l_plotlib == "gadfly"
eval(parse("""include(Pkg.dir("Weave","src","gadfly.jl"))"""))
rcParams[:plotlib] = "Gadfly"
end
end
return nothing
end
function get_cwd(doc::WeaveDoc, out_path)
#Set the output directory
if out_path == :doc
cwd = doc.path
elseif out_path == :pwd
cwd = pwd()
else
cwd = out_path
end
return cwd
end
function set_rc_params(formatdict, fig_path, fig_ext)
if fig_ext == nothing
rcParams[:chunk_defaults][:fig_ext] = formatdict[:fig_ext]
else
rcParams[:chunk_defaults][:fig_ext] = fig_ext
end
rcParams[:chunk_defaults][:fig_path] = fig_path
return nothing
end