Documentation updates

slava 2006-10-26 04:06:25 +00:00
parent 6dd14a741a
commit 0081e1d9bc
13 changed files with 169 additions and 76 deletions

View File

@ -12,10 +12,7 @@
- float boxing and overflow checks need a gc check too
- [ [ dup call ] dup call ] infer hangs
- growable data heap
- more compact relocation info
- flip may fail with >64kb string
- documentation:
- document columns
- update module system docs
+ ui:

View File

@ -173,7 +173,7 @@ ARTICLE: "cookbook-sources" "Source file cookbook"
"By convention, code is stored in files with the " { $snippet ".factor" } " filename extension. You can load source files using " { $link run-file } ":"
{ $code "\"hello.factor\" run-file" }
{ $references
{ }
"Programs larger than one source file or programs which depend on other libraries should be loaded via the module system instead. Even more advanced functionality can be implemented by calling the parser and source reader at runtime."
"sources"
"modules"
"parser"

View File

@ -44,13 +44,13 @@ ARTICLE: "handbook" "Factor documentation"
{ $heading "Environment reference" }
{ $subsection "cli" }
{ $subsection "tools" }
{ $subsection "modules" }
{ $subsection "help" }
{ $subsection "inference" }
{ $subsection "compiler" }
{ $heading "Graphical user interface" }
{ $subsection "ui-tools" }
{ $heading "Currently-loaded contributed modules" }
"See " { $link "modules" } " for details."
{ $outliner [ modules-help ] }
{ $heading "Index" }
{ $subsection "article-index" }

View File

@ -31,7 +31,7 @@ ARTICLE: "searching-help-impl" "Full-text search implementation"
{ $subsection index-text } ;
ARTICLE: "writing-help" "Writing documentation"
"By convention, documentation is written in files with the " { $snippet ".facts" } " filename extension."
"By convention, documentation is written in files with the " { $snippet ".facts" } " filename extension. Module documentation should follow a few conventions documented in " { $link "documenting-modules" } "."
$terpri
"A pair of parsing words are used to define free-standing articles and to associate documentation with words:"
{ $subsection POSTPONE: ARTICLE: }

View File

@ -10,7 +10,6 @@ PROVIDE: doc/handbook
"dataflow.facts"
"handbook.facts"
"hashtables.facts"
"help.facts"
"inference.facts"
"math.facts"
"objects.facts"
@ -19,6 +18,8 @@ PROVIDE: doc/handbook
"sequences.facts"
"streams.facts"
"syntax.facts"
"modules.facts"
"help.facts"
"tools.facts"
"words.facts"
"ui/tools.facts"

View File

@ -0,0 +1,97 @@
USING: definitions errors help image tools io kernel
listener memory modules parser prettyprint sequences test
words shells ;
ARTICLE: "module-organization" "Module organization"
"Modules are loaded from the Factor directory, and are conventionally placed in one of three subdirectories therein:"
{ $list
{ { $snippet "contrib/" } " - repository of user-contributed libraries, briefly summarized in " { $snippet "contrib/README.txt" } }
{ { $snippet "examples/" } " - small examples demonstrating language features" }
{ { $snippet "library/" } " - core code " }
}
"A module named " { $snippet "contrib/frob" } " must be defined in a file whose name takes one of the following two forms:"
{ $code "contrib/frob.factor" "contrib/frob/load.factor" }
"The former should only be used for very small modules; if your module needs unit tests, documentation or more than one source file (as most do), you need to create a new directory with a " { $snippet "load.factor" } " file in it."
$terpri
"When a module takes the latter form, the directory containing the load file is termed the " { $emphasis "module directory" } "." ;
ARTICLE: "using-modules" "Using modules"
"To load " { $snippet "contrib/concurrency" } " for instance, you simply issue the following command in the listener:"
{ $code "\"contrib/concurrency\" require" }
"The " { $link require } " word will load all dependencies and source files of the " { $snippet "contrib/concurrency" } " module."
{ $subsection require }
"Some modules are have a main entry point, and can be run much like an application in an operating system:"
{ $subsection run-module } ;
ARTICLE: "developing-modules" "Developing modules"
"To create a new module, you must first decide if the module is a single-file module or a directory with a load file; see " { $link "module-organization" } "."
$terpri
"If the module depends on other modules, the load file must first load them:"
{ $subsection POSTPONE: REQUIRES: }
"Then, it must define the module itself:"
{ $subsection POSTPONE: PROVIDE: }
"Finally, it can define a main entry point for use with " { $link run-module } ":"
{ $subsection POSTPONE: MAIN: }
"When working on a module, you can automatically reload any changed source files, in the correct order, without having to call " { $link run-file } " manually:"
{ $subsection reload-modules }
{ $subsection reset-modified }
{ $heading "Example " { $snippet "load.factor" } }
"Here is a simple module definition taken from " { $snippet "contrib/tetris/load.factor" } "; it demonstrates all of the above features:"
{ $code "REQUIRES: contrib/lazy-lists ;"
""
"PROVIDE: contrib/tetris"
"{ +files+ {"
" \"tetris-colours.factor\""
" \"tetromino.factor\""
" \"tetris-piece.factor\""
" \"tetris-board.factor\""
" \"tetris.factor\""
" \"tetris-gl.factor\""
" \"tetris-gadget.factor\""
"} }"
"{ +tests+ {"
" \"test/tetris-piece.factor\""
" \"test/tetris-board.factor\""
" \"test/tetris.factor\""
"} } ;"
""
"USE: tetris-gadget"
""
"MAIN: contrib/tetris tetris-window ;" } ;
ARTICLE: "testing-modules" "Unit testing modules"
"A unit test is a piece of code which starts with known input values, then compares the output of a word with an expected output, where the expected output is defined by the word's contract."
$terpri
"For example, if you were developing a word for computing symbolic derivatives, your unit tests would apply the word to certain input functions, comparing the results against the correct values. While the passing of these tests would not guarantee the algorithm is correct, it would at least ensure that what used to work keeps working, in that as soon as something breaks due to a change in another part of your program, failing tests will let you know."
$terpri
"Unit tests are placed in test harness files, separate from the rest of your source code. If the test harness needs to define words, they should be placed in the " { $snippet "temporary" } " vocabulary so that they can be forgotten after the tests have been run. Test harness files mainly consist of calls to the following two words:"
{ $subsection unit-test }
{ $subsection unit-test-fails }
{ $subsection assert-depth }
"Any non-trivial module should ship with unit tests in the " { $snippet "tests" } " subdirectory of the module directory. Unit test files should be listed in the " { $link +tests+ } " key of the " { $link POSTPONE: PROVIDE: } " form."
$terpri
"The following words run test harness files:"
{ $subsection test-module }
{ $subsection test-modules } ;
ARTICLE: "documenting-modules" "Documenting modules"
"Any non-trivial module should ship with documentation. Documentation " { $snippet ".facts" } " files should be listed along with your module's source files in the " { $link +files+ } " key passed to " { $link POSTPONE: PROVIDE: } ", and the main article should be referenced from the " { $link +help+ } " key."
$terpri
"Help markup is described in " { $link "writing-help" } ". Since help articles describing the core library have string names, a convention to avoid clashes is to name module help articles by arrays, where the first element is a string identifying the module, and the second identifies the article itself. For example, " { $snippet "{ \"concurrency\" \"processes\" }" } "." ;
ARTICLE: "submitting-modules" "Submitting modules"
"If you would like to contribute a module you wrote to Factor, please make sure of the following:"
{ $list
{ "The module actually is a module, and the load file has a " { $link POSTPONE: PROVIDE: } " form with the correct module name (including the " { $snippet "contrib/" } " prefix)" }
{ "The module is listed in " { $snippet "contrib/README.txt" } " and " { $snippet "contrib/all.factor" } }
"If the module is non-trivial, it should come with unit tests and documentation"
} ;
ARTICLE: "modules" "Modules and contributed libraries"
"The module system provides a set of conventions and tools for organizing large bodies of Factor code."
{ $subsection "module-organization" }
{ $subsection "using-modules" }
{ $subsection "developing-modules" }
{ $subsection "testing-modules" }
{ $subsection "documenting-modules" }
{ $subsection "submitting-modules" } ;

View File

@ -13,6 +13,10 @@ ARTICLE: "sequence-implementations" "Sequence implementations"
{ $subsection "quotations" }
"Integers support the sequence protocol:"
{ $subsection "sequences-integers" }
"Virtual sequences wrap an underlying sequence, and changes to the underlying sequence are reflected in the virtual sequence:"
{ $subsection <reversed> }
{ $subsection <slice> }
{ $subsection <column> }
"The " { $link f } " object also supports the sequence protocol. It responds with a length of zero, and instead of throwing an out of bounds error, outputs " { $link f } " when an element is accessed. This can simplify code that would like a dummy sequence behaving as if it has arbitrary length." ;
ARTICLE: "sequences-integers" "Integer sequences and counted loops"
@ -141,6 +145,7 @@ ARTICLE: "sequences-reshape" "Reshaping sequences"
{ $subsection group }
{ $subsection flatten }
{ $subsection flip }
{ $subsection <column> }
{ $subsection subst } ;
ARTICLE: "sequences-destructive" "Destructive operations"

View File

@ -6,20 +6,14 @@ ARTICLE: "tools" "Development tools"
"This section covers words which are used during development, and not usually invoked directly by user code."
$terpri
"There are two useful development tools which are complex enough that separate sections are devoted to them; see " { $link "inference" } " and " { $link "compiler" } "."
$terpri
"Interactive development:"
{ $subsection "listener" }
{ $subsection "debugger" }
{ $subsection "definitions" }
{ $subsection "word-introspection" }
{ $subsection "inspector" }
{ $subsection "annotations" }
"Working on a project:"
{ $subsection "sources" }
{ $subsection "modules" }
{ $subsection "images" }
{ $subsection "unit-test" }
"Advanced features:"
{ $subsection "memory" }
{ $subsection "timing" } ;
@ -53,50 +47,6 @@ $terpri
$terpri
"User-contributed libraries in the " { $snippet "contrib/" } " directory of the Factor distribution should be loaded via the high-level module system instead of the above words (" { $link "modules" } ")." ;
ARTICLE: "modules" "Modules and contributed libraries"
"The Factor distribution includes a selection of contributed libraries in the " { $snippet "contrib/" } " directory, which are managed by a simple module system."
$terpri
"To load " { $snippet "contrib/concurrency" } " for instance, you simply issue the following command in the listener:"
{ $code "\"contrib/concurrency\" require" }
"The " { $link require } " word will load all dependencies and source files of the " { $snippet "contrib/concurrency" } " module."
{ $subsection require }
"Some modules are simply reusable libraries of code. Other modules are more like applications, and have a main entry point:"
{ $subsection run-module }
"To define a new module named " { $snippet "contrib/frob" } ", create one of the following two files:"
{ $code "contrib/frob.factor" "contrib/frob/load.factor" }
"The module definition file should first list all required modules:"
{ $subsection POSTPONE: REQUIRES: }
"Required modules will be loaded first. Next, the source files and unit tests, if any, have to be registered:"
{ $subsection POSTPONE: PROVIDE: }
"It is important that the module path name matches the module name passed to " { $link POSTPONE: PROVIDE: } ", which should be " { $snippet "frob" } " in the above example."
$terpri
"Finally, if your module is an application, you can define a main entry point for " { $link run-module } ":"
{ $subsection POSTPONE: MAIN: }
"Here is a simple module definition taken from " { $snippet "contrib/tetris/load.factor" } ":"
{ $code "REQUIRES: contrib/lazy-lists ;"
""
"PROVIDE: contrib/tetris {"
" \"tetris-colours.factor\""
" \"tetromino.factor\""
" \"tetris-piece.factor\""
" \"tetris-board.factor\""
" \"tetris.factor\""
" \"tetris-gl.factor\""
" \"tetris-gadget.factor\""
"} {"
" \"test/tetris-piece.factor\""
" \"test/tetris-board.factor\""
" \"test/tetris.factor\""
"} ;"
""
"USE: tetris-gadget"
""
"MAIN: contrib/tetris tetris-window ;" }
"The following words are useful during development of modules:"
{ $subsection reload-modules }
{ $subsection load-module }
{ $subsection test-module } ;
ARTICLE: "debugger" "The debugger"
"If an expression entered in the listener throws an error, the error is printed to the output stream. A number of words facilitate interactive debugging of the error:"
{ $subsection :s }
@ -155,18 +105,6 @@ $terpri
"Removing definitions:"
{ $subsection forget } ;
ARTICLE: "unit-test" "Unit testing code"
"A unit test is a piece of code which starts with known input values, then compares the output of a word with an expected output, where the expected output is defined by the word's contract."
$terpri
"For example, if you were developing a word for computing symbolic derivatives, your unit tests would apply the word to certain input functions, comparing the results against the correct values."
$terpri
"If you maintain a complete collection of unit tests and run them frequently, then a failing unit test can allow you to accurately pinpoint a fault in your program. However, just because unit tests pass is not an indication the code is correct. Writing good unit tests is an art form, and encourages a certain approach to programming which results in simpler, more reusable code."
$terpri
"The following two words perform unit testing; they are usually placed inside test harness files which you run using " { $link run-file } ":"
{ $subsection unit-test }
{ $subsection unit-test-fails }
{ $subsection assert-depth } ;
ARTICLE: "timing" "Timing code"
"You can time the execution of a quotation in the listener:"
{ $subsection time }

View File

@ -39,3 +39,24 @@ HELP: <slice>
HELP: slice@
{ $values { "m" "a non-negative integer" } { "slice" "an instance of " { $link slice } } { "n" "a non-negative integer" } { "seq" "a sequence" } }
{ $description "Indexes into a slice. Helper word used to implement " { $link "sequence-protocol" } " methods for the " { $link reversed } " class." } ;
HELP: column
{ $class-description "A virtual sequence which presents a fixed column of a matrix represented as a sequence of rows." }
{ $see-also <column> } ;
HELP: <column>
{ $values { "seq" "a sequence" } { "n" "a non-negative integer" } }
{ $description "Outputs a new virtual sequence which presents a fixed column of a matrix represented as a sequence of rows." "The " { $snippet "i" } "th element of a column is the " { $snippet "n" } "th element of the " { $snippet "i" } "th element of" { $snippet "seq" } ". Every element of " { $snippet "seq" } " must be a sequence, and all sequences must have equal length." }
{ $examples
{ $example
"{ { 1 2 3 } { 4 5 6 } { 7 8 9 } } 0 <column> >array ."
"{ 1 4 7 }"
}
}
{ $notes
"In the same sense that " { $link <reversed> } " is a virtual variant of " { $link reverse } ", " { $link <column> } " is a virtual variant of " { $snippet "[ swap nth ] map-with" } "."
} ;
HELP: column@
{ $values { "m" "a non-negative integer" } { "column" "an instance of " { $link column } } { "n" "a non-negative integer" } { "seq" "a sequence" } }
{ $description "Indexes into a column view of a matrix. Helper word used to implement " { $link "sequence-protocol" } " methods for the " { $link column } " class." } ;

View File

@ -64,4 +64,5 @@ M: word article-content
] with-style ;
: $outliner ( element -- )
[ first call help-outliner ] ($block) ;
first call dup empty?
[ drop ] [ [ help-outliner ] ($block) ] if ;

