From 3f69df3ff576fd61a3d3ecf502a2fabe6a3899da Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Fri, 29 Jan 2016 10:42:50 -0800 Subject: [PATCH] simplify splicing; add to docs --- pollen/core.rkt | 20 +++++--------------- pollen/render.rkt | 23 ++++++++++++----------- pollen/scribblings/core.html | 2 ++ pollen/scribblings/core.scrbl | 11 +++++++++++ pollen/scribblings/world.html | 8 ++++++++ pollen/scribblings/world.scrbl | 4 +--- 6 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 pollen/scribblings/core.html create mode 100644 pollen/scribblings/world.html diff --git a/pollen/core.rkt b/pollen/core.rkt index ac1c53b..7a17679 100644 --- a/pollen/core.rkt +++ b/pollen/core.rkt @@ -6,7 +6,6 @@ "cache.rkt" "pagetree.rkt" "tag.rkt" - "private/to-string.rkt" "private/splice.rkt") (define is-meta-value? hash?) @@ -15,7 +14,7 @@ (define not-false? identity) (define+provide define-meta identity) ;; stub so it will be picked up for docs -(define+provide @ (make-default-tag-function '@)) + (define+provide/contract (select* key value-source) (coerce/symbol? (or/c is-meta-value? is-doc-value? pagenode? pathish?) . -> . (or/c #f txexpr-elements?)) @@ -104,6 +103,8 @@ (cached-doc (convert+validate-path pagenode-or-path 'get-doc))) +(define+provide @ (make-default-tag-function '@)) + (provide when/splice) (define-syntax (when/splice stx) (syntax-case stx () @@ -111,21 +112,10 @@ (with-syntax ([SPLICING-TAG (datum->syntax stx (world:current-splicing-tag))]) #'(if COND (with-handlers ([exn:fail? (λ(exn) (error (format "within when/splice, ~a" (exn-message exn))))]) - (list 'SPLICING-TAG BODY ...)) - ""))])) - - -(provide when/splice/text) -(define-syntax (when/splice/text stx) - (syntax-case stx () - [(_ COND BODY ...) - (with-syntax ([SPLICING-TAG (datum->syntax stx (world:current-splicing-tag))]) - #'(if COND - (with-handlers ([exn:fail? (λ(exn) (error (format "within when/splice, ~a" (exn-message exn))))]) - (map to-string (list BODY ...))) + (SPLICING-TAG BODY ...)) ""))])) (provide when/block) ; bw compat (define-syntax-rule (when/block cond body ...) - (when/splice/text cond body ...)) + (when/splice cond body ...)) diff --git a/pollen/render.rkt b/pollen/render.rkt index cc59570..ef25f78 100644 --- a/pollen/render.rkt +++ b/pollen/render.rkt @@ -176,19 +176,20 @@ (define expr-to-eval `(begin (require (for-syntax racket/base)) - (require pollen/private/include-template pollen/cache pollen/private/debug pollen/pagetree) + (require pollen/private/include-template pollen/cache pollen/private/debug pollen/pagetree pollen/core) ,(require-directory-require-files source-path) (parameterize ([current-pagetree (make-project-pagetree ,(world:current-project-root))]) - (let ([,(world:current-main-export) (cached-doc ,(path->string source-path))] - [,(world:current-meta-export) (cached-metas ,(path->string source-path))]) - (local-require pollen/template pollen/top pollen/core) + (let ([,(world:current-main-export source-path) (cached-doc ,(path->string source-path))] + [,(world:current-meta-export source-path) (cached-metas ,(path->string source-path))] + [,(world:current-splicing-tag source-path) (λ xs xs)]) ; splice behavior is different in textual context + (local-require pollen/template pollen/top) (define here (path->pagenode - (or (select-from-metas ',(world:current-here-path-key) ,(world:current-meta-export)) 'unknown))) + (or (select-from-metas ',(world:current-here-path-key source-path) ,(world:current-meta-export source-path)) 'unknown))) (cond - [(bytes? ,(world:current-main-export)) ,(world:current-main-export)] ; if main export is binary, just pass it through + [(bytes? ,(world:current-main-export source-path)) ,(world:current-main-export source-path)] ; if main export is binary, just pass it through [else ;; `include-template` is the slowest part of the operation (the eval itself is cheap) - (include-template #:command-char ,(world:current-command-char) (file ,(->string (find-relative-path source-dir template-path))))]))))) + (include-template #:command-char ,(world:current-command-char source-path) (file ,(->string (find-relative-path source-dir template-path))))]))))) (time (parameterize ([current-directory (->complete-path source-dir)]) ; because include-template wants to work relative to source location (render-through-eval expr-to-eval)))) @@ -213,7 +214,7 @@ (with-handlers ([exn:fail:contract? (λ _ #f)]) ; in case source-path doesn't work with cached-require (parameterize ([current-directory (world:current-project-root)]) (let* ([source-metas (cached-metas source-path)] - [template-name-or-names (select-from-metas (world:current-template-meta-key) source-metas)] ; #f or atom or list + [template-name-or-names (select-from-metas (world:current-template-meta-key source-path) source-metas)] ; #f or atom or list [template-name (cond [(list? template-name-or-names) (define result @@ -224,13 +225,13 @@ (define (get-default-template) (and output-path-ext - (let ([default-template-filename (add-ext (world:current-default-template-prefix) output-path-ext)]) + (let ([default-template-filename (add-ext (world:current-default-template-prefix source-path) output-path-ext)]) (find-upward-from source-path default-template-filename file-exists-or-has-source?)))) - + (define (get-fallback-template) (and output-path-ext (build-path (world:current-server-extras-path) - (add-ext (world:current-fallback-template-prefix) output-path-ext)))) + (add-ext (world:current-fallback-template-prefix source-path) output-path-ext)))) (or (file-exists-or-has-source? (get-template-from-metas)) (file-exists-or-has-source? (get-default-template)) diff --git a/pollen/scribblings/core.html b/pollen/scribblings/core.html new file mode 100644 index 0000000..f6a355a --- /dev/null +++ b/pollen/scribblings/core.html @@ -0,0 +1,2 @@ + +Core
6.4.0.4

Core

 (require pollen/core) package: pollen

These functions are automatically imported into every Pollen source file (meaning, as if they had been included in your "pollen.rkt").

1 Syntactic forms

syntax

(define-meta name value)

Add value to the metas of the current document, using name as the key.

You can retrieve a meta value — even in the same document where you define it — with (select-from-metas name metas).

For an introduction to metas, see (part "Inserting_metas").

syntax

(@ arg ...)

Splicing tag: signals that a list should be merged into its containing expression. You can use something other than @ by overriding world:current-splicing-tag.

Examples:
> (module splicer pollen/markup
  '(div "one" (@ "two" "three") "four"))
> (require 'splicer)
> doc

'(root (div "one" "two" "three" "four"))

syntax

(when/splice condition pollen-args)

If condition is true, put the pollen-args into the document. Within a template file, usually invoked like so:

◊when/splice[condition]{The text to insert.}

The inserted text can contain its own nested Pollen commands.

when/splice can be more convenient than when, because when will only use the last argument between the curly braces. when/splice, by contrast, treats everything between the curly braces as a block.

2 Data helpers

Functions for retrieving data out of Pollen source files. These are not the only options – you can, of course, use any of the usual Racket functions.

procedure

(get-doc doc-source)  (or/c txexpr? string?)

  doc-source : (or/c pagenode? pathish?)
Retrieve the doc export from doc-source, which can be either a path, path string, or pagenode that can be resolved into a source path. If doc-source cannot be resolved, raise an error.

If doc-source is a relative path or pagenode, it is treated as being relative to world:current-project-root. If that’s not what you want, you’ll need to convert it explicitly to a complete-path (e.g., with path->complete-path or ->complete-path).

If world:current-main-export has been overridden with a project-specific value, then that is retrieved instead.

procedure

(get-metas meta-source)  hash?

  meta-source : (or/c pagenode? pathish?)
Retrieve the metas export from meta-source, which can be either a path, path string, or pagenode that can be resolved into a source path. If meta-source cannot be resolved, raise an error.

If meta-source is a relative path or pagenode, it is treated as being relative to world:current-project-root. If that’s not what you want, you’ll need to convert it explicitly to a complete-path (e.g., with path->complete-path or ->complete-path).

If world:current-meta-export has been overridden with a project-specific value, then that is retrieved instead.

procedure

(select key value-source)  (or/c #f xexpr?)

  key : symbolish?
  value-source : (or/c hash? txexpr? pagenode? pathish?)

procedure

(select* key value-source)  (or/c #f (listof xexpr?))

  key : symbolish?
  value-source : (or/c hash? txexpr? pagenode? pathish?)
Find matches for key in value-source. The value-source can be 1) a hashtable of metas, 2) a tagged X-expression representing a doc, or 3) a pagenode or path that identifies a source file that provides metas and doc. In that case, first look for key in metas (using select-from-metas) and then in doc (using select-from-doc).

With select, you get the first result; with select*, you get them all.

In both cases, you get #f if there are no matches.

Note that if value-source is a relative path or pagenode, it is treated as being relative to world:current-project-root. If that’s not what you want, you’ll need to convert it explicitly to a complete-path (e.g., with path->complete-path or ->complete-path).

Examples:
> (module nut-butters pollen/markup
  '(div (question "Flavor?")
    (answer "Cashew") (answer "Almond")))
; Import doc from 'nut-butters submodule
> (require 'nut-butters)
> (select 'question  doc)

"Flavor?"

> (select 'answer  doc)

"Cashew"

> (select* 'answer  doc)

'("Cashew" "Almond")

> (select 'nonexistent-key doc)

#f

> (select* 'nonexistent-key doc)

#f

procedure

(select-from-doc key doc-source)  (or/c #f (listof xexpr?))

  key : symbolish?
  doc-source : (or/c txexpr? pagenodeish? pathish?)
Look up the value of key in doc-source. The doc-source argument can be either 1) a tagged X-expression representing a doc or 2) a pagenode or source path that identifies a source file that provides doc. If no value exists for key, you get #f.

Note that if doc-source is a relative path or pagenode, it is treated as being relative to world:current-project-root. If that’s not what you want, you’ll need to convert it explicitly to a complete-path (e.g., with path->complete-path or ->complete-path).

Examples:
> (module gelato pollen/markup
  '(div (question "Flavor?")
    (answer "Nocciola") (answer "Pistachio")))
; Import doc from 'gelato submodule
> (require 'gelato)
> (select-from-doc 'question  doc)

'("Flavor?")

> ('answer . select-from-doc . doc)

'("Nocciola" "Pistachio")

> (select-from-doc 'nonexistent-key doc)

#f

procedure

(select-from-metas key meta-source)  (or/c #f xexpr?)

  key : symbolish?
  meta-source : (or/c hash? pagenodeish? pathish?)
Look up the value of key in meta-source. The meta-source argument can be either 1) a hashtable representing metas or 2) a pagenode or source path that identifies a source file that provides metas. If no value exists for key, you get #f.

Note that if meta-source is a relative path or pagenode, it is treated as being relative to world:current-project-root. If that’s not what you want, you’ll need to convert it explicitly to a complete-path (e.g., with path->complete-path or ->complete-path).

Examples:
> (define metas (hash 'template "sub.xml.pp" 'target "print"))
> (select-from-metas 'template  metas)

"sub.xml.pp"

> ('target . select-from-metas . metas)

"print"

> (select-from-metas 'nonexistent-key metas)

#f

 
\ No newline at end of file diff --git a/pollen/scribblings/core.scrbl b/pollen/scribblings/core.scrbl index 4fe29b1..a13813d 100644 --- a/pollen/scribblings/core.scrbl +++ b/pollen/scribblings/core.scrbl @@ -22,6 +22,17 @@ You can retrieve a meta value — even in the same document where you define it For an introduction to metas, see @secref["Inserting_metas"]. +@defform[(\@ arg ...)] +Splicing tag: signals that a list should be merged into its containing expression. You can use something other than @racket[\@] by overriding @racket[world:current-splicing-tag]. + +@examples[#:eval my-eval +(module splicer pollen/markup +'(div "one" (\@ "two" "three") "four")) +(require 'splicer) +doc +] + + @defform[(when/splice condition pollen-args)] If @racket[_condition] is true, put the @racket[_pollen-args] into the document. Within a template file, usually invoked like so: diff --git a/pollen/scribblings/world.html b/pollen/scribblings/world.html new file mode 100644 index 0000000..a829c68 --- /dev/null +++ b/pollen/scribblings/world.html @@ -0,0 +1,8 @@ + +World
World
1 Parameters
world:  current-server-port
world:  current-project-root
world:  current-server-extras-path
world:  current-poly-target
2 World overrides
world:  default-port
world:  current-default-port
world:  main-export
world:  current-main-export
world:  meta-export
world:  current-meta-export
world:  meta-tag-name
world:  current-meta-tag-name
world:  server-extras-dir
world:  current-server-extras-dir
world:  extension-escape-char
world:  current-extension-escape-char
world:  preproc-source-ext
world:  current-preproc-source-ext
world:  markup-source-ext
world:  current-markup-source-ext
world:  markdown-source-ext
world:  current-markdown-source-ext
world:  null-source-ext
world:  current-null-source-ext
world:  pagetree-source-ext
world:  current-pagetree-source-ext
world:  template-source-ext
world:  current-template-source-ext
world:  scribble-source-ext
world:  current-scribble-source-ext
world:  decodable-extensions
world:  current-decodable-extensions
world:  default-pagetree
world:  current-default-pagetree
world:  pagetree-root-node
world:  current-pagetree-root-node
world:  main-root-node
world:  current-main-root-node
world:  block-tags
world:  current-block-tags
world:  command-char
world:  current-command-char
world:  default-template-prefix
world:  current-default-template-prefix
world:  fallback-template-prefix
world:  current-fallback-template-prefix
world:  template-meta-key
world:  current-template-meta-key
world:  newline
world:  current-newline
world:  linebreak-separator
world:  current-linebreak-separator
world:  paragraph-separator
world:  current-paragraph-separator
world:  dashboard-css
world:  current-dashboard-css
world:  paths-excluded-from-dashboard
world:  current-paths-excluded-from-dashboard
world:  render-cache-active
world:  current-render-cache-active
world:  compile-cache-active
world:  current-compile-cache-active
world:  compile-cache-max-size
world:  current-compile-cache-max-size
world:  unpublished-path?
world:  current-unpublished-path?
world:  here-path-key
world:  current-here-path-key
world:  splicing-tag
world:  current-splicing-tag
world:  poly-source-ext
world:  current-poly-source-ext
world:  poly-targets
world:  current-poly-targets
6.4.0.4

World

 (require pollen/world) package: pollen

Global values that are used throughout the Pollen system.

1 Parameters

I mean parameters in the Racket sense, i.e. values that can be fed to parameterize.

parameter

(world:current-server-port)  integer?

(world:current-server-port port)  void?
  port : integer?
A parameter that sets the HTTP port for the project server. Initialized to world:default-port.

parameter

(world:current-project-root)  path?

(world:current-project-root port)  void?
  port : path?
A parameter that holds the root directory of the current project (e.g., the directory where you launched raco pollen start).

parameter

(world:current-server-extras-path)  path?

(world:current-server-extras-path dir)  void?
  dir : path?
A parameter that reports the path to the directory of support files for the project server. Initialized to #f, but set to a proper value when the server runs.

parameter

(world:current-poly-target)  symbol?

(world:current-poly-target target)  void?
  target : symbol?
A parameter that reports the current rendering target for poly source files. Initialized to 'html.

2 World overrides

These values can be changed by overriding them in your "pollen.rkt" source file:

  1. Within this file, create a submodule called world.

  2. Within this submodule, use define to make a variable with the same name as the one in pollen/world, but without the world: prefix.

  3. Assign it whatever value you like.

  4. Repeat as needed.

When Pollen runs, these definitions will supersede those in pollen/world.

For instance, suppose you wanted the main export of every Pollen source file to be called van-halen rather than doc, the extension of Pollen markup files to be .rock rather than .pm, and the command character to be 🎸 instead of . Your "pollen.rkt" would look like this:

"pollen.rkt"
#lang racket/base
 
;; ... the usual definitions and tag functions ...
 
(module world racket/base
  (provide (all-defined-out))
  (define main-export 'van-halen)
  (define markup-source-ext 'rock)
  (define command-char #\🎸))

Though any of the values below can be overridden, it may not always be wise to do so. For instance, if you redefined world:fallback-template-prefix, you would simply break the fallback-template mechanism, because it would look for files that don’t exist. But we don’t live in a nanny state, so you are entrusted to say what you mean and accept the consequences.

Of course, you can restore the defaults simply by removing these defined values from "pollen.rkt".

These values are each equipped with a corresponding world:current-name function that will return the value loaded from the world submodule (if name was defined there), otherwise it returns the original value for world:name. For instance, world:command-char will always be , but in the example above, world:current-command-char would return 🎸.

value

world:default-port : integer?

procedure

(world:current-default-port)  integer?

Determines the default HTTP port for the project server. Initialized to 8080.

value

world:main-export : symbol?

procedure

(world:current-main-export)  symbol?

The main X-expression exported from a compiled Pollen source file. Initialized to doc.

value

world:meta-export : symbol?

procedure

(world:current-meta-export)  symbol?

The meta hashtable exported from a compiled Pollen source file. Initialized to metas.

value

world:meta-tag-name : symbol?

procedure

(world:current-meta-tag-name)  symbol?

Name of the tag used to mark metas within Pollen source.

value

world:server-extras-dir : string?

procedure

(world:current-server-extras-dir)  string?

Name of directory where server support files live. Initialized to server-extras.

Character for escaping output-file extensions within source-file names. Initialized to #\_.

value

world:preproc-source-ext : symbol?

procedure

(world:current-preproc-source-ext)  symbol?

value

world:markup-source-ext : symbol?

procedure

(world:current-markup-source-ext)  symbol?

value

world:markdown-source-ext : symbol?

procedure

(world:current-markdown-source-ext)  symbol?

value

world:null-source-ext : symbol?

procedure

(world:current-null-source-ext)  symbol?

value

world:pagetree-source-ext : symbol?

procedure

(world:current-pagetree-source-ext)  symbol?

value

world:template-source-ext : symbol?

procedure

(world:current-template-source-ext)  symbol?

value

world:scribble-source-ext : symbol?

procedure

(world:current-scribble-source-ext)  symbol?

File extensions for Pollen source files, initialized to the following values:

world:preproc-source-ext = 'pp +
world:markup-source-ext = 'pm +
world:markdown-source-ext = 'pmd +
world:null-source-ext = 'p +
world:pagetree-source-ext = 'ptree +
world:template-source-ext = 'pt +
world:scribble-source-ext = 'scrbl

value

world:decodable-extensions : (listof symbol?)

procedure

(world:current-decodable-extensions)  (listof symbol?)

File extensions that are eligible for decoding.

value

world:default-pagetree : string?

procedure

(world:current-default-pagetree)  string?

Pagetree that Pollen dashboard loads by default in each directory. Initialized to "index.ptree".

value

world:pagetree-root-node : symbol?

procedure

(world:current-pagetree-root-node)  symbol?

Name of the root node in a decoded pagetree. It’s ignored by the code, so its only role is to clue you in that you’re looking at something that came out of the pagetree decoder. Initialized to 'pagetree-root.

value

world:main-root-node : symbol?

procedure

(world:current-main-root-node)  symbol?

Name of the root node in a decoded doc. Initialized to 'root.

value

world:block-tags : (listof symbol?)

procedure

(world:current-block-tags)  (listof symbol?)

Tags that are treated as blocks by block-txexpr?. Initialized to the block-level elements in HTML5, namely:

address article aside blockquote body canvas dd div dl fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hgroup hr li main nav noscript ol output p pre section table tfoot ul video

... plus world:current-main-root-node.

value

world:command-char : char?

procedure

(world:current-command-char)  char?

The magic character that indicates a Pollen command, function, or variable. Initialized to #\◊.

Prefix of the default template. Initialized to "template".

Used to generate the name of the fallback template (i.e., the template used to render a Pollen markup file when no other template can be found). Prefix is combined with the output suffix of the source file. Initialized to "fallback".

value

world:template-meta-key : symbol?

procedure

(world:current-template-meta-key)  symbol?

Meta key used to store a template name for that particular source file. Initialized to 'template.

value

world:newline : string?

procedure

(world:current-newline)  string?

value

world:linebreak-separator : string?

procedure

(world:current-linebreak-separator)  string?

value

world:paragraph-separator : string?

procedure

(world:current-paragraph-separator)  string?

Default separators used in decoding. The first two are initialized to "\n"; the third to "\n\n".

value

world:dashboard-css : string?

procedure

(world:current-dashboard-css)  string?

CSS file used for the dashboard. Initialized to "poldash.css".

value

world:paths-excluded-from-dashboard : (listof path?)

procedure

(world:current-paths-excluded-from-dashboard)  (listof path?)

Paths not shown in the Pollen dashboard.

value

world:render-cache-active : boolean?

procedure

(world:current-render-cache-active)  boolean?

Whether the render cache, which speeds up interactive sessions by reusing rendered versions of Pollen output files, is active. Default is active (#t).

value

world:compile-cache-active : boolean?

procedure

(world:current-compile-cache-active)  boolean?

Whether the compile cache, which speeds up interactive sessions by saving compiled versions of Pollen source files, is active. Default is active (#t).

value

world:compile-cache-max-size : exact-positive-integer?

procedure

(world:current-compile-cache-max-size)

  exact-positive-integer?
Maximum size of the compile cache. Default is 10 megabytes.

value

world:unpublished-path? : (path? . -> . boolean?)

procedure

(world:current-unpublished-path?)  (path? . -> . boolean?)

Predicate that determines whether a path is omitted from (part "raco_pollen_publish") operations. If the predicate is #t, then the path is omitted. The default, therefore, is #f.

value

world:here-path-key : symbol?

procedure

(world:current-here-path-key)  symbol?

Key used to store the absolute path of the current source file in its metas hashtable. Default is 'here-path.

value

world:splicing-tag : symbol?

procedure

(world:current-splicing-tag)  symbol?

Key used to signal that an X-expression should be spliced into its containing X-expression. Default is '@.

value

world:poly-source-ext : symbol?

procedure

(world:current-poly-source-ext)  symbol?

Extension that indicates a source file can target multiple output types. Default is 'poly.

value

world:poly-targets : (listof symbol?)

procedure

(world:current-poly-targets)  (listof symbol?)

List of symbols that denotes the possible targets of a 'poly source file. Default is '(html).

 
\ No newline at end of file diff --git a/pollen/scribblings/world.scrbl b/pollen/scribblings/world.scrbl index 334cab0..861d4a2 100644 --- a/pollen/scribblings/world.scrbl +++ b/pollen/scribblings/world.scrbl @@ -25,7 +25,7 @@ A parameter that holds the root directory of the current project (e.g., the dire @defparam[world:current-server-extras-path dir path?]{ A parameter that reports the path to the directory of support files for the project server. Initialized to @racket[#f], but set to a proper value when the server runs.} -@defparam[world:current-poly-target target symbol??]{ +@defparam[world:current-poly-target target symbol?]{ A parameter that reports the current rendering target for @racket[poly] source files. Initialized to @racket['html].} @@ -78,8 +78,6 @@ Determines the default HTTP port for the project server. Initialized to @racket[ @defoverridable[meta-tag-name symbol?]{Name of the tag used to mark metas within Pollen source.} -@defoverridable[server-extras-dir string?]{Name of directory where server support files live. Initialized to @tt{server-extras}.} - @defoverridable[extension-escape-char char?]{Character for escaping output-file extensions within source-file names. Initialized to @racket[#\_].}