v0.3 rename / rebrand pedantic lint to help coverage; rewrite again

factor-shell
Cat Stevens 2018-02-03 13:16:53 -05:00 committed by John Benediktsson
parent de3d01daef
commit 0b6e1b2a5c
9 changed files with 289 additions and 166 deletions

View File

@ -0,0 +1,137 @@
USING: help help.lint.coverage help.lint.coverage.private help.markup help.syntax kernel
sequences strings vocabs words ;
IN: help.lint.coverage
<PRIVATE
: $related-subsections ( element -- )
[ related-words ] [ $subsections ] bi ;
PRIVATE>
ABOUT: "help.lint.coverage"
ARTICLE: "help.lint.coverage" "Help coverage linting"
"The " { $vocab-link "help.lint.coverage" } " vocabulary implements a very picky documentation completeness checker."
$nl
"The documentation coverage linter requires most words to have " { $link POSTPONE: HELP: } " declarations defining some of the "
{ $links $values $description $error-description $class-description $examples } " sections (see " { $links "element-types" } ")."
$nl
"This vocabulary is intended to be used alongside and after " { $vocab-link "help.lint" } ", not as a replacement for it."
$nl
"These words are provided to aid in writing more complete documentation:"
{ $related-subsections
<word-help-coverage>
<vocab-help-coverage>
<prefix-help-coverage>
}
"Coverage reports:"
{ $related-subsections
word-help-coverage
print-coverage
} ;
{ <word-help-coverage> <vocab-help-coverage> <prefix-help-coverage> word-help-coverage }
related-words
HELP: word-help-coverage
{ $class-description "A documentation coverage report for a single word." } ;
HELP: print-coverage
{ $values { "coverage" word-help-coverage } }
{ $contract "Displays a coverage object." }
{ $examples
{ $example
"USING: help.lint.coverage io ;"
"\\ <word-help-coverage> <word-help-coverage> print-coverage"
"Word '<word-help-coverage>' has 100% help coverage"
}
} ;
HELP: <prefix-help-coverage>
{ $values { "prefix" string } { "private?" boolean } { "coverage" sequence } }
{ $description "Runs the help coverage checker on every child vocabulary of the given " { $snippet "prefix" } ", including the base vocabulary. If " { $snippet "private?" } " is " { $snippet "f" } ", the prefix's child " { $snippet ".private" } " vocabularies are not checked. If " { $snippet "private?" } " is " { $snippet "t" } ", " { $emphasis "all" } " child vocabularies are checked." }
{ $examples
{ $example
"USING: help.lint.coverage prettyprint ;"
"\"help.lint.coverage\" f <prefix-help-coverage> ."
"{
{
T{ word-help-coverage
{ word-name <prefix-help-coverage> }
{ 100%-coverage? t }
}
T{ word-help-coverage
{ word-name <vocab-help-coverage> }
{ 100%-coverage? t }
}
T{ word-help-coverage
{ word-name <word-help-coverage> }
{ 100%-coverage? t }
}
T{ word-help-coverage
{ word-name print-coverage }
{ 100%-coverage? t }
}
T{ word-help-coverage
{ word-name word-help-coverage }
{ 100%-coverage? t }
}
T{ word-help-coverage
{ word-name word-help-coverage? }
{ 100%-coverage? t }
}
}
{ }
}"
}
} ;
HELP: <word-help-coverage>
{ $values { "word" { $or string word } } { "coverage" word-help-coverage } }
{ $contract "Looks up a word in the current scope and generates a documentation coverage report for it."}
{ $examples
{ $example
"USING: help.lint.coverage prettyprint ;"
"\\ <word-help-coverage> <word-help-coverage> ."
"T{ word-help-coverage
{ word-name <word-help-coverage> }
{ 100%-coverage? t }
}"
}
} ;
HELP: <vocab-help-coverage>
{ $values { "vocab-spec" { $or vocab string } } { "coverage" sequence } }
{ $description "Runs the help coverage checker on the vocabulary in the given " { $snippet "vocab-spec" } "." }
{ $examples
{ $example
"USING: help.lint.coverage prettyprint ;"
"\"help.lint.coverage\" <vocab-help-coverage> ."
"{
T{ word-help-coverage
{ word-name <prefix-help-coverage> }
{ 100%-coverage? t }
}
T{ word-help-coverage
{ word-name <vocab-help-coverage> }
{ 100%-coverage? t }
}
T{ word-help-coverage
{ word-name <word-help-coverage> }
{ 100%-coverage? t }
}
T{ word-help-coverage
{ word-name print-coverage }
{ 100%-coverage? t }
}
T{ word-help-coverage
{ word-name word-help-coverage }
{ 100%-coverage? t }
}
T{ word-help-coverage
{ word-name word-help-coverage? }
{ 100%-coverage? t }
}
}"
}
} ;