View File

@ -10,7 +10,7 @@ HELP: HELP:
"HELP: foo"
"{ $values { \"m\" \"an integer\" } { \"n\" \"an integer\" } }"
"{ $description \"Increments a value by 2.\" } ;"
"\ foo help"
"\\ foo help"
}
} ;

View File

@ -1,5 +1,5 @@
IN: modules
USING: help io ;
USING: help io parser ;
HELP: prefix-paths
{ $values { "name" "a module name string" } { "seq" "a sequence of strings" } { "newseq" "a new sequence of path name strings" } }
@ -33,7 +33,7 @@ $terpri
HELP: provide
{ $values { "name" "a string" } { "hash" "a hashtable" } }
{ $description "Registers a module definition and loads its source files. The possible hashtable are documented in the " { $link POSTPONE: PROVIDE: } " word. Usually instead of calling this word, module definitions use the parsing word " { $link POSTPONE: PROVIDE: } " instead." } ;
{ $description "Registers a module definition and loads its source files. The possible hashtable keys are documented in the " { $link POSTPONE: PROVIDE: } " word. Usually instead of calling this word, module definitions use the parsing word " { $link POSTPONE: PROVIDE: } " instead." } ;
HELP: test-module
{ $values { "name" "a module name string" } }
@ -45,3 +45,15 @@ HELP: test-modules
HELP: run-module
{ $values { "name" "a module name string" } }
{ $description "Runs the main entry point of the module, first loading the module if necessary using " { $link require } ". Entry points can be defined with the " { $link POSTPONE: MAIN: } " word." } ;
HELP: reload-module
{ $values { "module" "a " { $link module } " instance" } }
{ $description "Reloads any source files making up a module if they have been modified on disk since last being loaded. Most of the time " { $link reload-modules } " should be called instead." } ;
HELP: reload-modules
{ $description "Reloads all source files in all loaded modules which have been modified on disk since last being loaded." }
{ $notes "If modification times become invalid after moving sources or images between machines, and this word ends up trying to reload all library sources, call " { $link reset-modified } " from the listener." } ;
HELP: modules-help
{ $values { "seq" "a new sequence" } }
{ $description "Outputs a sequence of help articles which are the main entry points into the documentation of loaded modules. Modules can define documentation entry points with the " { $link +help+ } " key of the association list given in " { $link POSTPONE: PROVIDE: } "." } ;

