Skip to content

Commit eaec826

Browse files
authored
Ensure template is recompiled when template file changes (#65)
1 parent 12e307f commit eaec826

File tree

6 files changed

+35
-59
lines changed

6 files changed

+35
-59
lines changed

crates/boilerplate-macros/src/implementation.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use super::*;
33
pub(crate) struct Implementation<'src> {
44
pub(crate) body: TokenStream,
55
pub(crate) text: Vec<&'src str>,
6-
pub(crate) tokens: Vec<Token<'src>>,
76
}
87

98
impl<'src> Implementation<'src> {
@@ -48,6 +47,6 @@ impl<'src> Implementation<'src> {
4847
.parse()
4948
.unwrap();
5049

51-
Self { body, text, tokens }
50+
Self { body, text }
5251
}
5352
}

crates/boilerplate-macros/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use {
66
darling::FromDeriveInput,
77
new_mime_guess::Mime,
88
proc_macro2::{Span, TokenStream},
9-
quote::quote,
9+
quote::{quote, ToTokens, TokenStreamExt},
1010
std::path::Path,
1111
syn::{parse_macro_input, DeriveInput, Generics, Ident, LitStr},
1212
};
@@ -21,7 +21,7 @@ pub fn boilerplate(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
2121
let template = parse_macro_input!(input as LitStr);
2222
let src = template.value();
2323

24-
let Implementation { body, text, .. } = Implementation::parse(&src, false, true);
24+
let Implementation { body, text } = Implementation::parse(&src, false, true);
2525

2626
quote! {
2727
{

crates/boilerplate-macros/src/source.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,15 @@ impl Source {
1414
}
1515
}
1616
}
17+
18+
impl ToTokens for Source {
19+
fn to_tokens(&self, tokens: &mut TokenStream) {
20+
match self {
21+
Self::Literal(literal) => tokens.append(literal.token()),
22+
Self::Path(path) => {
23+
let path = LitStr::new(path, Span::call_site());
24+
tokens.append_all(quote!(include_str!(#path)));
25+
}
26+
}
27+
}
28+
}

crates/boilerplate-macros/src/template.rs

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -30,38 +30,10 @@ impl Template {
3030
let source = &self.source;
3131
let src = source.src();
3232

33-
let Implementation { body, text, tokens } = Implementation::parse(&src, self.escape, false);
33+
let Implementation { body, text } = Implementation::parse(&src, self.escape, false);
3434

3535
let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();
3636

37-
let tokens = if cfg!(feature = "reload") {
38-
let tokens = tokens
39-
.into_iter()
40-
.map(|token| match token {
41-
Token::Code { contents } => quote!(::boilerplate::Token::Code { contents: #contents }),
42-
Token::CodeLine { closed, contents } => {
43-
quote!(::boilerplate::Token::CodeLine { closed: #closed, contents: #contents })
44-
}
45-
Token::Interpolation { contents } => {
46-
quote!(::boilerplate::Token::Interpolation { contents: #contents })
47-
}
48-
Token::InterpolationLine { contents, closed } => {
49-
quote!(::boilerplate::Token::InterpolationLine { closed: #closed, contents: #contents })
50-
}
51-
Token::Text { contents, index } => quote!(::boilerplate::Token::Text {
52-
contents: #contents,
53-
index: #index
54-
}),
55-
})
56-
.collect::<Vec<TokenStream>>();
57-
58-
Some(quote! {
59-
const TOKENS: &'static [::boilerplate::Token<'static>] = &[ #(#tokens),* ];
60-
})
61-
} else {
62-
None
63-
};
64-
6537
let path = if cfg!(feature = "reload") {
6638
if let Source::Path(path) = &self.source {
6739
Some(quote!(const PATH: Option<&'static str> = Some(#path);))
@@ -76,9 +48,9 @@ impl Template {
7648

7749
quote! {
7850
impl #impl_generics ::boilerplate::Boilerplate for #ident #ty_generics #where_clause {
79-
const TEXT: &'static [&'static str] = &[ #(#text),* ];
51+
const TEMPLATE: &'static str = #source;
8052

81-
#tokens
53+
const TEXT: &'static [&'static str] = &[ #(#text),* ];
8254

8355
#path
8456

@@ -132,16 +104,6 @@ mod tests {
132104

133105
#[test]
134106
fn display_impl() {
135-
let tokens = if cfg!(feature = "reload") {
136-
Some(quote! {
137-
const TOKENS: &'static [::boilerplate::Token<'static>] = &[
138-
::boilerplate::Token::Text { contents: "", index: 0usize }
139-
];
140-
})
141-
} else {
142-
None
143-
};
144-
145107
let path = if cfg!(feature = "reload") {
146108
Some(quote!(
147109
const PATH: Option<&'static str> = None;
@@ -175,9 +137,9 @@ mod tests {
175137
.to_string(),
176138
quote!(
177139
impl ::boilerplate::Boilerplate for Foo {
178-
const TEXT: &'static [&'static str] = &[#text];
140+
const TEMPLATE: &'static str = "";
179141

180-
#tokens
142+
const TEXT: &'static [&'static str] = &[#text];
181143

182144
#path
183145

src/lib.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -703,13 +703,12 @@ mod reload;
703703
/// The boilerplate trait, automatically implemented by the `Boilerplate`
704704
/// derive macro.
705705
pub trait Boilerplate {
706+
/// The original template.
707+
const TEMPLATE: &'static str;
708+
706709
/// The parsed template's text blocks.
707710
const TEXT: &'static [&'static str];
708711

709-
#[cfg(feature = "reload")]
710-
/// The parsed template's tokens.
711-
const TOKENS: &'static [Token<'static>];
712-
713712
#[cfg(feature = "reload")]
714713
/// Path to the original template file.
715714
const PATH: Option<&'static str>;
@@ -734,16 +733,17 @@ pub trait Boilerplate {
734733
///
735734
/// - `src` - The new template source text.
736735
fn reload(&self, src: &str) -> Result<Reload<&Self>, Error> {
737-
let tokens = Token::parse(src).map_err(Error::Parse)?;
736+
let new = Token::parse(src).map_err(Error::ParseNew)?;
737+
let old = Token::parse(Self::TEMPLATE).map_err(Error::ParseOld)?;
738738

739-
if tokens.len() != Self::TOKENS.len() {
739+
if new.len() != old.len() {
740740
return Err(Error::Length {
741-
new: tokens.len(),
742-
old: Self::TOKENS.len(),
741+
new: new.len(),
742+
old: old.len(),
743743
});
744744
}
745745

746-
for (new, old) in tokens.iter().copied().zip(Self::TOKENS.iter().copied()) {
746+
for (new, old) in new.iter().zip(old) {
747747
if !new.is_compatible_with(old) {
748748
return Err(Error::Incompatible {
749749
new: new.to_string(),
@@ -754,7 +754,7 @@ pub trait Boilerplate {
754754

755755
Ok(Reload {
756756
inner: self,
757-
text: tokens
757+
text: new
758758
.into_iter()
759759
.filter_map(Token::text)
760760
.map(ToOwned::to_owned)

src/reload.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ pub enum Error {
2828
/// New template does not have the same number of blocks.
2929
Length { new: usize, old: usize },
3030
/// Failed to parse new template.
31-
Parse(boilerplate_parser::Error),
31+
ParseNew(boilerplate_parser::Error),
32+
/// Failed to parse old template.
33+
ParseOld(boilerplate_parser::Error),
3234
/// Template has no path
3335
Path,
3436
}
@@ -44,7 +46,8 @@ impl Display for Error {
4446
f,
4547
"new template has {new} blocks but old template has {old} blocks",
4648
),
47-
Self::Parse(err) => write!(f, "failed to parse new template: {err}"),
49+
Self::ParseNew(err) => write!(f, "failed to parse new template: {err}"),
50+
Self::ParseOld(err) => write!(f, "failed to parse old template: {err}"),
4851
Self::Path => write!(f, "template has no path"),
4952
}
5053
}

0 commit comments

Comments
 (0)