View File

@ -0,0 +1,36 @@
USING: help.lint.coverage help.lint.coverage.private help.markup
help.syntax kernel math.matrices sorting tools.test vocabs ;
IN: help.lint.coverage.tests
<PRIVATE
: empty ( a v -- x y ) ;
: nonexistent ( a v -- x y ) ;
: defined ( x -- x ) ;
HELP: empty { $examples } ;
HELP: nonexistent ;
HELP: defined { $examples { $example "USING: x ;" "blah" "hahaha" } } ;
PRIVATE>
{ t } [ \ empty empty-examples? ] unit-test
{ f } [ \ nonexistent empty-examples? ] unit-test
{ f } [ \ defined empty-examples? ] unit-test
{ f } [ \ keep empty-examples? ] unit-test
{ { $description $values } } [ \ empty missing-sections natural-sort ] unit-test
{ { $description $values } } [ \ defined missing-sections natural-sort ] unit-test
{ { } } [ \ keep missing-sections ] unit-test
{ { "a.b" "a.b.c" } } [ { "a.b" "a.b.private" "a.b.c.private" "a.b.c" } filter-private ] unit-test
{ "sections" } [ 0 "section" ?pluralize ] unit-test
{ "section" } [ 1 "section" ?pluralize ] unit-test
{ "sections" } [ 10 "section" ?pluralize ] unit-test
{ { $examples } } [ \ empty word-defines-sections ] unit-test
{ { $examples } } [ \ defined word-defines-sections ] unit-test
{ { } } [ \ nonexistent word-defines-sections ] unit-test
{ { $values $description $examples } } [ \ keep word-defines-sections ] unit-test
{ { $values $contract $examples } } [ \ <word-help-coverage> word-defines-sections ] unit-test
{ eye } [ "eye" loaded-vocab-names resolve-name-in ] unit-test

View File