View File

@ -275,9 +275,30 @@ HELP: REQUIRES:
{ $description "Loads a list of modules by calling " { $link require } " on each one." } ;
HELP: PROVIDE:
{ $syntax "PROVIDE: name files tests ;" }
{ $values { "name" "a string" } { "files" "a sequence of strings" } { "tests" "a sequence of strings" } }
{ $description "Registers a module definition and loads its source files by calling " { $link provide } "." } ;
{ $syntax "PROVIDE: name pairs... ;" }
{ $values { "name" "a string" } { "pairs" "a sequence of pairs, with keys described below" } }
{ $description "Registers a module definition and loads its source files by calling " { $link provide } "."
$terpri
"The module name is followed by key/value pairs, where the keys are drawn from the following set:"
{ $list
{ { $link +files+ } " - the value is a sequence of source file names" }
{ { $link +tests+ } " - the value is a sequence of unit test file names" }
{ { $link +help+ } " - the value is a help topic" }
}
"All keys are optional, and path names are relative to the main module directory."
$terpri
"Elements of path name lists can optionally be pairs, where the first element is a source file which is conditionally loaded if the quotation in the second element yields a true value." }
{ $examples
"An example where the conditional load feature is used to load platform-specific code:"
{ $code
"PROVIDE: contrib/calendar"
"{ +files+ {"
" { \"os-unix.factor\" [ unix? ] }"
" { \"os-win32.factor\" [ windows? ] }"
" \"calendar.factor\""
"} }"
"{ +tests+ { \"test/calendar.factor\" } } ;"
} } ;
HELP: MAIN:
{ $syntax "MAIN: name definition... ;" }