Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

[Diet] proposal for diet function support #37

Closed
zhaopuming opened this Issue · 5 comments

3 participants

@zhaopuming

Diet template currently has layout/extends support, and that's one of the two directions diet template relations. The other is template inclusion. Issue #32 addresses this.

My proposal is to support embeded template support, which I call a diet function



def css(filename)
    link(rel="stylesheet", type="text/css", href="/css/#{filename}.css")
    

Then in the same diet template, we could call this diet function


block head append
    call css("bootstrap")

And this would have the same effect with:


block head append
    link(rel="stylesheet", type="text/css", href="/css/bootstrap.css")

In this way user can declare their own functions to alleviate template writing.

we can call a diet function defined in another diet template:


    call another_template.css("bootstrap")

In child templates, we can call diet functions defined in its parent with


    call super.css("bootstrap")

if we call the render function, then it's then same as including another template


    call another_template.render(args...)

same as


    call another_template(args...)

In conclusion, diet function introduces three keywords: def, call, super, and its functionality would be a super set of simple template inclusion mechanizm. With diet functions, it's easy for a developer to define his own set of utility functions, and call them where ever they want.

The syntax is not important, in Play!framework (a web framework in Scala), they use @ symbol to do both def and call, and even evaluation

e.g.

definition


    @hello(name: String) {
        <p>Hello @name </p>
    }

calling


    ...
    @hello("david")
    ...

calling another template's function


    ...
    @another_template.hello("david")
    ...

Every Play template is a class. So they are just another way to define and call methods.

P.S. I took a look at diet template's code, and there are a bunch of d templates and CTFE code, which is beyond my ability (I'm a D newbie). Can you explain how Diet template is designed? maybe in a blog if you have time. When I'm much better at D coding, I will try to help :) I really am wishing vibe.d goes successful.

I imagined that a diet template is compiled into a class, with a render method. And layout extends are implemented by subclasses, whose render method calls super's render method. template inclusion would be implemented by calling render method in another template's class. Is this comprehension correct ?

@Aatch

There is some merit to this idea, however you can embed verbatim D code in diet templates. Also, there is a planned feature of filters that allow you to filter a block of text, these could be used as generic "functions".

In terms of design, Diet is based off of Jade, but does all the parsing at compile-time in order to produce native code that creates the templates.

Templates are not implemented as classes, as that would probably end up being too slow, but are implemented as generated templated functions. Basically when a diet template gets compiled, it is compiled into a function that mixins the generated D code for templates. The way extensions are implemented is that the "parent" is the actual template, and the extension is simply a list of blocks for editing the parent.

I can't really expand here since an issue report isn't really the place.

Basically, look at Jade for any planned features.

@zhaopuming

Thanks for the reply. Now I understand how diet template code is generated.

So given a diet template hello.dt:


p
    hello #{username}

in the runtime,


res.render!("hello.dt", username);

is already compiled and expanded (by mixin) in to code similar to written code


stream.write('<p>');
stream.write('hello');
stream.write(username);
stream.write('</p>');

instead of a runtime function call.

By using this mechanism, we save a runtime function call for each request. Or compared to class based template systems (Play2's template), we save a runtime call to a method in a class. I'm not sure that would improve much performance, as each request already does many function calls (url routing, request http parsing, parameter fetching, etc).

So does this imply the each time I call a render!(), the template code will be inserted(mixined) at that spot. Would that bring code bloat ?

@Aatch

Actually, no, there is not much code bloat. basically calling render!(templ, args...) instantiates the render template, with those arguments, mixing in the render template, not where you instantiate render. Since templates are instantiated on their arguments, each one will only be instantiated once.

The only thing that could be an issue is that different name order in the arguments would cause a different instantiation and therefore a new mixin of the template code, so I would suggest trying to keep variable order for your templates the same.

@zhaopuming

Thanks, I didn't quite understand template instantiation before. I'm looking forward to the filter feature :)

@s-ludwig s-ludwig was assigned
@s-ludwig
Owner

Sorry that I've taken so long to get this idea.. ;) but the part with the parametrized blocks (roughly mixins in Jade) is - and always was - already doable like this:

!!! 5
- function css(string filename)
    link(rel="stylesheet", type="text/css", href="/css/#{filename}.css")

html
    head
        - css("test.css");

And includes and filters also work now.

@s-ludwig s-ludwig closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.