@ -0,0 +1,115 @@
USING: accessors arrays classes classes.error combinators
combinators.short-circuit continuations english eval formatting
fry generic help help.lint help.lint.checks help.markup io
kernel math namespaces parser prettyprint sequences sets sorting
splitting strings summary vocabs words ;
FROM: namespaces => set ;
IN: help.lint.coverage
TUPLE: word-help-coverage
{ word-name word initial: POSTPONE: f }
{ omitted-sections sequence initial: { } }
{ empty-examples? boolean initial: f }
{ 100%-coverage? boolean initial: f } ;
<PRIVATE
! <<
CONSTANT: ignored-words {
$low-level-note
$prettyprinting-note
$values-x/y
$parsing-note
$io-error
$shuffle
$complex-shuffle
$nl
}
! >>
DEFER: ?pluralize
M: word-help-coverage summary
[ word-name>> [ vocabulary>> ] [ name>> ] bi "[%s] %s: " sprintf ] keep
dup 100%-coverage?>>
[ drop "full help coverage" append ]
[
[ empty-examples?>> "defined empty { $examples }, " "" ? ]
[ omitted-sections>> dup [
length "section" ?pluralize
] dip
[ name>> ] map ", " join
] bi
"%sshould define help %s %s" sprintf append
] if ; inline
: sorted-loaded-child-vocabs ( prefix -- assoc )
loaded-child-vocab-names natural-sort ; inline
: resolve-name-in ( name namespaces -- word )
"syntax" swap remove " " join
"USING: " " ; \\ " surround
prepend eval( -- word ) ;
: filter-private ( seq -- no-private )
[ ".private" ?tail nip not ] filter ; inline
: ?pluralize ( n singular -- singular/plural )
count-of-things " " split1 nip ;
: should-define ( word -- spec )
{
{ [ dup predicate? ] [ drop { } ] } ! predicate?s have generated docs
{ [ dup error-class? ] [ drop { $values $description $error-description } ] }
{ [ dup class? ] [ drop { $class-description } ] }
{ [ dup generic? ] [ drop { $values $contract $examples } ] }
{ [ dup word? ] [ drop { $values $description $examples } ] }
[ drop no-cond ]
} cond ;
: word-defines-sections ( word -- seq )
word-help [ ignored-words member? not ] filter [ ?first ] map ;
! only words that need examples, need to have them nonempty
! not defining examples is not the same as an empty { $examples }
: empty-examples? ( word -- ? )
word-help \ $examples swap elements [ f ] [ first rest empty? ] if-empty ;
: missing-sections ( word -- missing )
[ should-define ] [ word-defines-sections ] bi diff ;
PRIVATE>
GENERIC: print-coverage ( coverage-seq -- )
M: sequence print-coverage
[
[ print-coverage ] each
] [
[ [ 100%-coverage?>> ] count ] [ length ] bi /f
100 *
"\n%3.1f%% of words have complete documentation\n"
printf
] bi ;
M: word-help-coverage print-coverage
summary print ;
GENERIC: <word-help-coverage> ( word -- coverage )
M: word <word-help-coverage>
dup
[ missing-sections ]
[ empty-examples? ] bi
2dup 2array { { } f } =
word-help-coverage boa ; inline
M: string <word-help-coverage>
loaded-vocab-names resolve-name-in <word-help-coverage> ; inline
: <vocab-help-coverage> ( vocab-spec -- coverage )
[ auto-use? off vocab-words natural-sort [ <word-help-coverage> ] map ] with-scope ;
: <prefix-help-coverage> ( prefix private? -- coverage )
[
auto-use? off group-articles vocab-articles set
[ sorted-loaded-child-vocabs ] dip not
[ filter-private ] when
[ <vocab-help-coverage> ] map
] with-scope ;

View File

@ -0,0 +1 @@
Documentation coverage linter

View File

@ -1,83 +0,0 @@
USING: help help.lint.pedantic help.lint.pedantic.private help.markup help.syntax kernel
sequences strings vocabs words ;
IN: help.lint.pedantic
ABOUT: "help.lint.pedantic"
ARTICLE: "help.lint.pedantic" "Pedantic help coverage"
"pedant, " { $emphasis "n." } " one who pays more attention to formal rules and book learning than they merit."
$nl
"The " { $vocab-link "help.lint.pedantic" } " vocabulary implements a very picky documentation completeness checker -- your very own documentation pedant."
$nl
"The pedantic linter requires most words to have documentation defining the "
{ $links $values $description $error-description $class-description $examples } " sections (see " { $links "element-types" } ")."
$nl
"This vocabulary is intended to be used alongside and after " { $vocab-link "help.lint" } ", not as a replacement for it."
$nl
"These words are provided to aid in writing more complete documentation:"
{ $subsections
word-pedant
vocab-pedant
prefix-pedant
} ;
{ word-pedant vocab-pedant prefix-pedant } related-words
{ missing-sections empty-examples } related-words
HELP: missing-sections
{ $values { "missing-sections" sequence } { "word-name" word } }
{ $description "Throws an " { $link missing-sections } " error." }
{ $error-description "Thrown when a word's documentation is missing one or more sections required for it by " { $link should-define } "." } ;
HELP: empty-examples
{ $values { "word-name" word } }
{ $description "Throws an " { $link empty-examples } " error." }
{ $error-description "Thrown when a word's " { $link $examples } " section is missing or empty." } ;
HELP: prefix-pedant
{ $values { "prefix" string } { "private?" boolean } }
{ $description "Runs the help coverage checker on every child vocabulary of the given " { $snippet "prefix" } ", including the base vocabulary. If " { $snippet "private?" } " is " { $snippet "f" } ", the prefix's child " { $snippet ".private" } " vocabularies are not checked. If " { $snippet "private?" } " is " { $snippet "t" } ", " { $emphasis "all" } " child vocabularies are checked." }
{ $errors
{ $link empty-examples } " if a word has an empty " { $snippet "$examples" } " section
"
{ $link missing-sections } " if a word is missing a section entirely"
}
{ $examples
{ $example
"USING: help.lint.pedantic ;"
"\"help.lint.pedantic\" f prefix-pedant"
""
}
} ;
HELP: word-pedant
{ $values { "word" { $or string word } } }
{ $description "Runs the help coverage checker on the word described by " { $snippet "word-desc" } "." }
{ $errors
{ $link empty-examples } " if a word has an empty " { $snippet "$examples" } " section
"
{ $link missing-sections } " if a word is missing a section entirely"
}
{ $examples
{ $example
"USING: help.lint.pedantic ;"
"\\ word-pedant word-pedant"
""
}
} ;
HELP: vocab-pedant
{ $values { "vocab-spec" { $or vocab string } } }
{ $description "Runs the help coverage checker on the vocabulary in the given " { $snippet "vocab-spec" } "." }
{ $errors
{ $link empty-examples } " if a word has an empty " { $snippet "$examples" } " section
"
{ $link missing-sections } " if a word is missing a section entirely"
}
{ $examples
{ $example
"USING: help.lint.pedantic ;"
"\"help.lint.pedantic\" vocab-pedant"
""
}
} ;

