Reintroduce web response type for full pages

This commit is contained in:
Manuel Cillero 2024-11-24 09:23:24 +01:00
parent 04a365797d
commit b2b0d8bd3e
40 changed files with 1516 additions and 249 deletions

View file

@ -1,5 +1,4 @@
//! **`StaticFilesBundle`** uses [static_files](https://docs.rs/static-files/latest/static_files/)
//! to provide an easy way to embed static files or compiled SCSS files into your binary at compile
//! Provide an easy way to embed static files or compiled SCSS files into your binary at compile
//! time.
//!
//! ## Adding to your project
@ -24,9 +23,9 @@
//! use pagetop_build::StaticFilesBundle;
//!
//! fn main() -> std::io::Result<()> {
//! StaticFilesBundle::from_dir("./static", None) // Include all files.
//! .with_name("guides") // Name the generated module.
//! .build() // Build the bundle.
//! StaticFilesBundle::from_dir("./static", None)
//! .with_name("guides")
//! .build()
//! }
//! ```
//!
@ -67,7 +66,7 @@
//!
//! ## Generated module
//!
//! `StaticFilesBundle` generates a file in the standard directory
//! [`StaticFilesBundle`] generates a file in the standard directory
//! [OUT_DIR](https://doc.rust-lang.org/cargo/reference/environment-variables.html) where all
//! intermediate and output artifacts are placed during compilation. For example, if you use
//! `with_name("guides")`, it generates a file named `guides.rs`:
@ -78,15 +77,15 @@
//! ```rust#ignore
//! use pagetop::prelude::*;
//!
//! static_files!(guides);
//! include_files!(guides);
//! ```
//!
//! Or, access the entire bundle as a static `HashMap`:
//! Or, access the entire bundle as a global static `HashMap`:
//!
//! ```rust#ignore
//! use pagetop::prelude::*;
//!
//! static_files!(guides => BUNDLE_GUIDES);
//! include_files!(guides => BUNDLE_GUIDES);
//! ```
//!
//! You can build more than one resources file to compile with your project.
@ -98,6 +97,8 @@ use std::fs::{create_dir_all, remove_dir_all, File};
use std::io::Write;
use std::path::Path;
/// Generates the resources to embed at compile time using
/// [static_files](https://docs.rs/static-files/latest/static_files/).
pub struct StaticFilesBundle {
resource_dir: ResourceDir,
}

View file

@ -3,8 +3,110 @@ mod smart_default;
use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
use quote::{quote, quote_spanned, ToTokens};
use syn::{parse_macro_input, parse_str, DeriveInput, ItemFn};
/// Macro attribute to generate builder methods from `set_` methods.
///
/// This macro takes a method with the `set_` prefix and generates a corresponding method with the
/// `with_` prefix to use in the builder pattern.
///
/// # Panics
///
/// This function will panic if a parameter identifier is not found in the argument list.
///
/// # Examples
///
/// ```
/// #[fn_builder]
/// pub fn set_example(&mut self) -> &mut Self {
/// // implementation
/// }
/// ```
///
/// Will generate:
///
/// ```
/// pub fn with_example(mut self) -> Self {
/// self.set_example();
/// self
/// }
/// ```
#[proc_macro_attribute]
pub fn fn_builder(_: TokenStream, item: TokenStream) -> TokenStream {
let fn_set = parse_macro_input!(item as ItemFn);
let fn_set_name = fn_set.sig.ident.to_string();
if !fn_set_name.starts_with("set_") {
let expanded = quote_spanned! {
fn_set.sig.ident.span() =>
compile_error!("expected a \"pub fn set_...() -> &mut Self\" method");
};
return expanded.into();
}
let fn_with_name = fn_set_name.replace("set_", "with_");
let fn_with_generics = if fn_set.sig.generics.params.is_empty() {
fn_with_name.clone()
} else {
let g = &fn_set.sig.generics;
format!("{fn_with_name}{}", quote! { #g }.to_string())
};
let where_clause = fn_set
.sig
.generics
.where_clause
.as_ref()
.map_or(String::new(), |where_clause| {
format!("{} ", quote! { #where_clause }.to_string())
});
let args: Vec<String> = fn_set
.sig
.inputs
.iter()
.skip(1)
.map(|arg| arg.to_token_stream().to_string())
.collect();
let params: Vec<String> = args
.iter()
.map(|arg| {
arg.split_whitespace()
.next()
.unwrap()
.trim_end_matches(':')
.to_string()
})
.collect();
#[rustfmt::skip]
let fn_with = parse_str::<ItemFn>(format!(r#"
pub fn {fn_with_generics}(mut self, {}) -> Self {where_clause} {{
self.{fn_set_name}({});
self
}}
"#, args.join(", "), params.join(", ")
).as_str()).unwrap();
#[rustfmt::skip]
let fn_set_doc = format!(r##"
<p id="method.{fn_with_name}" style="margin-bottom: 12px;">Use
<code class="code-header">pub fn <span class="fn" href="#method.{fn_with_name}">{fn_with_name}</span>(self, ) -> Self</code>
for the <a href="#method.new">builder pattern</a>.
</p>
"##);
let expanded = quote! {
#[doc(hidden)]
#fn_with
#[inline]
#[doc = #fn_set_doc]
#fn_set
};
expanded.into()
}
#[proc_macro]
#[proc_macro_error]