rust/src/rustdoc/gen.rs

240 lines
5.2 KiB
Rust
Raw Normal View History

2012-01-17 19:44:32 -06:00
#[doc = "Generate markdown from a document tree"];
import std::io;
import std::io::writer_util;
export mk_pass;
fn mk_pass(
writer: fn~() -> io::writer
) -> pass {
ret fn~(
_srv: astsrv::srv,
doc: doc::cratedoc
) -> doc::cratedoc {
write_markdown(doc, writer());
doc
};
}
type ctxt = {
2012-01-16 23:37:29 -06:00
w: io::writer,
mutable depth: uint
};
2012-01-16 02:33:36 -06:00
fn write_markdown(
doc: doc::cratedoc,
writer: io::writer
) {
let ctxt = {
2012-01-16 23:37:29 -06:00
w: writer,
mutable depth: 1u
2012-01-16 02:33:36 -06:00
};
2012-01-16 23:37:29 -06:00
write_crate(ctxt, doc);
}
fn write_header(ctxt: ctxt, title: str) {
let hashes = str::from_chars(vec::init_elt('#', ctxt.depth));
ctxt.w.write_line(#fmt("%s %s", hashes, title));
ctxt.w.write_line("");
2012-01-16 02:59:18 -06:00
}
fn subsection(ctxt: ctxt, f: fn&()) {
ctxt.depth += 1u;
f();
ctxt.depth -= 1u;
}
2012-01-16 23:37:29 -06:00
fn write_crate(
ctxt: ctxt,
doc: doc::cratedoc
) {
write_header(ctxt, #fmt("Crate %s", doc.topmod.name));
write_top_module(ctxt, doc.topmod);
2012-01-16 17:44:10 -06:00
}
2012-01-16 02:59:18 -06:00
fn write_top_module(
ctxt: ctxt,
moddoc: doc::moddoc
) {
write_mod_contents(ctxt, moddoc);
2012-01-16 02:59:18 -06:00
}
fn write_mod(
ctxt: ctxt,
moddoc: doc::moddoc
) {
2012-01-17 01:10:25 -06:00
write_header(ctxt, #fmt("Module `%s`", moddoc.name));
write_mod_contents(ctxt, moddoc);
2012-01-16 02:59:18 -06:00
}
fn write_mod_contents(
ctxt: ctxt,
moddoc: doc::moddoc
) {
for fndoc in *moddoc.fns {
subsection(ctxt) {||
write_fn(ctxt, fndoc);
}
2012-01-16 02:59:18 -06:00
}
for moddoc in *moddoc.mods {
subsection(ctxt) {||
write_mod(ctxt, moddoc);
}
2012-01-16 02:59:18 -06:00
}
}
fn write_fn(
ctxt: ctxt,
2012-01-16 17:44:10 -06:00
doc: doc::fndoc
2012-01-16 02:59:18 -06:00
) {
2012-01-16 23:37:29 -06:00
write_header(ctxt, #fmt("Function `%s`", doc.name));
2012-01-18 01:39:22 -06:00
write_brief(ctxt, doc.brief);
write_desc(ctxt, doc.desc);
write_args(ctxt, doc.args);
write_return(ctxt, doc.return);
}
fn write_brief(
ctxt: ctxt,
brief: option<str>
) {
alt brief {
some(brief) {
ctxt.w.write_line(brief);
ctxt.w.write_line("");
}
none. { }
}
2012-01-18 01:39:22 -06:00
}
fn write_desc(
ctxt: ctxt,
desc: option<str>
) {
alt desc {
some(desc) {
ctxt.w.write_line(desc);
ctxt.w.write_line("");
}
none. { }
}
2012-01-18 01:39:22 -06:00
}
fn write_args(
ctxt: ctxt,
args: [(str, str)]
) {
for (arg, desc) in args {
ctxt.w.write_str("### Argument `" + arg + "`: ");
ctxt.w.write_str(desc)
}
2012-01-18 01:39:22 -06:00
}
fn write_return(
ctxt: ctxt,
return: option<doc::retdoc>
) {
alt return {
some(doc) {
alt doc.ty {
some(ty) {
ctxt.w.write_line(#fmt("Returns `%s`", ty));
ctxt.w.write_line("");
alt doc.desc {
some(d) {
ctxt.w.write_line(d);
}
none. { }
}
}
none. { fail "unimplemented"; }
}
}
none. { }
}
}
2012-01-16 02:33:36 -06:00
#[cfg(test)]
mod tests {
fn render(source: str) -> str {
let srv = astsrv::mk_srv_from_str(source);
let doc = extract::from_srv(srv, "");
let doc = attr_pass::mk_pass()(srv, doc);
let doc = tystr_pass::mk_pass()(srv, doc);
write_markdown_str(doc)
}
2012-01-16 02:33:36 -06:00
fn write_markdown_str(
doc: doc::cratedoc
2012-01-16 02:33:36 -06:00
) -> str {
let buffer = io::mk_mem_buffer();
let writer = io::mem_buffer_writer(buffer);
write_markdown(doc, writer);
2012-01-16 02:33:36 -06:00
ret io::mem_buffer_str(buffer);
}
#[test]
fn write_markdown_should_write_crate_header() {
let srv = astsrv::mk_srv_from_str("");
let doc = extract::from_srv(srv, "belch");
let doc = attr_pass::mk_pass()(srv, doc);
let markdown = write_markdown_str(doc);
assert str::contains(markdown, "# Crate belch");
2012-01-16 02:33:36 -06:00
}
2012-01-16 02:59:18 -06:00
#[test]
fn write_markdown_should_write_function_header() {
let markdown = render("fn func() { }");
2012-01-16 02:59:18 -06:00
assert str::contains(markdown, "## Function `func`");
}
2012-01-17 01:10:25 -06:00
#[test]
fn write_markdown_should_write_mod_headers() {
let markdown = render("mod moo { }");
2012-01-17 01:10:25 -06:00
assert str::contains(markdown, "## Module `moo`");
}
#[test]
fn should_leave_blank_line_after_header() {
let markdown = render("mod morp { }");
assert str::contains(markdown, "Module `morp`\n\n");
}
#[test]
fn should_leave_blank_line_between_fn_header_and_brief() {
let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
assert str::contains(markdown, "Function `a`\n\nbrief");
}
#[test]
fn should_leave_blank_line_after_brief() {
let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
assert str::contains(markdown, "brief\n\n");
}
#[test]
fn should_leave_blank_line_between_brief_and_desc() {
let markdown = render(
"#[doc(brief = \"brief\", desc = \"desc\")] fn a() { }"
);
assert str::contains(markdown, "brief\n\ndesc");
}
#[test]
fn should_write_return_type_on_new_line() {
let markdown = render("fn a() -> int { }");
assert str::contains(markdown, "\nReturns `int`");
}
#[test]
fn should_write_blank_line_between_return_type_and_next_header() {
let markdown = render(
"fn a() -> int { } \
fn b() -> int { }"
);
assert str::contains(markdown, "Returns `int`\n\n##");
}
2012-01-16 02:33:36 -06:00
}