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 run-anyways? #f)
|
||||
|
||||
(define do-test
|
||||
(match-lambda
|
||||
[(? string? s)
|
||||
(do-test (string->path s))]
|
||||
[(? path? p)
|
||||
(define ps (path->string p))
|
||||
(cond
|
||||
(define (do-test e [check-suffix? #f])
|
||||
(match e
|
||||
[(? string? s)
|
||||
(do-test (string->path s))]
|
||||
[(? path? p)
|
||||
(cond
|
||||
[(directory-exists? p)
|
||||
(for-each
|
||||
(λ (dp)
|
||||
(do-test (build-path p dp)))
|
||||
(do-test (build-path p dp) #t))
|
||||
(directory-list p))]
|
||||
[(and (file-exists? p)
|
||||
(regexp-match #rx"\\.rkt$" ps))
|
||||
(define fmod `(file ,ps))
|
||||
(define mod `(submod ,fmod ,submodule))
|
||||
(or (not check-suffix?)
|
||||
(regexp-match #rx#"\\.rkt$" (path->bytes p))))
|
||||
(define mod `(submod ,p ,submodule))
|
||||
(cond
|
||||
[(module-declared? mod #t)
|
||||
(dynamic-require mod #f)]
|
||||
[(and run-anyways? (module-declared? fmod #t))
|
||||
(dynamic-require fmod #f)])]
|
||||
[(and run-anyways? (module-declared? p #t))
|
||||
(dynamic-require p #f)])]
|
||||
[(not (file-exists? p))
|
||||
(error 'test "Given path ~e does not exist" p)])]))
|
||||
|
||||
(command-line
|
||||
#:program (short-program+command-name)
|
||||
#:once-each
|
||||
[("--submodule" "-s") submodule-str
|
||||
"Determines which submodule to load"
|
||||
(set! submodule (string->symbol submodule-str))]
|
||||
[("--submodule" "-s") name
|
||||
"Runs submodule <name> (defaults to `test')"
|
||||
(set! submodule (string->symbol name))]
|
||||
[("--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)]
|
||||
#:args files+directories
|
||||
(for-each do-test files+directories))
|
||||
#:args file-or-directory
|
||||
(for-each do-test file-or-directory))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#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))
|
||||
|
||||
|
@ -153,9 +154,21 @@ independently. Furthermore, if @filepath{park.rkt} is compiled to a
|
|||
bytecode file (via @exec{raco make}), then the code for
|
||||
@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,
|
||||
but @racket[module*] inverts the possibilities for reference between
|
||||
the submodule and enclosing module:
|
||||
Submodules can be nested within submodules, and a submodule can be
|
||||
referenced directly by a module other than its enclosing module by
|
||||
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[
|
||||
|
||||
|
@ -166,23 +179,56 @@ the submodule and enclosing module:
|
|||
|
||||
@item{A submodule declared with @racket[module*] can @racket[require]
|
||||
its enclosing module, but the enclosing module cannot
|
||||
@racket[require] the submodule. In addition, a @racket[module*]
|
||||
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].}
|
||||
@racket[require] the submodule.}
|
||||
|
||||
]
|
||||
|
||||
As an example of @racket[module*], the following variant of
|
||||
@filepath{cake.rkt} includes a @racket[main] submodule that calls
|
||||
@racket[print-cake]:
|
||||
In addition, a @racket[module*] form can specify @racket[#f] in place of an
|
||||
@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].
|
||||
|
||||
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[
|
||||
#:file "cake.rkt"
|
||||
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)
|
||||
(show " ~a " n #\.)
|
||||
|
@ -198,31 +244,100 @@ racket
|
|||
(print-cake 10))
|
||||
]
|
||||
|
||||
Running a module does not run its @racket[module*]-defined submodules,
|
||||
since the enclosing module cannot directly reference
|
||||
@racket[module*]-defined submodules. Nevertheless, running the above
|
||||
module via @exec{racket} or DrRacket prints a cake with 10 candles,
|
||||
because the @racket[main] submodule} is a special case.
|
||||
Running a module does not run its @racket[module*]-defined
|
||||
submodules. Nevertheless, running the above module via @exec{racket}
|
||||
or DrRacket prints a cake with 10 candles, because the @racket[main]
|
||||
@tech{submodule} is a special case.
|
||||
|
||||
When a module is provided as a program name to the @exec{racket}
|
||||
executable or run directly within DrRacket, if the module has a
|
||||
@as-index{@racket[main] submodule}, the @racket[main] submodule is run after its
|
||||
enclosing module. Declaring a @racket[main] submodule is often a
|
||||
useful describe tests or other extra actions to be performed when a
|
||||
module is run directly instead of @racket[required] as a library
|
||||
within a larger program.
|
||||
@as-index{@racket[main] submodule}, the @racket[main] submodule is run
|
||||
after its enclosing module. Declaring a @racket[main] submodule
|
||||
thus specifies extra actions to be performed when a module is run directly,
|
||||
instead of @racket[required] as a library within a larger program.
|
||||
|
||||
A @racket[main] submodule does not have to be declared with
|
||||
@racket[module*]. If the @racket[main] module does not need to use
|
||||
bindings from its enclosing module, it can be declared with
|
||||
@racket[module]. A @racket[main] submodule typically uses the
|
||||
bindings of its enclosing module, however, so @racket[main] is usually
|
||||
declared with @racket[module*].
|
||||
@racket[module]. More commonly, @racket[main] is declared using a
|
||||
third submodule form, @racket[module+]:
|
||||
|
||||
Submodules can be nested within submodules, and a submodule can be
|
||||
referenced directly by a module other than its enclosing module by
|
||||
using a @racket[submod] path as described in the
|
||||
@seclink["module-paths"]{next section}.
|
||||
@specform[
|
||||
(module+ name-id
|
||||
decl ...)
|
||||
]
|
||||
|
||||
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}
|
||||
|
||||
The @exec{raco test} command requires and runs the @racket['test]
|
||||
submodules associated with paths given on the command line. When a
|
||||
The @exec{raco test} command requires and runs the @racket[test]
|
||||
submodule (if any) associated with each path given on the command line. When a
|
||||
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:
|
||||
|
||||
@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},
|
||||
@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?]{
|
||||
|
||||
Returns a @tech{resolved module path} that encapsulates @racket[path].
|
||||
If @racket[path] is not a symbol, it normally should be
|
||||
Returns a @tech{resolved module path} that encapsulates @racket[path],
|
||||
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
|
||||
@racket[simplify-path]).
|
||||
|
||||
|
@ -38,9 +43,14 @@ A @tech{resolved module path} is interned. That is, if two
|
|||
@racket[eq?].}
|
||||
|
||||
@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?]{
|
||||
|
|
|
@ -290,6 +290,8 @@ See also @secref["module-eval-model"] and @secref["mod-parse"].
|
|||
@defform*[((module* id module-path form ...)
|
||||
(module* id #f form ...))]{
|
||||
|
||||
@guideintro["submodules"]{@racket[module*]}
|
||||
|
||||
Like @racket[module], but only for declaring a @tech{submodule} within
|
||||
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 ...)]{
|
||||
|
||||
@guideintro["main-and-test"]{@racket[module+]}
|
||||
|
||||
Declares and/or adds to a @tech{submodule} named @racket[id].
|
||||
|
||||
Each addition for @racket[id] is combined in order to form the entire
|
||||
|
|
Loading…
Reference in New Issue
Block a user