Hide askama_derive dependency inside askama (fixes #2)

This commit is contained in:
Dirkjan Ochtman 2017-03-06 22:40:04 +01:00
parent 0efd0c5cc5
commit 664398b225
15 changed files with 131 additions and 128 deletions

6
Cargo.lock generated
View File

@ -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)",
]

View File

@ -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

View File

@ -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" }

View File

@ -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();
}

View File

@ -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();
}

View File

@ -12,5 +12,5 @@ workspace = ".."
proc-macro = true
[dependencies]
askama = { path = "../askama", version = "0.2.1" }
nom = "2.1"
syn = "0.11"

View File

@ -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
View 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
}

View File

@ -7,7 +7,6 @@ build = "build.rs"
[dependencies]
askama = { path = "../askama", version = "*" }
askama_derive = { path = "../askama_derive", version = "*" }
[build-dependencies]
askama = { path = "../askama", version = "*" }

View File

@ -1,5 +1,4 @@
#[macro_use]
extern crate askama_derive;
extern crate askama;
use askama::Template;

View File

@ -1,6 +1,5 @@
extern crate askama;
#[macro_use]
extern crate askama_derive;
extern crate askama;
use askama::Template;

View File

@ -1,6 +1,5 @@
extern crate askama;
#[macro_use]
extern crate askama_derive;
extern crate askama;
use askama::Template;

View File

@ -1,5 +1,4 @@
#[macro_use]
extern crate askama_derive;
extern crate askama;
use askama::Template;