[web-devel] Uniform substitution for URLs, templates, messages and other expressions in Shakespearean templates

Sebastian Fischer mail at sebfisch.de
Sun Sep 23 14:37:20 CEST 2012


I rephrase to check if I understand correctly.

You want to make it an error to:

  1. accidentally splice something that is no URL into URL positions and
  2. splice sub-site URLs into the wrong sub site (or into the main
sub site) without proper wrapping.

Make sense, thanks!

Sebastian

On Sun, Sep 23, 2012 at 2:02 PM, Michael Snoyman <michael at snoyman.com> wrote:
> On Sun, Sep 23, 2012 at 11:14 AM, Sebastian Fischer <mail at sebfisch.de> wrote:
>> Hello,
>>
>> when writing my comparison of Hamlet with Heist and HXT
>> (https://gist.github.com/3757918) I noticed that Hamlet and HXT have
>> similar approaches to variable substitution but Hamlet's uses
>> different syntax for substituting URLs, templates, and other
>> expressions. I'd like to understand why.
>>
>> In HXT Haskell expressions can be substituted using the notation <%
>> ... %>. The rendering of substituted expression is type based and
>> specified separately for attribute- and element-positions via type
>> classes `EmbedAsAttribute` and `EmbedAsChild`.
>>
>> In Hamlet Haskell expressions can be substituted using the notation
>> #{...}. The rendering of substituted expressions is type based and
>> specified via the type class `ToMarkup` from the blaze-html package.
>> URLs are substituted using the notation @{...}, other templates using
>> ^{...} and messages for i18n using _{...}.
>>
>> What are the reasons for providing four different syntaxes for
>> variable subsitution if the substitution is type based? For example,
>> different escaping mechanisms (URL escaping for routes, HTML escaping
>> for strings) could already be accomplished with a single syntactical
>> construct based on different type-class instances to generate markup.
>>
>> Best,
>> Sebastian
>
> The most basic reason is because I think multiple syntaxes is a good
> thing. Embedding a URL is inherently a different activity than
> embedding a piece of text, and I'd like the code to reflect that. In
> Hamlet, the following is clear:
>
>     <a href=@{foo}>#{bar}
>
> I know that foo is a URL value, and bar is not. If I accidentally
> included the wrong type for `foo`, Hamlet can catch it.
>
> I actually contacted Jeremy off list about this issue to get a better
> understanding of how HXT works, and it seems to me that it's pushing a
> lot of the infrastructure into a monad with typeclass instances. I
> don't know all the details, so I can't really speak to that approach.
> But I *can* speak to how Hamlet was designed, and I think the fact
> that context is irrelevant is very powerful. Each Hamlet template is
> passed a URL rendering function, which ensures automatically that all
> embedded URLs are of the correct type.
>
> This is especially useful for cases such as subsites. Suppose that you
> have a subsite for static files, and you want to give a user a link to
> an image. You could construct such a static route along the lines of:
>
>     StaticRoute ["myimage.png"]
>
> (Yesod users will probably recognize that these links are
> automatically generated, so you could just use the `myimage_png`
> identifier, which ensures you do not have any typos.)
>
> The question is: what does `myimage_png` render to? And the answer
> depends entirely on your application. There are a number of
> possibilities:
>
> 1. You stuck your static subsite at the "standard" location of
> /static, so it renders to /static/myimage_png
> 2. You used a nonstandard location: /foo
> 3. You don't even have a static subsite set up
> 4. You have multiple static subsites set up
>
> In any event, trying to use `<img src=@{myimage_png}>` will fail in
> *all* of these cases with a message along the lines of "Route Static
> does not match Route App" which, if you're familiar with GHC error
> messages, means that you tried to use a route for the static subsite
> when you should have used a route for the application. The only way to
> create the link is to wrap up `myimage_png` in the appropriate
> constructor, which in common nomenclature would work out to `<img
> src=@{StaticR myimage_png}>`.
>
> The same kinds of arguments apply to i18n messages as well. Though it
> would be technically possible to instead just use a single typeclass
> and force all templates to run in a certain monad, I think the
> approach we have no is superior.
>
> So tl;dr: Passing around an explicit functions and making different
> types of interpolation look different is IMO better.
>
> Michael



More information about the web-devel mailing list