mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-28 05:21:14 +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"
|
||||
dependencies = [
|
||||
"askama 0.2.1",
|
||||
"askama_derive 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.2.1"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"askama_derive 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.2.1"
|
||||
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)",
|
||||
]
|
||||
|
||||
|
@ -79,8 +79,7 @@ In any Rust file inside your crate, add the following:
|
||||
|
||||
```rust
|
||||
#[macro_use]
|
||||
extern crate askama_derive; // for the custom derive implementation
|
||||
extern crate askama; // for the Template trait
|
||||
extern crate askama; // for the Template trait and custom derive macro
|
||||
|
||||
use askama::Template; // bring trait in scope
|
||||
|
||||
|
@ -16,5 +16,4 @@ readme = "../README.md"
|
||||
travis-ci = { repository = "djc/askama" }
|
||||
|
||||
[dependencies]
|
||||
nom = "2.1"
|
||||
syn = "0.11"
|
||||
askama_derive = { path = "../askama_derive", version = "0.2.1" }
|
||||
|
@ -182,8 +182,12 @@
|
||||
//! Expressions can be grouped using parentheses.
|
||||
|
||||
#[macro_use]
|
||||
extern crate nom;
|
||||
extern crate syn;
|
||||
extern crate askama_derive;
|
||||
|
||||
use std::env;
|
||||
use std::fs::{self, DirEntry};
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Main `Template` trait; implementations are generally derived
|
||||
pub trait Template {
|
||||
@ -197,73 +201,42 @@ pub trait Template {
|
||||
}
|
||||
}
|
||||
|
||||
mod generator;
|
||||
mod parser;
|
||||
mod path;
|
||||
|
||||
pub mod filters;
|
||||
pub use path::rerun_if_templates_changed;
|
||||
pub use askama_derive::*;
|
||||
|
||||
// Holds metadata for the template, based on the `template()` attribute.
|
||||
struct TemplateMeta {
|
||||
path: String,
|
||||
print: String,
|
||||
// Duplicates askama_derive::path::template_dir()
|
||||
fn template_dir() -> PathBuf {
|
||||
let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
path.push("templates");
|
||||
path
|
||||
}
|
||||
|
||||
// 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") }
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
if path.is_none() {
|
||||
panic!("template path not found in struct attributes");
|
||||
}
|
||||
TemplateMeta { path: path.unwrap(), print: print }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// 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.
|
||||
pub 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
|
||||
/// 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();
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
[dependencies]
|
||||
askama = { path = "../askama", version = "0.2.1" }
|
||||
nom = "2.1"
|
||||
syn = "0.11"
|
||||
|
@ -1,9 +1,78 @@
|
||||
extern crate askama;
|
||||
#[macro_use]
|
||||
extern crate nom;
|
||||
extern crate proc_macro;
|
||||
extern crate syn;
|
||||
|
||||
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))]
|
||||
pub fn derive_template(input: TokenStream) -> TokenStream {
|
||||
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,
|
||||
_ => 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]
|
||||
askama = { path = "../askama", version = "*" }
|
||||
askama_derive = { path = "../askama_derive", version = "*" }
|
||||
|
||||
[build-dependencies]
|
||||
askama = { path = "../askama", version = "*" }
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[macro_use]
|
||||
extern crate askama_derive;
|
||||
extern crate askama;
|
||||
|
||||
use askama::Template;
|
||||
|
@ -1,6 +1,5 @@
|
||||
extern crate askama;
|
||||
#[macro_use]
|
||||
extern crate askama_derive;
|
||||
extern crate askama;
|
||||
|
||||
use askama::Template;
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
extern crate askama;
|
||||
#[macro_use]
|
||||
extern crate askama_derive;
|
||||
extern crate askama;
|
||||
|
||||
use askama::Template;
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
#[macro_use]
|
||||
extern crate askama_derive;
|
||||
extern crate askama;
|
||||
|
||||
use askama::Template;
|
||||
|
Loading…
x
Reference in New Issue
Block a user