5.2 Elements
| (require punct/element) | package: punct-lib |
The bindings documented in this section are also provided by punct/core. The bindings in Working with elements are provided only by punct/element.
procedure
(default-element-function tag default-attr-kw default-attr-val ...) → (->* () #:rest any/c xexpr?) tag : symbol? default-attr-kw : keyword? default-attr-val : string?
You can also give keyword/value arguments to default-element-function itself; these will be set as default attributes/values in the custom element returned by the resulting function.
> (define aside (default-element-function 'aside)) > (aside "Hello") '(aside "Hello")
> (define kbd (default-element-function 'kbd #:alt "foo")) > (kbd "CTRL") '(kbd ((alt "foo")) "CTRL")
> (kbd "CTRL" #:data-code "1") '(kbd ((alt "foo") (data-code "1")) "CTRL")
If a keyword argument supplied at the call site has the same name as one of the default attributes, the call-site value overrides the default rather than duplicating it:
> (define span (default-element-function 'span #:class "default")) > (span "with default" #:id "a") '(span ((class "default") (id "a")) "with default")
> (span "overridden" #:class "custom") '(span ((class "custom")) "overridden")
Attribute values must be strings. A keyword argument whose value is #f is left out, which makes it easy to include an attribute only some of the time, and to remove a default at the call site. Any other value raises an error.
> (span "no class" #:class #f) '(span "no class")
> (span "count" #:count 3) span: attribute values must be strings or #f
attribute: 'count
value: 3
On Mac OS, type ALT+6 to produce § and ALT+7 to produce ¶.
If tag ends in either § or ¶, the resulting function will add a default block attribute of "root" or "single" respectively:
> (define info (default-element-function 'info§)) > (info "Note!") '(info ((block "root")) "Note!")
> (define mypar (default-element-function 'mypar¶)) > (mypar "Walnuts") '(mypar ((block "single")) "Walnuts")
If tag has a suffix of the form .foo, the resulting function will add a default 'class attribute whose value is set to "foo". Multiple such suffixes will add additional values to the 'class attribute.
> (define carton (default-element-function 'carton.xyz.abc)) > (carton "Cashews") '(carton ((class "xyz abc")) "Cashews")
> (define crate (default-element-function 'crate¶.foo)) > (crate "Pecans") '(crate ((block "single") (class "foo")) "Pecans")
Added in version 1.3 of package punct-lib.
Changed in version 1.5: Keyword arguments with a value of #f are left out; other
values that are not strings raise an error.
syntax
(define-element id [default-attr-kw default-attr-val ...])
(define-element id tag [default-attr-kw default-attr-val ...])
default-attr-kw : keyword?
default-attr-val : string?
If tag is supplied, it is used as the tag for the X-expressions generated by the resulting function:
> (define-element bowl container.bowl) > (bowl "Corn nuts") '(container ((class "bowl")) "Corn nuts")
> (define-element jar vessel¶ #:type "Glass") > (jar "Chestnuts") '(vessel ((type "Glass") (block "single")) "Chestnuts")
If tag is not supplied, the first argument is used both as the identifier for the function and for the tag in generated X-expressions:
> (define-element bag.xyz.abc) > (bag "Sunflower seeds") '(bag ((class "xyz abc")) "Sunflower seeds")
> (define-element packet¶.foo) > (packet "Raisins") '(packet ((block "single") (class "foo")) "Raisins")
As with default-element-function, keyword arguments at the call site override any matching defaults:
> (define-element note aside§ #:class "info") > (note "A note") '(aside ((class "info") (block "root")) "A note")
> (note "A warning" #:class "warning") '(aside ((block "root") (class "warning")) "A warning")
Added in version 1.3 of package punct-lib.
> (ref-attr '((class "info") (id "a")) 'id) "a"
> (ref-attr '((class "info")) 'id) #f
> (ref-attr '((class "info")) 'id "none") "none"
Changed in version 1.5 of package punct-lib: Added the default argument.
5.2.1 Working with elements
These functions take apart, change and search the elements produced by Punct’s parse. They follow the same rules Punct uses everywhere:
An element is any non-empty list whose first item is a symbol (its tag).
If the second item is a list of attributes (each a two-item list of a symbol and a string), it is the element’s attribute list. Everything after that is a child.
Children are not checked: they can be strings, other elements, or any other values.
Added in version 1.5 of package punct-lib.
Added in version 1.5 of package punct-lib.
A list in the second position that has a value that is not a string is not an attribute list, so it is returned as the first child.
> (element-parts '(p ((class "x")) "a" (em "b")))
'p
'((class "x"))
'("a" (em "b"))
> (element-parts '(p "a"))
'p
'()
'("a")
> (element-parts '(p ((count 3)) "a"))
'p
'()
'(((count 3)) "a")
Added in version 1.5 of package punct-lib.
procedure
(make-element tag [attrs children]) → element?
tag : symbol? attrs : (listof attr?) = '() children : list? = '()
> (make-element 'p '((class "x")) '("a")) '(p ((class "x")) "a")
> (make-element 'p '() '("a")) '(p "a")
Added in version 1.5 of package punct-lib.
procedure
(element-tag elem) → symbol?
elem : element?
procedure
(element-attrs elem) → (listof attr?)
elem : element?
procedure
(element-children elem) → list?
elem : element?
Added in version 1.5 of package punct-lib.
> (set-attr '((href "/x") (title "X")) 'href "/y") '((href "/y") (title "X"))
> (set-attr '((href "/x")) 'rel "external") '((href "/x") (rel "external"))
Added in version 1.5 of package punct-lib.
> (remove-attr '((id "a") (class "x")) 'id) '((class "x"))
Added in version 1.5 of package punct-lib.
> (element-map (λ (x) (if (string? x) (string-upcase x) x)) '(p ((class "x")) "a" (em "b"))) '(p ((class "x")) "A" (em "B"))
> (require racket/match)
> (element-map (match-lambda [(element 'a attrs kids) (make-element 'a (set-attr attrs 'rel "external") kids)] [x x]) '(p "See " (a ((href "https://example.com")) "this"))) '(p "See " (a ((href "https://example.com") (rel "external")) "this"))
Added in version 1.5 of package punct-lib.
procedure
(element-find pred v) → (or/c element? #f)
pred : (-> element? any/c) v : any/c
procedure
(element-find* pred v) → (listof element?)
pred : (-> element? any/c) v : any/c
> (define (link? e) (eq? (element-tag e) 'link)) > (define body '(paragraph (link ((dest "/a")) "A") " and " (bold (link ((dest "/b")) "B")))) > (element-find link? body) '(link ((dest "/a")) "A")
> (element-find* link? body) '((link ((dest "/a")) "A") (link ((dest "/b")) "B"))
> (element-find* (λ (e) (eq? (element-tag e) 'table)) body) '()
Added in version 1.5 of package punct-lib.
match expander
(element tag-pat attrs-pat children-pat)
> (match '(a ((href "/x")) "X") [(element 'a (list-no-order (list 'href url) _ ...) kids) (list url kids)]) '("/x" ("X"))
> (match '(p "Hello") [(element tag '() kids) (list tag kids)]) '(p ("Hello"))
Added in version 1.5 of package punct-lib.