[racket] Using `dynamic-require` for optional user-supplied "template" code?

From: Greg Hendershott (greghendershott at gmail.com)
Date: Thu May 23 14:25:11 EDT 2013

p.s.

> Also: Am I correct that the user-supplied function gets JIT-ed, and
> there's no big performance hit from this?  (I think the answer is no,

That question had mixed polarities. :)  I should have written, I think
the answer is No there's no big performance hit, and Yes it gets
JIT-ed.

On Thu, May 23, 2013 at 2:22 PM, Greg Hendershott
<greghendershott at gmail.com> wrote:
> I've never had a reason to use `dynamic-require`, but now I think I do.
>
> For my Frog static blog generator, I'd like to provide a light
> "template" feature, where the user can override the default layout of
> the main container <div> in the page.
>
> I have an existing function that returns an xexpr for this. So my idea
> is to let the user optionally supply a `template.rkt` file that
> `provide`s a function named (say) `container` that returns (listof
> xexpr?).
>
> So I think what I want to do is something like this:
>
> (define (container-proc)
>   (define p (build-path (src-path) "template.rkt"))
>   (cond [(file-exists? p)
>          (dynamic-require p
>                           'container
>                           (thunk default-container))]
>         [else default-container]))
>
> The built-in `default-container` looks something like this:
>
> (define (default-container bootstrap-row-class ;"row" or "row-fluid"
>                            bodies              ;listof xexpr?: main content
>                            tocs                ;listof xexpr?: TOC
>                            tags/feeds          ;listof xexpr?: tag/feed links
>                            follow)             ;listof xexpr?: Twitter, etc.
>   `((div ([class ,bootstrap-row-class])
>          ;; Left column
>          (div ([id "left-sidebar"]
>                [class "span2 bs-docs-sidebar"])
>               , at tocs
>               (p nbsp))
>          ;; Main column
>          (div ([id "content"]
>                [class "span8"])
>               , at bodies)
>          ;; Right column
>          (div ([id "right-sidebar"]
>                [class "span2"])
>               ,@(tags/feeds)
>               ,@(follow)))))
>
> The user-supplied template.rkt would provide some variation on it. For
> example they don't want any left column with a TOC, so they supply
> this:
>
> ;; template.rkt
> #lang racket
> (provide container)
> (define (container bootstrap-row-class ;"row" or "row-fluid"
>                    bodies              ;listof xexpr?: main content
>                    tocs                ;listof xexpr?: TOC
>                    tags/feeds          ;listof xexpr?: tag/feed links
>                    follow)             ;listof xexpr?: Twitter, etc.
>   `((div ([class ,bootstrap-row-class])
>          ;; Don't want any left column; ignore `tocs`
>          ;; Main column
>          (div ([id "content"]
>                [class "span9"]) ;wider
>               , at bodies)
>          ;; Right column: Tags/feeds/follow
>          (div ([id "right-sidebar"]
>                [class "span3"]) ;wider
>               ,@(tags/feeds)
>               ,@(follow)))))
>
> In a quick experiment this seems to work fine. I could also go further
> and make this a tiny s-exp #lang, to make the end user experience even
> simpler. But meanwhile, and before that, I just want to make sure that
> `dynamic-require` is a reasonable way to do this?  Does anyone
> disagree?
>
> Also: Am I correct that the user-supplied function gets JIT-ed, and
> there's no big performance hit from this?  (I think the answer is no,
> because from reviewing Racket's own source, I got the impression that
> all modules are built on dynamic-require, but I might have
> understood.)
>
> Thank you in advance for any advice or suggestions!

Posted on the users mailing list.