add scribble/examples

The `scribble/examples` library provides a cleaner and more modern
interface for evaluation compared to `scribble/eval`.
This commit is contained in:
Matthew Flatt 2015-12-11 10:55:00 -07:00
parent f1f47c5f16
commit 50f835c4f1
6 changed files with 494 additions and 230 deletions

View File

@ -1,172 +1,112 @@
#lang scribble/doc #lang scribble/doc
@(require scribble/manual @(require scribble/manual
"utils.rkt" "utils.rkt"
(for-label racket/sandbox (for-label scribble/eval
racket/sandbox
racket/pretty racket/pretty
file/convertible file/convertible
racket/serialize)) racket/serialize))
@title[#:tag "eval"]{Evaluation and Examples} @(define-syntax-rule (define-new-examples new-examples)
(begin
(require (for-label scribble/examples))
(define new-examples @racket[examples])))
@(define-new-examples new-examples)
@title[#:tag "old-eval"]{Legacy Evaluation}
@defmodule[scribble/eval]{The @racketmodname[scribble/eval] library provides
an older interface to the functionality of @racketmodname[scribble/examples].
The @racketmodname[scribble/examples] library should be used, instead.}
In addition to the forms listed below, @racket[scribble/eval]
re-exports several functions from @racket[scribble/examples]:
@racket[make-base-eval] @racket[make-base-eval-factory],
@racket[make-eval-factory], @racket[make-log-based-eval],
@racket[close-eval], and @racket[scribble-eval-handler].
@defmodule[scribble/eval]{The @racket[scribble/eval] library provides
utilities for evaluating code at document-build time and incorporating
the results in the document, especially to show example uses of
defined procedures and syntax.}
@defform/subs[(interaction maybe-options datum ...) @defform/subs[(interaction maybe-options datum ...)
([maybe-options maybe-eval maybe-escape maybe-disallow-errors] ([maybe-options maybe-eval maybe-escape maybe-no-errors]
[maybe-eval code:blank [maybe-eval code:blank
(code:line #:eval eval-expr)] (code:line #:eval eval-expr)]
[maybe-escape code:blank [maybe-escape code:blank
(code:line #:escape escape-id)] (code:line #:escape escape-id)]
[maybe-disallow-errors code:blank [maybe-no-errors code:blank
(code:line #:no-errors? no-errors?-expr)])]{ (code:line #:no-errors? no-errors?-expr)])]{
Like @racket[racketinput], except that the result for each input Like @|new-examples| from @racketmodname[scribble/examples], except that
@racket[datum] is shown on the next line. The result is determined by
evaluating the @racket[quote]d form of the @racket[datum] using the
evaluator produced by @racket[eval-expr], if provided.
The @racket[eval-expr] must produce a sandbox evaluator via
@racket[make-evaluator] or @racket[make-module-evaluator] with the
@racket[sandbox-output] and @racket[sandbox-error-output] parameters
set to @racket['string]. If @racket[eval-expr] is not provided or is
@racket[#f], an evaluator is created using @racket[make-base-eval]. See also
@racket[make-eval-factory].
If @racket[no-errors?-expr] is provided and produces a true
value, then when evaluating a @racket[datum] produces an error (and
@racket[datum] does not have an @racket[eval:error] wrapper), an
exception is raised by @racket[interaction]. Otherwise, any exception
produced by a @racket[datum] evaluation is typeset as an error result.
If the value of @racket[current-print] in the sandbox is changed from
its default value, or if @racket[print-as-expression] in the sandbox
is set to @racket[#f], then each evaluation result is formatted to a
port by applying @racket[(current-print)] to the value; the output
port is set to a pipe that supports specials in the sense of
@racket[write-special], and non-character values written to the port
are used as @tech{content}. Otherwise, when the default
@racket[current-print] is in place, result values are typeset using
@racket[to-element/no-color].
Certain patterns in @racket[datum] are treated specially:
@itemlist[ @itemlist[
@item{A @racket[datum] of the form @item{the ``Examples:'' label is always supressed,}
@racket[(@#,indexed-racket[code:line] _code-datum (@#,racketidfont{code:comment} _comment-datum ...))]
is treated as @racket[_code-datum] for evaluation.}
@item{A @racket[datum] of the form @item{exceptions raised during the evaluation of a @racket[datum] are
@racket[(@#,indexed-racket[code:line] _code-datum ...)] always rendered as errors, unless @racket[#:no-errors?] is
evaluates each @racket[_code-datum], but only the last result is used.} specified with a true value; and}
@item{Other uses of @racketidfont{code:comment}, @racketidfont{code:contract}, and @item{the @racket[#:once] option is never implicitly used.}
@racketidfont{code:blank} are stripped from each @racket[datum]
before evaluation.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:error] #,(svar eval-datum))] is
treated like @racket[_eval-datum], but @racket[_eval-datum] is
expected to raise an exception, and an error is shown as the
evaluation's result---even if @racket[#:no-errors? #t] is
specified for the @racket[interactions] form.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:alts] #,(svar show-datum) #,(svar eval-datum))]
is treated as @svar[show-datum] for typesetting and @svar[eval-datum] for evaluation.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:check] #,(svar eval-datum) #,(svar expect-datum))]
is treated like @racket[_eval-datum], but @svar[check-datum] is also
evaluated, and an error is raised if they are not @racket[equal?].}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:result] _content-expr _out-expr _err-expr)]
involves no sandboxed evaluation; instead, the @tech{content} result of @racket[_content-expr] is used as the
typeset form of the result, @racket[_out-expr] is treated as output printed
by the expression, and @racket[_err-expr] is error output printed by the
expression. The @racket[_out-expr] and/or @racket[_err-expr] can be omitted,
in which case they default to empty strings.
Normally, @racketidfont{eval:result}
is used in the second part of an @racketidfont{eval:alts} combination.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:results] _content-list-expr _out-expr _err-expr)]
is treated like an @racketidfont{eval:result} form, except that @racket[_content-list-expr]
should produce a list of @tech{content} for multiple results of evaluation. As
with @racketidfont{eval:result}, @racket[_out-expr] and @racket[_err-expr] are optional.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:no-prompt] _eval-datum ...)]
is treated like @racket[(@#,racket[code:line] _eval-datum ...)], but no prompt is shown before
the group, and a blank line is added before and after
@(svar eval-datum) and its result.}
] ]
As an example,
@codeblock|{
#lang scribble/manual
@(require racket/sandbox
scribble/eval)
@(define my-evaluator
(parameterize ([sandbox-output 'string]
[sandbox-error-output 'string])
(make-evaluator 'typed/racket/base)))
@interaction[#:eval my-evaluator
(: my-sqr (Real -> Real))
(define (my-sqr x)
(* x x))
(my-sqr 42)]
}|
uses an evaluator whose language is @racketmodname[typed/racket/base].
@history[#:changed "1.14" @elem{Added @racket[#:no-errors?], @history[#:changed "1.14" @elem{Added @racket[#:no-errors?],
@racket[eval:no-prompt], and @racket[eval:no-prompt], and
@racket[eval:error], and changed @racket[eval:error], and changed
@racket[code:line] to support multiple @racket[code:line] to support multiple
@racket[_datum]s.}]} @racket[_datum]s.}]}
@defform[(interaction0 maybe-options datum ...)]{ @defform[(interaction0 maybe-options datum ...)]{
Like @racket[interaction], but without insetting the code via Like @racket[interaction], but without insetting the code via
@racket[nested].} @racket[nested].
Use @|new-examples| with @racket[#:no-indent], instead.}
@defform[(interaction/no-prompt maybe-eval maybe-escape datum)]{ @defform[(interaction/no-prompt maybe-eval maybe-escape datum)]{
Like @racket[interaction], but does not render each @racket[datum] with a prompt. Like @racket[interaction], but does not render each @racket[datum] with a prompt.
}
Use @|new-examples| with @racket[#:no-prompt], instead.}
@defform[(interaction-eval maybe-eval datum)]{ @defform[(interaction-eval maybe-eval datum)]{
Like @racket[interaction], evaluates the @racket[quote]d form of Like @racket[interaction], evaluates the @racket[quote]d form of
@racket[datum], but returns the empty string and does not catch @racket[datum], but returns the empty string and does not catch
exceptions (so @racket[eval:error] has no effect).} exceptions (so @racket[eval:error] has no effect).
Use @|new-examples| with @racket[#:hidden], instead.}
@defform[(interaction-eval-show maybe-eval datum)]{ @defform[(interaction-eval-show maybe-eval datum)]{
Like @racket[interaction-eval], but produces an element representing Like @racket[interaction-eval], but produces an element representing
the printed form of the evaluation result.} the printed form of the evaluation result.
Use @|new-examples| with @racket[#:result-only], instead.}
@defform[(racketblock+eval maybe-eval maybe-escape datum ...)]{ @defform[(racketblock+eval maybe-eval maybe-escape datum ...)]{
Combines @racket[racketblock] and @racket[interaction-eval].} Combines @racket[racketblock] and @racket[interaction-eval].
Use @|new-examples| with @racket[#:no-result], instead.}
@defform[(racketblock0+eval maybe-eval maybe-escape datum ...)]{ @defform[(racketblock0+eval maybe-eval maybe-escape datum ...)]{
Combines @racket[racketblock0] and @racket[interaction-eval].} Combines @racket[racketblock0] and @racket[interaction-eval].
Use @|new-examples| with @racket[#:no-result] and
@racket[#:no-indent], instead.}
@defform[(racketmod+eval maybe-eval maybe-escape name datum ...)]{ @defform[(racketmod+eval maybe-eval maybe-escape name datum ...)]{
Combines @racket[racketmod] and @racket[interaction-eval].} Combines @racket[racketmod] and @racket[interaction-eval].
Use @|new-examples| with @racket[#:lang], instead.}
@defform[(def+int maybe-options defn-datum expr-datum ...)]{ @defform[(def+int maybe-options defn-datum expr-datum ...)]{
@ -178,31 +118,45 @@ space is inserted before the @racket[expr-datum]s.}
@defform[(defs+int maybe-options (defn-datum ...) expr-datum ...)]{ @defform[(defs+int maybe-options (defn-datum ...) expr-datum ...)]{
Like @racket[def+int], but for multiple leading definitions.} Like @racket[def+int], but for multiple leading definitions.
Use @|new-examples| with @racket[eval:no-prompt] wrappers on
definitions, instead.}
@defform[(examples maybe-options datum ...)]{ @defform[(examples maybe-options datum ...)]{
Like @racket[interaction], but with an ``Examples:'' label prefixed.} Like @racket[interaction], but with an ``Examples:'' label prefixed.
Use @|new-examples| from @racketmodname[scribble/examples], instead.}
@defform[(examples* label-expr maybe-options datum ...)]{ @defform[(examples* label-expr maybe-options datum ...)]{
Like @racket[examples], but using the result of @racket[label-expr] in Like @racket[examples], but using the result of @racket[label-expr] in
place of the default ``Examples:'' label.} place of the default ``Examples:'' label.
Use @|new-examples| from @racketmodname[scribble/examples] with the
@racket[#:label] option, instead.}
@defform[(defexamples maybe-options datum ...)]{ @defform[(defexamples maybe-options datum ...)]{
Like @racket[examples], but each definition using @racket[define] or Like @racket[examples], but each definition using @racket[define] or
@racket[define-struct] among the @racket[datum]s is typeset without a @racket[define-struct] among the @racket[datum]s is typeset without a
prompt, and with line of space after it.} prompt, and with line of space after it.
Use @|new-examples| with @racket[eval:no-prompt] wrappers on
definitions, instead.}
@defform[(defexamples* label-expr maybe-options datum ...)]{ @defform[(defexamples* label-expr maybe-options datum ...)]{
Like @racket[defexamples], but using the result of @racket[label-expr] in Like @racket[defexamples], but using the result of @racket[label-expr] in
place of the default ``Examples:'' label.} place of the default ``Examples:'' label.
Use @|new-examples| with the @racket[#:label] option and
@racket[eval:no-prompt] wrappers on definitions, instead.}
@defproc*[([(as-examples [b block?]) block?] @defproc*[([(as-examples [b block?]) block?]
@ -213,114 +167,6 @@ place of the default ``Examples:'' label.}
Adds an ``examples'' label to @racket[b], using either a default label Adds an ``examples'' label to @racket[b], using either a default label
or the given @racket[label].} or the given @racket[label].}
@defproc[(make-base-eval [#:pretty-print? pretty-print? any/c #t]
[#:lang lang
(or/c module-path?
(list/c 'special symbol?)
(cons/c 'begin list?))
'(begin)]
[input-program any/c] ...)
(any/c . -> . any)]{
Creates an evaluator using @racket[(make-evaluator 'racket/base #:lang lang input-program ...)],
setting sandbox parameters to disable limits, setting the outputs to
@racket['string], and not adding extra security guards.
If @racket[pretty-print?] is true, the sandbox's printer is set to
@racket[pretty-print-handler]. In that case, values that are convertible
in the sense of @racket[convertible?] are printed using @racket[write-special],
except that values that are serializable in the sense of @racket[serializable?]
are serialized for tranfers from inside the sandbox to outside (which can avoid
pulling code and support from the sandboxed environment into the document-rendering
environment).
@history[#:changed "1.6" @elem{Changed treatment of convertible values that are
serializable.}]}
@defproc[(make-base-eval-factory [mod-paths (listof module-path?)]
[#:pretty-print? pretty-print? any/c #t]
[#:lang lang
(or/c module-path?
(list/c 'special symbol?)
(cons/c 'begin list?))
'(begin)])
(-> (any/c . -> . any))]{
Produces a function that is like @racket[make-base-eval], except that
each module in @racket[mod-paths] is attached to the evaluator's
namespace. The modules are loaded and instantiated once (when the
returned @racket[make-base-eval]-like function is called the first
time) and then attached to each evaluator that is created.}
@defproc[(make-eval-factory [mod-paths (listof module-path?)]
[#:pretty-print? pretty-print? any/c #t]
[#:lang lang
(or/c module-path?
(list/c 'special symbol?)
(cons/c 'begin list?))
'(begin)])
(-> (any/c . -> . any))]{
Like @racket[make-base-eval-factory], but each module in @racket[mod-paths] is
also required into the top-level environment for each generated evaluator.}
@defproc[(make-log-based-eval [log-file path-string?]
[mode (or/c 'record 'replay)])
(-> any/c any)]{
Creates an evaluator (like @racket[make-base-eval]) that uses a log
file to either record or replay evaluations.
If @racket[mode] is @racket['record], the evaluator records every
interaction to @racket[log-file], replacing @racket[log-file] if it
already exists. The result of each interaction must be
@seclink["serialization" #:doc '(lib
"scribblings/reference/reference.scrbl")]{serializable}.
If @racket[mode] is @racket['replay], the evaluator uses the contents
of @racket[log-file] instead of actually performing evaluatings. For
each interaction, it compares the term to evaluate against the next
interaction recorded in @racket[log-file]. If the term matches, the
stored result is returned; if not, the evaluator raises an error
indicating that it is out of sync with @racket[log-file].
Use @racket[make-log-based-eval] to document libraries when the
embedded examples rely on external features that may not be present or
appropriately configured on all machines.
@history[#:added "1.12"]{}
}
@defproc[(close-eval [eval (any/c . -> . any)]) (one-of/c "")]{
Shuts down an evaluator produced by @racket[make-base-eval]. Use
@racket[close-eval] when garbage collection cannot otherwise reclaim
an evaluator (e.g., because it is defined in a module body).}
@defparam[scribble-eval-handler handler
((any/c . -> . any) any/c boolean? . -> . any)]{
A parameter that serves as a hook for evaluation. The evaluator to use
is supplied as the first argument to the parameter's value, and the
second argument is the form to evaluate. The last argument is
@racket[#t] if exceptions are being captured (to display exception
results), @racket[#f] otherwise.}
@defparam[scribble-exn->string handler (-> (or/c exn? any/c) string?)]{
A parameter that controls how exceptions are rendered by
@racket[interaction]. Defaults to
@racketblock[(λ (e)
(if (exn? e)
(exn-message e)
(format "uncaught exception: ~s" e)))]
}
@defform[(with-eval-preserve-source-locations expr ...)]{ @defform[(with-eval-preserve-source-locations expr ...)]{
By default, the evaluation forms provided by this module, such as By default, the evaluation forms provided by this module, such as
@ -329,4 +175,6 @@ locations from the expressions they evaluate. Within a
@racket[with-eval-preserve-source-locations] form, the source @racket[with-eval-preserve-source-locations] form, the source
locations are preserved. This can be useful for documenting forms that locations are preserved. This can be useful for documenting forms that
depend on source locations, such as Redex's typesetting macros. depend on source locations, such as Redex's typesetting macros.
}
Use @|new-examples| with the @racket[#:preserve-source-locations]
option, instead.}

View File

@ -0,0 +1,303 @@
#lang scribble/doc
@(require scribble/manual
"utils.rkt"
(for-label scribble/examples
racket/sandbox
racket/pretty
file/convertible
racket/serialize))
@title[#:tag "eval"]{Evaluation and Examples}
@defmodule[scribble/examples #:use-sources (scribble/eval scribble/examples)]{The
@racket[scribble/examples] library provides
utilities for evaluating code at document-build time and incorporating
the results in the document, especially to show example uses of
defined procedures and syntax.}
@history[#:added "1.14"]
@defform/subs[(examples option ... datum ...)
([option (code:line #:eval eval-expr)
#:once
(code:line #:escape escape-id)
(code:line #:label label-expr)
#:hidden
#:result-only
#:no-inset
#:no-prompt
#:preserve-source-locations
#:no-result
(code:line #:lang language-name)])]{
Similar to @racket[racketinput], except that the result for each input
@racket[datum] is shown on the next line. The result is determined by
evaluating the @racket[quote]d form of the @racket[datum] using the
evaluator produced by @racket[eval-expr].
Each keyword option can be provided at most once:
@itemlist[
@item{@racket[#:eval eval-expr] --- Specifies an evaluator, where
@racket[eval-expr] must produce either @racket[#f] or a sandbox
evaluator via @racket[make-evaluator] or
@racket[make-module-evaluator] with the @racket[sandbox-output]
and @racket[sandbox-error-output] parameters set to
@racket['string]. If @racket[eval-expr] is not provided or is
@racket[#f], an evaluator is created using
@racket[make-base-eval]. See also @racket[make-eval-factory].}
@item{@racket[#:once] --- Specifies that the evaluator should be
closed with @racket[close-eval] after the all @racket[datum]s
are evaluated. The @racket[#:once] option is assumed if
@racket[#:eval] is not specified.}
@item{@racket[@#,racket[#:escape] escape-id] --- Specifies an escape
identifier, as in @racket[racketblock].}
@item{@racket[#:label label-expr] --- Specifies a label for the
examples, which defaults to ``Example:'' or ``Examples:''
(depending on the number of @racket[datum]s). A @racket[#f]
value for @racket[label-expr] suppresses the label.}
@item{@racket[#:hidden] --- Specifies that the @racket[datum]s and
results should not be typeset, but instead evaluated for a
side-effect, and disables @racket[eval:error]. Typically, this
option is combined with @racket[#:eval] to configure an
evaluator.}
@item{@racket[#:result-only] --- Specifies that the @racket[datum]
results should be typeset, but not the @racket[datum]s
themselves, and implies @racket[#:label #f].}
@item{@racket[#:no-result] --- Implies @racket[#:no-prompt] and
@racket[#:label #f], specifies that no results should be
typeset, and disables @racket[eval:error].}
@item{@racket[#:no-inset] --- Specifies that the examples should be
typeset without indentation, i.e., like @racket[racketinput0]
instead of @racket[racketinput].}
@item{@racket[#:no-prompt] --- Specifies that each examples should
be typeset without a leading prompt, i.e., like
@racket[racketblock] instead of @racket[racketinput]. A prompt
can be omitted from a specific @racket[_datum] by wrapping it
with @racket[eval:no-prompt].}
@item{@racket[#:preserve-source-locations] --- Specifies that the
original source locations for each @racket[datum] should be
preserved for evaluation. Preserving source locations can be
useful for documenting forms that depend on source locations,
such as Redex's typesetting macros.}
@item{@racket[#:lang] --- Implies @racket[#:no-result] prefixes the
typeset @racket[datum] sequence with a @hash-lang[] line using
@racket[language-name] as the module's language.}
]
Certain patterns in @racket[datum] are treated specially:
@itemlist[
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[code:line] _code-datum (@#,racketidfont{code:comment} _comment-datum ...))]
is treated as @racket[_code-datum] for evaluation.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[code:line] _code-datum ...)]
evaluates each @racket[_code-datum], but only the last result is used.}
@item{Other uses of @racketidfont{code:comment}, @racketidfont{code:contract}, and
@racketidfont{code:blank} are stripped from each @racket[datum]
before evaluation.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:error] #,(svar eval-datum))] is
treated like @racket[_eval-datum], but @racket[_eval-datum] is
expected to raise an exception, and an error is shown as the
evaluation's result---even if @racket[#:no-errors? #t] is
specified for the @racket[interactions] form.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:alts] #,(svar show-datum) #,(svar eval-datum))]
is treated as @svar[show-datum] for typesetting and @svar[eval-datum] for evaluation.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:check] #,(svar eval-datum) #,(svar expect-datum))]
is treated like @racket[_eval-datum], but @svar[check-datum] is also
evaluated, and an error is raised if they are not @racket[equal?].}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:result] _content-expr _out-expr _err-expr)]
involves no sandboxed evaluation; instead, the @tech{content} result of @racket[_content-expr] is used as the
typeset form of the result, @racket[_out-expr] is treated as output printed
by the expression, and @racket[_err-expr] is error output printed by the
expression. The @racket[_out-expr] and/or @racket[_err-expr] can be omitted,
in which case they default to empty strings.
Normally, @racketidfont{eval:result}
is used in the second part of an @racketidfont{eval:alts} combination.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:results] _content-list-expr _out-expr _err-expr)]
is treated like an @racketidfont{eval:result} form, except that @racket[_content-list-expr]
should produce a list of @tech{content} for multiple results of evaluation. As
with @racketidfont{eval:result}, @racket[_out-expr] and @racket[_err-expr] are optional.}
@item{A @racket[datum] of the form
@racket[(@#,indexed-racket[eval:no-prompt] _eval-datum ...)]
is treated like @racket[(@#,racket[code:line] _eval-datum ...)], but no prompt is shown before
the group, and a blank line is added before and after
@(svar eval-datum) and its result.}
]
A @racket[datum] cannot be a keyword. To specify a @racket[datum] that
is a keyword, wrap it with @racket[code:line].
When evaluating a @racket[datum] produces an error (and @racket[datum]
does not have an @racket[eval:error] wrapper), an exception is raised
by @racket[examples].
If the value of @racket[current-print] in the sandbox is changed from
its default value, or if @racket[print-as-expression] in the sandbox
is set to @racket[#f], then each evaluation result is formatted to a
port by applying @racket[(current-print)] to the value; the output
port is set to a pipe that supports specials in the sense of
@racket[write-special], and non-character values written to the port
are used as @tech{content}. Otherwise, when the default
@racket[current-print] is in place, result values are typeset using
@racket[to-element/no-color].
As an example,
@codeblock|{
#lang scribble/manual
@(require racket/sandbox
scribble/eval)
@(define my-evaluator
(parameterize ([sandbox-output 'string]
[sandbox-error-output 'string])
(make-evaluator 'typed/racket/base)))
@examples[#:eval my-evaluator
(: my-sqr (Real -> Real))
(define (my-sqr x)
(* x x))
(my-sqr 42)]
}|
uses an evaluator whose language is @racketmodname[typed/racket/base].}
@defproc[(make-base-eval [#:pretty-print? pretty-print? any/c #t]
[#:lang lang
(or/c module-path?
(list/c 'special symbol?)
(cons/c 'begin list?))
'(begin)]
[input-program any/c] ...)
(any/c . -> . any)]{
Creates an evaluator using @racket[(make-evaluator 'racket/base #:lang lang input-program ...)],
setting sandbox parameters to disable limits, setting the outputs to
@racket['string], and not adding extra security guards.
If @racket[pretty-print?] is true, the sandbox's printer is set to
@racket[pretty-print-handler]. In that case, values that are convertible
in the sense of @racket[convertible?] are printed using @racket[write-special],
except that values that are serializable in the sense of @racket[serializable?]
are serialized for tranfers from inside the sandbox to outside (which can avoid
pulling code and support from the sandboxed environment into the document-rendering
environment).
@history[#:changed "1.6" @elem{Changed treatment of convertible values that are
serializable.}]}
@defproc[(make-base-eval-factory [mod-paths (listof module-path?)]
[#:pretty-print? pretty-print? any/c #t]
[#:lang lang
(or/c module-path?
(list/c 'special symbol?)
(cons/c 'begin list?))
'(begin)])
(-> (any/c . -> . any))]{
Produces a function that is like @racket[make-base-eval], except that
each module in @racket[mod-paths] is attached to the evaluator's
namespace. The modules are loaded and instantiated once (when the
returned @racket[make-base-eval]-like function is called the first
time) and then attached to each evaluator that is created.}
@defproc[(make-eval-factory [mod-paths (listof module-path?)]
[#:pretty-print? pretty-print? any/c #t]
[#:lang lang
(or/c module-path?
(list/c 'special symbol?)
(cons/c 'begin list?))
'(begin)])
(-> (any/c . -> . any))]{
Like @racket[make-base-eval-factory], but each module in @racket[mod-paths] is
also required into the top-level environment for each generated evaluator.}
@defproc[(make-log-based-eval [log-file path-string?]
[mode (or/c 'record 'replay)])
(-> any/c any)]{
Creates an evaluator (like @racket[make-base-eval]) that uses a log
file to either record or replay evaluations.
If @racket[mode] is @racket['record], the evaluator records every
interaction to @racket[log-file], replacing @racket[log-file] if it
already exists. The result of each interaction must be
@seclink["serialization" #:doc '(lib
"scribblings/reference/reference.scrbl")]{serializable}.
If @racket[mode] is @racket['replay], the evaluator uses the contents
of @racket[log-file] instead of actually performing evaluatings. For
each interaction, it compares the term to evaluate against the next
interaction recorded in @racket[log-file]. If the term matches, the
stored result is returned; if not, the evaluator raises an error
indicating that it is out of sync with @racket[log-file].
Use @racket[make-log-based-eval] to document libraries when the
embedded examples rely on external features that may not be present or
appropriately configured on all machines.
@history[#:added "1.12"]}
@defproc[(close-eval [eval (any/c . -> . any)]) (one-of/c "")]{
Shuts down an evaluator produced by @racket[make-base-eval]. Use
@racket[close-eval] when garbage collection cannot otherwise reclaim
an evaluator (e.g., because it is defined in a module body).}
@defparam[scribble-eval-handler handler
((any/c . -> . any) any/c boolean? . -> . any)]{
A parameter that serves as a hook for evaluation. The evaluator to use
is supplied as the first argument to the parameter's value, and the
second argument is the form to evaluate. The last argument is
@racket[#t] if exceptions are being captured (to display exception
results), @racket[#f] otherwise.}
@defparam[scribble-exn->string handler (-> (or/c exn? any/c) string?)]{
A parameter that controls how exceptions are rendered by
@racket[interaction]. Defaults to
@racketblock[(λ (e)
(if (exn? e)
(exn-message e)
(format "uncaught exception: ~s" e)))]
}
@; ------------------------------------------------------------
@include-section["eval.scrbl"]

View File

@ -19,7 +19,7 @@ relevant libraries and APIs in detail.
@include-section["style.scrbl"] @include-section["style.scrbl"]
@include-section["manual.scrbl"] @include-section["manual.scrbl"]
@include-section["scheme.scrbl"] @include-section["scheme.scrbl"]
@include-section["eval.scrbl"] @include-section["examples.scrbl"]
@include-section["srcdoc.scrbl"] @include-section["srcdoc.scrbl"]
@include-section["bnf.scrbl"] @include-section["bnf.scrbl"]
@include-section["compat.scrbl"] @include-section["compat.scrbl"]

View File

@ -23,7 +23,6 @@
scribble/racket scribble/racket
scribble/html-properties scribble/html-properties
scribble/latex-properties scribble/latex-properties
scribble/eval
scribble/bnf) scribble/bnf)
(provide scribble-examples litchar/lines doc-render-examples) (provide scribble-examples litchar/lines doc-render-examples)

View File

@ -315,7 +315,8 @@
render+output) render+output)
(lambda (str) (lambda (str)
(if (eval-results? str) (if (eval-results? str)
(list (map formatted-result (eval-results-contents str)) (list #f
(map formatted-result (eval-results-contents str))
(eval-results-out str) (eval-results-out str)
(eval-results-err str)) (eval-results-err str))
(extract-to-evaluate (extract-to-evaluate

View File

@ -0,0 +1,113 @@
#lang racket/base
(require "eval.rkt"
(only-in "struct.rkt" make-paragraph)
(for-syntax racket/base
syntax/parse))
(provide examples
;; Re-exports:
make-base-eval
make-base-eval-factory
make-eval-factory
close-eval
scribble-exn->string
scribble-eval-handler
make-log-based-eval)
(define example-title
(make-paragraph (list "Example:")))
(define examples-title
(make-paragraph (list "Examples:")))
(define-syntax (examples stx)
(syntax-parse stx
[(_ (~or (~optional (~seq #:eval eval:expr))
(~optional (~and #:once once-kw))
(~optional (~seq #:escape escape:id))
(~optional (~seq #:label title:expr))
(~optional (~and #:no-inset no-inset-kw))
(~optional (~and #:no-prompt no-prompt-kw))
(~optional (~and #:result-only no-form-kw))
(~optional (~and #:no-result block-kw))
(~optional (~and #:hidden no-result-kw))
(~optional (~and #:preserve-source-locations preserve-srclocs-kw))
(~optional (~seq #:lang module-name)))
...
form:expr ...)
(define once? (or (attribute once-kw)
(not (attribute eval))))
(define eval-stx (or (attribute eval) #'(make-base-eval)))
(define base-form
(with-syntax ([eval (if once? #'once-eval eval-stx)]
[escape (or (attribute escape) #'unsyntax)])
(cond
[(attribute block-kw)
(when (attribute module-name)
(raise-syntax-error #f "#:block and #:module are mutually exclusive" stx))
(cond
[(attribute no-inset-kw)
(syntax/loc stx
(racketblock0+eval #:eval eval #:escape escape
form ...))]
[else
(syntax/loc stx
(racketblock+eval #:eval eval #:escape escape
form ...))])]
[(attribute module-name)
(syntax/loc stx
(racketmod+eval #:eval eval #:escape escape module-name
form ...))]
[(attribute no-result-kw)
(syntax/loc stx
(interaction-eval #:eval eval form ...))]
[(attribute no-form-kw)
(syntax/loc stx
(interaction-eval-show #:eval eval form ...))]
[(attribute no-prompt-kw)
(syntax/loc stx
(interaction/no-prompt #:eval eval #:escape escape #:no-errors? #t
form ...))]
[(attribute no-inset-kw)
(syntax/loc stx
(interaction0 #:eval eval #:escape escape #:no-errors? #t
form ...))]
[else
(syntax/loc stx
(interaction #:eval eval #:escape escape #:no-errors? #t
form ...))])))
(define srcloced-form
(cond
[(attribute preserve-srclocs-kw)
(with-syntax ([base-form base-form])
(syntax/loc stx
(with-eval-preserve-source-locations base-form)))]
[else base-form]))
(define examples-form
(cond
[(or (attribute title)
(not (or (attribute block-kw)
(attribute module-name)
(attribute no-result-kw)
(attribute no-form-kw))))
(with-syntax ([srcloced-form srcloced-form]
[title (or (attribute title)
(cond
[(= 1 (length (syntax->list #'(form ...))))
#'example-title]
[else #'examples-title]))])
(syntax/loc stx (as-examples title srcloced-form)))]
[else
srcloced-form]))
(if once?
(with-syntax ([eval eval-stx]
[examples-form examples-form])
(syntax/loc stx
(let ([once-eval eval])
(begin0
examples-form
(close-eval eval)))))
examples-form)]))