mirror of https://github.com/rwf2/Rocket.git
Improve documentation for contrib library.
This commit is contained in:
parent
fec2866517
commit
804154e537
|
@ -10,7 +10,7 @@ use rocket::response::data;
|
|||
use self::serde::{Serialize, Deserialize};
|
||||
use self::serde_json::Error as JSONError;
|
||||
|
||||
/// The JSON datatype, which implements both `FromRequest` and `Responder`. This
|
||||
/// The JSON type, which implements both `FromRequest` and `Responder`. This
|
||||
/// type allows you to trivially consume and respond with JSON in your Rocket
|
||||
/// application.
|
||||
///
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#[macro_export]
|
||||
/// Returns a hashset with the extensions of all of the enabled template
|
||||
/// engines from the set of template engined passed in.
|
||||
macro_rules! engine_set {
|
||||
($($feature:expr => $engine:ident),+,) => ({
|
||||
use std::collections::HashSet;
|
||||
|
@ -18,7 +19,11 @@ macro_rules! engine_set {
|
|||
});
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
/// Renders the template named `name` with the given template info `info` and
|
||||
/// context `ctxt` using one of the templates in the template set passed in. It
|
||||
/// does this by checking if the template's extension matches the engine's
|
||||
/// extension, and if so, calls the engine's `render` method. All of this only
|
||||
/// happens for engine's that have been enabled as features by the user.
|
||||
macro_rules! render_set {
|
||||
($name:expr, $info:expr, $ctxt:expr, $($feature:expr => $engine:ident),+,) => ({$(
|
||||
#[cfg(feature = $feature)]
|
||||
|
@ -36,7 +41,7 @@ macro_rules! render_set {
|
|||
fn $engine<T: Serialize>(_: &str, _: &TemplateInfo, _: &T)
|
||||
-> Option<Template> { None }
|
||||
|
||||
if let Some(template) = $engine($name, &$info, &$ctxt) {
|
||||
if let Some(template) = $engine($name, &$info, $ctxt) {
|
||||
return template
|
||||
}
|
||||
)+});
|
||||
|
|
|
@ -18,6 +18,85 @@ use rocket::response::{Content, Outcome, FreshHyperResponse, Responder};
|
|||
use rocket::{Rocket, ContentType};
|
||||
use self::glob::glob;
|
||||
|
||||
/// The Template type implements generic support for template rendering in
|
||||
/// Rocket.
|
||||
///
|
||||
/// Templating in Rocket words by first discovering all of the templates inside
|
||||
/// the template directory. The template directory is configurable via the
|
||||
/// `template_dir` configuration parameter. The path set in `template_dir`
|
||||
/// should be relative to the Rocket configuration file. See the [configuration
|
||||
/// chapter](https://rocket.rs/guide/configuration) of the guide for more
|
||||
/// information on configuration.
|
||||
///
|
||||
/// Templates are discovered according to their extension. At present, this
|
||||
/// library supports the following templates and extensions:
|
||||
///
|
||||
/// * **Tera**: `.tera`
|
||||
/// * **Handlebars**: `.hbs`
|
||||
///
|
||||
/// Any file that ends with one of these extension will be discovered and
|
||||
/// rendered with the corresponding templating engine. The name of the template
|
||||
/// will be the path to the template file relative to `template_dir` minus at
|
||||
/// most two extensions. The following are examples of template names (on the
|
||||
/// right) given that the template is at the path on the left.
|
||||
///
|
||||
/// * `{template_dir}/index.html.hbs` => index
|
||||
/// * `{template_dir}/index.hbs` => index
|
||||
/// * `{template_dir}/dir/index.hbs` => dir/index
|
||||
/// * `{template_dir}/dir/index.html.hbs` => dir/index
|
||||
/// * `{template_dir}/index.template.html.hbs` => index.template
|
||||
/// * `{template_dir}/subdir/index.template.html.hbs` => subdir/index.template
|
||||
///
|
||||
/// The recommended naming scheme is to use two extensions: one for the file
|
||||
/// type, and one for the template extension. This means that template
|
||||
/// extensions should look like: `.html.hbs`, `.html.tera`, `.xml.hbs`, etc.
|
||||
///
|
||||
/// Templates are rendered with the `render` method. The method takes in the
|
||||
/// name of a template and a context to render the template with. The context
|
||||
/// can be any type that implements `Serialize` from
|
||||
/// [Serde](https://github.com/serde-rs/json) and would serialize to an `Object`
|
||||
/// value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// To render a template named "index" with a `HashMap` as the context:
|
||||
///
|
||||
/// ```rust
|
||||
/// use rocket_contrib::Template;
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let context: HashMap<&str, &str> = HashMap::new();
|
||||
/// // ... add key/value pairs to `context` ...
|
||||
/// let _template = Template::render("index", &context);
|
||||
/// ```
|
||||
///
|
||||
/// The Template type implements Rocket's `Responder` trait, so it can be
|
||||
/// returned from a request handler directly:
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[get("/")]
|
||||
/// fn index() -> Template {
|
||||
/// let context = ...;
|
||||
/// Template::render("index", &context)
|
||||
/// }
|
||||
/// ```
|
||||
#[derive(Debug)]
|
||||
pub struct Template(Option<String>, Option<String>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TemplateInfo {
|
||||
/// The complete path, including `template_dir`, to this template.
|
||||
full_path: PathBuf,
|
||||
/// The complete path, without `template_dir`, to this template.
|
||||
path: PathBuf,
|
||||
/// The complete path, with `template_dir`, without the template extension.
|
||||
canonical_path: PathBuf,
|
||||
/// The extension of for the engine of this template.
|
||||
extension: String,
|
||||
/// The extension before the engine extension in the template, if any.
|
||||
data_type: Option<String>
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref TEMPLATES: HashMap<String, TemplateInfo> = discover_templates();
|
||||
// FIXME: Ensure template_dir is an absolute path starting at crate root.
|
||||
|
@ -25,55 +104,14 @@ lazy_static! {
|
|||
Rocket::config("template_dir").unwrap_or("templates").to_string();
|
||||
}
|
||||
|
||||
/// Removes the file path's extension or does nothing if there is none.
|
||||
fn remove_extension<P: AsRef<Path>>(path: P) -> PathBuf {
|
||||
PathBuf::from(path.as_ref().file_stem().unwrap())
|
||||
}
|
||||
|
||||
fn discover_templates() -> HashMap<String, TemplateInfo> {
|
||||
// Keep this set in-sync with the `render_set` invocation.
|
||||
let engines = engine_set![
|
||||
"tera_templates" => tera_templates,
|
||||
"handlebars_templates" => handlebars_templates,
|
||||
];
|
||||
|
||||
let mut templates = HashMap::new();
|
||||
for ext in engines {
|
||||
let mut path: PathBuf = [&*TEMPLATE_DIR, "**", "*"].iter().collect();
|
||||
path.set_extension(ext);
|
||||
for p in glob(path.to_str().unwrap()).unwrap().filter_map(Result::ok) {
|
||||
let canonical_path = remove_extension(&p);
|
||||
let name = remove_extension(&canonical_path);
|
||||
let data_type = canonical_path.extension();
|
||||
templates.insert(name.to_string_lossy().into_owned(), TemplateInfo {
|
||||
full_path: p.to_path_buf(),
|
||||
path: p.strip_prefix(&*TEMPLATE_DIR).unwrap().to_path_buf(),
|
||||
canonical_path: canonical_path.clone(),
|
||||
extension: p.extension().unwrap().to_string_lossy().into_owned(),
|
||||
data_type: data_type.map(|d| d.to_string_lossy().into_owned())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
templates
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Template(Option<String>, Option<String>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TemplateInfo {
|
||||
full_path: PathBuf,
|
||||
path: PathBuf,
|
||||
canonical_path: PathBuf,
|
||||
extension: String,
|
||||
data_type: Option<String>
|
||||
}
|
||||
|
||||
impl Template {
|
||||
pub fn render<S, T>(name: S, context: T) -> Template
|
||||
/// Render the template named `name` with the context `context`. The
|
||||
/// template is not actually rendered until the response is needed by
|
||||
/// Rocket. As such, the `Template` type should be used only as a
|
||||
/// `Responder`.
|
||||
pub fn render<S, T>(name: S, context: &T) -> Template
|
||||
where S: AsRef<str>, T: Serialize
|
||||
{
|
||||
{
|
||||
let name = name.as_ref();
|
||||
let template = TEMPLATES.get(name);
|
||||
if template.is_none() {
|
||||
|
@ -104,3 +142,40 @@ impl Responder for Template {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the file path's extension or does nothing if there is none.
|
||||
fn remove_extension<P: AsRef<Path>>(path: P) -> PathBuf {
|
||||
PathBuf::from(path.as_ref().file_stem().unwrap())
|
||||
}
|
||||
|
||||
/// Returns a HashMap of `TemplateInfo`'s for all of the templates in
|
||||
/// `TEMPLATE_DIR`. Templates are all files that match one of the extensions for
|
||||
/// engine's in `engine_set`.
|
||||
fn discover_templates() -> HashMap<String, TemplateInfo> {
|
||||
// Keep this set in-sync with the `render_set` invocation.
|
||||
let engines = engine_set![
|
||||
"tera_templates" => tera_templates,
|
||||
"handlebars_templates" => handlebars_templates,
|
||||
];
|
||||
|
||||
let mut templates = HashMap::new();
|
||||
for ext in engines {
|
||||
let mut path: PathBuf = [&*TEMPLATE_DIR, "**", "*"].iter().collect();
|
||||
path.set_extension(ext);
|
||||
for p in glob(path.to_str().unwrap()).unwrap().filter_map(Result::ok) {
|
||||
let canonical_path = remove_extension(&p);
|
||||
let name = remove_extension(&canonical_path);
|
||||
let data_type = canonical_path.extension();
|
||||
templates.insert(name.to_string_lossy().into_owned(), TemplateInfo {
|
||||
full_path: p.to_path_buf(),
|
||||
path: p.strip_prefix(&*TEMPLATE_DIR).unwrap().to_path_buf(),
|
||||
canonical_path: canonical_path.clone(),
|
||||
extension: p.extension().unwrap().to_string_lossy().into_owned(),
|
||||
data_type: data_type.map(|d| d.to_string_lossy().into_owned())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
templates
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue