[racket] Dynamic Templates?

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Mon Oct 14 15:31:31 EDT 2013

I think the advice that Robby gives is probably better, but...

If you only need to pick up changes to a module (as opposed to running
a module afresh for its side effects), and if you're using 5.90.x, you
could try using `dynamic-rerequire` in a single namespace to reload
modules.

At Mon, 14 Oct 2013 13:22:21 -0500, Robby Findler wrote:
> Did you try using namespace-attach-module to attach 'racket and
> 'web-server/templates? Something like:
> 
>   (define orig-ns (current-namespace))
>   (parameterize ([current-namespace (make-base-empty-namespace)])
>     (namespace-attach-module orig-ns 'racket)
>     (namespace-attach-module orig-ns 'web-server/templates)
>     (namespace-require 'racket)
>     (eval `(begin
>              (require web-server/templates)
>              (require ,my-source-path-string)
>              (include-template ,my-template-path-string))
>           (current-namespace)))
> 
> But 7 seconds seems remarkably long (I see a speed up of about 50% for that
> function (with the my-source-path-string and my-template-path-string lines
> commented out): from 250 to 170 msec).
> 
> It may be that your .zo files or something are not up to date. So you may
> want to stick a 'raco make' somewhere in there to avoid recompiling your
> files every time and just recompile the ones that changed.
> 
> Robby
> 
> 
> 
> 
> On Mon, Oct 14, 2013 at 1:14 PM, Matthew Butterick
> <mb.list.acct at gmail.com>wrote:
> 
> > At RacketCon I talked about my Pollen system for making web pages. Though
> > I don't use the Racket webserver to provide live generation of web pages, I
> > do use it to provide a kind of browser-assisted REPL for development. As I
> > edit the project files, I want to reload the URL in the browser and see the
> > changes (without restarting the webserver).
> >
> > Moreover, since it's a development tool, it wants to be maximally dynamic.
> > For instance, I might be editing source files containing page content, or
> > the design templates (which might also contain Racket code), or supporting
> > Racket libraries (e.g., CSS generators).
> >
> > Jay has suggested that this can be done with eval. And indeed it can.
> > Here's the quasicode I use:
> >
> >   (parameterize ([current-namespace (make-base-empty-namespace)])
> >     (namespace-require 'racket)
> >     (eval `(begin
> >              (require web-server/templates)
> >              (require ,my-source-path-string)
> >              (include-template ,my-template-path-string))
> >           (current-namespace))))
> >
> > This works great, with one wrinkle: it's the slowest operation in the
> > whole system, taking about 7-8 secs to render each page. This is not a
> > grave hardship, and certainly faster than restarting the web server. But
> > I'd still be curious if I'm overlooking a better approach.
> >
> > In general, the render time is fairly consistent regardless of what's in
> > the page, which suggests to me that most of the expense comes from setting
> > up the fresh namespace. I did try making a namespace separately and reusing
> > it, but that didn't work (code wouldn't get reloaded). Is there a way to
> > "clean" a namespace that's cheaper than setting up a new one?
> >
> > Another option I considered is starting up another instance of Racket in a
> > subprocess, but it would need to be made into a synchronous operation. Long
> > drive for a short day at the beach, etc.
> >
> > It's also possible that I'm running up against the irreducible cost of
> > high-quality eval, in which case, I will accept it and move on.
> >
> >
> > Matthew Butterick
> >
> >
> >
> >
> > On Thu, Jun 6, 2013 at 7:36 PM, Greg Hendershott <
> > greghendershott at gmail.com> wrote:
> >
> >> Great timing! It's been on my short list to make my static blog
> >> generator more flexible. From
> >> http://docs.racket-lang.org/web-server/templates.html I got the idea
> >> that it would be suitable only for static templates, but now I
> >> understand that's not the case. Today I made a topic branch using this
> >> approach that's working well, which I plan to merge after some testing
> >> and polishing.
> >>
> >> p.s. Maybe it's obvious, but because `include-template` uses
> >> `include-at/relative-to/reader`, it won't include a template if you
> >> give it a full path. Maybe there's a more-elegant way, but I found it
> >> worked to parameterize `current-directory` around the call to `eval`.
> >>
> >>
> >> On Wed, Jun 5, 2013 at 4:45 PM, Jay McCarthy <jay.mccarthy at gmail.com>
> >> wrote:
> >> > While it is supposed to be pithy, it is also serious.
> >> >
> >> > When I wrote it, I imagine that people would do something like this:
> >> >
> >> > #lang racket/base
> >> > (require web-server/templates)
> >> >
> >> > (define (template-content t x)
> >> >   (eval #`(let ([x #,x]) (include-template #,t))))
> >> >
> >> > (template-content "t.txt" 5)
> >> > (template-content "t.txt" 6)
> >> >
> >> > and trust that the template wouldn't include @(system "rm -fr /"). I
> >> > think that a simple eval works just fine for when you, the programmer,
> >> > want to change the content dynamic (although I'd say it is better to
> >> > use the web-server language so you can restart with the same
> >> > continuations, etc.)
> >> >
> >> > Your solution is great for a template that a user provides, although
> >> > it has the hole that the template could call @include-template and
> >> > maybe find itself and go into a infinite loop, so it's not totally
> >> > "secure" unless you use a sandbox.
> >> >
> >> > Jay
> >> >
> >> > On Wed, Jun 5, 2013 at 1:53 PM, Joe Gibbs Politz <joe at cs.brown.edu>
> >> wrote:
> >> >> I'm writing a web server in a #lang that doesn't support macros or
> >> >> syntactic abstraction.  I would like to be able to use some sort of
> >> >> templating dynamically with bindings given by values, e.g.
> >> >>
> >> >> template.render("page-with-hole-for-username.html", { username: "Joe"
> >> })
> >> >>
> >> >> The FAQ (
> >> 
> http://docs.racket-lang.org/web-server/faq.html#(part._.How_do_.I_use_templates
> __dynamically__)
> >> )
> >> >> in the documentation for templates ends with this pithy
> >> >> recommendation:
> >> >>
> >> >> "If you insist on dynamicism, there is always eval."
> >> >>
> >> >> I assume this isn't intended seriously, and instead to discourage what
> >> >> I'm asking about, but I'm unfortunately not seeing another way to
> >> >> write my program.  The code at the end of this message seems like the
> >> >> best I can do while being relatively safe, but also like a dubious
> >> >> inclusion on a web server given the eval.
> >> >>
> >> >> Is this the best I can hope for?  Is there another collection I should
> >> >> be looking into?  Any other recommendations?
> >> >>
> >> >> Thanks!
> >> >> Joe P.
> >> >>
> >> >>
> >> >> #lang racket/base
> >> >>
> >> >> (require
> >> >>   web-server/templates)
> >> >>
> >> >> (define (render-template filename dict)
> >> >>   (define namespace-for-template (make-empty-namespace))
> >> >>   (namespace-attach-module (current-namespace) 'web-server/templates
> >> >> namespace-for-template)
> >> >>   (hash-map dict
> >> >>     (lambda (key value)
> >> >>       (define name-of-identifier (string->symbol key))
> >> >>       (namespace-set-variable-value!
> >> >>         name-of-identifier
> >> >>         value
> >> >>         #f
> >> >>         namespace-for-template)))
> >> >>   (parameterize [(current-namespace namespace-for-template)]
> >> >>     (namespace-require 'web-server/templates))
> >> >>   (define to-eval #`(include-template #,(datum->syntax
> >> >> #'render-template filename)))
> >> >>   (eval to-eval namespace-for-template))
> >> >> ____________________
> >> >>   Racket Users list:
> >> >>   http://lists.racket-lang.org/users
> >> >
> >> >
> >> >
> >> > --
> >> > Jay McCarthy <jay at cs.byu.edu>
> >> > Assistant Professor / Brigham Young University
> >> > http://faculty.cs.byu.edu/~jay
> >> >
> >> > "The glory of God is Intelligence" - D&C 93
> >> > ____________________
> >> >   Racket Users list:
> >> >   http://lists.racket-lang.org/users
> >> ____________________
> >>   Racket Users list:
> >>   http://lists.racket-lang.org/users
> >>
> >
> >
> > ____________________
> >   Racket Users list:
> >   http://lists.racket-lang.org/users
> >
> >
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users

Posted on the users mailing list.