v0.3 rename / rebrand pedantic lint to help coverage; rewrite again
parent
de3d01daef
commit
0b6e1b2a5c
|
@ -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 }
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
}
|
||||||
|
} ;
|
|
@ -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
|
|
@ -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 ;
|
|
@ -0,0 +1 @@
|
||||||
|
Documentation coverage linter
|
|
@ -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"
|
|
||||||
""
|
|
||||||
}
|
|
||||||
} ;
|
|
|
@ -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 ;
|
|
|
@ -1 +0,0 @@
|
||||||
Pedantic help coverage checker
|
|
Loading…
Reference in New Issue