GithubHelp home page GithubHelp logo

temple's Introduction

Temple Build Status

Surprisingly Flexible, Compile Time, Zero Overhead, Embedded Template Engine for D

About

Temple is a templating engine written in D, allowing D code to be embedded and executed in text files. The engine converts text to code at compile time, so there is zero overhead interpreting templates at runtime, allowing for very fast rendering.

Temple supports passing any number of arbitrary variables to templates, as well as nesting and yielding templates within each other, capturing blocks of template code, and optional fine-grain filtering of generated text (e.g for escaping generated strings/safe strings).

Vibe.d compatible! See the Vibe.d Usage section.

Temple works with

  • DMD >= 2.066
  • LDC >= 0.15-alpha1
  • GDC >= 4.9.2

And probably more, but that's what it's been officially tested with.

Table of Contents

Usage

If using dub, include temple as a dependency in dub.json, or all of the files in src/temple in your build process, and import temple;.

Going from a template string to a rendered template follows the process:

  • Compile the template with the compile_temple or compile_temple_file functions, resulting in a CompiledTemple
  • Call 'toString' or 'render' on the resulting CompiledTemple
  • Optionally pass in a TempleContext to pass variables to the template

Optional Filters can be supplied to compile_template[_file] to filter dynamic template content.

The Temple Syntax

The template syntax is based off of that of eRuby (but can be changed by modifying temple/delims.d). D statements go between <% %> delimers. If you wish to capture the result of a D expression, place it between <%= %> delimers, and it will be converted to a string using std.conv's to.

Shorthand delimers are also supported: A line beginning with % is considered a statement and executed; a line beginning with %= is evaluated and the result is written to the output stream.

Note that expressions within <%= %> and %= should not end with a semicolon, while statements within <% %> and % should.

Quick Reference:

Input Output
foo foo
<% "foo"; %> <no output>
<%= "foo" %> foo
%= "foo" ~ " " ~ "bar" foo bar
% "foo"; <no output>
Foreach
% foreach(i; 0..3) {
	Index: <%= i %>
% }
Index: 0
Index: 1
Index: 2
Foreach, alt
% import std.conv;
<% foreach(i; 0..3) { %>
	%= "Index: " ~ to!string(i)
<% } %>
Index: 0
Index: 1
Index: 2
If/else if/else statements
% auto a = "bar";
% if(a == "foo") {
	Foo!
% } else if(a == "bar") {
	Bar!
% } else {
	Baz!
% }
Bar!
Overall usage
auto hello = compile_temple!`Hello, <%= var.name %>!`
auto ctx = new TempleContext();
ctx.name = "Jimmy";

writeln(hello.toString(ctx));
Hello, Jimmy!

Contexts

The TempleContext type is used to pass variables to templates. The struct responds to opDispatch, and returns variables in the Variant type. Use Variant#get to convert the variable to its intended type. TemplateContext#var(string) is used to retrieve variables in the context, and can be called directly with var in the template:

auto context = new TempleContext();
context.name = "dymk";
context.should_bort = true;

Passed to:

<% /* Variant can be converted to a string automatically */ %>
Hello, <%= var("name") %>

<% /* Conversion of a Variant to a bool */ %>
% if(var("should_bort").get!bool) {
	Yep, gonna bort
% } else {
	Nope, not gonna bort
% }

<% /* Variants are returned by reference, and can be (re)assigned */ %>
<% var("written_in") = "D" %>
Temple is written in: <%= var("written_in") %>
}

Results in:

Hello, dymk
Yep, gonna bort
Temple is written in: D

Variables can also be accessed directly via the dot operator, much like setting them.

auto context = new TempleContext();
context.foo = "Foo!";
context.bar = 10;
<%= var.foo %>
<%= var.bar %>

<% var.baz = true; %>
<%= var.baz %>
}

Prints:

Foo!
10
true

For more information, see the Variant documentation on the dlang website

Using CompiledTemple

Both compile_temple!"template string" and compile_temple_file!"filename" return a CompiledTemple. The CompiledTemple exposes two rendering methods, toString, and render, both of which take an optional TemplateContext.

string CompiledTemple#toString(TempleContext = null)

Evaluates the template and returns the resulting string

import
  temple.temple,
  std.stdio,
  std.string;

void main()
{
	auto tlate = compile_temple!"foo, bar, baz";
	writeln(tlate.toString()); // Prints "foo, bar, baz"
}

An example passing a TempleContext:

void main()
{
	auto tlate = compile_temple!q{
		Hello, <%= var("name") %>
	};

	auto context = new TempleContext();
	context.name = "dymk";

	writeln(tlate.toString(ctx)); // Prints "Hello, dymk"
}
void CompiledTemple#render(Sink, TempleContext = null)

Incrementally evaluates the template into Sink, which can be one of the following:

  • an std.stdio.File
  • an arbitrary OutputRange (as determined by std.range.isOutputRange!(T, string))
  • a function or delegate that can take a string: void delegate(string str) {}

Using render greatly decreases the number of allocations that must be made compared to toString.

auto tlate = compile_temple!q{
	Hello, <%= var("name") %>
};

tlate.render(stdout); // render into stdout

// incrementally render into function/delegate
tlate.render(function(str) {
	write(str);
});

