Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added string-include #482

Closed
wants to merge 1 commit into from
Closed

Conversation

UplinkCoder
Copy link
Contributor

added a few functions to templ/diet.d and a hook to it in server.d

you can now import a stringTemplate as ALIAS

Multiple String-imports per file are now supported.

this however involved adding a template form bearophile

I think this is now mergeable...

added a few functions to templ/diet.d and a hook to it in server.d

you can now import a stringTemplate as ALIAS

Multiple String-imports per file are now supported.

this however involved adding a template form bearophile

I think this is now mergeable...
@UplinkCoder
Copy link
Contributor Author

this is the same as #480

@s-ludwig
Copy link
Member

Okay so to recap, this currently works like this:

  • Any string templates are passed as aliases to a compile time string constant (enum)
  • In Diet templates, a new syntax import #{ident} is added (in line with string interpolations)
  • Any such string pattern is found and the corresponding constant is looked up in the alias list that was passed and then inserted as a TemplateBlock

It's a nice idea that I didn't think of. However, I'm a little worried that the #{} syntax suggests something that isn't true - in particular it suggests, that it is possible to insert arbitrary expressions, which isn't actually the case. I would be much happier if the normal import ident syntax would be used in this case, but then there is the issue of a nice interface for passing the string template blocks, or at least the code for that gets more complicated.

On that topic I found the idea of @etcimon interesting (if I understood it right) to use a named enum and use the keys as names:

enum MyBlocks {
    something = "p Hello, World\n\timg(src=\"images/hello.png\")",
    somethingElse = "p Bye"
}
compileDietFile(..., MyBlocks);

A template could then do:

import something
import somethingElse

However, it feels a little strange, as this would basically require building a separate type for each Diet template instantiation. I've also never seen something like this used and I'm always a little careful with such neat tricks, because they can quickly make a library totally impossible to decipher if overused.

I don't like all the talk about iterating over files in views/ folders and modifying DUB to support that, but that's a different topic. On the other hand, this lead me to the thought that all of this could be nicely solved by "leaving compile time land" and simply instantiating completely separate templates for the included blocks that just use the same internal output stream. This should actually work right now, just with an awkward syntax and it would break indentation:

!!! 5
html
   - compileDietFile!("head.dt")(stream__);
   - compileDietString!(my_ct_template)(stream__);

This has the nice side effect of reducing the computation time and memory usage during CTFE (both grow faster than linear with the size of a Diet template file). So to make this happen, two main changes would be necessary:

  • include ident would simply be mapped to the equivalent of - compileDietFile("ident", ALIASES)(stream__) instead of appending to the TemplateBlock[] array
  • An additional indentation parameter needs to be added to compileDietFile to let this nest properly in the generated HTML output

import #{expr} would then simply be mapped to - compileDietString!(expr, ALIASES(stream__, indent_level) and voilà, it's even possible to specify arbitrary (compile time) expressions!

I didn't have much time to think this though, so there may be something that I've overlooked, but so far this looks like a promising approach. And BTW, even the named enum use case would work: include #{MyBlocks.something}

Granted, the #{} for includes is still different from other uses of it, because it must be CTFEable, but it's much closer and IMO close enough to warrant using the same syntax. If anybody wanted to go completely crazy with this, we could also define a compile time string interpolation syntax (!!{expr}?) that can be used for import, as well as everywhere else and will always be evaluated at compile time, but that will require a bit of work.

@etcimon
Copy link
Contributor

etcimon commented Jan 27, 2014

The compileDietString forces the diet templates to be available during the compilation of the library. Though I was hoping for a lazy import where numerous other projects can add their diet templates inside another, which could have been possible through a views folder scan, but I guess it'll have to be done by using a string delegate-callback event handling array in diet templates or some other workaround.

@s-ludwig
Copy link
Member

The compileDietString forces the diet templates to be available during the compilation of the library.

Since you can pass things from the application down to the library as template parameters, there is nothing that speaks against inserting application templates into library code. A lot of possible interfaces could be bolted on this approach, you enum based idea is just one example.

@UplinkCoder
Copy link
Contributor Author

I find include #{} is intuitve after all who would wan't to include 3*3 ?
It is a neat combination of two core concepts in the diet-template-languge