View File

@ -1,82 +0,0 @@
USING: accessors arrays classes combinators
combinators.short-circuit continuations english eval formatting
fry help help.lint help.lint.checks help.markup kernel
namespaces parser prettyprint sequences sets sorting splitting
strings summary vocabs words ;
FROM: namespaces => set ;
IN: help.lint.pedantic
ERROR: missing-sections
{ word-name word initial: POSTPONE: f }
{ missing-sections sequence initial: { } } ;
ERROR: empty-examples { word-name initial: POSTPONE: f } ;
<PRIVATE
DEFER: ?pluralize
M: empty-examples summary
word-name>> "Word '%s' has defined empty $examples section" sprintf ;
M: missing-sections summary
[ word-name>> ] [
missing-sections>> dup [
length "section" ?pluralize
] dip
[ name>> ] map ", " join
] bi
"Word '%s' should define help %s: %s" sprintf ;
: sorted-loaded-child-vocabs ( prefix -- assoc )
loaded-child-vocab-names natural-sort ; inline
: filter-private ( seq -- no-private )
[ ".private" ?tail nip not ] filter ; inline
: ?pluralize ( n singular -- singular/plural )
count-of-things " " split1 nip ;
: should-define ( word -- spec )
{
{ [ dup predicate? ] [ drop { } ] } ! predicate?s have generated docs
{ [ dup error? ] [ drop { $values $description $error-description } ] }
{ [ dup class? ] [ drop { $class-description } ] }
{ [ dup word? ] [ drop { $values $description $examples } ] }
[ drop no-cond ]
} cond ;
: word-defines-sections ( word -- seq )
word-help [ first ] map ;
: missing-examples? ( word -- ? )
word-help \ $examples swap elements empty? ;
: check-examples ( word -- )
[ missing-examples? ] keep '[ _ empty-examples ] when ;
: check-sections ( word -- )
[ ] [ should-define ] [ word-defines-sections ] tri
diff [ drop ] [ missing-sections ] if-empty ;
PRIVATE>
GENERIC: word-pedant ( word -- )
M: word word-pedant
{
{ [ dup predicate? ] [ drop ] }
{ [ dup error? ] [ check-sections ] }
{ [ dup word? ] [ [ check-sections ] [ check-examples ] bi ] }
[ drop no-cond ]
} cond ; inline
M: string word-pedant
"\\ " prepend eval( -- word ) word-pedant ; inline
: vocab-pedant ( vocab-spec -- )
[ auto-use? off vocab-words natural-sort [ word-pedant ] each ] with-scope ;
: prefix-pedant ( prefix private? -- )
[
auto-use? off group-articles vocab-articles set
[ sorted-loaded-child-vocabs ] dip not
[ filter-private ] when
[ vocab-pedant ] each
] with-scope ;

View File

@ -1 +0,0 @@
Pedantic help coverage checker