compile_temple_file

compile_temple_file is the same as compile_temple, but takes a file name to read as a template instead of the template string directly. Temple template files typically end with the extension .emd ("embedded d").

template.emd:

It's <%= var("hour") %> o'clock.

main.d:

import
  templ.templ,
  std.stdio;

void main() {
	auto tplate = compile_temple_file!"template.emd";

	auto context = new TempleContext();
	context.hour = 5;

	tplate.render(stdout);
}
It's 5 o'clock

Nested Templates

#render can be called within templates to nest templates. By default, the current context is passed to the nested template, and any filters applied to the nester are applied to the nestee. A different context can be passed explicitly by calling #render_with(TemplateContext) instead.

a.emd

<html>
	<body>
		<p>Hello, from the 'a' template!</p>
		<%= render!"b.emd"() %>
	<body>
</html>

b.emd

<p>And this is the 'b' template!</p>

Rendering a.emd would result in:

<html>
	<body>
		<p>Hello, from the 'a' template!</p>
		<p>And this is the 'b' template!</p>
	<body>
</html>

Layouts and Yielding

Templates can be made into parent layouts, where the child is rendered when #yield is called. Setting the child for a template is done by calling layout on the parent.

void main()
{
	auto parent = compile_temple!"before <%= yield %> after";
	auto child  = compile_temple!"between";

	auto composed = parent.layout(&child);
	composed.render(stdout);
}
before between after

Capture Blocks

Blocks of template can be captured into a variable, by wrapping the desired code inside of a delegate, and passing that to capture. Capture blocks can be nested. Capture blocks do not render directly to a string, but rather a range, meaning that evaluating a capture block will result in evaluating the entire capture block multiple times.

Capture has the signature string capture(T...)(void delegate(T) block, T args), and can be called from user defined functions as well (See the Helpers section).

Example:

<% auto outer = capture(() { %>
	Outer, first
	<% auto inner = capture(() { %>
		Inner, first
	<% }); %>
	Outer, second

	<%= inner %>
<% }); %>

<%= outer %>
Outer, first
Outer, second
	Inner, first

Helpers (A-la Rails View Helpers)

Helpers aren't a built in feature of Temple, but they are a very useful pattern for DRYing up templates. Here's a partial implementation of Rails' form_for helper:

<%
import std.string;
struct FormHelper
{
	string model_name;

	auto field_for(string field_name, string type="text")
	{
		if(model_name != "")
		{
			field_name = "%s[%s]".format(model_name, field_name);
		}

		return `<input type="%s" name="%s" />`.format(type, field_name);
	}

	auto submit(string value = "Submit")
	{
		return `<input type="button" value="%s" />`.format(value);
	}
}

auto form_for(
	string action,
	string name,
	void delegate(FormHelper) block)
{
	auto form_body = capture(block, FormHelper(name));
	return `
		<form action="%s" method="POST">
			%s
		</form>`.format(action, form_body);
}
%>

<%= form_for("/shorten", "", (f) { %>
	Shorten a URL:
	<%= f.field_for("url") %>
	<%= f.submit("Shorten URL") %>
<% }); %>

<%= form_for("/person", "person", (f) { %>
	Name: <%= f.field_for("name") %>
	Age: <%= f.field_for("age") %>
	DOB: <%= f.field_for("date_of_birth", "date") %>
	<%= f.submit %>
<% }); %>

Renders:

<form action="/shorten" method="POST">
	Shorten a URL:
	<input type="text" name="url" />
	<input type="button" value="Shorten URL" />
</form>

<form action="/person" method="POST">
	Name: <input type="text" name="person[name]" />
	Age: <input type="text" name="person[age]" />
	DOB: <input type="date" name="person[date_of_birth]" />
	<input type="button" value="Submit" />
</form>

Filters

Filters are a way to filter and transform the dynamic parts of the template, before it is written to the output buffer. A filter takes the form of a struct or class that defines various overloads of the static method temple_filter. The temple_filter methods can either:

  • Take two parameters: a TempleOutputStream to write their result to, and the input to filter, e.g.
    • `void temple_filter(ref TempleOutputStream ob, string str) { ob.put(str); }
  • Take one parameter and return a string:

Example, wrapping evaluated text in quotes:

struct QuoteFilter
{
	static string temple_filter(string raw)
	{
		return `"` ~ raw ~ `"`;
	}

	static string temple_filter(T)(T raw)
	{
		return temple_filter(to!string(raw));
	}
}

auto render = compile_temple!(QuoteFilter, q{
	Won't be quoted
	<%= "Will be quoted" %>
	<%= 10 %>
});
writeln(templeToString(&render));
Won't be quoted
"Will be quoted"
"10"

The temple_filter method isn't limited to filtering only strings, however. Any arbitrary type can be passed in. They can also define any arbitrary methods to use in the template, provided they don't clash with the methods that TempleContext defines.

Example, implementing safe/unsafe strings for conditional escaping of input:

private struct SafeDemoFilter
{
	static private struct SafeString
	{
		string value;
	}

	static string temple_filter(SafeString ts)
	{
		return ts.value;
	}

	static string temple_filter(string str)
	{
		return "!" ~ str ~ "!";
	}

	static SafeString safe(string str)
	{
		return SafeString(str);
	}
}

auto templ = compile_temple!(q{
	foo (filtered):   <%= "mark me" %>
	foo (unfiltered): <%= safe("don't mark me") %>
}, SafeDemoFilter);

templ.render(stdout);
foo (filtered):   !mark me!
foo (unfiltered): don't mark me

Filters are propagated to nested templates:

a.emd:

<%= safe("foo1") %>
<%= "foo2" %>
foo3
<%= render!"b.emd" %>
foo4

b.emd

<%= safe("bar1") %>
<%= "bar2" %>
bar3

a.emd rendered with the SafeDemoFilter:

foo1
!foo2!
foo3
bar1
!bar2!
bar3
foo4

TempleFilter

TempleFilter is not a filter itself, but rather allows a filter to be applied to entire family of Temple templates, grouping them under a single name.

Example usage:

struct MyFilter {
	static string temple_filter(string unfiltered) {
		return "!" ~ unfiltered ~ "!";
	}
}

// All Temple templates under Filtered will have MyFilter applied to them
alias Filtered = TempleFilter!MyFilter;

auto child = Filtered.Temple!`
	foo
	<%= "bar" %>
