aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2017-02-05 15:18:47 +0100
committerLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2017-02-05 15:18:47 +0100
commit723567ba0c8d28a292b87d6d65cb97e4b4406e4b (patch)
tree0e27ef09553e55acff4789260928080e9c911c23
parent2355f4eb0b8fb33ef2d0994f4f54aa2615b8fa29 (diff)
downloadaskama-723567ba0c8d28a292b87d6d65cb97e4b4406e4b.tar.gz
askama-723567ba0c8d28a292b87d6d65cb97e4b4406e4b.tar.bz2
askama-723567ba0c8d28a292b87d6d65cb97e4b4406e4b.zip
Implement basic support for template inheritance
-rw-r--r--askama/src/generator.rs100
-rw-r--r--testing/templates/base.html2
-rw-r--r--testing/templates/child.html2
-rw-r--r--testing/tests/inheritance.rs19
4 files changed, 121 insertions, 2 deletions
diff --git a/askama/src/generator.rs b/askama/src/generator.rs
index 61d4fab..4c2adef 100644
--- a/askama/src/generator.rs
+++ b/askama/src/generator.rs
@@ -193,6 +193,23 @@ impl Generator {
}
}
+ fn block_methods(&mut self, blocks: &Vec<Node>) {
+ for b in blocks {
+ if let &Node::BlockDef(name, ref nodes) = b {
+ self.writeln("#[allow(unused_variables)]");
+ self.writeln(&format!(
+ "fn render_block_{}_into(&self, writer: &mut std::fmt::Write) {{",
+ name));
+ self.indent();
+ self.handle(&nodes);
+ self.dedent();
+ self.writeln("}");
+ } else {
+ panic!("only block definitions allowed");
+ }
+ }
+ }
+
fn path_based_name(&mut self, ast: &syn::DeriveInput, path: &str) {
let encoded = path_as_identifier(path);
let original = ast.ident.as_ref();
@@ -219,15 +236,94 @@ impl Generator {
self.writeln("}");
}
+ fn trait_impl(&mut self, ast: &syn::DeriveInput, base: &str, blocks: &Vec<Node>) {
+ let anno = annotations(&ast.generics);
+ self.writeln(&format!("impl{} TraitFrom{} for {}{} {{",
+ anno, path_as_identifier(base),
+ ast.ident.as_ref(), anno));
+ self.indent();
+
+ self.block_methods(blocks);
+
+ self.dedent();
+ self.writeln("}");
+ }
+
+ fn trait_based_impl(&mut self, ast: &syn::DeriveInput) {
+ let anno = annotations(&ast.generics);
+ self.writeln(&format!("impl{} askama::Template for {}{} {{",
+ anno, ast.ident.as_ref(), anno));
+ self.indent();
+
+ self.writeln("fn render_into(&self, writer: &mut std::fmt::Write) {");
+ self.indent();
+ self.writeln("self.render_trait_into(writer);");
+ self.dedent();
+ self.writeln("}");
+
+ self.dedent();
+ self.writeln("}");
+ }
+
+ fn template_trait(&mut self, ast: &syn::DeriveInput, path: &str,
+ blocks: &Vec<Node>, nodes: &Vec<Node>) {
+ let anno = annotations(&ast.generics);
+ self.writeln(&format!("trait{} TraitFrom{}{} {{", anno,
+ path_as_identifier(path), anno));
+ self.indent();
+
+ self.block_methods(blocks);
+
+ self.writeln("fn render_trait_into(&self, writer: &mut std::fmt::Write) {");
+ self.indent();
+ self.handle(nodes);
+ self.dedent();
+ self.writeln("}");
+
+ self.dedent();
+ self.writeln("}");
+ }
+
fn result(self) -> String {
self.buf
}
}
-pub fn generate(ast: &syn::DeriveInput, path: &str, nodes: Vec<Node>) -> String {
+pub fn generate(ast: &syn::DeriveInput, path: &str, mut nodes: Vec<Node>) -> String {
+ let mut base: Option<Expr> = None;
+ let mut blocks = Vec::new();
+ let mut content = Vec::new();
+ for n in nodes.drain(..) {
+ match n {
+ Node::Extends(path) => {
+ match base {
+ Some(_) => panic!("multiple extend blocks found"),
+ None => { base = Some(path); },
+ }
+ },
+ Node::BlockDef(name, _) => {
+ blocks.push(n);
+ content.push(Node::Block(name));
+ },
+ _ => { content.push(n); },
+ }
+ }
+
let mut gen = Generator::new();
gen.path_based_name(ast, path);
- gen.template_impl(ast, &nodes);
+ if blocks.len() > 0 {
+ if let Some(extends) = base {
+ if let Expr::StrLit(base_path) = extends {
+ gen.trait_impl(ast, &base_path, &blocks);
+ }
+ } else {
+ gen.template_trait(ast, path, &blocks, &content);
+ gen.trait_impl(ast, path, &Vec::new());
+ }
+ gen.trait_based_impl(ast);
+ } else {
+ gen.template_impl(ast, &content);
+ }
gen.result()
}
diff --git a/testing/templates/base.html b/testing/templates/base.html
new file mode 100644
index 0000000..f40d867
--- /dev/null
+++ b/testing/templates/base.html
@@ -0,0 +1,2 @@
+{% block content %}{% endblock %}
+Copyright 2017
diff --git a/testing/templates/child.html b/testing/templates/child.html
new file mode 100644
index 0000000..23aed37
--- /dev/null
+++ b/testing/templates/child.html
@@ -0,0 +1,2 @@
+{% extends "base.html" %}
+{% block content %}Content goes here{% endblock %}
diff --git a/testing/tests/inheritance.rs b/testing/tests/inheritance.rs
new file mode 100644
index 0000000..ebcca70
--- /dev/null
+++ b/testing/tests/inheritance.rs
@@ -0,0 +1,19 @@
+extern crate askama;
+#[macro_use]
+extern crate askama_derive;
+
+use askama::Template;
+
+#[derive(Template)]
+#[template(path = "base.html")]
+struct BaseTemplate { }
+
+#[derive(Template)]
+#[template(path = "child.html")]
+struct ChildTemplate { }
+
+#[test]
+fn test_simple_extends() {
+ let t = ChildTemplate { };
+ assert_eq!(t.render(), "Content goes here\nCopyright 2017\n");
+}