Pollen Component
1 Overview
2 Installation
3 Usage
components-output-types
define-component
current-pollen-component-dynamic-type
4 Acknowledgments
5 Changelog
5.1 0.0.5 · 2018-05-03
5.1.1 Added
5.2 0.0.4 · 2017-03-08
5.2.1 Fixed
5.3 0.0.3 · 2017-02-13
5.3.1 Added
5.4 0.0.2 · 2017-02-12
5.4.1 Added
5.5 0.0.1 · 2017-01-21
5.5.1 Added
7.1

Pollen Component

Leandro Facchinetti <[email protected]>

 (require pollen-component) package: pollen-component

Component-based development for Pollen.

Version

 

0.0.5

Documentation

 

Racket Documentation

License

 

GNU General Public License Version 3

Code of Conduct

 

Contributor Covenant v1.4.0

Distribution

 

Racket Package

Source

 

GitHub

Bug Reports

 

GitHub Issues

Contributions

 

GitHub Pull Requests

1 Overview

Pollen projects are generally structured like the following:

"pollen.rkt"

#lang racket
 
(provide (all-defined-out))
 
(define (link href . elements)
  `(a ((href ,href)) ,@elements))

"styles.css.pp"

#lang pollen
 
a { color: red; }

"scripts.js.pp"

#lang pollen
 
var links = document.getElementsByTagName('a'); // 

"index.html.pm"

#lang pollen
 
Without link["http://…"]{Pollen Component}.

The separation of structure ("pollen.rkt"), appearance ("styles.css.pp"), behavior ("scripts.js.pp") and content ("index.html.pm") is a good idea that stood the test of time. So much so, that it is not particular of Pollen projects, but the standard in document-preparation systems like the web and LaTeX. Its main advantage is consistency: generated documents use the same fonts, colors, sizes and so on throughout the pages because those are specified in a single place.

The problems with this model begin when changing from questions like “what are all the styles in effect on this document?” to questions like “what constitutes a link on this document?” To answer this, it is necessary to open at least three files—"pollen.rkt", "styles.css.pp" and "scripts.js.pp"—and search for the snippets relevant to links. One sees only the pieces and has to imagine the full picture. Also, as the project grows, it becomes harder to understand the far-reached effects the parts have on one another.

Recently, modern web development tools including React and Polymer popularized one solution to these issues: components. Components bring together the definitions of structure, appearance and behavior for distinguishable parts of the document.

Components do not replace the traditional architecture. For example, the cascading behavior of CSS is still useful to guarantee consistency throughout the document. But components yield better organization for elements that make sense on their own: links, menus and tag functions in general.

While tools like React and Polymer target application development, we believe that document-preparation systems can benefit from components as well. Thus, we present Pollen Component: an extension to Pollen that allows for component-based development.

The example above becomes the following with Pollen Component:

"pollen.rkt"

#lang racket
(require pollen-component
         racket/dict racket/string racket/format)
 
(provide (all-defined-out)
         (all-from-out racket/dict racket/string racket/format))
 
(components-output-types #:dynamic html #:static css javascript)
 
(define-component (link href . elements)
  #:html
  `(a ((href ,href)) ,@elements)
  #:css
  "a { color: red; }"
  #:javascript
  "var links = document.getElementsByTagName('a'); // …")

"styles.css.pp"

#lang pollen
 
(string-join
  (for/list ([(component css) (in-dict (components/css))])
    (~a "/*" component "*/" css)))

"scripts.js.pp"

#lang pollen
 
(string-join
  (for/list ([(component javascript)
              (in-dict (components/javascript))])
    (~a "/*" component "*/" javascript)))

"index.html.pm"

#lang pollen
 
Welcome to link["http://…"]{Pollen Component}.

Unleash the full power of Pollen Component by defining CSS with CSS-expressions and JavaScript with Urlang:

"pollen.rkt"

#lang racket
(require pollen-component css-expr urlang)
 
(provide (all-defined-out))
 
(current-urlang-echo? #t)
 
(components-output-types #:dynamic html
                         #:static css javascript)
 
(define-syntax-rule (javascript expressions ...)
  (with-output-to-string
      (λ ()
        (urlang
         (urmodule
          javascript-module expressions ...)))))
 
(define-component (link href . elements)
  #:html
  `(a ((href ,href)) ,@elements)
  #:css
  (css-expr [a #:color red])
  #:javascript
  (javascript
   (import document)
   (define links (document.getElementsByTagName "a"))))

2 Installation

Pollen Component is a Racket package. Install it in DrRacket or with the following command line:

$ raco pkg install pollen-component

3 Usage

syntax

(components-output-types
 [#:dynamic dynamic ...] [#:static static ...])
 
  dynamic : identifier?
  static : identifier?

See Pollen Component in action on my personal website (source). It also uses CSS-expressions to define CSS.

Use components-output-types in "pollen.rkt" to specify the output types supported by components. The dynamic output types are those for which one would create tag functions, for example, HTML, Atom and LaTeX. The static output types are the styles and behavior that support the document, for example, CSS, JavaScript and LaTeX styles.

The static output types receive this name because, with respect to the component being defined, the contents of the static output types are always the same and known at the time of defining the component. In contrast, the contents of dynamic output types will not be known until the component is used. For example, there may be many different HTML links on a page, so a link component would have HTML as a dynamic output type; but the styles associated with links are always the same, defined in a stylesheet, so CSS would be a static output type.

Using components-output-types introduces bindings for define-component and components/<static>s (one for each static output type) in the current environment. Thus, components-output-types must come first and appear only once.

syntax

(define-component form
  [#:output-type body ...+]
  ...)
The available #:output-types are those declared in components-output-types.

The body corresponding to dynamic output types turn into a function tag that detects the output type of the current document and executes the appropriate code. Undefined dynamic output types fall back to default-tag-function.

The body corresponding to static output types are accumulated in Racket parameters of association lists named components/<static>. There is one components/<static> parameter for each static output type. The keys are the components names (as symbols) and the values are the components contents for that output type as defined by body.

A parameter that for using component outside a Pollen scope. Use this to set the dynamic output type in places where the Pollen metas variable is undefined, for example, to define components in files other than "pollen.rkt".

"component.rkt"

#lang racket
(require pollen-component)
(provide (all-defined-out))
 
(components-output-types #:dynamic html txt #:static css javascript)
 
(define-component (test a)
  #:html
  `(p ,a)
  #:txt
  (format "Hey you wrote : ~a" a))
 
; get the html version
(parameterize ([current-pollen-component-dynamic-type "html"])
  (test "hello"))
 
; get the txt version
(parameterize ([current-pollen-component-dynamic-type "txt"])
  (test "hello"))

4 Acknowledgments

Thank you Matthew Butterick for Pollen and for the feedback given in private email conversations. Thank you Greg Trzeciak for the feedback given in private conversations. Thank you Luke Whittlesey for contributing current-pollen-component-dynamic-type. Thank you all Racket developers. Thank you all users of this library.

5 Changelog

This section documents all notable changes to pollen-component. It follows recommendations from Keep a CHANGELOG and uses Semantic Versioning. Each released version is a Git tag.

5.1 0.0.5 · 2018-05-03

5.1.1 Added

5.2 0.0.4 · 2017-03-08

5.2.1 Fixed

5.3 0.0.3 · 2017-02-13

5.3.1 Added

5.4 0.0.2 · 2017-02-12

5.4.1 Added

5.5 0.0.1 · 2017-01-21

5.5.1 Added