@etcimon
Copy link
Contributor

etcimon commented Jan 27, 2014

there is nothing that speaks against inserting application templates into library code.

If the routes are setup by the end application I can't argue about that, but if the library handles it's own router registration, making that information available during registration of the request handlers is a little more complicated than, say, setting up a delegate array.

@UplinkCoder
Copy link
Contributor Author

@etcimon
I just use a function that allows the user of your library to inquire about wich templates they provide
if this function can be call at ct you are golden

@s-ludwig
Copy link
Member

UplinkCoder:

I find include #{} is intuitve after all who would wan't to include 3*3 ?

Note 3*3, but what about generateIndex(...) or the mentioned MyBlocks.something.

etcimon:

there is nothing that speaks against inserting application templates into library code.
If the routes are setup by the end application I can't argue about that, but if the library handles it's own router registration, making that information available during registration of the request handlers is a little more complicated than, say, setting up a delegate array.

Then the library should simply offer a template parameter to pass the required information down to the Diet templates somehow.

@UplinkCoder
Copy link
Contributor Author

we could of course convert every past variable to an enum ...
than this would work

@UplinkCoder
Copy link
Contributor Author

or constrain these values to be string enums I mean noone can expect magic from an include statement ...
plus this syntax is so very neat ....
or don't you think so

@etcimon
Copy link
Contributor

etcimon commented Jan 27, 2014

Then the library should simply offer a template parameter to pass the required information down to the Diet templates somehow.

The way I'm currently writing the CMS / Framework, the request handlers in the libraries can't be templated because they're added to a hash map all the way up in the compilation chain, where they can be enabled or disabled through runtime configurations. It's fine if there's no integrated workaround, I'm a little stuck with my own problems on this one heh ;)

@s-ludwig
Copy link
Member

or constrain these values to be string enums I mean noone can expect magic from an include statement ...
plus this syntax is so very neat ....
or don't you think so

Is this directed at me? If so, my proposal actually supports your proposed syntax, just that it also supports arbitrary expressions and thus opens up a number of additional possibilities.

@UplinkCoder
Copy link
Contributor Author

every expression past in has to evalute to a valid diet-template sooner or later.
thinks like generateIndex!(...) are the very reason I added stringTemplates!

@s-ludwig
Copy link
Member

The way I'm currently writing the CMS / Framework, the request handlers in the libraries can't be templated because they're added to a hash map all the way up in the compilation chain, where they can be enabled or disabled through runtime configurations. It's fine if there's no integrated workaround, I'm a little stuck with my own problems on this one heh ;)

Can't the templates be instantiated and the resulting handlers then be inserted into the map?

@UplinkCoder
Copy link
Contributor Author

I would rather want to know if there is anything you @s-ludwig or @etcimon you would want me to fix in my current implementation

@etcimon
Copy link
Contributor

etcimon commented Jan 27, 2014

I would rather want to know if there is anything you @s-ludwig or @etcimon you would want me to fix in my current impementation

I'm satisfied with the implementation

Can't the templates be instantiated and the resulting handlers then be inserted into the map?

I'll put the little hamster in the wheel and come up with an answer to that. I must've tried thinking about that subject alone for 60 hours but it's still not so obvious yet. I've only been reasoning around templates for like 6 months, so my brain spends most of its time "loading..." before I can visualize. =/

@UplinkCoder
Copy link
Contributor Author

etcimon, please explain to me exactly what you are trying to do.
I have a feeling that there maybe is a mutual interest, If so
I'll help where I can.

@etcimon
Copy link
Contributor

etcimon commented Jan 27, 2014

Just as a side-note, before I found vibe.d, I was going to use QxOrm with Qt and startup a webserver on there, or cpp-netlib with boost spirit and SOCI, and 10 other libs. The Qt signals system strictly prevented classes that use signals to use templates, and I was out of my mind trying to make a list of headers that doesn't lose ordering so I needed boost multi index and for that I needed to modify cpp-netlib entirely. But either way I had 30mb of executables with 15 dll, 5mb just for UTF-8 support. What a fucking trainwreck. I'm glad the same is possible here in under 2 mb