`;

auto parent = Filtered.TempleLayout!`
	header
	<%= yield %>
	footer
`

parent.layout(&child).render(stdout);

Which would render:

header
foo
!bar!
footer

Vibe.d Integration

Temple will expose functions for integrating with Vibe.d if compiled together (e.g. Have_vibe_d is defined) The addition to the Temple API is:

  • void renderTemple(string temple)(HTTPServerRequest, Context = null)
  • void renderTempleFile(string filename)(HTTPServerRequest, Context = null)
  • void renderTempleLayoutFile(string layoutfile, string partialfile)(HTTPServerRequest, Context = null)
  • struct TempleHtmlFilter

where Context can be an HTTPServerResponse, or a TempleContext. If it is a HTTPServerResponse, then the contents of the params hash will be the context for the template.

Usage is similar to Vibe.d's render function:

void doRequest(HTTPServerRequest req, HTTPServerResponse res) {

	// Client requested with query string `?name=foo`

	req.renderTemple!(`
		Hello, world!
		And hello, <%= var.name %>!
	`)(res);

}

Would result in this HTTP response:

Hello, world!
And hello, foo!

Dynamic content is passed through Vibe's HTML filter before being rendered, unless it is marked as safe, by calling safe("your string").

void doRequest(HTTPServerRequest req, HTTPServerResponse res) {

	// Client requested with query string `?name=foo`

	req.renderTemple!(`
		<html>
			<body>
				Here's a thing!
				<%= "<p>Escape me!</p>" %>
				<%= safe("<span>Don't escape me!</span>") %>
			</body>
		</html>
		Hello, world!
		And hello, <%= var.name %>!
	`)(res);

}

Would result in the HTTP response:

<html>
	<body>
		Here's a thing!
		&lt;p&gt;Escape me!&lt;/p&gt;
		<span>Don't escape me!</span>
	</body>
</html>

Example: Simple Webpages

Here's a slightly more complex example, demonstrating how to use the library to render HTML templates inside of a common layout.

void main()
{
	auto parent = compile_temple_file!"layout.html.emd";
	auto child  = compile_temple_file!"_partial.html.emd";

	parent.layout(&child).render(stdout);
}

layout.html.emd

<html>
	<head>
		<title>dymk's awesome website</title>
	</head>
	<body>
		%= render!"common/_sidebar.html.emd"()
		%= yield
		%= render!"common/_footer.html.emd"()
	</body>
</html>

common/_sidebar.html.emd

<ul>
	<li><a href="/">Home</a></li>
	<li><a href="/about">About</a></li>
	<li><a href="/contact">Contact</a></li>
</ul>

common/_footer.html.emd

<footer>
	2013 (C) dymk .: built with Temple :.
</footer>

_partial.html.emd

<section>
	TODO: Write a website
</section>

Output:

<html>
	<head>
		<title>dymk's awesome website</title>
	</head>
	<body>
		<ul>
			<li><a href="/">Home</a></li>
			<li><a href="/about">About</a></li>
			<li><a href="/contact">Contact</a></li>
		</ul>
		<section>
			TODO: Write a website
		</section>
		<footer>
			2013 (C) dymk .: built with Temple :.
		</footer>
	</body>
</html>

Notes

The D compiler must be told which directories are okay to import text from. Use the -J<folder> compiler switch or stringImportPaths in Dub to include your template directory so Temple can access them.

For more examples, take a look atsrc/temple/test/common.d's unittests; they provide very good coverage of the library's abilities.

License

Temple is distributed under the Boost Software License.

temple's People

Contributors

bryant1410 avatar chrishalebarnes avatar dymk avatar gedaiu avatar jgoett154 avatar yoplitein avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

temple's Issues

Error when compiling with DMD 2.068.1-b2

I compile temple with the latest beta and get:

C:\Dev\dmd2\windows\bin....\src\phobos\std\variant.d: Error: function std.variant.VariantN!20u.VariantN.__xopEquals errors compiling the function

I compile without defining the version identifier that enable vibe.d.
This is important because it may be a Phobos regression and the release will come fast.

Can I use "return" in Temple templates?

Before 0.6.1 release, I had this in my template, and it worked:

% if (post.stub) {
    <h1>THIS POST DOES NOT EXIST</h1>
    % return;
% }

I'm not sure whether such construction is legal and allowed but it seemed to be the most easy way to implement some primitive «validation» inside the template.

Now, this template causes error:

skins/iamlex1/parts/post.inc.html(33): Warning: statement is not reachable

Is it a bug, or is my template really shouldn't work?

And, is there some other legal way to «quit the template» from inside it?

Add get() method to TempleContext

Why don't you add a function like this into TempleContext? (This snippet does not work because of some Temple's template magic which I couldn't understand)

T get(T)(in string name, lazy T defValue=T.init)
{
    return (name in vars) ? vars[name].get!T : defValue;
}

It is for convenient usage like:

auto someBool = var.get!bool("someBool", false);  // parameter is false if not set
auto someInt  = var.get!int("someInt", -1);       // parameter is -1 if not set

Error when compiling on 32-bit machine

My friend with a 32-bit Ubuntu can't compile Temple without manually modifying sources:

../../../.dub/packages/temple-master/src/temple/func_string_gen.d(237): Error: cannot implicitly convert expression ((*cDelimPos)._expand_field_0) of type ulong to uint
../../../.dub/packages/temple-master/src/temple/func_string_gen.d(302): Error: function temple.util.munchHeadOf (ref string a, ref string b, uint amt) is not callable using argument types (string, string, ulong)
../../../.dub/packages/temple-master/src/temple/func_string_gen.d(312): Error: cannot implicitly convert expression (delim_pos) of type immutable(ulong) to uint
../../../.dub/packages/temple-master/src/temple/func_string_gen.d(313): Error: function temple.util.munchHeadOf (ref string a, ref string b, uint amt) is not callable using argument types (string, string, immutable(ulong))
../../../.dub/packages/temple-master/src/temple/temple.d(60): called from here: __temple_gen_temple_func_string("", "", "")
TempleFunc(68): Error: argument to mixin must be a string, not (__TempleFuncStr) of type const(immutable(char)[])
src/temple/temple.d(75): Error: undefined identifier TempleFunc
src/temple/temple.d(169): Error: template instance temple.temple.Temple!("", "", void) error instantiating
Compiling Temple with Vibed support
FAIL ../../../.dub/packages/temple-master/.dub/build/-debug-linux.posix-x86-dmd_2066-6394FE5D72CAB3DB200BBDB968FC3BD4/ temple staticLibrary
Error executing command build: dmd failed with exit code 1.

Proper usage with vibe.d's web interface

Hi,
there is an example of vibe.d integration in the docs, but it uses "raw" low-levev rounting, where every route handler takes HTTPServerRequest and HTTPServerResponse as parameters:

void handleRequest(HTTPServerRequest req, HTTPServerResponse res) {
    if (req.path == "/")
        res.writeBody("Hello, World!", "text/plain");
}

...semething like this.

Vibe.d also offers WebFramework feature, which doesn't use HTTPServerRequest and HTTPServerResponse explicitly. Typical route handler in this case looks like this:

void index() {
    bool authenticated = ms_authenticated;
    render!("index.dt", authenticated);
}

Since Temple's renderTempleFile and frieds requires HTTPServerResponse-type parameter, it's not clear to me how to use it with WebFramework. Right now I'm doing it this way:

void index(HTTPServerResponse res) {
    auto context = new TempleContext;
    context.pagetitle = "Test";
    renderTempleFile!("index.html.emd")(res, context);
}

It works, but I hope there is more elegant way.

Improved Vibe.d Compatibility

It'd be nice to have first class support for Temple in Vibe.d (or perhaps the other way around).

@s-ludwig, are there any particular features in Diet that Temple could incorporate, to ease its use in Vibe.d?

Template doesn't compile

(I'm very sorry about the totally unuseful title of the issue, but I have no idea about what happened.)

When compiling my project with Dub, one of my Temple files causes problems. Here's how the file looks like:

% auto showComments = var.showComments.get!bool;

... (some other code that works) ...

% if (showComments && post.children.length > 0) {
    <div class="comments">
        % foreach (comment; post.children) {
            % auto context = new TempleContext;
            % context.post = post;
            % context.comment = comment;
            % context.isChild = false;
            %=renderWith!"skins/parts/comment.inc.html"(context)
        % }
    </div>
% }

This file (post.inc.html) is included from another template file. When Temple compiles this file, this stucks with this line in console:

Compiling skins/parts/post.inc.html...

When I throw the whole if block away, the project compiles normally.

I also tried to change something in the code above: I removed the if condition, I removed the renderWith line, etc. Sometimes the template started compiling in a very strange way:

Compiling skins/parts/post.inc.html...
Compiling skins/parts/post.inc.html...
Compiling skins/parts/post.inc.html...
...

And so on, until I kill the process of compiling. If I don't do this, sometimes my computer became frozen, and I couldn't do anything for minutes. :-(

So, what's wrong with the part of template above?

Build fails with dmd v2.075.1

src/temple/temple.d(164,10): Deprecation: temple.util.std is not visible from module temple
src/temple/temple.d(210,8): Deprecation: temple.vibe.vibe is not visible from module temple
src/temple/temple.d(211,27): Deprecation: temple.vibe.vibe is not visible from module temple
src/temple/temple.d(211,27): Error: template instance isOutputRange!(StreamOutputRange, string) does not match template declaration isOutputRange(R, E)
src/temple/temple.d(211,13): while evaluating: static assert(isOutputRange!(StreamOutputRange, string))

Root package contains reference to invalid package

I'm not sure what happened, that's why I make here a duplicate of an issue I reported to Dub: Root package contains reference to invalid package.

In short: when compiling my project that requires both vibe-d and temple, I get this line in verbose mode:

Package temple contains invalid dependency vibe-d (ci=6)

It happened right now. I updated all projects several days ago, and everything worked well. Now, after another upgrade, I can't compile my project anymore. :-(

Do you have any ideas what could happen? Thank you.

Remove Short delimers

It does not seem they fill a useful role; 99% of all Temple templates I've seen in the wild only use <% %> and <%= %> delimiters.

The temple parsing code is also made overly complex due to supporting Short delimers.

If anyone has been using Short delimers, and finds them useful, let me know, and I'll add them back in, but in the meantime, I'll remove this feature.

Templates break with double-quotes

This library would be perfect for a project I'm working on, but I encountered a small issue which prevents its use. When a template contains a double-quote ("), compilation fails. Since my project is generating HTML, my templates contain quite a few double-quotes.

Example app.d:

import templ.templ;
import std.stdio;

void main()
{
    struct TemplCtx {
        string foo = "bar";
    }
    auto render = mixin(Templ!(TemplCtx, import("template.erd")));

    auto context = TemplCtx();
    writeln(render(context));
}

Example template.erd:

Value of foo: "<%= foo %>"

Output of dub build:

Checking dependencies in '/Users/rchouinard/D/templ-test'
Building configuration "application", build type debug
Compiling...
source/app.d(17): Error: Escape String literal \" is deprecated, use double quoted string literal "\"" instead
source/app.d(18): Error: unterminated string constant starting at source/app.d(18)
source/app.d(22): Error: found 'EOF' when expecting ','
source/app.d(22): Error: found 'EOF' when expecting ')'
source/app.d(22): Error: found 'EOF' when expecting ';' following statement
source/app.d(22): Error: found 'EOF' when expecting '}' following compound statement
source/app.d(22): Error: found 'EOF' when expecting '}' following compound statement
Error: DMD compile run failed with exit code 1

Run 'dub help' for usage information.

Temple.lib does not compile with dmd 2.066.1

output log:

C:...\func_string_gen.d(237): Error: cannot implicitly convert expression ((*cDelimPos)._expand_field_0) of type ulong to uint
C:...\func_string_gen.d(302): Error: function temple.util.munchHeadOf (ref string a, ref string b, uint amt) is not callable using argument types (string, string, ulong)
C:...func_string_gen.d(312): Error: cannot implicitly convert expression (delim_pos) of type immutable(ulong) to uint
C:...\func_string_gen.d(313): Error: function temple.util.munchHeadOf (ref string a, ref string b, uint amt) is not callable using argument types (string, string, immutable(ulong))
C:...\temple.d(60): called from here: __temple_gen_temple_func_string("", "", "")
TempleFunc(68): Error: argument to mixin must be a string, not (__TempleFuncStr) of type const(immutable(char)[])
src/temple/temple.d(75): Error: u

tried with dub and or dmd from console, same output.

New Tag

Please add a new tag that includes my earlier fixes.

Temple always compiles all the templates

Hello. I have a problem, though I am not 100% sure it is related to Temple.

Every time I change anything — anything! — in my project, all my template files are recompiled. Even when there's no need to recompile them. For example, here's the build output after I just re-saved main.d without touching any of the Temple's files (and main.d doesn't directly calls Temple at all).

Package derelict-util can be upgraded from 1.0.2 to 1.0.3.

## Warning for package landopyre ##

The following compiler flags have been specified in the package description
file. They are handled by DUB and direct use in packages is discouraged.
Alternatively, you can set the DFLAGS environment variable to pass custom flags
to the compiler, or use one of the suggestions below:

unittests: Call DUB with --build=unittest

WARNING: A deprecated branch based version specification is used for the dependency derelict-pq. Please use numbered versions instead. Also note that you can still use the dub.selections.json file to override a certain dependency to use a branch instead.
WARNING: A deprecated branch based version specification is used for the dependency kxml. Please use numbered versions instead. Also note that you can still use the dub.selections.json file to override a certain dependency to use a branch instead.
WARNING: A deprecated branch based version specification is used for the dependency temple. Please use numbered versions instead. Also note that you can still use the dub.selections.json file to override a certain dependency to use a branch instead.
Use "dub upgrade" to perform those changes.
Target derelict-util 1.0.2 is up to date. Use --force to rebuild.
Target derelict-pq ~master is up to date. Use --force to rebuild.
Target kxml ~master is up to date. Use --force to rebuild.
Target vibe-d 0.7.20 is up to date. Use --force to rebuild.
Target temple ~master is up to date. Use --force to rebuild.
Building landopyre ~master configuration "application", build type debug.
Compiling using dmd...
Compiling Temple with Vibed support
Compiling skins/colorized/login.html...
Compiling sql/queries/ViewFullBlog.sql...
Compiling skins/colorized/blog.html...
Compiling skins/colorized/parts/_top.inc.html...
Compiling skins/colorized/parts/post.inc.html...
Compiling skins/colorized/parts/allcomments.inc.html...
Compiling skins/colorized/parts/comment.inc.html...
Compiling skins/colorized/parts/_bottom.inc.html...
Compiling sql/queries/ViewFullBlogByTag.sql...
Compiling sql/queries/bypubid/by-Login-Id.sql...
Compiling sql/queries/ViewPost.sql...
Compiling skins/colorized/post.html...
Compiling skins/colorized/write.html...
Compiling skins/colorized/club.html...
Compiling sql/queries/bypubid/by-Club-Id.sql...
Compiling skins/colorized/whatsnew.html...
Compiling skins/colorized/zh.html...
Compiling sql/queries/bypubid/by-Club-Id-ReplyId.sql...
Compiling sql/queries/bypubid/by-Login-Id-ReplyId.sql...
Compiling sql/queries/GetRootParent.sql...
Linking...

Here's my dub.json:

{
    "name": "landopyre",
    "copyright": "Copyright © 2014, Maaaks",
    "authors": ["Maaaks"],
    "dependencies": {
        "derelict-pq": "~master",
        "kxml": "~master",
        "temple": "~master",
        "vibe-d": ">=0.7.11",
    },
    "versions": ["VibeCustomMain"],
    "targetType": "executable",
    "targetPath": ".build",
    "sourcePaths": [".", "/d/Sources/DUB-REPO/DIni/src"],
    "stringImportPaths": ["."],
    "buildOptions": ["unittests"],
    "libs": ["curl"]
}

I would like to avoid unneccessary template recompiling to speed up the build process.

Can the problem be caused by Temple, or by any of other components I use?

Can't compile with unittests

Dub fails to build temple with unittest enabled.

[~] dub build temple --build=unittest
There was no package description found for the application in '/home'.
Building package temple in /home/.dub/packages/temple-0.7.2/
WARNING: A deprecated branch based version specification is used for the dependency vibe-d. Please use numbered versions instead. Also note that you can still use the dub.selections.json file to override a certain dependency to use a branch instead.
Building temple 0.7.2 configuration "lib", build type unittest.
Running dmd...
Compiling Temple with Vibed support
Compiling test8_building_helpers.emd...
src/temple/temple.d(94): Error: need -Jpath switch to import text file test8_building_helpers.emd
src/temple/temple.d(99): Error: template instance temple.compile_temple_file!("test8_building_helpers.emd", void) error instantiating
.dub/packages/temple-0.7.2/src/temple/tests/capture.d(51):        instantiated from here: TempleFile!"test8_building_helpers.emd"
.dub/packages/temple-0.7.2/src/temple/tests/capture.d(52): Error: forward reference to inferred return type of function call 'TempleFile'
Compiling test1.emd...
src/temple/temple.d(94): Error: need -Jpath switch to import text file test1.emd
.dub/packages/temple-0.7.2/src/temple/tests/common.d(153): Error: template instance temple.compile_temple_file!("test1.emd", void) error instantiating
Compiling test2.emd...
src/temple/temple.d(94): Error: need -Jpath switch to import text file test2.emd
.dub/packages/temple-0.7.2/src/temple/tests/common.d(160): Error: template instance temple.compile_temple_file!("test2.emd", void) error instantiating
Compiling test3_nester.emd...
src/temple/temple.d(94): Error: need -Jpath switch to import text file test3_nester.emd
.dub/packages/temple-0.7.2/src/temple/tests/common.d(172): Error: template instance temple.compile_temple_file!("test3_nester.emd", void) error instantiating
Compiling test4_root.emd...
src/temple/temple.d(94): Error: need -Jpath switch to import text file test4_root.emd
.dub/packages/temple-0.7.2/src/temple/tests/common.d(179): Error: template instance temple.compile_temple_file!("test4_root.emd", void) error instantiating
Compiling test5_layout.emd...
src/temple/temple.d(94): Error: need -Jpath switch to import text file test5_layout.emd
.dub/packages/temple-0.7.2/src/temple/tests/common.d(206): Error: template instance temple.compile_temple_file!("test5_layout.emd", void) error instantiating
Compiling test5_partial1.emd...
src/temple/temple.d(94): Error: need -Jpath switch to import text file test5_partial1.emd
.dub/packages/temple-0.7.2/src/temple/tests/common.d(207): Error: template instance temple.compile_temple_file!("test5_partial1.emd", void) error instantiating
Compiling test5_partial2.emd...
src/temple/temple.d(94): Error: need -Jpath switch to import text file test5_partial2.emd
.dub/packages/temple-0.7.2/src/temple/tests/common.d(208): Error: template instance temple.compile_temple_file!("test5_partial2.emd", void) error instantiating
Compiling test6_layout.emd...
src/temple/temple.d(94): Error: need -Jpath switch to import text file test6_layout.emd
.dub/packages/temple-0.7.2/src/temple/tests/common.d(220): Error: template instance temple.compile_temple_file!("test6_layout.emd", void) error instantiating
Compiling test6_partial.emd...
src/temple/temple.d(94): Error: need -Jpath switch to import text file test6_partial.emd
.dub/packages/temple-0.7.2/src/temple/tests/common.d(221): Error: template instance temple.compile_temple_file!("test6_partial.emd", void) error instantiating
FAIL .dub/packages/temple-0.7.2/.dub/build/lib-unittest-linux.posix-x86_64-dmd_2066-C104B171B144A0D2194A1C131F43AE29/ temple staticLibrary
Error executing command build: dmd failed with exit code 1.

Vibe.d support broken for vibe.d 0.2.78

Compiling Temple with Vibed support
../../../.dub/packages/temple-0.7.4/src/temple/vibe.d(90,15): Error: expression req.params of type DictionaryList!(string, true, 8LU, false) does not have a boolean value

looks like this pull request will fix it: #36

Please could you take the pull request and apply it.

Documentation typo?

https://github.com/dymk/temple#vibed-integration

void renderTemple(string temple)(HTTPServerRequest, Context = null)
void renderTempleFile(string filename)(HTTPServerRequest, Context = null)
void renderTempleLayoutFile(string layoutfile, string partialfile)(HTTPServerRequest, Context = null)

This functions actually takes HTTPServerResponse as a parameter.

PR Into Vibe.d?

Have you ever considered making a PR into Vibe.d with this? This would be extremely useful for those who do not wish to use diet/jade. Just my thoughts on it. Maybe when its stable enough (if nots not stable already), you could fork vibe.d and implement it and have options in the settings to choose between this and diet templates.

Compilation is painfully slow

Compilation of simple ~130 LOC html with one variable takes about 2 minutes and awful amount of RAM. Actual app is pretty trivial:

import vibe.d;
import temple;

class WebInterface 
{
    void index(HTTPServerResponse res) {
        auto context = new TempleContext;
        context.pagetitle = "Test";
        renderTempleFile!("index.html.emd")(res, context);
    }
}

shared static this()
{
    auto router = new URLRouter;
    router.registerWebInterface(new WebInterface);
    router.get("*", serveStaticFiles("./public/"));
    auto settings = new HTTPServerSettings;
    settings.port = 8080;
    settings.bindAddresses = ["::1", "127.0.0.1"];
    listenHTTP(settings, router);
}

It seems that compilation time doesn't depend much on amount of variables, but it's heavily affected by total LOC count. This compiles blazingly fast:

<h2 class="post-title"><%= var.pagetitle %></h2>

This freezes my PC for 2 mins, 100% CPU load:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Главная | Язык программирования D</title>
        <link href="favicon.png" type="image/png" rel="icon">
        <link href="favicon.png" type="image/png" rel="shortcut icon">
        <link href='https://fonts.googleapis.com/css?family=Arimo&subset=latin,cyrillic' rel='stylesheet' type='text/css'>
        <link rel="stylesheet" href="assets/css/normalize.css">
        <link rel="stylesheet" href="assets/css/pure-min.css">
        <link rel="stylesheet" href="assets/css/grids-responsive-min.css">
        <link rel="stylesheet" href="assets/css/style.css">
        <link rel="stylesheet" href="assets/css/mono-blue.css">
        <script src='https://www.google.com/recaptcha/api.js'></script>
        <script src="assets/js/highlight.pack.js"></script>
        <script>hljs.initHighlightingOnLoad();</script>
    </head>

    <body>
        <aside>
            <header>
                <h1 class="site-title"><a href="[[++site_url]]"><span>D</span>programming</a></h1>
                <h2 class="site-description">Сайт о языке программирования D</h2>

                <nav>
                    <ul>
                        <li class="first active"><a href="http://dprogramming.ru/" title="Главная" >Главная</a></li>
                        <li><a href="news/" title="Новости" >Новости</a></li>
                        <li><a href="articles/" title="Статьи" >Статьи</a></li>
                        <li><a href="http://dlanguage.ru/" title="Форум" >Форум</a></li>
                        <li class="last"><a href="about.html" title="О сайте" >О сайте</a></li>
                    </ul>
                </nav>

                <h3>Последние новости</h3>
                <ul class="latest-posts">
                </ul>

                <h3>Последние статьи</h3>
                <ul class="latest-posts">
                </ul>
            </header>
        </aside>

        <main>
        <section class="post main">
            <header class="post-header">
                <h2 class="post-title"><%= var.pagetitle %></h2>
            </header>

            <div class="post-description">
                <div class="pure-g start">
                    <div class="pure-u-1-3">
                        <h3>Основное</h3>

                        <ul>
                            <li><a href="http://dlang.org"><img class="icon" src="assets/images/dlang-icon.jpg">dlang.org</a></li>
                            <li><a href="http://dlang.org/dmd-windows.html">DMD</a> - "эталонный" компилятор.</li>
                            <li><a href="http://gdcproject.org/">GDC</a> - компилятор на основе GCC</li>
                            <li><a href="http://wiki.dlang.org/LDC">LDC</a> - компилятор на основе LLVM</li>
                            <li><a href="https://github.com/SDC-Developers/SDC">SDC</a> - экспериментальный компилятор</li>
                            <li><a href="http://code.dlang.org/"><img class="icon" src="assets/images/dub-icon.png">DUB - официальный менеджер пакетов</a></li>
                            <li><a href="http://dlang.org/dstyle.html">Стиль кода</a></li>
                            <li><a href="http://dlang.org/bugstats.php">Багтрекер</a></li>
                            <li><a href="https://github.com/D-Programming-Language"><img class="icon" src="assets/images/github-icon.png">GitHub</a></li>
                            <li><a href="https://ru.wikipedia.org/wiki/D_%28%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F%29"><img class="icon" src="assets/images/wiki-icon.png">D в русскоязычной Википедии</a></li>
                        </ul>
                    </div>

                    <div class="pure-u-1-3">
                        <h3>Документация</h3>
                        <ul>
                            <li><a href="http://dlang.org/spec.html">Спецификация языка</a></li>
                            <li><a href="http://dlang.org/phobos/index.html">Phobos - стандартная библиотека</a></li>
                            <li><a href="http://wiki.dlang.org/"><img class="icon" src="assets/images/wiki-icon.png">Официальная вики</a></li>
                        </ul>
                    </div>

                    <div class="pure-u-1-3">
                        <h3>Онлайн-сообщества</h3>

                        <ul>
                            <li><a href="http://forum.dlang.org/"><img class="icon" src="assets/images/dlang-icon.jpg">[en] Официальный форум</a></li>
                            <li><a href="http://planet.dsource.org/">[en] Planet D</a> - Агрегатор англоязычных блогов</li>
                            <li><a href="http://arsdnet.net/this-week-in-d/">[en] This week in D</a> - еженедельный дайджест</li>
                            <li><a href="https://trello.com/b/XoFjxiqG/active"><img class="icon" src="assets/images/trello-icon.png">D в Trello</a></li>
                            <li><a href="http://dlanguage.ru/"><img class="icon" src="assets/images/dlanguage-icon.gif">dlanguage.ru</a> - русскоязычный форум</li>
                            <li><a href="http://dlang.ru">dlang.ru</a> - русскоязычное сообщество (under construction)</li>
                            <li><a href="https://vk.com/vk_dlang"><img class="icon" src="assets/images/vk-icon.png">Группа вКонтакте</a></li>
                            <li><a href="https://www.facebook.com/dlang.org"><img class="icon" src="assets/images/facebook-icon.png">[en] Страница на Facebook</a></li>
                        </ul>
                    </div>
                </div>

                <div class="pure-g start">
                    <div class="pure-u-1-3">
                        <h3>Инструменты и утилиты</h3>
                        <ul>
                            <li><a href="http://dlang.org/rdmd.html">rdmd</a> - утилита ускорения сборки</li>
                            <li><a href="https://github.com/Hackerpilot/Dscanner">Dscanner</a> - анализатор и линтер (<a href="http://dprogramming.ru/articles/dscanner-overview.html">+статья</a>)</li>
                            <li><a href="https://github.com/Hackerpilot/dfmt">dfmt</a> - форматтер кода</li>
                            <li><a href="https://github.com/Hackerpilot/dfix">dfix</a> - обновление deprecated-кода</li>
                            <li><a href="http://dlang.org/htod.html">htod</a> - конвертер заголовочных файлов C в D</li>
                        </ul>
                    </div>

                    <div class="pure-u-1-3">
                        <h3>Онлайн-инструменты</h3>
                        <ul>
                            <li><a href="http://dpaste.dzfl.pl/">DPaste</a> - выполнение D-кода в браузере</li>
                            <li><a href="http://asm.dlang.org/">asm.dlang.org</a> - онлайн-компилятор и дизассемблер</li>
                        </ul>
                    </div>

                    <div class="pure-u-1-3">
                        <h3>Книги и туториалы</h3>
                        <ul>
                            <li><a href="http://ddili.org/ders/d.en/">[en] Programming in D</a> - бесплатная олайн-книга</li>
                            <li><a href="http://qznc.github.io/d-tut/">[en] Pragmatic D tutorial</a></li>
                            <li><a href="http://www.pluralsight.com/courses/introduction-to-d">[en] Introduction to D</a> - видеокурс на Pluralsight</li>
                            <li><a href="http://d.readthedocs.org/en/latest/">[en] Quick start with D</a> на readthedocs.org</li>
                        </ul>
                    </div>
                </div>
            </div>
        </section>
        </main>
    </body>
</html>

...and this is just a plain html with one Temple var.

unittests is outdated?

Used test string from travis-ci script:

$ dub --build=unittest --config=unittest 
Target vibe-d 0.7.24 is up to date. Use --force to rebuild.
Building temple 0.7.3+commit.4.g66def3e configuration "unittest", build type unittest.
Compiling using dmd...
Compiling Temple with Vibed support
src/temple/temple.d(211): Error: static assert  (isOutputRange!(OutputStream, string)) is false
FAIL .dub/build/unittest-unittest-linux.posix-x86_64-dmd_2067-B5243AF6FD7D2C79B1473483C8C3DDA6/ temple executable
Error executing command run:
dmd failed with exit code 1.

Improve whitespace handling

E.g. statements insert a newline, and they probably shouldn't.

Probably will need to write a whitespace spec at some point.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.