rustdoc: Vastly simplify the document model

Don't attempt to impose any structure for documenting arguments, return
values, etc.
This commit is contained in:
Brian Anderson 2012-03-09 17:23:56 -08:00
parent 9f4c0d71e5
commit 0905ad2bbe
12 changed files with 38 additions and 1245 deletions

View File

@ -9,10 +9,8 @@ import rustc::syntax::ast;
import rustc::front::attr;
import core::tuple;
export crate_attrs, basic_attrs, fn_attrs, arg_attrs,
variant_attrs, res_attrs, method_attrs;
export parse_crate, parse_basic, parse_fn,
parse_variant, parse_res, parse_method;
export crate_attrs, basic_attrs, variant_attrs;
export parse_crate, parse_basic, parse_variant;
export parse_hidden;
type crate_attrs = {
@ -24,27 +22,10 @@ type basic_attrs = {
desc: option<str>
};
type fn_attrs = {
args: [arg_attrs],
return: option<str>,
failure: option<str>
};
type arg_attrs = {
name: str,
desc: str
};
type variant_attrs = {
desc: option<str>
};
type res_attrs = {
args: [arg_attrs]
};
type method_attrs = fn_attrs;
#[cfg(test)]
mod test {
@ -231,72 +212,6 @@ fn parse_long_doc<T>(
}
}
fn parse_fn(attrs: [ast::attribute]) -> fn_attrs {
parse_long_doc(attrs, parse_fn_long_doc)
}
fn parse_fn_long_doc(items: [@ast::meta_item]) -> fn_attrs {
let return = attr::meta_item_value_from_list(items, "return");
let failure = attr::meta_item_value_from_list(items, "failure");
let args = parse_args(items);
{
args: args,
return: return,
failure: failure
}
}
fn parse_args(items: [@ast::meta_item]) -> [arg_attrs] {
alt attr::meta_item_list_from_list(items, "args") {
some(items) {
vec::filter_map(items) {|item|
option::map(attr::name_value_str_pair(item)) { |pair|
{
name: tuple::first(pair),
desc: tuple::second(pair)
}
}
}
}
none { [] }
}
}
#[test]
fn parse_fn_should_handle_undocumented_functions() {
let source = "";
let attrs = test::parse_attributes(source);
let attrs = parse_fn(attrs);
assert attrs.return == none;
assert vec::len(attrs.args) == 0u;
}
#[test]
fn parse_fn_should_parse_the_return_value_description() {
let source = "#[doc(return = \"return value\")]";
let attrs = test::parse_attributes(source);
let attrs = parse_fn(attrs);
assert attrs.return == some("return value");
}
#[test]
fn parse_fn_should_parse_the_argument_descriptions() {
let source = "#[doc(args(a = \"arg a\", b = \"arg b\"))]";
let attrs = test::parse_attributes(source);
let attrs = parse_fn(attrs);
assert attrs.args[0] == {name: "a", desc: "arg a"};
assert attrs.args[1] == {name: "b", desc: "arg b"};
}
#[test]
fn parse_fn_should_parse_failure_conditions() {
let source = "#[doc(failure = \"it's the fail\")]";
let attrs = test::parse_attributes(source);
let attrs = parse_fn(attrs);
assert attrs.failure == some("it's the fail");
}
fn parse_variant(attrs: [ast::attribute]) -> variant_attrs {
parse_short_doc_or(
attrs,
@ -342,29 +257,6 @@ fn should_parse_variant_long_doc() {
assert attrs.desc == some("a");
}
fn parse_res(attrs: [ast::attribute]) -> res_attrs {
parse_long_doc(attrs, parse_res_long_doc)
}
fn parse_res_long_doc(items: [@ast::meta_item]) -> res_attrs {
{
args: parse_args(items)
}
}
#[test]
fn shoulde_parse_resource_arg() {
let source = "#[doc(args(a = \"b\"))]";
let attrs = test::parse_attributes(source);
let attrs = parse_res(attrs);
assert attrs.args[0].name == "a";
assert attrs.args[0].desc == "b";
}
fn parse_method(attrs: [ast::attribute]) -> method_attrs {
parse_fn(attrs)
}
fn parse_hidden(attrs: [ast::attribute]) -> bool {
parse_short_doc_or(
attrs,

View File

@ -26,9 +26,7 @@ fn run(
let fold = fold::fold({
fold_crate: fold_crate,
fold_item: fold_item,
fold_fn: fold_fn,
fold_enum: fold_enum,
fold_res: fold_res,
fold_iface: fold_iface,
fold_impl: fold_impl
with *fold::default_any_fold(srv)
@ -130,103 +128,12 @@ fn should_extract_native_fn_attributes() {
assert doc.cratemod().nmods()[0].fns[0].desc() == some("test");
}
fn fold_fn(
fold: fold::fold<astsrv::srv>,
doc: doc::fndoc
) -> doc::fndoc {
let srv = fold.ctxt;
let doc = fold::default_seq_fold_fn(fold, doc);
let attrs = parse_item_attrs(srv, doc.id(), attr_parser::parse_fn);
ret merge_fn_attrs(doc, attrs);
fn merge_fn_attrs(
doc: doc::fndoc,
attrs: attr_parser::fn_attrs
) -> doc::fndoc {
ret {
args: merge_arg_attrs(doc.args, attrs.args),
return: merge_ret_attrs(doc.return, attrs.return),
failure: attrs.failure
with doc
};
}
}
fn merge_arg_attrs(
docs: [doc::argdoc],
attrs: [attr_parser::arg_attrs]
) -> [doc::argdoc] {
par::seqmap(docs) {|doc|
alt vec::find(attrs) {|attr|
attr.name == doc.name
} {
some(attr) {
{
desc: some(attr.desc)
with doc
}
}
none { doc }
}
}
// FIXME: Warning when documenting a non-existent arg
}
fn merge_ret_attrs(
doc: doc::retdoc,
attrs: option<str>
) -> doc::retdoc {
{
desc: attrs
with doc
}
}
#[test]
fn should_extract_fn_attributes() {
let doc = test::mk_doc("#[doc = \"test\"] fn a() -> int { }");
assert doc.cratemod().fns()[0].desc() == some("test");
}
#[test]
fn should_extract_fn_arg_attributes() {
let doc = test::mk_doc("#[doc(args(a = \"b\"))] fn c(a: bool) { }");
assert doc.cratemod().fns()[0].args[0].desc == some("b");
}
#[test]
fn should_extract_fn_return_attributes() {
let source = "#[doc(return = \"what\")] fn a() -> int { }";
astsrv::from_str(source) {|srv|
let doc = extract::from_srv(srv, "");
let doc = tystr_pass::mk_pass().f(srv, doc);
let fold = fold::default_any_fold(srv);
let doc = fold_fn(fold, doc.cratemod().fns()[0]);
assert doc.return.desc == some("what");
}
}
#[test]
fn should_preserve_fn_sig() {
let source = "fn a() -> int { }";
astsrv::from_str(source) {|srv|
let doc = extract::from_srv(srv, "");
let doc = tystr_pass::mk_pass().f(srv, doc);
let fold = fold::default_any_fold(srv);
let doc = fold_fn(fold, doc.cratemod().fns()[0]);
assert doc.sig == some("fn a() -> int");
}
}
#[test]
fn should_extract_fn_failure_conditions() {
let doc = test::mk_doc("#[doc(failure = \"what\")] fn a() { }");
assert doc.cratemod().fns()[0].failure == some("what");
}
#[test]
fn should_extract_const_docs() {
let doc = test::mk_doc("#[doc(brief = \"foo\", desc = \"bar\")]\
@ -284,49 +191,6 @@ fn should_extract_variant_docs() {
assert doc.cratemod().enums()[0].variants[0].desc == some("c");
}
fn fold_res(
fold: fold::fold<astsrv::srv>,
doc: doc::resdoc
) -> doc::resdoc {
let srv = fold.ctxt;
let doc = fold::default_seq_fold_res(fold, doc);
let attrs = parse_item_attrs(srv, doc.id(), attr_parser::parse_res);
{
args: par::seqmap(doc.args) {|doc|
alt vec::find(attrs.args) {|attr|
attr.name == doc.name
} {
some(attr) {
{
desc: some(attr.desc)
with doc
}
}
none { doc }
}
}
with doc
}
}
#[test]
fn should_extract_res_docs() {
let doc = test::mk_doc("#[doc(brief = \"a\", desc = \"b\")]\
resource r(b: bool) { }");
assert doc.cratemod().resources()[0].brief() == some("a");
assert doc.cratemod().resources()[0].desc() == some("b");
}
#[test]
fn should_extract_res_arg_docs() {
let doc = test::mk_doc("#[doc(args(a = \"b\"))]\
resource r(a: bool) { }");
assert doc.cratemod().resources()[0].args[0].name == "a";
assert doc.cratemod().resources()[0].args[0].desc == some("b");
}
fn fold_iface(
fold: fold::fold<astsrv::srv>,
doc: doc::ifacedoc
@ -346,30 +210,21 @@ fn merge_method_attrs(
docs: [doc::methoddoc]
) -> [doc::methoddoc] {
type method_attrs = (attr_parser::basic_attrs,
attr_parser::method_attrs);
// Create an assoc list from method name to attributes
let attrs: [(str, method_attrs)] = astsrv::exec(srv) {|ctxt|
let attrs: [(str, attr_parser::basic_attrs)] = astsrv::exec(srv) {|ctxt|
alt ctxt.ast_map.get(item_id) {
ast_map::node_item(@{
node: ast::item_iface(_, methods), _
}, _) {
par::seqmap(methods) {|method|
(method.ident,
(attr_parser::parse_basic(method.attrs),
attr_parser::parse_method(method.attrs)
))
(method.ident, attr_parser::parse_basic(method.attrs))
}
}
ast_map::node_item(@{
node: ast::item_impl(_, _, _, methods), _
}, _) {
par::seqmap(methods) {|method|
(method.ident,
(attr_parser::parse_basic(method.attrs),
attr_parser::parse_method(method.attrs)
))
(method.ident, attr_parser::parse_basic(method.attrs))
}
}
_ { fail "unexpected item" }
@ -378,15 +233,11 @@ fn merge_method_attrs(
vec::map2(docs, attrs) {|doc, attrs|
assert doc.name == tuple::first(attrs);
let basic_attrs = tuple::first(tuple::second(attrs));
let method_attrs = tuple::second(tuple::second(attrs));
let basic_attrs = tuple::second(attrs);
{
brief: basic_attrs.brief,
desc: basic_attrs.desc,
args: merge_arg_attrs(doc.args, method_attrs.args),
return: merge_ret_attrs(doc.return, method_attrs.return),
failure: method_attrs.failure
desc: basic_attrs.desc
with doc
}
}
@ -402,20 +253,10 @@ fn should_extract_iface_docs() {
fn should_extract_iface_method_docs() {
let doc = test::mk_doc(
"iface i {\
#[doc(\
brief = \"brief\",\
desc = \"desc\",\
args(a = \"a\"),\
return = \"return\",\
failure = \"failure\")]\
#[doc = \"desc\"]\
fn f(a: bool) -> bool;\
}");
assert doc.cratemod().ifaces()[0].methods[0].brief == some("brief");
assert doc.cratemod().ifaces()[0].methods[0].desc == some("desc");
assert doc.cratemod().ifaces()[0].methods[0].args[0].desc == some("a");
assert doc.cratemod().ifaces()[0].methods[0].return.desc
== some("return");
assert doc.cratemod().ifaces()[0].methods[0].failure == some("failure");
}
@ -443,19 +284,10 @@ fn should_extract_impl_docs() {
fn should_extract_impl_method_docs() {
let doc = test::mk_doc(
"impl i for int {\
#[doc(\
brief = \"brief\",\
desc = \"desc\",\
args(a = \"a\"),\
return = \"return\",\
failure = \"failure\")]\
#[doc = \"desc\"]\
fn f(a: bool) -> bool { }\
}");
assert doc.cratemod().impls()[0].methods[0].brief == some("brief");
assert doc.cratemod().impls()[0].methods[0].desc == some("desc");
assert doc.cratemod().impls()[0].methods[0].args[0].desc == some("a");
assert doc.cratemod().impls()[0].methods[0].return.desc == some("return");
assert doc.cratemod().impls()[0].methods[0].failure == some("failure");
}
#[test]

View File

@ -50,6 +50,11 @@ type itemdoc = {
reexport: bool
};
type simpleitemdoc = {
item: itemdoc,
sig: option<str>
};
type moddoc = {
item: itemdoc,
items: [itemtag],
@ -61,27 +66,9 @@ type nmoddoc = {
fns: [fndoc]
};
type constdoc = {
item: itemdoc,
ty: option<str>
};
type constdoc = simpleitemdoc;
type fndoc = {
item: itemdoc,
args: [argdoc],
return: retdoc,
failure: option<str>,
sig: option<str>
};
type argdoc = {
name: str,
desc: option<str>
};
type retdoc = {
desc: option<str>
};
type fndoc = simpleitemdoc;
type enumdoc = {
item: itemdoc,
@ -94,11 +81,7 @@ type variantdoc = {
sig: option<str>
};
type resdoc = {
item: itemdoc,
args: [argdoc],
sig: option<str>
};
type resdoc = simpleitemdoc;
type ifacedoc = {
item: itemdoc,
@ -110,9 +93,6 @@ type methoddoc = {
brief: option<str>,
desc: option<str>,
sections: [section],
args: [argdoc],
return: retdoc,
failure: option<str>,
sig: option<str>
};
@ -123,10 +103,7 @@ type impldoc = {
methods: [methoddoc]
};
type tydoc = {
item: itemdoc,
sig: option<str>
};
type tydoc = simpleitemdoc;
type index = {
entries: [index_entry]
@ -355,6 +332,10 @@ impl of item for itemtag {
}
}
impl of item for simpleitemdoc {
fn item() -> itemdoc { self.item }
}
impl of item for moddoc {
fn item() -> itemdoc { self.item }
}
@ -363,22 +344,10 @@ impl of item for nmoddoc {
fn item() -> itemdoc { self.item }
}
impl of item for fndoc {
fn item() -> itemdoc { self.item }
}
impl of item for constdoc {
fn item() -> itemdoc { self.item }
}
impl of item for enumdoc {
fn item() -> itemdoc { self.item }
}
impl of item for resdoc {
fn item() -> itemdoc { self.item }
}
impl of item for ifacedoc {
fn item() -> itemdoc { self.item }
}
@ -387,10 +356,6 @@ impl of item for impldoc {
fn item() -> itemdoc { self.item }
}
impl of item for tydoc {
fn item() -> itemdoc { self.item }
}
impl util<A:item> for A {
fn id() -> ast_id {
self.item().id

View File

@ -68,9 +68,9 @@ fn moddoc_from_mod(
nmoddoc_from_mod(itemdoc, nm)
))
}
ast::item_fn(decl, _, _) {
ast::item_fn(_, _, _) {
some(doc::fntag(
fndoc_from_fn(itemdoc, decl)
fndoc_from_fn(itemdoc)
))
}
ast::item_const(_, _) {
@ -83,9 +83,9 @@ fn moddoc_from_mod(
enumdoc_from_enum(itemdoc, variants)
))
}
ast::item_res(decl, _, _, _, _) {
ast::item_res(_, _, _, _, _) {
some(doc::restag(
resdoc_from_resource(itemdoc, decl)
resdoc_from_resource(itemdoc)
))
}
ast::item_iface(_, methods) {
@ -121,54 +121,25 @@ fn nmoddoc_from_mod(
fns: par::seqmap(module.items) {|item|
let itemdoc = mk_itemdoc(item.id, item.ident);
alt item.node {
ast::native_item_fn(decl, _) {
fndoc_from_fn(itemdoc, decl)
ast::native_item_fn(_, _) {
fndoc_from_fn(itemdoc)
}
}
}
}
}
fn fndoc_from_fn(
itemdoc: doc::itemdoc,
decl: ast::fn_decl
) -> doc::fndoc {
fn fndoc_from_fn(itemdoc: doc::itemdoc) -> doc::fndoc {
{
item: itemdoc,
args: argdocs_from_args(decl.inputs),
return: {
desc: none
},
failure: none,
sig: none
}
}
#[test]
fn should_extract_fn_args() {
let source = "fn a(b: int, c: int) { }";
let ast = parse::from_str(source);
let doc = extract(ast, "");
let fn_ = doc.cratemod().fns()[0];
assert fn_.args[0].name == "b";
assert fn_.args[1].name == "c";
}
fn argdocs_from_args(args: [ast::arg]) -> [doc::argdoc] {
par::seqmap(args, argdoc_from_arg)
}
fn argdoc_from_arg(arg: ast::arg) -> doc::argdoc {
{
name: arg.ident,
desc: none
}
}
fn constdoc_from_const(itemdoc: doc::itemdoc) -> doc::constdoc {
{
item: itemdoc,
ty: none
sig: none
}
}
@ -216,13 +187,9 @@ fn should_extract_enum_variants() {
assert doc.cratemod().enums()[0].variants[0].name == "v";
}
fn resdoc_from_resource(
itemdoc: doc::itemdoc,
decl: ast::fn_decl
) -> doc::resdoc {
fn resdoc_from_resource(itemdoc: doc::itemdoc) -> doc::resdoc {
{
item: itemdoc,
args: argdocs_from_args(decl.inputs),
sig: none
}
}
@ -234,12 +201,6 @@ fn should_extract_resources() {
assert doc.cratemod().resources()[0].name() == "r";
}
#[test]
fn should_extract_resource_args() {
let doc = test::mk_doc("resource r(b: bool) { }");
assert doc.cratemod().resources()[0].args[0].name == "b";
}
fn ifacedoc_from_iface(
itemdoc: doc::itemdoc,
methods: [ast::ty_method]
@ -252,11 +213,6 @@ fn ifacedoc_from_iface(
brief: none,
desc: none,
sections: [],
args: argdocs_from_args(method.decl.inputs),
return: {
desc: none
},
failure: none,
sig: none
}
}
@ -275,12 +231,6 @@ fn should_extract_iface_methods() {
assert doc.cratemod().ifaces()[0].methods[0].name == "f";
}
#[test]
fn should_extract_iface_method_args() {
let doc = test::mk_doc("iface i { fn f(a: bool); }");
assert doc.cratemod().ifaces()[0].methods[0].args[0].name == "a";
}
fn impldoc_from_impl(
itemdoc: doc::itemdoc,
methods: [@ast::method]
@ -295,11 +245,6 @@ fn impldoc_from_impl(
brief: none,
desc: none,
sections: [],
args: argdocs_from_args(method.decl.inputs),
return: {
desc: none
},
failure: none,
sig: none
}
}
@ -324,12 +269,6 @@ fn should_extract_impl_methods() {
assert doc.cratemod().impls()[0].methods[0].name == "f";
}
#[test]
fn should_extract_impl_method_args() {
let doc = test::mk_doc("impl i for int { fn f(a: bool) { } }");
assert doc.cratemod().impls()[0].methods[0].args[0].name == "a";
}
fn tydoc_from_ty(
itemdoc: doc::itemdoc
) -> doc::tydoc {

View File

@ -424,10 +424,7 @@ fn write_fn(
doc.sig,
doc.brief(),
doc.desc(),
doc.sections(),
doc.args,
doc.return,
doc.failure
doc.sections()
);
}
@ -436,16 +433,10 @@ fn write_fnlike(
sig: option<str>,
brief: option<str>,
desc: option<str>,
sections: [doc::section],
args: [doc::argdoc],
return: doc::retdoc,
failure: option<str>
sections: [doc::section]
) {
write_sig(ctxt, sig);
write_common(ctxt, brief, desc, sections);
write_args(ctxt, args);
write_return(ctxt, return);
write_failure(ctxt, failure);
}
fn write_sig(ctxt: ctxt, sig: option<str>) {
@ -509,131 +500,12 @@ fn should_leave_blank_line_between_fn_header_and_sig() {
assert str::contains(markdown, "Function `a`\n\n fn a()");
}
fn write_args(
ctxt: ctxt,
args: [doc::argdoc]
) {
if vec::is_not_empty(args) {
write_lead(ctxt, "Arguments");
ctxt.w.write_line("");
ctxt.w.write_line("");
vec::iter(args) {|arg| write_arg(ctxt, arg) };
ctxt.w.write_line("");
}
}
fn write_arg(ctxt: ctxt, arg: doc::argdoc) {
ctxt.w.write_str(#fmt(
"* `%s`",
arg.name
));
alt arg.desc {
some(desc) {
ctxt.w.write_str(#fmt(" - %s", desc));
}
none { }
}
ctxt.w.write_line("");
}
#[test]
fn should_write_argument_list() {
let source = "fn a(b: int, c: int) { }";
let markdown = test::render(source);
assert str::contains(
markdown,
"__Arguments__: \n\
\n\
* `b`\n\
* `c`\n\
\n"
);
}
#[test]
fn should_not_write_arguments_if_none() {
let source = "fn a() { } fn b() { }";
let markdown = test::render(source);
assert !str::contains(markdown, "Arguments");
}
#[test]
fn should_write_argument_description() {
let source = "#[doc(args(a = \"milk\"))] fn f(a: bool) { }";
let markdown = test::render(source);
assert str::contains(markdown, "`a` - milk");
}
fn write_return(
ctxt: ctxt,
doc: doc::retdoc
) {
alt doc.desc {
some(d) {
write_lead(ctxt, "Return value");
ctxt.w.write_line(d);
ctxt.w.write_line("");
}
none { }
}
}
#[test]
fn should_write_return_type_on_new_line() {
let markdown = test::render(
"#[doc(return = \"test\")] fn a() -> int { }");
assert str::contains(markdown, "\n__Return value__: test");
}
#[test]
fn should_write_blank_line_between_return_type_and_next_header() {
let markdown = test::render(
"#[doc(return = \"test\")] fn a() -> int { } \
fn b() -> int { }"
);
assert str::contains(markdown, "__Return value__: test\n\n##");
}
#[test]
fn should_not_write_return_type_when_there_is_none() {
let markdown = test::render("fn a() { }");
assert !str::contains(markdown, "Return value");
}
#[test]
fn should_write_blank_line_after_return_description() {
let markdown = test::render(
"#[doc(return = \"blorp\")] fn a() -> int { }"
);
assert str::contains(markdown, "blorp\n\n");
}
fn write_failure(ctxt: ctxt, str: option<str>) {
alt str {
some(str) {
write_lead(ctxt, "Failure conditions");
ctxt.w.write_line(str);
ctxt.w.write_line("");
}
none { }
}
}
#[test]
fn should_write_failure_conditions() {
let markdown = test::render(
"#[doc(failure = \"it's the fail\")] fn a () { }");
assert str::contains(
markdown,
"\n\n__Failure conditions__: it's the fail\n\n");
}
fn write_const(
ctxt: ctxt,
doc: doc::constdoc
) {
write_header(ctxt, h2, doc::consttag(doc));
write_sig(ctxt, doc.ty);
write_sig(ctxt, doc.sig);
write_common(ctxt, doc.brief(), doc.desc(), doc.sections());
}
@ -739,7 +611,6 @@ fn write_res(ctxt: ctxt, doc: doc::resdoc) {
write_header(ctxt, h2, doc::restag(doc));
write_sig(ctxt, doc.sig);
write_common(ctxt, doc.brief(), doc.desc(), doc.sections());
write_args(ctxt, doc.args);
}
#[test]
@ -754,13 +625,6 @@ fn should_write_resource_signature() {
assert str::contains(markdown, "\n resource r(a: bool)\n");
}
#[test]
fn should_write_resource_args() {
let markdown = test::render("#[doc(args(a = \"b\"))]\
resource r(a: bool) { }");
assert str::contains(markdown, "__Arguments__: \n\n* `a` - b");
}
fn write_iface(ctxt: ctxt, doc: doc::ifacedoc) {
write_header(ctxt, h2, doc::ifacetag(doc));
write_common(ctxt, doc.brief(), doc.desc(), doc.sections());
@ -778,10 +642,7 @@ fn write_method(ctxt: ctxt, doc: doc::methoddoc) {
doc.sig,
doc.brief,
doc.desc,
doc.sections,
doc.args,
doc.return,
doc.failure
doc.sections
);
}
@ -819,41 +680,6 @@ fn should_write_iface_method_signature() {
assert str::contains(markdown, "\n fn a()");
}
#[test]
fn should_write_iface_method_argument_header() {
let markdown = test::render(
"iface a { fn a(b: int); }");
assert str::contains(markdown, "\n\n__Arguments__: \n\n");
}
#[test]
fn should_write_iface_method_arguments() {
let markdown = test::render(
"iface a { fn a(b: int); }");
assert str::contains(markdown, "* `b`\n");
}
#[test]
fn should_not_write_iface_method_arguments_if_none() {
let markdown = test::render(
"iface a { fn a(); }");
assert !str::contains(markdown, "Arguments");
}
#[test]
fn should_write_iface_method_return_info() {
let markdown = test::render(
"iface a { #[doc(return = \"test\")] fn a() -> int; }");
assert str::contains(markdown, "__Return value__: test");
}
#[test]
fn should_write_iface_method_failure_conditions() {
let markdown = test::render(
"iface a { #[doc(failure = \"nuked\")] fn a(); }");
assert str::contains(markdown, "__Failure conditions__: nuked");
}
fn write_impl(ctxt: ctxt, doc: doc::impldoc) {
write_header(ctxt, h2, doc::impltag(doc));
write_common(ctxt, doc.brief(), doc.desc(), doc.sections());
@ -900,41 +726,6 @@ fn should_write_impl_method_signature() {
assert str::contains(markdown, "\n fn a()");
}
#[test]
fn should_write_impl_method_argument_header() {
let markdown = test::render(
"impl a for int { fn a(b: int) { } }");
assert str::contains(markdown, "\n\n__Arguments__: \n\n");
}
#[test]
fn should_write_impl_method_arguments() {
let markdown = test::render(
"impl a for int { fn a(b: int) { } }");
assert str::contains(markdown, "* `b`\n");
}
#[test]
fn should_not_write_impl_method_arguments_if_none() {
let markdown = test::render(
"impl a for int { fn a() { } }");
assert !str::contains(markdown, "Arguments");
}
#[test]
fn should_write_impl_method_return_info() {
let markdown = test::render(
"impl a for int { #[doc(return = \"test\")] fn a() -> int { } }");
assert str::contains(markdown, "__Return value__: test");
}
#[test]
fn should_write_impl_method_failure_conditions() {
let markdown = test::render(
"impl a for int { #[doc(failure = \"nuked\")] fn a() { } }");
assert str::contains(markdown, "__Failure conditions__: nuked");
}
fn write_type(
ctxt: ctxt,
doc: doc::tydoc

View File

@ -1,129 +0,0 @@
#[doc = "Prunes args, retvals of the document tree that \
contain no documentation"];
export mk_pass;
fn mk_pass() -> pass {
{
name: "prune_undoc_details",
f: run
}
}
fn run(
_srv: astsrv::srv,
doc: doc::doc
) -> doc::doc {
let fold = fold::fold({
fold_fn: fold_fn,
fold_res: fold_res,
fold_iface: fold_iface,
fold_impl: fold_impl
with *fold::default_any_fold(())
});
fold.fold_doc(fold, doc)
}
fn fold_fn(
fold: fold::fold<()>,
doc: doc::fndoc
) -> doc::fndoc {
let doc = fold::default_seq_fold_fn(fold, doc);
{
args: prune_args(doc.args)
with doc
}
}
fn prune_args(docs: [doc::argdoc]) -> [doc::argdoc] {
vec::filter_map(docs) {|doc|
if option::is_some(doc.desc) {
some(doc)
} else {
none
}
}
}
#[test]
fn should_elide_undocumented_arguments() {
let doc = test::mk_doc("#[doc = \"hey\"] fn a(b: int) { }");
assert vec::is_empty(doc.cratemod().fns()[0].args);
}
fn fold_res(
fold: fold::fold<()>,
doc: doc::resdoc
) -> doc::resdoc {
let doc = fold::default_seq_fold_res(fold, doc);
{
args: prune_args(doc.args)
with doc
}
}
#[test]
fn should_elide_undocumented_resource_args() {
let doc = test::mk_doc("#[doc = \"drunk\"]\
resource r(a: bool) { }");
assert vec::is_empty(doc.cratemod().resources()[0].args);
}
fn fold_iface(
fold: fold::fold<()>,
doc: doc::ifacedoc
) -> doc::ifacedoc {
let doc = fold::default_seq_fold_iface(fold, doc);
{
methods: prune_methods(doc.methods)
with doc
}
}
fn prune_methods(docs: [doc::methoddoc]) -> [doc::methoddoc] {
par::anymap(docs) {|doc|
{
args: prune_args(doc.args)
with doc
}
}
}
#[test]
fn should_elide_undocumented_iface_method_args() {
let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }");
assert vec::is_empty(doc.cratemod().ifaces()[0].methods[0].args);
}
fn fold_impl(
fold: fold::fold<()>,
doc: doc::impldoc
) -> doc::impldoc {
let doc = fold::default_seq_fold_impl(fold, doc);
{
methods: prune_methods(doc.methods)
with doc
}
}
#[test]
fn should_elide_undocumented_impl_method_args() {
let doc = test::mk_doc(
"#[doc = \"hey\"] impl i for int { fn a(b: bool) { } }");
assert vec::is_empty(doc.cratemod().impls()[0].methods[0].args);
}
#[cfg(test)]
mod test {
fn mk_doc(source: str) -> doc::doc {
astsrv::from_str(source) {|srv|
let doc = extract::from_srv(srv, "");
let doc = attr_pass::mk_pass().f(srv, doc);
run(srv, doc)
}
}
}

View File

@ -1,377 +0,0 @@
#[doc = "Prunes items of the document tree that contain no documentation"];
export mk_pass;
fn mk_pass() -> pass {
{
name: "prune_undoc_items",
f: run
}
}
type ctxt = {
mutable have_docs: bool
};
fn run(
_srv: astsrv::srv,
doc: doc::doc
) -> doc::doc {
let ctxt = {
mutable have_docs: true
};
let fold = fold::fold({
fold_mod: fold_mod,
fold_fn: fold_fn,
fold_const: fold_const,
fold_enum: fold_enum,
fold_res: fold_res,
fold_iface: fold_iface,
fold_impl: fold_impl,
fold_type: fold_type
with *fold::default_any_fold(ctxt)
});
fold.fold_doc(fold, doc)
}
fn fold_mod(
fold: fold::fold<ctxt>,
doc: doc::moddoc
) -> doc::moddoc {
let doc = {
items: vec::filter_map(doc.items) {|itemtag|
alt itemtag {
doc::modtag(moddoc) {
let doc = fold.fold_mod(fold, moddoc);
if fold.ctxt.have_docs {
some(doc::modtag(doc))
} else {
none
}
}
doc::fntag(fndoc) {
let doc = fold.fold_fn(fold, fndoc);
if fold.ctxt.have_docs {
some(doc::fntag(doc))
} else {
none
}
}
doc::consttag(constdoc) {
let doc = fold.fold_const(fold, constdoc);
if fold.ctxt.have_docs {
some(doc::consttag(doc))
} else {
none
}
}
doc::enumtag(enumdoc) {
let doc = fold.fold_enum(fold, enumdoc);
if fold.ctxt.have_docs {
some(doc::enumtag(doc))
} else {
none
}
}
doc::restag(resdoc) {
let doc = fold.fold_res(fold, resdoc);
if fold.ctxt.have_docs {
some(doc::restag(doc))
} else {
none
}
}
doc::ifacetag(ifacedoc) {
let doc = fold.fold_iface(fold, ifacedoc);
if fold.ctxt.have_docs {
some(doc::ifacetag(doc))
} else {
none
}
}
doc::impltag(impldoc) {
let doc = fold.fold_impl(fold, impldoc);
if fold.ctxt.have_docs {
some(doc::impltag(doc))
} else {
none
}
}
doc::tytag(tydoc) {
let doc = fold.fold_type(fold, tydoc);
if fold.ctxt.have_docs {
some(doc::tytag(doc))
} else {
none
}
}
_ { some(itemtag) }
}
}
with fold::default_any_fold_mod(fold, doc)
};
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| vec::is_not_empty(doc.items);
ret doc;
}
fn fold_fn(
fold: fold::fold<ctxt>,
doc: doc::fndoc
) -> doc::fndoc {
let doc = fold::default_seq_fold_fn(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| args_have_docs(doc.args)
|| doc.return.desc != none
|| doc.failure != none;
ret doc;
}
fn args_have_docs(docs: [doc::argdoc]) -> bool {
vec::foldl(false, docs) {|accum, doc|
accum || doc.desc != none
}
}
#[test]
fn should_elide_fns_with_undocumented_arguments() {
let doc = test::mk_doc("fn a(a: int) { }");
assert vec::is_empty(doc.cratemod().fns());
}
#[test]
fn should_not_elide_fns_with_documented_arguments() {
let doc = test::mk_doc("#[doc(args(a = \"b\"))] fn a(a: int) { }");
assert vec::is_not_empty(doc.cratemod().fns());
}
#[test]
fn should_not_elide_fns_with_documented_failure_conditions() {
let doc = test::mk_doc("#[doc(failure = \"yup\")] fn a() { }");
assert vec::is_not_empty(doc.cratemod().fns());
}
#[test]
fn should_elide_undocumented_mods() {
let doc = test::mk_doc("mod a { }");
assert vec::is_empty(doc.cratemod().mods());
}
#[test]
fn should_not_elide_undocument_mods_with_documented_mods() {
let doc = test::mk_doc("mod a { #[doc = \"b\"] mod b { } }");
assert vec::is_not_empty(doc.cratemod().mods());
}
#[test]
fn should_not_elide_undocument_mods_with_documented_fns() {
let doc = test::mk_doc("mod a { #[doc = \"b\"] fn b() { } }");
assert vec::is_not_empty(doc.cratemod().mods());
}
#[test]
fn should_elide_undocumented_fns() {
let doc = test::mk_doc("fn a() { }");
assert vec::is_empty(doc.cratemod().fns());
}
fn fold_const(
fold: fold::fold<ctxt>,
doc: doc::constdoc
) -> doc::constdoc {
let doc = fold::default_seq_fold_const(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none;
ret doc;
}
#[test]
fn should_elide_undocumented_consts() {
let doc = test::mk_doc("const a: bool = true;");
assert vec::is_empty(doc.cratemod().consts());
}
fn fold_enum(fold: fold::fold<ctxt>, doc: doc::enumdoc) -> doc::enumdoc {
let doc = {
variants: vec::filter_map(doc.variants) {|variant|
if variant.desc != none {
some(variant)
} else {
none
}
}
with fold::default_seq_fold_enum(fold, doc)
};
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| vec::is_not_empty(doc.variants);
ret doc;
}
#[test]
fn should_elide_undocumented_enums() {
let doc = test::mk_doc("enum a { b }");
assert vec::is_empty(doc.cratemod().enums());
}
#[test]
fn should_elide_undocumented_variants() {
let doc = test::mk_doc("#[doc = \"a\"] enum a { b }");
assert vec::is_empty(doc.cratemod().enums()[0].variants);
}
#[test]
fn should_not_elide_enums_with_documented_variants() {
let doc = test::mk_doc("enum a { #[doc = \"a\"] b }");
assert vec::is_not_empty(doc.cratemod().enums());
}
fn fold_res(fold: fold::fold<ctxt>, doc: doc::resdoc) -> doc::resdoc {
let doc = fold::default_seq_fold_res(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| args_have_docs(doc.args);
ret doc;
}
#[test]
fn should_elide_undocumented_resources() {
let doc = test::mk_doc("resource r(a: bool) { }");
assert vec::is_empty(doc.cratemod().resources());
}
#[test]
fn should_not_elide_resources_with_documented_args() {
let doc = test::mk_doc("#[doc(args(a = \"drunk\"))]\
resource r(a: bool) { }");
assert vec::is_not_empty(doc.cratemod().resources());
}
fn fold_iface(
fold: fold::fold<ctxt>,
doc: doc::ifacedoc
) -> doc::ifacedoc {
let doc = fold::default_seq_fold_iface(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| methods_have_docs(doc.methods);
ret doc;
}
fn methods_have_docs(docs: [doc::methoddoc]) -> bool {
vec::foldl(false, docs) {|accum, doc|
accum
|| doc.brief != none
|| doc.desc != none
|| args_have_docs(doc.args)
|| doc.return.desc != none
|| doc.failure != none
}
}
#[test]
fn should_elide_undocumented_ifaces() {
let doc = test::mk_doc("iface i { fn a(); }");
assert vec::is_empty(doc.cratemod().ifaces());
}
#[test]
fn should_not_elide_documented_ifaces() {
let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }");
assert vec::is_not_empty(doc.cratemod().ifaces());
}
#[test]
fn should_elide_ifaces_with_undocumented_args() {
let doc = test::mk_doc("iface i { fn a(b: bool); }");
assert vec::is_empty(doc.cratemod().ifaces());
}
#[test]
fn should_not_elide_ifaces_with_documented_methods() {
let doc = test::mk_doc("iface i { #[doc = \"hey\"] fn a(); }");
assert vec::is_not_empty(doc.cratemod().ifaces());
}
#[test]
fn should_not_elide_undocumented_iface_methods() {
let doc = test::mk_doc("#[doc = \"hey\"] iface i { fn a(); }");
assert vec::is_not_empty(doc.cratemod().ifaces()[0].methods);
}
fn fold_impl(
fold: fold::fold<ctxt>,
doc: doc::impldoc
) -> doc::impldoc {
let doc = fold::default_seq_fold_impl(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none
|| methods_have_docs(doc.methods);
ret doc;
}
#[test]
fn should_elide_undocumented_impls() {
let doc = test::mk_doc("impl i for int { fn a() { } }");
assert vec::is_empty(doc.cratemod().impls());
}
#[test]
fn should_not_elide_documented_impls() {
let doc = test::mk_doc("#[doc = \"hey\"] impl i for int { fn a() { } }");
assert vec::is_not_empty(doc.cratemod().impls());
}
#[test]
fn should_not_elide_impls_with_documented_methods() {
let doc = test::mk_doc("impl i for int { #[doc = \"hey\"] fn a() { } }");
assert vec::is_not_empty(doc.cratemod().impls());
}
#[test]
fn should_not_elide_undocumented_impl_methods() {
let doc = test::mk_doc("#[doc = \"hey\"] impl i for int { fn a() { } }");
assert vec::is_not_empty(doc.cratemod().impls()[0].methods);
}
fn fold_type(
fold: fold::fold<ctxt>,
doc: doc::tydoc
) -> doc::tydoc {
let doc = fold::default_seq_fold_type(fold, doc);
fold.ctxt.have_docs =
doc.brief() != none
|| doc.desc() != none;
ret doc;
}
#[test]
fn should_elide_undocumented_types() {
let doc = test::mk_doc("type t = int;");
assert vec::is_empty(doc.cratemod().types());
}
#[cfg(test)]
mod test {
fn mk_doc(source: str) -> doc::doc {
astsrv::from_str(source) {|srv|
let doc = extract::from_srv(srv, "");
let doc = attr_pass::mk_pass().f(srv, doc);
run(srv, doc)
}
}
}

View File

@ -24,8 +24,6 @@ mod fold;
mod path_pass;
mod attr_pass;
mod tystr_pass;
mod prune_undoc_details_pass;
mod prune_undoc_items_pass;
mod prune_unexported_pass;
mod prune_hidden_pass;
mod desc_to_brief_pass;

View File

@ -143,9 +143,6 @@ fn run(config: config::config) {
tystr_pass::mk_pass(),
path_pass::mk_pass(),
attr_pass::mk_pass(),
prune_undoc_details_pass::mk_pass(),
// FIXME: This pass should be optional
// prune_undoc_items_pass::mk_pass(),
prune_hidden_pass::mk_pass(),
desc_to_brief_pass::mk_pass(),
unindent_pass::mk_pass(),

View File

@ -20,9 +20,7 @@ fn run(
) -> doc::doc {
let fold = fold::fold({
fold_item: fold_item,
fold_fn: fold_fn,
fold_enum: fold_enum,
fold_res: fold_res,
fold_iface: fold_iface,
fold_impl: fold_impl
with *fold::default_any_fold(op)
@ -54,26 +52,6 @@ fn apply_to_sections(op: op, sections: [doc::section]) -> [doc::section] {
}
}
fn fold_fn(fold: fold::fold<op>, doc: doc::fndoc) -> doc::fndoc {
let fold_ctxt = fold.ctxt;
let doc = fold::default_seq_fold_fn(fold, doc);
{
args: par::anymap(doc.args) {|doc|
{
desc: maybe_apply_op(fold_ctxt, doc.desc)
with doc
}
},
return: {
desc: maybe_apply_op(fold.ctxt, doc.return.desc)
with doc.return
},
failure: maybe_apply_op(fold.ctxt, doc.failure)
with doc
}
}
fn fold_enum(fold: fold::fold<op>, doc: doc::enumdoc) -> doc::enumdoc {
let fold_ctxt = fold.ctxt;
let doc = fold::default_seq_fold_enum(fold, doc);
@ -89,21 +67,6 @@ fn fold_enum(fold: fold::fold<op>, doc: doc::enumdoc) -> doc::enumdoc {
}
}
fn fold_res(fold: fold::fold<op>, doc: doc::resdoc) -> doc::resdoc {
let fold_ctxt = fold.ctxt;
let doc = fold::default_seq_fold_res(fold, doc);
{
args: par::anymap(doc.args) {|arg|
{
desc: maybe_apply_op(fold_ctxt, arg.desc)
with arg
}
}
with doc
}
}
fn fold_iface(fold: fold::fold<op>, doc: doc::ifacedoc) -> doc::ifacedoc {
let doc = fold::default_seq_fold_iface(fold, doc);
@ -118,18 +81,7 @@ fn apply_to_methods(op: op, docs: [doc::methoddoc]) -> [doc::methoddoc] {
{
brief: maybe_apply_op(op, doc.brief),
desc: maybe_apply_op(op, doc.desc),
sections: apply_to_sections(op, doc.sections),
args: par::anymap(doc.args) {|doc|
{
desc: maybe_apply_op(op, doc.desc)
with doc
}
},
return: {
desc: maybe_apply_op(op, doc.return.desc)
with doc.return
},
failure: maybe_apply_op(op, doc.failure)
sections: apply_to_sections(op, doc.sections)
with doc
}
}
@ -174,13 +126,6 @@ fn should_execute_op_on_resource_desc() {
assert doc.cratemod().resources()[0].desc() == some("a");
}
#[test]
fn should_execute_op_on_resource_args() {
let doc = test::mk_doc(
"#[doc(args(a = \" a \"))] resource r(a: bool) { }");
assert doc.cratemod().resources()[0].args[0].desc == some("a");
}
#[test]
fn should_execute_op_on_iface_brief() {
let doc = test::mk_doc(
@ -209,26 +154,6 @@ fn should_execute_op_on_iface_method_desc() {
assert doc.cratemod().ifaces()[0].methods[0].desc == some("a");
}
#[test]
fn should_execute_op_on_iface_method_args() {
let doc = test::mk_doc(
"iface i { #[doc(args(a = \" a \"))] fn a(a: bool); }");
assert doc.cratemod().ifaces()[0].methods[0].args[0].desc == some("a");
}
#[test]
fn should_execute_op_on_iface_method_return() {
let doc = test::mk_doc(
"iface i { #[doc(return = \" a \")] fn a() -> int; }");
assert doc.cratemod().ifaces()[0].methods[0].return.desc == some("a");
}
#[test]
fn should_execute_op_on_iface_method_failure_condition() {
let doc = test::mk_doc("iface i { #[doc(failure = \" a \")] fn a(); }");
assert doc.cratemod().ifaces()[0].methods[0].failure == some("a");
}
#[test]
fn should_execute_op_on_impl_brief() {
let doc = test::mk_doc(
@ -257,28 +182,6 @@ fn should_execute_op_on_impl_method_desc() {
assert doc.cratemod().impls()[0].methods[0].desc == some("a");
}
#[test]
fn should_execute_op_on_impl_method_args() {
let doc = test::mk_doc(
"impl i for int { #[doc(args(a = \" a \"))] fn a(a: bool) { } }");
assert doc.cratemod().impls()[0].methods[0].args[0].desc == some("a");
}
#[test]
fn should_execute_op_on_impl_method_return() {
let doc = test::mk_doc(
"impl i for int { #[doc(return = \" a \")] fn a() -> int { fail } }");
assert doc.cratemod().impls()[0].methods[0].return.desc == some("a");
}
#[test]
fn should_execute_op_on_impl_method_failure_condition() {
let doc = test::mk_doc(
"impl i for int { #[doc(failure = \" a \")] fn a() { } }");
assert doc.cratemod().impls()[0].methods[0].failure == some("a");
}
#[test]
fn should_execute_op_on_type_brief() {
let doc = test::mk_doc(

View File

@ -40,24 +40,6 @@ fn should_trim_fn() {
assert doc.cratemod().fns()[0].desc() == some("desc");
}
#[test]
fn should_trim_args() {
let doc = test::mk_doc("#[doc(args(a = \"\na\n\"))] fn a(a: int) { }");
assert doc.cratemod().fns()[0].args[0].desc == some("a");
}
#[test]
fn should_trim_ret() {
let doc = test::mk_doc("#[doc(return = \"\na\n\")] fn a() -> int { }");
assert doc.cratemod().fns()[0].return.desc == some("a");
}
#[test]
fn should_trim_failure_conditions() {
let doc = test::mk_doc("#[doc(failure = \"\na\n\")] fn a() -> int { }");
assert doc.cratemod().fns()[0].failure == some("a");
}
#[cfg(test)]
mod test {
fn mk_doc(source: str) -> doc::doc {

View File

@ -81,7 +81,7 @@ fn fold_const(
let srv = fold.ctxt;
{
ty: some(astsrv::exec(srv) {|ctxt|
sig: some(astsrv::exec(srv) {|ctxt|
alt check ctxt.ast_map.get(doc.id()) {
ast_map::node_item(@{
node: ast::item_const(ty, _), _
@ -97,7 +97,7 @@ fn fold_const(
#[test]
fn should_add_const_types() {
let doc = test::mk_doc("const a: bool = true;");
assert doc.cratemod().consts()[0].ty == some("bool");
assert doc.cratemod().consts()[0].sig == some("bool");
}
fn fold_enum(