Anyways, I think I just need to be able to have a static string delegate()[string][string] callback where diet templates can callback with a command like fetch "onMenuLoaded", I can implement it myself if it's necessary

@UplinkCoder
Copy link
Contributor Author

I don't like workarounds
I like workthroughs
I also like extending vibe.d, the codebase is a treat

@UplinkCoder
Copy link
Contributor Author

@s-ludwig should I start documenting the string-include ?
while I'm on it is there any other documenation that is vital to write ?
I'm just in the mood of writing docs right now :p

@etcimon
Copy link
Contributor

etcimon commented Jan 27, 2014

I wouldn't deem callback capability like a workaround. I think templating it through chains of libraries could be too complicated, I'd love if we could just add a fetch command or callback or whatever, you name it.

@UplinkCoder
Copy link
Contributor Author

@etcimon well
on reflection
the string does not have to be an enum
as long as it has a value when the diet template is beeing renderd

@UplinkCoder
Copy link
Contributor Author

just like any other value used in a diet template

@s-ludwig
Copy link
Member

should I start documenting the string-include ?

Let's still wait with it until this is all finished.

while I'm on it is there any other documenation that is vital to write ?
I'm just in the mood of writing docs right now :p

You hear that very seldom from a developer, most developers just always say they hate writing docs ;) (I'd actually love to finish some parts of the documentation, but there always seem to be more important tasks). How about starting to write something for the include section in the Diet docs (albeit leaving out the #{} addition until it's done)?

@etcimon
Copy link
Contributor

etcimon commented Jan 27, 2014

as long as it has a value when the diet template is beeing renderd

That's the thing, once the diet template is rendered there's currently no way I can push in some diet templates compiled in adjacent libraries. A delegate array where you can push pointers to compiled templates or such, would be perfect for that, I'd sure love to know if we intend on doing this :)

@UplinkCoder
Copy link
Contributor Author

@s-ludwig
Sure, I'm already familiar with the way it works
Do you have any rules regarding docs ?

@etcimon by library you mean a collection of tempates where source is avilable
or are we talking about .a-files ?

@s-ludwig
Copy link
Member

@etcimon: Wouldn't you typically need some way to pass arguments to the application defined template includes? If that's the case, you'll need some kind of templated interface anyway. The only other alternative would be to pass the stream__ variable to a callback (is this what you were thinking about?):

in some some library Diet template:

- foreach (cb; applicationCallbacks)
    - cb(stream__);

application code:

void some_include(OutputStream dst)
{
    compileDietFile!("some_include.dt", ...)(dst);
}

registerIncludeCallback(&some_include);

registerIncludeCallback would be a function defined in the library that collects all callbacks to be used as includes.

@s-ludwig
Copy link
Member

@UplinkCoder:

Do you have any rules regarding docs ?

It should just be in well written English and otherwise just roughly follow the style of the other sections (a brief description and a short example).

@etcimon
Copy link
Contributor

etcimon commented Jan 27, 2014

registerIncludeCallback would be a function defined in the library that collects all callbacks to be used as includes.

Yes, perfect ! With possibly a predicate as well, taking the name of the calling diet template as a parameter or something of the sorts.

Wouldn't you typically need some way to pass arguments to the application defined template includes? If that's the case, you'll need some kind of templated interface anyway.

The framework I'm working on has plenty of statically defined collections e.g. This.config["key"] This.cache["key"], This.cache.list["key"] This.session["var"] which are lazily evaluated, and are all web request-specific. As a matter of fact, the entire framework is based off the TaskLocal variable of a request which could come from many domains really, and the runtime configuration file sets the boundaries on those collections depending on the domain or library where the request comes from. The compiled diet template is bound to this framework, and so the data is forcefully consistent across all the libraries no matter which template arguments are used.. I've already though of using Json or Values (msgpackd) variables to fetch data that was serialized with a defined type, but since we're not working with the views folder scanning strategy that's not necessary really.

s-ludwig added a commit that referenced this pull request Feb 11, 2014
This commit prepares for support of string templates, originally proposed by Stefan Koch (Uplink_Coder) in #482.
@UplinkCoder UplinkCoder deleted the stringTemplate branch June 7, 2014 09:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants