mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-28 13:30:59 +00:00
Hide askama_derive dependency inside askama (fixes #2)
This commit is contained in:
parent
0efd0c5cc5
commit
664398b225
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -3,22 +3,20 @@ name = "askama_testing"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"askama 0.2.1",
|
"askama 0.2.1",
|
||||||
"askama_derive 0.2.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "askama"
|
name = "askama"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nom 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"askama_derive 0.2.1",
|
||||||
"syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "askama_derive"
|
name = "askama_derive"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"askama 0.2.1",
|
"nom 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -79,8 +79,7 @@ In any Rust file inside your crate, add the following:
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate askama_derive; // for the custom derive implementation
|
extern crate askama; // for the Template trait and custom derive macro
|
||||||
extern crate askama; // for the Template trait
|
|
||||||
|
|
||||||
use askama::Template; // bring trait in scope
|
use askama::Template; // bring trait in scope
|
||||||
|
|
||||||
|
@ -16,5 +16,4 @@ readme = "../README.md"
|
|||||||
travis-ci = { repository = "djc/askama" }
|
travis-ci = { repository = "djc/askama" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nom = "2.1"
|
askama_derive = { path = "../askama_derive", version = "0.2.1" }
|
||||||
syn = "0.11"
|
|
||||||
|
@ -182,8 +182,12 @@
|
|||||||
//! Expressions can be grouped using parentheses.
|
//! Expressions can be grouped using parentheses.
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate nom;
|
extern crate askama_derive;
|
||||||
extern crate syn;
|
|
||||||
|
use std::env;
|
||||||
|
use std::fs::{self, DirEntry};
|
||||||
|
use std::io;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
/// Main `Template` trait; implementations are generally derived
|
/// Main `Template` trait; implementations are generally derived
|
||||||
pub trait Template {
|
pub trait Template {
|
||||||
@ -197,73 +201,42 @@ pub trait Template {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod generator;
|
|
||||||
mod parser;
|
|
||||||
mod path;
|
|
||||||
|
|
||||||
pub mod filters;
|
pub mod filters;
|
||||||
pub use path::rerun_if_templates_changed;
|
pub use askama_derive::*;
|
||||||
|
|
||||||
// Holds metadata for the template, based on the `template()` attribute.
|
// Duplicates askama_derive::path::template_dir()
|
||||||
struct TemplateMeta {
|
fn template_dir() -> PathBuf {
|
||||||
path: String,
|
let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||||
print: String,
|
path.push("templates");
|
||||||
|
path
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a `TemplateMeta` based on the `template()` attribute data found
|
fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
|
||||||
// in the parsed struct or enum. Will panic if it does not find the required
|
if dir.is_dir() {
|
||||||
// template path, or if the `print` key has an unexpected value.
|
for entry in try!(fs::read_dir(dir)) {
|
||||||
fn get_template_meta(ast: &syn::DeriveInput) -> TemplateMeta {
|
let entry = try!(entry);
|
||||||
let mut path = None;
|
let path = entry.path();
|
||||||
let mut print = "none".to_string();
|
if path.is_dir() {
|
||||||
let attr = ast.attrs.iter().find(|a| a.name() == "template").unwrap();
|
try!(visit_dirs(&path, cb));
|
||||||
if let syn::MetaItem::List(_, ref inner) = attr.value {
|
} else {
|
||||||
for nm_item in inner {
|
cb(&entry);
|
||||||
if let syn::NestedMetaItem::MetaItem(ref item) = *nm_item {
|
|
||||||
if let syn::MetaItem::NameValue(ref key, ref val) = *item {
|
|
||||||
match key.as_ref() {
|
|
||||||
"path" => if let syn::Lit::Str(ref s, _) = *val {
|
|
||||||
path = Some(s.clone());
|
|
||||||
} else {
|
|
||||||
panic!("template path must be string literal");
|
|
||||||
},
|
|
||||||
"print" => if let syn::Lit::Str(ref s, _) = *val {
|
|
||||||
print = s.clone();
|
|
||||||
} else {
|
|
||||||
panic!("print value must be string literal");
|
|
||||||
},
|
|
||||||
_ => { panic!("unsupported annotation key found") }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if path.is_none() {
|
Ok(())
|
||||||
panic!("template path not found in struct attributes");
|
|
||||||
}
|
|
||||||
TemplateMeta { path: path.unwrap(), print: print }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes a `syn::DeriveInput` and generates source code for it
|
/// Build script helper to rebuild crates if contained templates have changed
|
||||||
///
|
///
|
||||||
/// Reads the metadata from the `template()` attribute to get the template
|
/// Iterates over all files in the template dir (`templates` in
|
||||||
/// metadata, then fetches the source from the filesystem. The source is
|
/// `CARGO_MANIFEST_DIR`) and writes a `cargo:rerun-if-changed=` line for each
|
||||||
/// parsed, and the parse tree is fed to the code generator. Will print
|
/// of them to stdout.
|
||||||
/// the parse tree and/or generated source according to the `print` key's
|
///
|
||||||
/// value as passed to the `template()` attribute.
|
/// This helper method can be used in build scripts (`build.rs`) in crates
|
||||||
pub fn build_template(ast: &syn::DeriveInput) -> String {
|
/// that have templates, to make sure the crate gets rebuilt when template
|
||||||
let meta = get_template_meta(ast);
|
/// source code changes.
|
||||||
let mut src = path::get_template_source(&meta.path);
|
pub fn rerun_if_templates_changed() {
|
||||||
if src.ends_with('\n') {
|
visit_dirs(&template_dir(), &|e: &DirEntry| {
|
||||||
let _ = src.pop();
|
println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap());
|
||||||
}
|
}).unwrap();
|
||||||
let nodes = parser::parse(&src);
|
|
||||||
if meta.print == "ast" || meta.print == "all" {
|
|
||||||
println!("{:?}", nodes);
|
|
||||||
}
|
|
||||||
let code = generator::generate(ast, &meta.path, nodes);
|
|
||||||
if meta.print == "code" || meta.print == "all" {
|
|
||||||
println!("{}", code);
|
|
||||||
}
|
|
||||||
code
|
|
||||||
}
|
}
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
use std::env;
|
|
||||||
use std::fs::{self, DirEntry, File};
|
|
||||||
use std::io::{self, Read};
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
|
|
||||||
fn template_dir() -> PathBuf {
|
|
||||||
let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
|
||||||
path.push("templates");
|
|
||||||
path
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_template_source(tpl_file: &str) -> String {
|
|
||||||
let mut path = template_dir();
|
|
||||||
path.push(Path::new(tpl_file));
|
|
||||||
let mut f = File::open(path).unwrap();
|
|
||||||
let mut s = String::new();
|
|
||||||
f.read_to_string(&mut s).unwrap();
|
|
||||||
s
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_dirs(dir: &Path, cb: &Fn(&DirEntry)) -> io::Result<()> {
|
|
||||||
if dir.is_dir() {
|
|
||||||
for entry in try!(fs::read_dir(dir)) {
|
|
||||||
let entry = try!(entry);
|
|
||||||
let path = entry.path();
|
|
||||||
if path.is_dir() {
|
|
||||||
try!(visit_dirs(&path, cb));
|
|
||||||
} else {
|
|
||||||
cb(&entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Build script helper to rebuild crates if contained templates have changed
|
|
||||||
///
|
|
||||||
/// Iterates over all files in the template dir (`templates` in
|
|
||||||
/// `CARGO_MANIFEST_DIR`) and writes a `cargo:rerun-if-changed=` line for each
|
|
||||||
/// of them to stdout.
|
|
||||||
///
|
|
||||||
/// This helper method can be used in build scripts (`build.rs`) in crates
|
|
||||||
/// that have templates, to make sure the crate gets rebuilt when template
|
|
||||||
/// source code changes.
|
|
||||||
pub fn rerun_if_templates_changed() {
|
|
||||||
visit_dirs(&template_dir(), &|e: &DirEntry| {
|
|
||||||
println!("cargo:rerun-if-changed={}", e.path().to_str().unwrap());
|
|
||||||
}).unwrap();
|
|
||||||
}
|
|
@ -12,5 +12,5 @@ workspace = ".."
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
askama = { path = "../askama", version = "0.2.1" }
|
nom = "2.1"
|
||||||
syn = "0.11"
|
syn = "0.11"
|
||||||
|
@ -1,9 +1,78 @@
|
|||||||
extern crate askama;
|
#[macro_use]
|
||||||
|
extern crate nom;
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
extern crate syn;
|
extern crate syn;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
mod generator;
|
||||||
|
mod parser;
|
||||||
|
mod path;
|
||||||
|
|
||||||
|
// Holds metadata for the template, based on the `template()` attribute.
|
||||||
|
struct TemplateMeta {
|
||||||
|
path: String,
|
||||||
|
print: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a `TemplateMeta` based on the `template()` attribute data found
|
||||||
|
// in the parsed struct or enum. Will panic if it does not find the required
|
||||||
|
// template path, or if the `print` key has an unexpected value.
|
||||||
|
fn get_template_meta(ast: &syn::DeriveInput) -> TemplateMeta {
|
||||||
|
let mut path = None;
|
||||||
|
let mut print = "none".to_string();
|
||||||
|
let attr = ast.attrs.iter().find(|a| a.name() == "template").unwrap();
|
||||||
|
if let syn::MetaItem::List(_, ref inner) = attr.value {
|
||||||
|
for nm_item in inner {
|
||||||
|
if let syn::NestedMetaItem::MetaItem(ref item) = *nm_item {
|
||||||
|
if let syn::MetaItem::NameValue(ref key, ref val) = *item {
|
||||||
|
match key.as_ref() {
|
||||||
|
"path" => if let syn::Lit::Str(ref s, _) = *val {
|
||||||
|
path = Some(s.clone());
|
||||||
|
} else {
|
||||||
|
panic!("template path must be string literal");
|
||||||
|
},
|
||||||
|
"print" => if let syn::Lit::Str(ref s, _) = *val {
|
||||||
|
print = s.clone();
|
||||||
|
} else {
|
||||||
|
panic!("print value must be string literal");
|
||||||
|
},
|
||||||
|
_ => { panic!("unsupported annotation key found") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if path.is_none() {
|
||||||
|
panic!("template path not found in struct attributes");
|
||||||
|
}
|
||||||
|
TemplateMeta { path: path.unwrap(), print: print }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Takes a `syn::DeriveInput` and generates source code for it
|
||||||
|
///
|
||||||
|
/// Reads the metadata from the `template()` attribute to get the template
|
||||||
|
/// metadata, then fetches the source from the filesystem. The source is
|
||||||
|
/// parsed, and the parse tree is fed to the code generator. Will print
|
||||||
|
/// the parse tree and/or generated source according to the `print` key's
|
||||||
|
/// value as passed to the `template()` attribute.
|
||||||
|
fn build_template(ast: &syn::DeriveInput) -> String {
|
||||||
|
let meta = get_template_meta(ast);
|
||||||
|
let mut src = path::get_template_source(&meta.path);
|
||||||
|
if src.ends_with('\n') {
|
||||||
|
let _ = src.pop();
|
||||||
|
}
|
||||||
|
let nodes = parser::parse(&src);
|
||||||
|
if meta.print == "ast" || meta.print == "all" {
|
||||||
|
println!("{:?}", nodes);
|
||||||
|
}
|
||||||
|
let code = generator::generate(ast, &meta.path, nodes);
|
||||||
|
if meta.print == "code" || meta.print == "all" {
|
||||||
|
println!("{}", code);
|
||||||
|
}
|
||||||
|
code
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro_derive(Template, attributes(template))]
|
#[proc_macro_derive(Template, attributes(template))]
|
||||||
pub fn derive_template(input: TokenStream) -> TokenStream {
|
pub fn derive_template(input: TokenStream) -> TokenStream {
|
||||||
let ast = syn::parse_derive_input(&input.to_string()).unwrap();
|
let ast = syn::parse_derive_input(&input.to_string()).unwrap();
|
||||||
@ -11,5 +80,5 @@ pub fn derive_template(input: TokenStream) -> TokenStream {
|
|||||||
syn::Body::Struct(ref data) => data,
|
syn::Body::Struct(ref data) => data,
|
||||||
_ => panic!("#[derive(Template)] can only be used with structs"),
|
_ => panic!("#[derive(Template)] can only be used with structs"),
|
||||||
};
|
};
|
||||||
askama::build_template(&ast).parse().unwrap()
|
build_template(&ast).parse().unwrap()
|
||||||
}
|
}
|
||||||
|
19
askama_derive/src/path.rs
Normal file
19
askama_derive/src/path.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Read;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
fn template_dir() -> PathBuf {
|
||||||
|
let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||||
|
path.push("templates");
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_template_source(tpl_file: &str) -> String {
|
||||||
|
let mut path = template_dir();
|
||||||
|
path.push(Path::new(tpl_file));
|
||||||
|
let mut f = File::open(path).unwrap();
|
||||||
|
let mut s = String::new();
|
||||||
|
f.read_to_string(&mut s).unwrap();
|
||||||
|
s
|
||||||
|
}
|
@ -7,7 +7,6 @@ build = "build.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
askama = { path = "../askama", version = "*" }
|
askama = { path = "../askama", version = "*" }
|
||||||
askama_derive = { path = "../askama_derive", version = "*" }
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
askama = { path = "../askama", version = "*" }
|
askama = { path = "../askama", version = "*" }
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate askama_derive;
|
|
||||||
extern crate askama;
|
extern crate askama;
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
extern crate askama;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate askama_derive;
|
extern crate askama;
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
extern crate askama;
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate askama_derive;
|
extern crate askama;
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate askama_derive;
|
|
||||||
extern crate askama;
|
extern crate askama;
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user