doc corrections and improvements related to submodules
In particular, add `module+' to the Guide.
This commit is contained in:
parent
d4d5ca70fb
commit
876bc6f02b
|
@ -7,38 +7,37 @@
|
||||||
(define submodule 'test)
|
(define submodule 'test)
|
||||||
(define run-anyways? #f)
|
(define run-anyways? #f)
|
||||||
|
|
||||||
(define do-test
|
(define (do-test e [check-suffix? #f])
|
||||||
(match-lambda
|
(match e
|
||||||
[(? string? s)
|
[(? string? s)
|
||||||
(do-test (string->path s))]
|
(do-test (string->path s))]
|
||||||
[(? path? p)
|
[(? path? p)
|
||||||
(define ps (path->string p))
|
(cond
|
||||||
(cond
|
|
||||||
[(directory-exists? p)
|
[(directory-exists? p)
|
||||||
(for-each
|
(for-each
|
||||||
(λ (dp)
|
(λ (dp)
|
||||||
(do-test (build-path p dp)))
|
(do-test (build-path p dp) #t))
|
||||||
(directory-list p))]
|
(directory-list p))]
|
||||||
[(and (file-exists? p)
|
[(and (file-exists? p)
|
||||||
(regexp-match #rx"\\.rkt$" ps))
|
(or (not check-suffix?)
|
||||||
(define fmod `(file ,ps))
|
(regexp-match #rx#"\\.rkt$" (path->bytes p))))
|
||||||
(define mod `(submod ,fmod ,submodule))
|
(define mod `(submod ,p ,submodule))
|
||||||
(cond
|
(cond
|
||||||
[(module-declared? mod #t)
|
[(module-declared? mod #t)
|
||||||
(dynamic-require mod #f)]
|
(dynamic-require mod #f)]
|
||||||
[(and run-anyways? (module-declared? fmod #t))
|
[(and run-anyways? (module-declared? p #t))
|
||||||
(dynamic-require fmod #f)])]
|
(dynamic-require p #f)])]
|
||||||
[(not (file-exists? p))
|
[(not (file-exists? p))
|
||||||
(error 'test "Given path ~e does not exist" p)])]))
|
(error 'test "Given path ~e does not exist" p)])]))
|
||||||
|
|
||||||
(command-line
|
(command-line
|
||||||
#:program (short-program+command-name)
|
#:program (short-program+command-name)
|
||||||
#:once-each
|
#:once-each
|
||||||
[("--submodule" "-s") submodule-str
|
[("--submodule" "-s") name
|
||||||
"Determines which submodule to load"
|
"Runs submodule <name> (defaults to `test')"
|
||||||
(set! submodule (string->symbol submodule-str))]
|
(set! submodule (string->symbol name))]
|
||||||
[("--run-if-absent" "-r")
|
[("--run-if-absent" "-r")
|
||||||
"When set, raco test will require the default module if the given submodule is not present."
|
"Require base module if submodule is absent"
|
||||||
(set! run-anyways? #t)]
|
(set! run-anyways? #t)]
|
||||||
#:args files+directories
|
#:args file-or-directory
|
||||||
(for-each do-test files+directories))
|
(for-each do-test file-or-directory))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#lang scribble/doc
|
#lang scribble/doc
|
||||||
@(require scribble/manual scribble/eval "guide-utils.rkt")
|
@(require scribble/manual scribble/eval "guide-utils.rkt"
|
||||||
|
(for-label rackunit))
|
||||||
|
|
||||||
@(define cake-eval (make-base-eval))
|
@(define cake-eval (make-base-eval))
|
||||||
|
|
||||||
|
@ -153,9 +154,21 @@ independently. Furthermore, if @filepath{park.rkt} is compiled to a
|
||||||
bytecode file (via @exec{raco make}), then the code for
|
bytecode file (via @exec{raco make}), then the code for
|
||||||
@filepath{park.rkt} or the code for @racket[zoo] can be loaded independently.
|
@filepath{park.rkt} or the code for @racket[zoo] can be loaded independently.
|
||||||
|
|
||||||
A @racket[module*] form is similar to a nested @racket[module] form,
|
Submodules can be nested within submodules, and a submodule can be
|
||||||
but @racket[module*] inverts the possibilities for reference between
|
referenced directly by a module other than its enclosing module by
|
||||||
the submodule and enclosing module:
|
using a @racket[submod] path as described in
|
||||||
|
@seclink["module-paths"]{a later section}.
|
||||||
|
|
||||||
|
A @racket[module*] form is similar to a nested @racket[module] form:
|
||||||
|
|
||||||
|
@specform[
|
||||||
|
(module* name-id initial-module-path-or-#f
|
||||||
|
decl ...)
|
||||||
|
]
|
||||||
|
|
||||||
|
The @racket[module*] form differs from @racket[module] in that it
|
||||||
|
inverts the possibilities for reference between the submodule and
|
||||||
|
enclosing module:
|
||||||
|
|
||||||
@itemlist[
|
@itemlist[
|
||||||
|
|
||||||
|
@ -166,23 +179,56 @@ the submodule and enclosing module:
|
||||||
|
|
||||||
@item{A submodule declared with @racket[module*] can @racket[require]
|
@item{A submodule declared with @racket[module*] can @racket[require]
|
||||||
its enclosing module, but the enclosing module cannot
|
its enclosing module, but the enclosing module cannot
|
||||||
@racket[require] the submodule. In addition, a @racket[module*]
|
@racket[require] the submodule.}
|
||||||
form can specify @racket[#f] as its
|
|
||||||
@racket[_initial-module-path], in which case the submodule sees
|
|
||||||
all of the enclosing module's bindings---including bindings
|
|
||||||
that are not exported via @racket[provide].}
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
As an example of @racket[module*], the following variant of
|
In addition, a @racket[module*] form can specify @racket[#f] in place of an
|
||||||
@filepath{cake.rkt} includes a @racket[main] submodule that calls
|
@racket[_initial-module-path], in which case the submodule sees all of
|
||||||
@racket[print-cake]:
|
the enclosing module's bindings---including bindings that are not
|
||||||
|
exported via @racket[provide].
|
||||||
|
|
||||||
|
One use of submodule declared with @racket[module*] and @racket[#f] is
|
||||||
|
to export additional bindings through a submodule that are not
|
||||||
|
normally exported from the module:
|
||||||
|
|
||||||
@racketmod[
|
@racketmod[
|
||||||
#:file "cake.rkt"
|
#:file "cake.rkt"
|
||||||
racket
|
racket
|
||||||
|
|
||||||
(provide print-cake)
|
(provide print-cacke)
|
||||||
|
|
||||||
|
(define (print-cake n)
|
||||||
|
(show " ~a " n #\.)
|
||||||
|
(show " .-~a-. " n #\|)
|
||||||
|
(show " | ~a | " n #\space)
|
||||||
|
(show "---~a---" n #\-))
|
||||||
|
|
||||||
|
(define (show fmt n ch)
|
||||||
|
(printf fmt (make-string n ch))
|
||||||
|
(newline))
|
||||||
|
|
||||||
|
(module* extras #f
|
||||||
|
(provide show))
|
||||||
|
]
|
||||||
|
|
||||||
|
In this revised @filepath{cake.rkt} module, @racket[show] is not
|
||||||
|
imported by a module that uses @racket[(require "cake.rkt")], since
|
||||||
|
most clients of @filepath{cake.rkt} will not want the extra function. A
|
||||||
|
module can require the @racket[extra] @tech{submodule}
|
||||||
|
(using the @racket[submod] form described in
|
||||||
|
@seclink["module-paths"]{a later section}) to access the otherwise
|
||||||
|
hidden @racket[show] function.
|
||||||
|
|
||||||
|
@; ----------------------------------------------------------------------
|
||||||
|
@section[#:tag "main-and-test"]{Main and Test Submodules}
|
||||||
|
|
||||||
|
The following variant of @filepath{cake.rkt} includes a @racket[main]
|
||||||
|
submodule that calls @racket[print-cake]:
|
||||||
|
|
||||||
|
@racketmod[
|
||||||
|
#:file "cake.rkt"
|
||||||
|
racket
|
||||||
|
|
||||||
(define (print-cake n)
|
(define (print-cake n)
|
||||||
(show " ~a " n #\.)
|
(show " ~a " n #\.)
|
||||||
|
@ -198,31 +244,100 @@ racket
|
||||||
(print-cake 10))
|
(print-cake 10))
|
||||||
]
|
]
|
||||||
|
|
||||||
Running a module does not run its @racket[module*]-defined submodules,
|
Running a module does not run its @racket[module*]-defined
|
||||||
since the enclosing module cannot directly reference
|
submodules. Nevertheless, running the above module via @exec{racket}
|
||||||
@racket[module*]-defined submodules. Nevertheless, running the above
|
or DrRacket prints a cake with 10 candles, because the @racket[main]
|
||||||
module via @exec{racket} or DrRacket prints a cake with 10 candles,
|
@tech{submodule} is a special case.
|
||||||
because the @racket[main] submodule} is a special case.
|
|
||||||
|
|
||||||
When a module is provided as a program name to the @exec{racket}
|
When a module is provided as a program name to the @exec{racket}
|
||||||
executable or run directly within DrRacket, if the module has a
|
executable or run directly within DrRacket, if the module has a
|
||||||
@as-index{@racket[main] submodule}, the @racket[main] submodule is run after its
|
@as-index{@racket[main] submodule}, the @racket[main] submodule is run
|
||||||
enclosing module. Declaring a @racket[main] submodule is often a
|
after its enclosing module. Declaring a @racket[main] submodule
|
||||||
useful describe tests or other extra actions to be performed when a
|
thus specifies extra actions to be performed when a module is run directly,
|
||||||
module is run directly instead of @racket[required] as a library
|
instead of @racket[required] as a library within a larger program.
|
||||||
within a larger program.
|
|
||||||
|
|
||||||
A @racket[main] submodule does not have to be declared with
|
A @racket[main] submodule does not have to be declared with
|
||||||
@racket[module*]. If the @racket[main] module does not need to use
|
@racket[module*]. If the @racket[main] module does not need to use
|
||||||
bindings from its enclosing module, it can be declared with
|
bindings from its enclosing module, it can be declared with
|
||||||
@racket[module]. A @racket[main] submodule typically uses the
|
@racket[module]. More commonly, @racket[main] is declared using a
|
||||||
bindings of its enclosing module, however, so @racket[main] is usually
|
third submodule form, @racket[module+]:
|
||||||
declared with @racket[module*].
|
|
||||||
|
|
||||||
Submodules can be nested within submodules, and a submodule can be
|
@specform[
|
||||||
referenced directly by a module other than its enclosing module by
|
(module+ name-id
|
||||||
using a @racket[submod] path as described in the
|
decl ...)
|
||||||
@seclink["module-paths"]{next section}.
|
]
|
||||||
|
|
||||||
|
A submodule declared with @racket[module+] is like one declared with
|
||||||
|
@racket[module*] using @racket[#f] as its
|
||||||
|
@racket[_initial-module-path] (i.e., there's no
|
||||||
|
@racket[_initial-module-path] for @racket[module+]). In addition,
|
||||||
|
multiple @racket[module+] forms can specify the same submodule name,
|
||||||
|
in which case the bodies of the @racket[module+] forms are combined to
|
||||||
|
form a single submodule.
|
||||||
|
|
||||||
|
The splicing behavior of @racket[module+] is particularly useful for
|
||||||
|
defining a @racket[test] submodule, which can be conveniently run
|
||||||
|
using @exec{raco test} in much the same way that @racket[main] is
|
||||||
|
conveniently run with @exec{racket}. For example, the following
|
||||||
|
@filepath{physics.rkt} module exports @racket[drop] and
|
||||||
|
@racket[to-energy] functions, and it defines a @racket[test] module to
|
||||||
|
hold unit tests:
|
||||||
|
|
||||||
|
@racketmod[
|
||||||
|
#:file "physics.rkt"
|
||||||
|
racket
|
||||||
|
(module+ test
|
||||||
|
(require rackunit)
|
||||||
|
(define ε 1e-10))
|
||||||
|
|
||||||
|
(provide drop
|
||||||
|
to-energy)
|
||||||
|
|
||||||
|
(define (drop t)
|
||||||
|
(* 1/2 9.8 t t))
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
(check-= (drop 0) 0 ε)
|
||||||
|
(check-= (drop 10) 490 ε))
|
||||||
|
|
||||||
|
(define (to-energy m)
|
||||||
|
(* m (expt 299792458.0 2)))
|
||||||
|
|
||||||
|
(module+ test
|
||||||
|
(check-= (to-energy 0) 0 ε)
|
||||||
|
(check-= (to-energy 1) 9e+16 1e+15))
|
||||||
|
]
|
||||||
|
|
||||||
|
This module is equivalent to using @racket[module*]:
|
||||||
|
|
||||||
|
@racketmod[
|
||||||
|
#:file "physics.rkt"
|
||||||
|
racket
|
||||||
|
|
||||||
|
(provide drop
|
||||||
|
to-energy)
|
||||||
|
|
||||||
|
(define (drop t)
|
||||||
|
(* 1/2 #e9.8 t t))
|
||||||
|
|
||||||
|
(define (to-energy m)
|
||||||
|
(* m (expt 299792458 2)))
|
||||||
|
|
||||||
|
(module* test #f
|
||||||
|
(require rackunit)
|
||||||
|
(define ε 1e-10)
|
||||||
|
(check-= (drop 0) 0 ε)
|
||||||
|
(check-= (drop 10) 490 ε)
|
||||||
|
(check-= (to-energy 0) 0 ε)
|
||||||
|
(check-= (to-energy 1) 9e+16 1e+15))
|
||||||
|
]
|
||||||
|
|
||||||
|
Using @racket[module+] instead of @racket[module*] allows tests to be
|
||||||
|
interleaved with function definitions.
|
||||||
|
|
||||||
|
The splicing behavior of @racket[module+] is also sometimes helpful
|
||||||
|
for a @racket[main] module. In any case, @racket[(module+ main ....)]
|
||||||
|
is preferred as more readable than @racket[(module* main #f ....)].
|
||||||
|
|
||||||
@; ----------------------------------------------------------------------
|
@; ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
|
@ -7,15 +7,19 @@
|
||||||
|
|
||||||
@title[#:tag "test"]{@exec{raco test}: Run tests}
|
@title[#:tag "test"]{@exec{raco test}: Run tests}
|
||||||
|
|
||||||
The @exec{raco test} command requires and runs the @racket['test]
|
The @exec{raco test} command requires and runs the @racket[test]
|
||||||
submodules associated with paths given on the command line. When a
|
submodule (if any) associated with each path given on the command line. When a
|
||||||
path refers to a directory, the tool recursively discovers all
|
path refers to a directory, the tool recursively discovers all
|
||||||
internal files that end in @filepath{.rkt} and inspects them as well.
|
files that end in @filepath{.rkt} within the directory and runs their
|
||||||
|
@racket[test] submodules.
|
||||||
|
|
||||||
The @exec{raco test} command accepts a few flags:
|
The @exec{raco test} command accepts a few flags:
|
||||||
|
|
||||||
@itemize[
|
@itemize[
|
||||||
@item{@DFlag{s} @nonterm{id} or @DFlag{submodule} @nonterm{id}--- Requires the submodule @nonterm{id} rather than @racket['test].}
|
@item{@Flag{s} @nonterm{name} or @DFlag{submodule} @nonterm{name}
|
||||||
|
--- Requires the submodule @nonterm{name} rather than @racket[test].}
|
||||||
|
|
||||||
@item{@DFlag{r} or @DFlag{run-if-absent}--- Requires the default module if the given submodule is not present in a file.}
|
@item{@Flag{r} or @DFlag{run-if-absent}
|
||||||
|
--- Requires the top-level module of a file if the relevant submodule is not
|
||||||
|
present.}
|
||||||
]
|
]
|
||||||
|
|
|
@ -24,11 +24,16 @@ to another module.
|
||||||
Returns @racket[#f] if @racket[v] is a @tech{resolved module path},
|
Returns @racket[#f] if @racket[v] is a @tech{resolved module path},
|
||||||
@racket[#f] otherwise.}
|
@racket[#f] otherwise.}
|
||||||
|
|
||||||
@defproc[(make-resolved-module-path [path (or/c symbol? (and/c path? complete-path?))])
|
@defproc[(make-resolved-module-path [path (or/c symbol?
|
||||||
|
(and/c path? complete-path?)
|
||||||
|
(cons/c (or/c symbol?
|
||||||
|
(and/c path? complete-path?))
|
||||||
|
(listof symbol?)))])
|
||||||
resolved-module-path?]{
|
resolved-module-path?]{
|
||||||
|
|
||||||
Returns a @tech{resolved module path} that encapsulates @racket[path].
|
Returns a @tech{resolved module path} that encapsulates @racket[path],
|
||||||
If @racket[path] is not a symbol, it normally should be
|
where a list @racket[path] corresponds to a @tech{submodule} path.
|
||||||
|
If @racket[path] is a path or starts with a path, the path normally should be
|
||||||
@tech{cleanse}d (see @racket[cleanse-path]) and simplified (see
|
@tech{cleanse}d (see @racket[cleanse-path]) and simplified (see
|
||||||
@racket[simplify-path]).
|
@racket[simplify-path]).
|
||||||
|
|
||||||
|
@ -38,9 +43,14 @@ A @tech{resolved module path} is interned. That is, if two
|
||||||
@racket[eq?].}
|
@racket[eq?].}
|
||||||
|
|
||||||
@defproc[(resolved-module-path-name [module-path resolved-module-path?])
|
@defproc[(resolved-module-path-name [module-path resolved-module-path?])
|
||||||
(or/c path? symbol?)]{
|
(or/c symbol?
|
||||||
|
(and/c path? complete-path?)
|
||||||
|
(cons/c (or/c symbol?
|
||||||
|
(and/c path? complete-path?))
|
||||||
|
(listof symbol?)))]{
|
||||||
|
|
||||||
Returns the path or symbol encapsulated by a @tech{resolved module path}.}
|
Returns the path or symbol encapsulated by a @tech{resolved module path}.
|
||||||
|
A list result corresponds to a @tech{submodule} path.}
|
||||||
|
|
||||||
|
|
||||||
@defproc[(module-path? [v any/c]) boolean?]{
|
@defproc[(module-path? [v any/c]) boolean?]{
|
||||||
|
|
|
@ -290,6 +290,8 @@ See also @secref["module-eval-model"] and @secref["mod-parse"].
|
||||||
@defform*[((module* id module-path form ...)
|
@defform*[((module* id module-path form ...)
|
||||||
(module* id #f form ...))]{
|
(module* id #f form ...))]{
|
||||||
|
|
||||||
|
@guideintro["submodules"]{@racket[module*]}
|
||||||
|
|
||||||
Like @racket[module], but only for declaring a @tech{submodule} within
|
Like @racket[module], but only for declaring a @tech{submodule} within
|
||||||
a module, and for submodules that may @racket[require] the enclosing module.
|
a module, and for submodules that may @racket[require] the enclosing module.
|
||||||
|
|
||||||
|
@ -306,6 +308,8 @@ have no effect on the submodule.}
|
||||||
|
|
||||||
@defform[(module+ id form ...)]{
|
@defform[(module+ id form ...)]{
|
||||||
|
|
||||||
|
@guideintro["main-and-test"]{@racket[module+]}
|
||||||
|
|
||||||
Declares and/or adds to a @tech{submodule} named @racket[id].
|
Declares and/or adds to a @tech{submodule} named @racket[id].
|
||||||
|
|
||||||
Each addition for @racket[id] is combined in order to form the entire
|
Each addition for @racket[id] is combined in order to form the entire
|
||||||
|
|
Loading…
Reference in New Issue
Block a user