Modularize contrib.

This commit is contained in:
Sergio Benitez 2018-10-06 17:24:11 -07:00
parent 28f2a33abd
commit 9cb031a47d
31 changed files with 285 additions and 331 deletions

View File

@ -11,46 +11,46 @@ keywords = ["rocket", "web", "framework", "contrib", "contributed"]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
[features] [features]
default = ["json", "static_files"] # Internal use only.
templates = ["serde", "serde_json", "glob"]
databases = ["r2d2", "rocket_contrib_codegen/database_attribute"]
# User-facing features.
default = ["json", "serve"]
json = ["serde", "serde_json"] json = ["serde", "serde_json"]
msgpack = ["serde", "rmp-serde"] msgpack = ["serde", "rmp-serde"]
tera_templates = ["tera", "templates"] tera_templates = ["tera", "templates"]
handlebars_templates = ["handlebars", "templates"] handlebars_templates = ["handlebars", "templates"]
static_files = [] serve = []
# Internal use only.
templates = ["serde", "serde_json", "glob"]
# Database pooling features. # The barage of user-facing database features.
# Internal use only. diesel_sqlite_pool = ["databases", "diesel/sqlite", "diesel/r2d2"]
database_pool_codegen = ["rocket_contrib_codegen", "rocket_contrib_codegen/database_attribute"] diesel_postgres_pool = ["databases", "diesel/postgres", "diesel/r2d2"]
database_pool = ["r2d2", "database_pool_codegen"] diesel_mysql_pool = ["databases", "diesel/mysql", "diesel/r2d2"]
# External features. postgres_pool = ["databases", "postgres", "r2d2_postgres"]
diesel_postgres_pool = ["database_pool", "diesel/postgres", "diesel/r2d2"] mysql_pool = ["databases", "mysql", "r2d2_mysql"]
diesel_sqlite_pool = ["database_pool", "diesel/sqlite", "diesel/r2d2"] sqlite_pool = ["databases", "rusqlite", "r2d2_sqlite"]
diesel_mysql_pool = ["database_pool", "diesel/mysql", "diesel/r2d2"] cypher_pool = ["databases", "rusted_cypher", "r2d2_cypher"]
postgres_pool = ["database_pool", "postgres", "r2d2_postgres"] redis_pool = ["databases", "redis", "r2d2_redis"]
mysql_pool = ["database_pool", "mysql", "r2d2_mysql"]
sqlite_pool = ["database_pool", "rusqlite", "r2d2_sqlite"]
cypher_pool = ["database_pool", "rusted_cypher", "r2d2_cypher"]
redis_pool = ["database_pool", "redis", "r2d2_redis"]
[dependencies] [dependencies]
# Global dependencies.
rocket = { version = "0.4.0-dev", path = "../../core/lib/" } rocket = { version = "0.4.0-dev", path = "../../core/lib/" }
log = "0.4" log = "0.4"
# UUID dependencies.
uuid = { version = "0.7", optional = true }
# Serialization and templating dependencies. # Serialization and templating dependencies.
serde = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
serde_json = { version = "1.0.26", optional = true } serde_json = { version = "1.0.26", optional = true }
rmp-serde = { version = "^0.13", optional = true } rmp-serde = { version = "^0.13", optional = true }
# Templating dependencies only. # Templating dependencies.
handlebars = { version = "1.0", optional = true } handlebars = { version = "1.0", optional = true }
glob = { version = "0.2", optional = true } glob = { version = "0.2", optional = true }
tera = { version = "0.11", optional = true } tera = { version = "0.11", optional = true }
# UUID dependencies.
uuid = { version = "0.7", optional = true }
# Database dependencies # Database dependencies
diesel = { version = "1.0", default-features = false, optional = true } diesel = { version = "1.0", default-features = false, optional = true }
postgres = { version = "0.15", optional = true } postgres = { version = "0.15", optional = true }

View File

@ -1,4 +1,3 @@
#![doc(cfg(feature = "diesel_sqlite_pool"))]
//! Traits, utilities, and a macro for easy database connection pooling. //! Traits, utilities, and a macro for easy database connection pooling.
//! //!
//! # Overview //! # Overview
@ -351,50 +350,41 @@
//! implementing the [`Poolable`] trait. See the documentation for [`Poolable`] //! implementing the [`Poolable`] trait. See the documentation for [`Poolable`]
//! for more details on how to implement it. //! for more details on how to implement it.
//! //!
//! [`FromRequest`]: rocket::FromRequest //! [`FromRequest`]: rocket::request::FromRequest
//! [request guards]: rocket::FromRequest //! [request guards]: rocket::request::FromRequest
//! [`Poolable`]: databases::Poolable //! [`Poolable`]: databases::Poolable
pub extern crate r2d2; pub extern crate r2d2;
#[cfg(any(feature = "diesel_sqlite_pool",
feature = "diesel_postgres_pool",
feature = "diesel_mysql_pool"))]
pub extern crate diesel;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt::{self, Display, Formatter}; use std::fmt::{self, Display, Formatter};
use std::marker::{Send, Sized}; use std::marker::{Send, Sized};
use rocket::config::{self, Value}; use rocket::config::{self, Value};
#[doc(inline)]
pub use rocket_contrib_codegen::database;
use self::r2d2::ManageConnection; use self::r2d2::ManageConnection;
#[cfg(any(feature = "diesel_sqlite_pool", feature = "diesel_postgres_pool", feature = "diesel_mysql_pool"))] #[doc(hidden)] pub use rocket_contrib_codegen::*;
pub extern crate diesel;
#[cfg(feature = "postgres_pool")] #[cfg(feature = "postgres_pool")] pub extern crate postgres;
pub extern crate postgres; #[cfg(feature = "postgres_pool")] pub extern crate r2d2_postgres;
#[cfg(feature = "postgres_pool")]
pub extern crate r2d2_postgres;
#[cfg(feature = "mysql_pool")] #[cfg(feature = "mysql_pool")] pub extern crate mysql;
pub extern crate mysql; #[cfg(feature = "mysql_pool")] pub extern crate r2d2_mysql;
#[cfg(feature = "mysql_pool")]
pub extern crate r2d2_mysql;
#[cfg(feature = "sqlite_pool")] #[cfg(feature = "sqlite_pool")] pub extern crate rusqlite;
pub extern crate rusqlite; #[cfg(feature = "sqlite_pool")] pub extern crate r2d2_sqlite;
#[cfg(feature = "sqlite_pool")]
pub extern crate r2d2_sqlite;
#[cfg(feature = "cypher_pool")] #[cfg(feature = "cypher_pool")] pub extern crate rusted_cypher;
pub extern crate rusted_cypher; #[cfg(feature = "cypher_pool")] pub extern crate r2d2_cypher;
#[cfg(feature = "cypher_pool")]
pub extern crate r2d2_cypher;
#[cfg(feature = "redis_pool")] #[cfg(feature = "redis_pool")] pub extern crate redis;
pub extern crate redis; #[cfg(feature = "redis_pool")] pub extern crate r2d2_redis;
#[cfg(feature = "redis_pool")]
pub extern crate r2d2_redis;
/// A structure representing a particular database configuration. /// A structure representing a particular database configuration.
/// ///
@ -447,14 +437,14 @@ pub enum DbError<T> {
/// Error returned on invalid database configurations. /// Error returned on invalid database configurations.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DatabaseConfigError { pub enum ConfigError {
/// The `databases` configuration key is missing or is empty. /// The `databases` configuration key is missing or is empty.
MissingTable, MissingTable,
/// The requested database configuration key is missing from the active /// The requested database configuration key is missing from the active
/// configuration. /// configuration.
MissingKey, MissingKey,
/// The configuration associated with the key isn't a /// The configuration associated with the key isn't a
/// [Table](::rocket::config::Table). /// [`Table`](::rocket::config::Table).
MalformedConfiguration, MalformedConfiguration,
/// The required `url` key is missing. /// The required `url` key is missing.
MissingUrl, MissingUrl,
@ -488,7 +478,7 @@ pub enum DatabaseConfigError {
/// # /// #
/// # use std::{collections::BTreeMap, mem::drop}; /// # use std::{collections::BTreeMap, mem::drop};
/// # use rocket::{fairing::AdHoc, config::{Config, Environment, Value}}; /// # use rocket::{fairing::AdHoc, config::{Config, Environment, Value}};
/// use rocket_contrib::databases::{database_config, DatabaseConfigError}; /// use rocket_contrib::databases::{database_config, ConfigError};
/// ///
/// # let mut databases = BTreeMap::new(); /// # let mut databases = BTreeMap::new();
/// # /// #
@ -517,7 +507,7 @@ pub enum DatabaseConfigError {
/// assert_eq!(other_config.url, "mysql://root:root@localhost/database"); /// assert_eq!(other_config.url, "mysql://root:root@localhost/database");
/// ///
/// let error = database_config("invalid_db", rocket.config()).unwrap_err(); /// let error = database_config("invalid_db", rocket.config()).unwrap_err();
/// assert_eq!(error, DatabaseConfigError::MissingKey); /// assert_eq!(error, ConfigError::MissingKey);
/// # } /// # }
/// # /// #
/// # Ok(rocket) /// # Ok(rocket)
@ -526,27 +516,27 @@ pub enum DatabaseConfigError {
pub fn database_config<'a>( pub fn database_config<'a>(
name: &str, name: &str,
from: &'a config::Config from: &'a config::Config
) -> Result<DatabaseConfig<'a>, DatabaseConfigError> { ) -> Result<DatabaseConfig<'a>, ConfigError> {
// Find the first `databases` config that's a table with a key of 'name' // Find the first `databases` config that's a table with a key of 'name'
// equal to `name`. // equal to `name`.
let connection_config = from.get_table("databases") let connection_config = from.get_table("databases")
.map_err(|_| DatabaseConfigError::MissingTable)? .map_err(|_| ConfigError::MissingTable)?
.get(name) .get(name)
.ok_or(DatabaseConfigError::MissingKey)? .ok_or(ConfigError::MissingKey)?
.as_table() .as_table()
.ok_or(DatabaseConfigError::MalformedConfiguration)?; .ok_or(ConfigError::MalformedConfiguration)?;
let maybe_url = connection_config.get("url") let maybe_url = connection_config.get("url")
.ok_or(DatabaseConfigError::MissingUrl)?; .ok_or(ConfigError::MissingUrl)?;
let url = maybe_url.as_str().ok_or(DatabaseConfigError::MalformedUrl)?; let url = maybe_url.as_str().ok_or(ConfigError::MalformedUrl)?;
let pool_size = connection_config.get("pool_size") let pool_size = connection_config.get("pool_size")
.and_then(Value::as_integer) .and_then(Value::as_integer)
.unwrap_or(from.workers as i64); .unwrap_or(from.workers as i64);
if pool_size < 1 || pool_size > u32::max_value() as i64 { if pool_size < 1 || pool_size > u32::max_value() as i64 {
return Err(DatabaseConfigError::InvalidPoolSize(pool_size)); return Err(ConfigError::InvalidPoolSize(pool_size));
} }
let mut extras = connection_config.clone(); let mut extras = connection_config.clone();
@ -556,25 +546,25 @@ pub fn database_config<'a>(
Ok(DatabaseConfig { url, pool_size: pool_size as u32, extras: extras }) Ok(DatabaseConfig { url, pool_size: pool_size as u32, extras: extras })
} }
impl<'a> Display for DatabaseConfigError { impl<'a> Display for ConfigError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
DatabaseConfigError::MissingTable => { ConfigError::MissingTable => {
write!(f, "A table named `databases` was not found for this configuration") write!(f, "A table named `databases` was not found for this configuration")
}, },
DatabaseConfigError::MissingKey => { ConfigError::MissingKey => {
write!(f, "An entry in the `databases` table was not found for this key") write!(f, "An entry in the `databases` table was not found for this key")
}, },
DatabaseConfigError::MalformedConfiguration => { ConfigError::MalformedConfiguration => {
write!(f, "The configuration for this database is malformed") write!(f, "The configuration for this database is malformed")
} }
DatabaseConfigError::MissingUrl => { ConfigError::MissingUrl => {
write!(f, "The connection URL is missing for this database") write!(f, "The connection URL is missing for this database")
}, },
DatabaseConfigError::MalformedUrl => { ConfigError::MalformedUrl => {
write!(f, "The specified connection URL is malformed") write!(f, "The specified connection URL is malformed")
}, },
DatabaseConfigError::InvalidPoolSize(invalid_size) => { ConfigError::InvalidPoolSize(invalid_size) => {
write!(f, "'{}' is not a valid value for `pool_size`", invalid_size) write!(f, "'{}' is not a valid value for `pool_size`", invalid_size)
}, },
} }
@ -782,7 +772,7 @@ impl Poolable for redis::Connection {
mod tests { mod tests {
use std::collections::BTreeMap; use std::collections::BTreeMap;
use rocket::{Config, config::{Environment, Value}}; use rocket::{Config, config::{Environment, Value}};
use super::{DatabaseConfigError::*, database_config}; use super::{ConfigError::*, database_config};
#[test] #[test]
fn no_database_entry_in_config_returns_error() { fn no_database_entry_in_config_returns_error() {

View File

@ -1,3 +1,6 @@
extern crate serde;
extern crate serde_json;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::io::{self, Read}; use std::io::{self, Read};
@ -7,25 +10,32 @@ use rocket::data::{Outcome, Transform, Transform::*, Transformed, Data, FromData
use rocket::response::{self, Responder, content}; use rocket::response::{self, Responder, content};
use rocket::http::Status; use rocket::http::Status;
use serde::{Serialize, Serializer}; use self::serde::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer}; use self::serde::de::{Deserialize, Deserializer};
use serde_json;
/// The JSON type: implements `FromData` and `Responder`, allowing you to easily #[doc(hidden)]
/// consume and respond with JSON. pub use self::serde_json::{json_internal, json_internal_vec};
/// The JSON type: implements [`FromData`] and [`Responder`], allowing you to
/// easily consume and respond with JSON.
/// ///
/// ## Receiving JSON /// ## Receiving JSON
/// ///
/// If you're receiving JSON data, simply add a `data` parameter to your route /// If you're receiving JSON data, simply add a `data` parameter to your route
/// arguments and ensure the type of the parameter is a `Json<T>`, where `T` is /// arguments and ensure the type of the parameter is a `Json<T>`, where `T` is
/// some type you'd like to parse from JSON. `T` must implement `Deserialize` or /// some type you'd like to parse from JSON. `T` must implement [`Deserialize`]
/// `DeserializeOwned` from [`serde`](https://github.com/serde-rs/json). The /// or from [`serde`]. The data is parsed from the HTTP request body.
/// data is parsed from the HTTP request body.
/// ///
/// ```rust,ignore /// ```rust
/// #[post("/users/", format = "json", data = "<user>")] /// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket;
/// # extern crate rocket_contrib;
/// # type User = usize;
/// use rocket_contrib::json::Json;
///
/// #[post("/users", format = "json", data = "<user>")]
/// fn new_user(user: Json<User>) { /// fn new_user(user: Json<User>) {
/// ... /// /* ... */
/// } /// }
/// ``` /// ```
/// ///
@ -37,14 +47,20 @@ use serde_json;
/// ## Sending JSON /// ## Sending JSON
/// ///
/// If you're responding with JSON data, return a `Json<T>` type, where `T` /// If you're responding with JSON data, return a `Json<T>` type, where `T`
/// implements `Serialize` from [Serde](https://github.com/serde-rs/json). The /// implements [`Serialize`] from [`serde`]. The content type of the response is
/// content type of the response is set to `application/json` automatically. /// set to `application/json` automatically.
///
/// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket;
/// # extern crate rocket_contrib;
/// # type User = usize;
/// use rocket_contrib::json::Json;
/// ///
/// ```rust,ignore
/// #[get("/users/<id>")] /// #[get("/users/<id>")]
/// fn user(id: usize) -> Json<User> { /// fn user(id: usize) -> Json<User> {
/// let user_from_id = User::from(id); /// let user_from_id = User::from(id);
/// ... /// /* ... */
/// Json(user_from_id) /// Json(user_from_id)
/// } /// }
/// ``` /// ```
@ -70,7 +86,7 @@ impl<T> Json<T> {
/// ///
/// # Example /// # Example
/// ```rust /// ```rust
/// # use rocket_contrib::Json; /// # use rocket_contrib::json::Json;
/// let string = "Hello".to_string(); /// let string = "Hello".to_string();
/// let my_json = Json(string); /// let my_json = Json(string);
/// assert_eq!(my_json.into_inner(), "Hello".to_string()); /// assert_eq!(my_json.into_inner(), "Hello".to_string());
@ -183,7 +199,7 @@ impl<T> DerefMut for Json<T> {
/// # #![feature(proc_macro_hygiene, decl_macro)] /// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # #[macro_use] extern crate rocket_contrib; /// # #[macro_use] extern crate rocket_contrib;
/// use rocket_contrib::JsonValue; /// use rocket_contrib::json::JsonValue;
/// ///
/// #[get("/json")] /// #[get("/json")]
/// fn get_json() -> JsonValue { /// fn get_json() -> JsonValue {
@ -265,14 +281,14 @@ impl<'a> Responder<'a> for JsonValue {
/// #[macro_use] extern crate rocket_contrib; /// #[macro_use] extern crate rocket_contrib;
/// ``` /// ```
/// ///
/// The return type of a `json!` invocation is [`JsonValue`]. A value created /// The return type of a `json!` invocation is [`JsonValue`](json::JsonValue). A
/// with this macro can be returned from a handler as follows: /// value created with this macro can be returned from a handler as follows:
/// ///
/// ```rust /// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)] /// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # #[macro_use] extern crate rocket_contrib; /// # #[macro_use] extern crate rocket_contrib;
/// use rocket_contrib::JsonValue; /// use rocket_contrib::json::JsonValue;
/// ///
/// #[get("/json")] /// #[get("/json")]
/// fn get_json() -> JsonValue { /// fn get_json() -> JsonValue {
@ -283,9 +299,9 @@ impl<'a> Responder<'a> for JsonValue {
/// } /// }
/// ``` /// ```
/// ///
/// The `Responder` implementation for `JsonValue` serializes the value into a /// The [`Responder`](rocket::response::Responder) implementation for
/// JSON string and sets it as the body of the response with a `Content-Type` of /// `JsonValue` serializes the value into a JSON string and sets it as the body
/// `application/json`. /// of the response with a `Content-Type` of `application/json`.
/// ///
/// # Examples /// # Examples
/// ///
@ -358,6 +374,6 @@ impl<'a> Responder<'a> for JsonValue {
#[macro_export] #[macro_export]
macro_rules! json { macro_rules! json {
($($json:tt)+) => { ($($json:tt)+) => {
$crate::JsonValue(json_internal!($($json)+)) $crate::json::JsonValue($crate::json::json_internal!($($json)+))
}; };
} }

View File

@ -16,13 +16,13 @@
//! common modules exposed by default. The present feature list is below, with //! common modules exposed by default. The present feature list is below, with
//! an asterisk next to the features that are enabled by default: //! an asterisk next to the features that are enabled by default:
//! //!
//! * [json*](Json) //! * [json*](type@json) - JSON (de)serialization
//! * [static_files*](static_files) //! * [serve*](serve) - Static File Serving
//! * [msgpack](MsgPack) //! * [msgpack](msgpack) - MessagePack (de)serialization
//! * [handlebars_templates](Template) //! * [handlebars_templates](templates) - Handlebars Templating
//! * [tera_templates](Template) //! * [tera_templates](templates) - Tera Templating
//! * [uuid](Uuid) //! * [uuid](uuid) - UUID (de)serialization
//! * [${database}_pool](databases) //! * [${database}_pool](databases) - Database Configuration and Pooling
//! //!
//! The recommend way to include features from this crate via Cargo in your //! The recommend way to include features from this crate via Cargo in your
//! project is by adding a `[dependencies.rocket_contrib]` section to your //! project is by adding a `[dependencies.rocket_contrib]` section to your
@ -42,59 +42,14 @@
#[allow(unused_imports)] #[macro_use] extern crate log; #[allow(unused_imports)] #[macro_use] extern crate log;
#[allow(unused_imports)] #[macro_use] extern crate rocket; #[allow(unused_imports)] #[macro_use] extern crate rocket;
#[cfg(feature = "serde")] #[cfg(feature="json")] #[macro_use] pub mod json;
extern crate serde; #[cfg(feature="serve")] pub mod serve;
#[cfg(feature="msgpack")] pub mod msgpack;
#[cfg(feature="templates")] pub mod templates;
#[cfg(feature="uuid")] pub mod uuid;
#[cfg(feature="databases")] pub mod databases;
#[cfg(feature = "json")]
extern crate serde_json;
#[cfg(feature = "json")]
pub use serde_json::{json_internal, json_internal_vec};
#[cfg(feature = "handlebars_templates")]
pub extern crate handlebars;
#[cfg(feature = "tera_templates")]
pub extern crate tera;
#[cfg(feature = "json")]
#[cfg_attr(feature = "json", macro_use)]
#[doc(hidden)]
pub mod json;
#[cfg(feature = "json")]
pub use json::{Json, JsonError, JsonValue};
#[cfg(feature = "msgpack")]
#[doc(hidden)]
pub mod msgpack;
#[cfg(feature = "msgpack")]
pub use msgpack::{MsgPack, MsgPackError};
#[cfg(feature = "templates")]
mod templates;
#[cfg(feature = "templates")]
pub use templates::{Engines, Template, TemplateMetadata};
#[cfg(feature = "uuid")]
mod uuid;
#[cfg(feature = "uuid")]
pub use uuid::{Uuid, UuidParseError};
#[cfg(feature = "static_files")]
pub mod static_files;
#[cfg(feature = "database_pool")]
pub mod databases;
#[cfg(feature = "database_pool_codegen")]
#[allow(unused_imports)] #[allow(unused_imports)]
#[macro_use] #[macro_use]
#[cfg(feature="databases")]
extern crate rocket_contrib_codegen; extern crate rocket_contrib_codegen;
#[cfg(feature = "database_pool_codegen")]
#[doc(hidden)]
pub use rocket_contrib_codegen::*;

View File

@ -1,3 +1,4 @@
extern crate serde;
extern crate rmp_serde; extern crate rmp_serde;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@ -9,31 +10,28 @@ use rocket::data::{Outcome, Transform, Transform::*, Transformed, Data, FromData
use rocket::response::{self, Responder, Response}; use rocket::response::{self, Responder, Response};
use rocket::http::Status; use rocket::http::Status;
use serde::Serialize; use self::serde::Serialize;
use serde::de::Deserialize; use self::serde::de::Deserialize;
pub use self::rmp_serde::decode::Error as MsgPackError; pub use self::rmp_serde::decode::Error;
/// The `MsgPack` type: implements `FromData` and `Responder`, allowing you to /// The `MsgPack` type: implements [`FromData`] and [`Responder`], allowing you
/// easily consume and respond with MessagePack data. /// to easily consume and respond with MessagePack data.
/// ///
/// ## Receiving MessagePack /// ## Receiving MessagePack
/// ///
/// If you're receiving MessagePack data, simply add a `data` parameter to your /// If you're receiving MessagePack data, simply add a `data` parameter to your
/// route arguments and ensure the type of the parameter is a `MsgPack<T>`, /// route arguments and ensure the type of the parameter is a `MsgPack<T>`,
/// where `T` is some type you'd like to parse from MessagePack. `T` must /// where `T` is some type you'd like to parse from MessagePack. `T` must
/// implement `Deserialize` or `DeserializeOwned` from /// implement [`Deserialize`] from [`serde`]. The data is parsed from the HTTP
/// [`serde`](https://github.com/serde-rs/serde). The data is parsed from the /// request body.
/// HTTP request body.
/// ///
/// ```rust /// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)] /// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// # type User = usize; /// # type User = usize;
/// # fn main() { } /// use rocket_contrib::msgpack::MsgPack;
/// #
/// use rocket_contrib::MsgPack;
/// ///
/// #[post("/users", format = "msgpack", data = "<user>")] /// #[post("/users", format = "msgpack", data = "<user>")]
/// fn new_user(user: MsgPack<User>) { /// fn new_user(user: MsgPack<User>) {
@ -49,18 +47,15 @@ pub use self::rmp_serde::decode::Error as MsgPackError;
/// ## Sending MessagePack /// ## Sending MessagePack
/// ///
/// If you're responding with MessagePack data, return a `MsgPack<T>` type, /// If you're responding with MessagePack data, return a `MsgPack<T>` type,
/// where `T` implements `Serialize` from /// where `T` implements [`Serialize`] from [`serde`]. The content type of the
/// [serde](https://github.com/serde-rs/serde). The content type of the response /// response is set to `application/msgpack` automatically.
/// is set to `application/msgpack` automatically.
/// ///
/// ```rust /// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)] /// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// # type User = usize; /// # type User = usize;
/// # fn main() { } /// use rocket_contrib::msgpack::MsgPack;
/// #
/// use rocket_contrib::MsgPack;
/// ///
/// #[get("/users/<id>")] /// #[get("/users/<id>")]
/// fn user(id: usize) -> MsgPack<User> { /// fn user(id: usize) -> MsgPack<User> {
@ -92,7 +87,7 @@ impl<T> MsgPack<T> {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// # use rocket_contrib::MsgPack; /// # use rocket_contrib::msgpack::MsgPack;
/// let string = "Hello".to_string(); /// let string = "Hello".to_string();
/// let my_msgpack = MsgPack(string); /// let my_msgpack = MsgPack(string);
/// assert_eq!(my_msgpack.into_inner(), "Hello".to_string()); /// assert_eq!(my_msgpack.into_inner(), "Hello".to_string());
@ -107,7 +102,7 @@ impl<T> MsgPack<T> {
const LIMIT: u64 = 1 << 20; const LIMIT: u64 = 1 << 20;
impl<'a, T: Deserialize<'a>> FromData<'a> for MsgPack<T> { impl<'a, T: Deserialize<'a>> FromData<'a> for MsgPack<T> {
type Error = MsgPackError; type Error = Error;
type Owned = Vec<u8>; type Owned = Vec<u8>;
type Borrowed = [u8]; type Borrowed = [u8];
@ -116,12 +111,12 @@ impl<'a, T: Deserialize<'a>> FromData<'a> for MsgPack<T> {
let size_limit = r.limits().get("msgpack").unwrap_or(LIMIT); let size_limit = r.limits().get("msgpack").unwrap_or(LIMIT);
match d.open().take(size_limit).read_to_end(&mut buf) { match d.open().take(size_limit).read_to_end(&mut buf) {
Ok(_) => Borrowed(Success(buf)), Ok(_) => Borrowed(Success(buf)),
Err(e) => Borrowed(Failure((Status::BadRequest, MsgPackError::InvalidDataRead(e)))) Err(e) => Borrowed(Failure((Status::BadRequest, Error::InvalidDataRead(e))))
} }
} }
fn from_data(_: &Request, o: Transformed<'a, Self>) -> Outcome<Self, Self::Error> { fn from_data(_: &Request, o: Transformed<'a, Self>) -> Outcome<Self, Self::Error> {
use self::MsgPackError::*; use self::Error::*;
let buf = o.borrowed()?; let buf = o.borrowed()?;
match rmp_serde::from_slice(&buf) { match rmp_serde::from_slice(&buf) {

View File

@ -46,7 +46,7 @@ impl Options {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// use rocket_contrib::static_files::Options; /// use rocket_contrib::serve::Options;
/// ///
/// let index_request = Options::Index | Options::DotFiles; /// let index_request = Options::Index | Options::DotFiles;
/// assert!(index_request.contains(Options::Index)); /// assert!(index_request.contains(Options::Index));
@ -96,7 +96,7 @@ impl ::std::ops::BitOr for Options {
/// ```rust /// ```rust
/// # extern crate rocket; /// # extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use rocket_contrib::static_files::StaticFiles; /// use rocket_contrib::serve::StaticFiles;
/// ///
/// fn main() { /// fn main() {
/// # if false { /// # if false {
@ -122,7 +122,7 @@ impl ::std::ops::BitOr for Options {
/// ```rust /// ```rust
/// # extern crate rocket; /// # extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use rocket_contrib::static_files::StaticFiles; /// use rocket_contrib::serve::StaticFiles;
/// ///
/// fn main() { /// fn main() {
/// # if false { /// # if false {
@ -151,7 +151,7 @@ impl StaticFiles {
/// ```rust /// ```rust
/// # extern crate rocket; /// # extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use rocket_contrib::static_files::StaticFiles; /// use rocket_contrib::serve::StaticFiles;
/// ///
/// fn main() { /// fn main() {
/// # if false { /// # if false {
@ -177,7 +177,7 @@ impl StaticFiles {
/// ```rust /// ```rust
/// # extern crate rocket; /// # extern crate rocket;
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use rocket_contrib::static_files::{StaticFiles, Options}; /// use rocket_contrib::serve::{StaticFiles, Options};
/// ///
/// fn main() { /// fn main() {
/// # if false { /// # if false {

View File

@ -1,18 +1,17 @@
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::collections::HashMap; use std::collections::HashMap;
use super::{Engines, TemplateInfo}; use templates::{glob, Engines, TemplateInfo};
use super::glob;
use rocket::http::ContentType; use rocket::http::ContentType;
pub struct Context { crate struct Context {
/// The root of the template directory. /// The root of the template directory.
pub root: PathBuf, crate root: PathBuf,
/// Mapping from template name to its information. /// Mapping from template name to its information.
pub templates: HashMap<String, TemplateInfo>, crate templates: HashMap<String, TemplateInfo>,
/// Loaded template engines /// Loaded template engines
pub engines: Engines, crate engines: Engines,
} }
impl Context { impl Context {

View File

@ -1,19 +1,17 @@
use std::collections::HashMap; use std::collections::HashMap;
use super::serde::Serialize; use templates::{TemplateInfo, serde::Serialize};
use super::TemplateInfo;
#[cfg(feature = "tera_templates")] use super::tera_templates::Tera; #[cfg(feature = "tera_templates")] use templates::tera::Tera;
#[cfg(feature = "handlebars_templates")] use super::handlebars_templates::Handlebars; #[cfg(feature = "handlebars_templates")] use templates::handlebars::Handlebars;
pub trait Engine: Send + Sync + 'static { crate trait Engine: Send + Sync + 'static {
const EXT: &'static str; const EXT: &'static str;
fn init(templates: &[(&str, &TemplateInfo)]) -> Option<Self> where Self: Sized; fn init(templates: &[(&str, &TemplateInfo)]) -> Option<Self> where Self: Sized;
fn render<C: Serialize>(&self, name: &str, context: C) -> Option<String>; fn render<C: Serialize>(&self, name: &str, context: C) -> Option<String>;
} }
#[doc(cfg(feature = "tera_templates"))]
/// A structure exposing access to templating engines. /// A structure exposing access to templating engines.
/// ///
/// Calling methods on the exposed template engine types may require importing /// Calling methods on the exposed template engine types may require importing
@ -21,13 +19,14 @@ pub trait Engine: Send + Sync + 'static {
/// imported from the reexported crate at the root of `rocket_contrib` to avoid /// imported from the reexported crate at the root of `rocket_contrib` to avoid
/// version mismatches. For instance, when registering a Tera filter, the /// version mismatches. For instance, when registering a Tera filter, the
/// [`tera::Value`] and [`tera::Result`] types are required. Import them from /// [`tera::Value`] and [`tera::Result`] types are required. Import them from
/// `rocket_contrib::tera`. The example below illustrates this: /// `rocket_contrib::templates::tera`. The example below illustrates this:
/// ///
/// ```rust /// ```rust
/// # #[cfg(feature = "tera_templates")] {
/// use std::collections::HashMap; /// use std::collections::HashMap;
/// ///
/// use rocket_contrib::{Template, Engines}; /// use rocket_contrib::templates::{Template, Engines};
/// use rocket_contrib::tera::{self, Value}; /// use rocket_contrib::templates::tera::{self, Value};
/// ///
/// fn my_filter(value: Value, _: HashMap<String, Value>) -> tera::Result<Value> { /// fn my_filter(value: Value, _: HashMap<String, Value>) -> tera::Result<Value> {
/// # /* /// # /*
@ -38,25 +37,22 @@ pub trait Engine: Send + Sync + 'static {
/// Template::custom(|engines: &mut Engines| { /// Template::custom(|engines: &mut Engines| {
/// engines.tera.register_filter("my_filter", my_filter); /// engines.tera.register_filter("my_filter", my_filter);
/// }); /// });
/// # }
/// ``` /// ```
/// ///
/// [`tera::Value`]: ::tera::Value /// [`tera::Value`]: ::templates::tera::Value
/// [`tera::Result`]: ::tera::Result /// [`tera::Result`]: ::templates::tera::Result
pub struct Engines { pub struct Engines {
#[cfg(feature = "tera_templates")] /// A `Tera` templating engine. This field is only available when the
/// A [`Tera`] structure. This field is only available when the
/// `tera_templates` feature is enabled. When calling methods on the `Tera` /// `tera_templates` feature is enabled. When calling methods on the `Tera`
/// instance, ensure you use types imported from `rocket_contrib::tera` to /// instance, ensure you use types imported from
/// avoid version mismatches. /// `rocket_contrib::templates::tera` to avoid version mismatches.
/// #[cfg(feature = "tera_templates")]
/// [`Tera`]: tera::Tera
pub tera: Tera, pub tera: Tera,
/// A [`Handlebars`] structure. This field is only available when the /// The Handlebars templating engine. This field is only available when the
/// `handlebars_templates` feature is enabled. When calling methods on the /// `handlebars_templates` feature is enabled. When calling methods on the
/// `Tera` instance, ensure you use types /// `Tera` instance, ensure you use types imported from
/// imported from `rocket_contrib::handlebars` to avoid version mismatches. /// `rocket_contrib::templates::handlebars` to avoid version mismatches.
///
/// [`Handlebars`]: handlebars::Handlebars
#[cfg(feature = "handlebars_templates")] #[cfg(feature = "handlebars_templates")]
pub handlebars: Handlebars, pub handlebars: Handlebars,
} }

View File

@ -1,28 +1,26 @@
use super::DEFAULT_TEMPLATE_DIR; use templates::{DEFAULT_TEMPLATE_DIR, Context, Engines};
use super::context::Context;
use super::engine::Engines;
use rocket::Rocket; use rocket::Rocket;
use rocket::config::ConfigError; use rocket::config::ConfigError;
use rocket::fairing::{Fairing, Info, Kind}; use rocket::fairing::{Fairing, Info, Kind};
pub use self::context::ContextManager; crate use self::context::ContextManager;
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
mod context { mod context {
use std::ops::Deref; use std::ops::Deref;
use super::Context; use templates::Context;
/// Wraps a Context. With `cfg(debug_assertions)` active, this structure /// Wraps a Context. With `cfg(debug_assertions)` active, this structure
/// additionally provides a method to reload the context at runtime. /// additionally provides a method to reload the context at runtime.
pub struct ContextManager(Context); crate struct ContextManager(Context);
impl ContextManager { impl ContextManager {
pub fn new(ctxt: Context) -> ContextManager { crate fn new(ctxt: Context) -> ContextManager {
ContextManager(ctxt) ContextManager(ctxt)
} }
pub fn context<'a>(&'a self) -> impl Deref<Target=Context> + 'a { crate fn context<'a>(&'a self) -> impl Deref<Target=Context> + 'a {
&self.0 &self.0
} }
} }
@ -36,13 +34,13 @@ mod context {
use std::sync::{RwLock, Mutex}; use std::sync::{RwLock, Mutex};
use std::sync::mpsc::{channel, Receiver}; use std::sync::mpsc::{channel, Receiver};
use super::{Context, Engines}; use templates::{Context, Engines};
use self::notify::{raw_watcher, RawEvent, RecommendedWatcher, RecursiveMode, Watcher}; use self::notify::{raw_watcher, RawEvent, RecommendedWatcher, RecursiveMode, Watcher};
/// Wraps a Context. With `cfg(debug_assertions)` active, this structure /// Wraps a Context. With `cfg(debug_assertions)` active, this structure
/// additionally provides a method to reload the context at runtime. /// additionally provides a method to reload the context at runtime.
pub struct ContextManager { crate struct ContextManager {
/// The current template context, inside an RwLock so it can be updated. /// The current template context, inside an RwLock so it can be updated.
context: RwLock<Context>, context: RwLock<Context>,
/// A filesystem watcher and the receive queue for its events. /// A filesystem watcher and the receive queue for its events.
@ -50,7 +48,7 @@ mod context {
} }
impl ContextManager { impl ContextManager {
pub fn new(ctxt: Context) -> ContextManager { crate fn new(ctxt: Context) -> ContextManager {
let (tx, rx) = channel(); let (tx, rx) = channel();
let watcher = if let Ok(mut watcher) = raw_watcher(tx) { let watcher = if let Ok(mut watcher) = raw_watcher(tx) {
@ -73,7 +71,7 @@ mod context {
} }
} }
pub fn context<'a>(&'a self) -> impl Deref<Target=Context> + 'a { crate fn context<'a>(&'a self) -> impl Deref<Target=Context> + 'a {
self.context.read().unwrap() self.context.read().unwrap()
} }
@ -85,7 +83,7 @@ mod context {
/// have been changes since the last reload, all templates are /// have been changes since the last reload, all templates are
/// reinitialized from disk and the user's customization callback is run /// reinitialized from disk and the user's customization callback is run
/// again. /// again.
pub fn reload_if_needed<F: Fn(&mut Engines)>(&self, custom_callback: F) { crate fn reload_if_needed<F: Fn(&mut Engines)>(&self, custom_callback: F) {
self.watcher.as_ref().map(|w| { self.watcher.as_ref().map(|w| {
let rx_lock = w.lock().expect("receive queue lock"); let rx_lock = w.lock().expect("receive queue lock");
let mut changed = false; let mut changed = false;
@ -117,7 +115,7 @@ pub struct TemplateFairing {
/// The user-provided customization callback, allowing the use of /// The user-provided customization callback, allowing the use of
/// functionality specific to individual template engines. In debug mode, /// functionality specific to individual template engines. In debug mode,
/// this callback might be run multiple times as templates are reloaded. /// this callback might be run multiple times as templates are reloaded.
pub(crate) custom_callback: Box<Fn(&mut Engines) + Send + Sync + 'static>, crate custom_callback: Box<Fn(&mut Engines) + Send + Sync + 'static>,
} }
impl Fairing for TemplateFairing { impl Fairing for TemplateFairing {

View File

@ -1,9 +1,7 @@
extern crate handlebars; use templates::serde::Serialize;
use templates::{Engine, TemplateInfo};
use super::serde::Serialize; pub use templates::handlebars::Handlebars;
use super::{Engine, TemplateInfo};
pub use self::handlebars::Handlebars;
impl Engine for Handlebars { impl Engine for Handlebars {
const EXT: &'static str = "hbs"; const EXT: &'static str = "hbs";

View File

@ -2,43 +2,23 @@ use rocket::{Request, State, Outcome};
use rocket::http::Status; use rocket::http::Status;
use rocket::request::{self, FromRequest}; use rocket::request::{self, FromRequest};
use super::ContextManager; use templates::ContextManager;
/// Implements [`FromRequest`] for dynamiclly querying template metadata. /// Request guard for dynamiclly querying template metadata.
/// ///
/// # Usage /// # Usage
/// ///
/// First, ensure that the template [fairing](rocket::fairing), /// The `Metadata` type implements Rocket's [`FromRequest`] trait, so it can be
/// [`Template::fairing()`](::Template::fairing()) is attached to your Rocket /// used as a request guard in any request handler.
/// application:
///
/// ```rust
/// # extern crate rocket;
/// # extern crate rocket_contrib;
/// #
/// use rocket_contrib::Template;
///
/// fn main() {
/// rocket::ignite()
/// .attach(Template::fairing())
/// // ...
/// # ;
/// }
/// ```
///
/// The `TemplateMetadata` type implements Rocket's `FromRequest` trait, so it
/// can be used as a request guard in any request handler.
/// ///
/// ```rust /// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)] /// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket; /// # #[macro_use] extern crate rocket;
/// # #[macro_use] extern crate rocket_contrib; /// # #[macro_use] extern crate rocket_contrib;
/// # fn main() { } /// use rocket_contrib::templates::{Template, Metadata};
/// #
/// use rocket_contrib::{Template, TemplateMetadata};
/// ///
/// #[get("/")] /// #[get("/")]
/// fn homepage(metadata: TemplateMetadata) -> Template { /// fn homepage(metadata: Metadata) -> Template {
/// # use std::collections::HashMap; /// # use std::collections::HashMap;
/// # let context: HashMap<String, String> = HashMap::new(); /// # let context: HashMap<String, String> = HashMap::new();
/// // Conditionally render a template if it's available. /// // Conditionally render a template if it's available.
@ -48,19 +28,27 @@ use super::ContextManager;
/// Template::render("fallback", &context) /// Template::render("fallback", &context)
/// } /// }
/// } /// }
///
///
/// fn main() {
/// rocket::ignite()
/// .attach(Template::fairing())
/// // ...
/// # ;
/// }
/// ``` /// ```
pub struct TemplateMetadata<'a>(&'a ContextManager); pub struct Metadata<'a>(&'a ContextManager);
impl<'a> TemplateMetadata<'a> { impl<'a> Metadata<'a> {
/// Returns `true` if the template with name `name` was loaded at start-up /// Returns `true` if the template with name `name` was loaded at start-up
/// time. Otherwise, returns `false`. /// time. Otherwise, returns `false`.
/// ///
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// use rocket_contrib::TemplateMetadata; /// use rocket_contrib::templates::Metadata;
/// ///
/// fn handler(metadata: TemplateMetadata) { /// fn handler(metadata: Metadata) {
/// // Returns `true` if the template with name `"name"` was loaded. /// // Returns `true` if the template with name `"name"` was loaded.
/// let loaded = metadata.contains_template("name"); /// let loaded = metadata.contains_template("name");
/// } /// }
@ -73,13 +61,13 @@ impl<'a> TemplateMetadata<'a> {
/// Retrieves the template metadata. If a template fairing hasn't been attached, /// Retrieves the template metadata. If a template fairing hasn't been attached,
/// an error is printed and an empty `Err` with status `InternalServerError` /// an error is printed and an empty `Err` with status `InternalServerError`
/// (`500`) is returned. /// (`500`) is returned.
impl<'a, 'r> FromRequest<'a, 'r> for TemplateMetadata<'a> { impl<'a, 'r> FromRequest<'a, 'r> for Metadata<'a> {
type Error = (); type Error = ();
fn from_request(request: &'a Request) -> request::Outcome<Self, ()> { fn from_request(request: &'a Request) -> request::Outcome<Self, ()> {
request.guard::<State<ContextManager>>() request.guard::<State<ContextManager>>()
.succeeded() .succeeded()
.and_then(|cm| Some(Outcome::Success(TemplateMetadata(cm.inner())))) .and_then(|cm| Some(Outcome::Success(Metadata(cm.inner()))))
.unwrap_or_else(|| { .unwrap_or_else(|| {
error_!("Uninitialized template context: missing fairing."); error_!("Uninitialized template context: missing fairing.");
info_!("To use templates, you must attach `Template::fairing()`."); info_!("To use templates, you must attach `Template::fairing()`.");

View File

@ -2,7 +2,10 @@ extern crate serde;
extern crate serde_json; extern crate serde_json;
extern crate glob; extern crate glob;
#[cfg(feature = "tera_templates")] pub extern crate tera;
#[cfg(feature = "tera_templates")] mod tera_templates; #[cfg(feature = "tera_templates")] mod tera_templates;
#[cfg(feature = "handlebars_templates")] pub extern crate handlebars;
#[cfg(feature = "handlebars_templates")] mod handlebars_templates; #[cfg(feature = "handlebars_templates")] mod handlebars_templates;
mod engine; mod engine;
@ -11,11 +14,12 @@ mod context;
mod metadata; mod metadata;
pub use self::engine::Engines; pub use self::engine::Engines;
pub use self::metadata::TemplateMetadata; pub use self::metadata::Metadata;
crate use self::context::Context;
crate use self::fairing::ContextManager;
use self::engine::Engine; use self::engine::Engine;
use self::fairing::{TemplateFairing, ContextManager}; use self::fairing::TemplateFairing;
use self::context::Context;
use self::serde::Serialize; use self::serde::Serialize;
use self::serde_json::{Value, to_value}; use self::serde_json::{Value, to_value};
use self::glob::glob; use self::glob::glob;
@ -99,14 +103,12 @@ const DEFAULT_TEMPLATE_DIR: &str = "templates";
/// application: /// application:
/// ///
/// ```rust /// ```rust
/// extern crate rocket; /// # extern crate rocket;
/// extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// /// use rocket_contrib::templates::Template;
/// use rocket_contrib::Template;
/// ///
/// fn main() { /// fn main() {
/// rocket::ignite() /// rocket::ignite()
/// // ...
/// .attach(Template::fairing()) /// .attach(Template::fairing())
/// // ... /// // ...
/// # ; /// # ;
@ -116,10 +118,16 @@ const DEFAULT_TEMPLATE_DIR: &str = "templates";
/// The `Template` type implements Rocket's [`Responder`] trait, so it can be /// The `Template` type implements Rocket's [`Responder`] trait, so it can be
/// returned from a request handler directly: /// returned from a request handler directly:
/// ///
/// ```rust,ignore /// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket;
/// # #[macro_use] extern crate rocket_contrib;
/// # fn context() { }
/// use rocket_contrib::templates::Template;
///
/// #[get("/")] /// #[get("/")]
/// fn index() -> Template { /// fn index() -> Template {
/// let context = ...; /// let context = context();
/// Template::render("index", &context) /// Template::render("index", &context)
/// } /// }
/// ``` /// ```
@ -136,7 +144,7 @@ pub struct Template {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct TemplateInfo { crate struct TemplateInfo {
/// The complete path, including `template_dir`, to this template. /// The complete path, including `template_dir`, to this template.
path: PathBuf, path: PathBuf,
/// The extension for the engine of this template. /// The extension for the engine of this template.
@ -166,7 +174,7 @@ impl Template {
/// extern crate rocket; /// extern crate rocket;
/// extern crate rocket_contrib; /// extern crate rocket_contrib;
/// ///
/// use rocket_contrib::Template; /// use rocket_contrib::templates::Template;
/// ///
/// fn main() { /// fn main() {
/// rocket::ignite() /// rocket::ignite()
@ -192,7 +200,7 @@ impl Template {
/// extern crate rocket; /// extern crate rocket;
/// extern crate rocket_contrib; /// extern crate rocket_contrib;
/// ///
/// use rocket_contrib::Template; /// use rocket_contrib::templates::Template;
/// ///
/// fn main() { /// fn main() {
/// rocket::ignite() /// rocket::ignite()
@ -218,7 +226,7 @@ impl Template {
/// ///
/// ```rust /// ```rust
/// use std::collections::HashMap; /// use std::collections::HashMap;
/// use rocket_contrib::Template; /// use rocket_contrib::templates::Template;
/// ///
/// // Create a `context`. Here, just an empty `HashMap`. /// // Create a `context`. Here, just an empty `HashMap`.
/// let mut context = HashMap::new(); /// let mut context = HashMap::new();
@ -235,9 +243,9 @@ impl Template {
/// Render the template named `name` with the context `context` into a /// Render the template named `name` with the context `context` into a
/// `String`. This method should **not** be used in any running Rocket /// `String`. This method should **not** be used in any running Rocket
/// application. This method should only be used during testing to /// application. This method should only be used during testing to validate
/// validate `Template` responses. For other uses, use /// `Template` responses. For other uses, use [`render()`](#method.render)
/// [`render`](#method.render) instead. /// instead.
/// ///
/// The `context` can be of any type that implements `Serialize`. This is /// The `context` can be of any type that implements `Serialize`. This is
/// typically a `HashMap` or a custom `struct`. /// typically a `HashMap` or a custom `struct`.
@ -253,7 +261,7 @@ impl Template {
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// use std::collections::HashMap; /// use std::collections::HashMap;
/// ///
/// use rocket_contrib::Template; /// use rocket_contrib::templates::Template;
/// use rocket::local::Client; /// use rocket::local::Client;
/// ///
/// fn main() { /// fn main() {

View File

@ -1,9 +1,7 @@
extern crate tera; use templates::serde::Serialize;
use templates::{Engine, TemplateInfo};
use super::serde::Serialize; pub use templates::tera::Tera;
use super::{Engine, TemplateInfo};
pub use self::tera::Tera;
impl Engine for Tera { impl Engine for Tera {
const EXT: &'static str = "tera"; const EXT: &'static str = "tera";

View File

@ -1,4 +1,4 @@
extern crate uuid as uuid_ext; pub extern crate uuid as uuid_crate;
use std::fmt; use std::fmt;
use std::str::FromStr; use std::str::FromStr;
@ -7,7 +7,7 @@ use std::ops::Deref;
use rocket::request::{FromParam, FromFormValue}; use rocket::request::{FromParam, FromFormValue};
use rocket::http::RawStr; use rocket::http::RawStr;
pub use self::uuid_ext::parser::ParseError as UuidParseError; pub use self::uuid_crate::parser::ParseError;
/// Implements [`FromParam`] and [`FromFormValue`] for accepting UUID values /// Implements [`FromParam`] and [`FromFormValue`] for accepting UUID values
/// from the [`uuid`] crate. /// from the [`uuid`] crate.
@ -26,7 +26,12 @@ pub use self::uuid_ext::parser::ParseError as UuidParseError;
/// ///
/// You can use the `Uuid` type directly as a target of a dynamic parameter: /// You can use the `Uuid` type directly as a target of a dynamic parameter:
/// ///
/// ```rust,ignore /// ```rust
/// # #![feature(proc_macro_hygiene, decl_macro)]
/// # #[macro_use] extern crate rocket;
/// # #[macro_use] extern crate rocket_contrib;
/// use rocket_contrib::uuid::Uuid;
///
/// #[get("/users/<id>")] /// #[get("/users/<id>")]
/// fn user(id: Uuid) -> String { /// fn user(id: Uuid) -> String {
/// format!("We found: {}", id) /// format!("We found: {}", id)
@ -35,18 +40,18 @@ pub use self::uuid_ext::parser::ParseError as UuidParseError;
/// ///
/// You can also use the `Uuid` as a form value, including in query strings: /// You can also use the `Uuid` as a form value, including in query strings:
/// ///
/// ```rust,ignore /// ```rust
/// #[derive(FromForm)] /// # #![feature(proc_macro_hygiene, decl_macro)]
/// struct UserQuery { /// # #[macro_use] extern crate rocket;
/// id: Uuid /// # #[macro_use] extern crate rocket_contrib;
/// } /// use rocket_contrib::uuid::Uuid;
/// ///
/// #[post("/user?<user_query>")] /// #[get("/user?<id>")]
/// fn user(user_query: UserQuery) -> String { /// fn user(id: Uuid) -> String {
/// format!("User ID: {}", user_query.id) /// format!("User ID: {}", id)
/// } /// }
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Uuid(uuid_ext::Uuid); pub struct Uuid(uuid_crate::Uuid);
impl Uuid { impl Uuid {
/// Consumes the Uuid wrapper, returning the underlying `Uuid` type. /// Consumes the Uuid wrapper, returning the underlying `Uuid` type.
@ -54,17 +59,21 @@ impl Uuid {
/// # Example /// # Example
/// ```rust /// ```rust
/// # extern crate rocket_contrib; /// # extern crate rocket_contrib;
/// # extern crate uuid;
/// # use std::str::FromStr; /// # use std::str::FromStr;
/// # fn main() { /// # fn main() {
/// use rocket_contrib::uuid::{uuid_crate, Uuid};
///
/// let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; /// let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2";
/// let real_uuid = uuid::Uuid::from_str(uuid_str).unwrap(); /// let real_uuid = uuid_crate::Uuid::from_str(uuid_str).unwrap();
/// let my_inner_uuid = rocket_contrib::Uuid::from_str(uuid_str).unwrap().into_inner(); /// let my_inner_uuid = Uuid::from_str(uuid_str)
/// .expect("valid UUID string")
/// .into_inner();
///
/// assert_eq!(real_uuid, my_inner_uuid); /// assert_eq!(real_uuid, my_inner_uuid);
/// # } /// # }
/// ``` /// ```
#[inline(always)] #[inline(always)]
pub fn into_inner(self) -> uuid_ext::Uuid { pub fn into_inner(self) -> uuid_crate::Uuid {
self.0 self.0
} }
} }
@ -77,10 +86,10 @@ impl fmt::Display for Uuid {
} }
impl<'a> FromParam<'a> for Uuid { impl<'a> FromParam<'a> for Uuid {
type Error = UuidParseError; type Error = ParseError;
/// A value is successfully parsed if `param` is a properly formatted Uuid. /// A value is successfully parsed if `param` is a properly formatted Uuid.
/// Otherwise, a `UuidParseError` is returned. /// Otherwise, a `ParseError` is returned.
#[inline(always)] #[inline(always)]
fn from_param(param: &'a RawStr) -> Result<Uuid, Self::Error> { fn from_param(param: &'a RawStr) -> Result<Uuid, Self::Error> {
param.parse() param.parse()
@ -99,7 +108,7 @@ impl<'v> FromFormValue<'v> for Uuid {
} }
impl FromStr for Uuid { impl FromStr for Uuid {
type Err = UuidParseError; type Err = ParseError;
#[inline] #[inline]
fn from_str(s: &str) -> Result<Uuid, Self::Err> { fn from_str(s: &str) -> Result<Uuid, Self::Err> {
@ -108,23 +117,23 @@ impl FromStr for Uuid {
} }
impl Deref for Uuid { impl Deref for Uuid {
type Target = uuid_ext::Uuid; type Target = uuid_crate::Uuid;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.0 &self.0
} }
} }
impl PartialEq<uuid_ext::Uuid> for Uuid { impl PartialEq<uuid_crate::Uuid> for Uuid {
#[inline(always)] #[inline(always)]
fn eq(&self, other: &uuid_ext::Uuid) -> bool { fn eq(&self, other: &uuid_crate::Uuid) -> bool {
self.0.eq(other) self.0.eq(other)
} }
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::uuid_ext; use super::uuid_crate;
use super::Uuid; use super::Uuid;
use super::FromParam; use super::FromParam;
use super::FromStr; use super::FromStr;
@ -147,8 +156,8 @@ mod test {
fn test_into_inner() { fn test_into_inner() {
let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2";
let uuid_wrapper = Uuid::from_param(uuid_str.into()).unwrap(); let uuid_wrapper = Uuid::from_param(uuid_str.into()).unwrap();
let real_uuid: uuid_ext::Uuid = uuid_str.parse().unwrap(); let real_uuid: uuid_crate::Uuid = uuid_str.parse().unwrap();
let inner_uuid: uuid_ext::Uuid = uuid_wrapper.into_inner(); let inner_uuid: uuid_crate::Uuid = uuid_wrapper.into_inner();
assert_eq!(real_uuid, inner_uuid) assert_eq!(real_uuid, inner_uuid)
} }
@ -156,7 +165,7 @@ mod test {
fn test_partial_eq() { fn test_partial_eq() {
let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2"; let uuid_str = "c1aa1e3b-9614-4895-9ebd-705255fa5bc2";
let uuid_wrapper = Uuid::from_param(uuid_str.into()).unwrap(); let uuid_wrapper = Uuid::from_param(uuid_str.into()).unwrap();
let real_uuid: uuid_ext::Uuid = uuid_str.parse().unwrap(); let real_uuid: uuid_crate::Uuid = uuid_str.parse().unwrap();
assert_eq!(uuid_wrapper, real_uuid) assert_eq!(uuid_wrapper, real_uuid)
} }

View File

@ -1,7 +1,7 @@
extern crate rocket; extern crate rocket;
extern crate rocket_contrib; extern crate rocket_contrib;
#[cfg(feature = "databases")] #[cfg(all(feature = "diesel_sqlite_pool", feature = "diesel_postgres_pool"))]
mod databases_tests { mod databases_tests {
use rocket_contrib::databases::{database, diesel}; use rocket_contrib::databases::{database, diesel};

View File

@ -3,13 +3,13 @@
extern crate rocket; extern crate rocket;
extern crate rocket_contrib; extern crate rocket_contrib;
#[cfg(feature = "static_files")] #[cfg(feature = "static")]
mod static_files_tests { mod static_tests {
use std::{io::Read, fs::File}; use std::{io::Read, fs::File};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use rocket::{self, Rocket}; use rocket::{self, Rocket};
use rocket_contrib::static_files::{StaticFiles, Options}; use rocket_contrib::serve::{StaticFiles, Options};
use rocket::http::Status; use rocket::http::Status;
use rocket::local::Client; use rocket::local::Client;

View File

@ -1,6 +1,9 @@
#![feature(proc_macro_hygiene, decl_macro)] #![feature(proc_macro_hygiene, decl_macro)]
#[cfg(feature = "templates")]
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
#[cfg(feature = "templates")]
extern crate rocket_contrib; extern crate rocket_contrib;
#[cfg(feature = "templates")] #[cfg(feature = "templates")]
@ -9,10 +12,10 @@ mod templates_tests {
use rocket::{Rocket, http::RawStr}; use rocket::{Rocket, http::RawStr};
use rocket::config::{Config, Environment}; use rocket::config::{Config, Environment};
use rocket_contrib::{Template, TemplateMetadata}; use rocket_contrib::templates::{Template, Metadata};
#[get("/<engine>/<name>")] #[get("/<engine>/<name>")]
fn template_check(md: TemplateMetadata, engine: &RawStr, name: &RawStr) -> Option<()> { fn template_check(md: Metadata, engine: &RawStr, name: &RawStr) -> Option<()> {
match md.contains_template(&format!("{}/{}", engine, name)) { match md.contains_template(&format!("{}/{}", engine, name)) {
true => Some(()), true => Some(()),
false => None false => None

View File

@ -1,7 +1,7 @@
#![feature(proc_macro_hygiene, decl_macro)] #![feature(proc_macro_hygiene, decl_macro)]
extern crate rocket_contrib;
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
extern crate rocket_contrib;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -11,7 +11,7 @@ use std::collections::HashMap;
use rocket::request::Form; use rocket::request::Form;
use rocket::response::Redirect; use rocket::response::Redirect;
use rocket::http::{Cookie, Cookies}; use rocket::http::{Cookie, Cookies};
use rocket_contrib::Template; use rocket_contrib::templates::Template;
#[derive(FromForm)] #[derive(FromForm)]
struct Message { struct Message {

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use super::rocket; use super::rocket;
use rocket::local::Client; use rocket::local::Client;
use rocket::http::*; use rocket::http::*;
use rocket_contrib::Template; use rocket_contrib::templates::Template;
#[test] #[test]
fn test_submit() { fn test_submit() {

View File

@ -8,7 +8,7 @@ extern crate rocket_contrib;
use rocket::Request; use rocket::Request;
use rocket::response::Redirect; use rocket::response::Redirect;
use rocket_contrib::{Template, handlebars}; use rocket_contrib::templates::{Template, handlebars};
use handlebars::{Helper, Handlebars, Context, RenderContext, Output, HelperResult, JsonRender}; use handlebars::{Helper, Handlebars, Context, RenderContext, Output, HelperResult, JsonRender};

View File

@ -3,7 +3,7 @@ use super::{rocket, TemplateContext};
use rocket::local::{Client, LocalResponse}; use rocket::local::{Client, LocalResponse};
use rocket::http::Method::*; use rocket::http::Method::*;
use rocket::http::Status; use rocket::http::Status;
use rocket_contrib::Template; use rocket_contrib::templates::Template;
macro_rules! dispatch { macro_rules! dispatch {
($method:expr, $path:expr, $test_fn:expr) => ({ ($method:expr, $path:expr, $test_fn:expr) => ({

View File

@ -6,10 +6,11 @@
#[cfg(test)] mod tests; #[cfg(test)] mod tests;
use rocket::State;
use rocket_contrib::{Json, JsonValue};
use std::collections::HashMap;
use std::sync::Mutex; use std::sync::Mutex;
use std::collections::HashMap;
use rocket::State;
use rocket_contrib::json::{Json, JsonValue};
// The type to represent the ID of a message. // The type to represent the ID of a message.
type ID = usize; type ID = usize;

View File

@ -6,7 +6,7 @@ extern crate rocket_contrib;
#[cfg(test)] mod tests; #[cfg(test)] mod tests;
use rocket_contrib::MsgPack; use rocket_contrib::msgpack::MsgPack;
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct Message<'r> { struct Message<'r> {

View File

@ -11,7 +11,7 @@ use rocket::outcome::IntoOutcome;
use rocket::request::{self, Form, FlashMessage, FromRequest, Request}; use rocket::request::{self, Form, FlashMessage, FromRequest, Request};
use rocket::response::{Redirect, Flash}; use rocket::response::{Redirect, Flash};
use rocket::http::{Cookie, Cookies}; use rocket::http::{Cookie, Cookies};
use rocket_contrib::Template; use rocket_contrib::templates::Template;
#[derive(FromForm)] #[derive(FromForm)]
struct Login { struct Login {

View File

@ -3,7 +3,7 @@ extern crate rocket_contrib;
#[cfg(test)] mod tests; #[cfg(test)] mod tests;
use rocket_contrib::static_files::StaticFiles; use rocket_contrib::serve::StaticFiles;
fn rocket() -> rocket::Rocket { fn rocket() -> rocket::Rocket {
rocket::ignite().mount("/", StaticFiles::from("static")) rocket::ignite().mount("/", StaticFiles::from("static"))

View File

@ -11,7 +11,7 @@ use std::collections::HashMap;
use rocket::Request; use rocket::Request;
use rocket::response::Redirect; use rocket::response::Redirect;
use rocket_contrib::Template; use rocket_contrib::templates::Template;
#[derive(Serialize)] #[derive(Serialize)]
struct TemplateContext { struct TemplateContext {

View File

@ -2,7 +2,7 @@ use super::rocket;
use rocket::local::{Client, LocalResponse}; use rocket::local::{Client, LocalResponse};
use rocket::http::Method::*; use rocket::http::Method::*;
use rocket::http::Status; use rocket::http::Status;
use rocket_contrib::Template; use rocket_contrib::templates::Template;
macro_rules! dispatch { macro_rules! dispatch {
($method:expr, $path:expr, $test_fn:expr) => ({ ($method:expr, $path:expr, $test_fn:expr) => ({

View File

@ -20,4 +20,4 @@ rand = "0.5"
[dependencies.rocket_contrib] [dependencies.rocket_contrib]
path = "../../contrib/lib" path = "../../contrib/lib"
default_features = false default_features = false
features = ["tera_templates", "diesel_sqlite_pool", "static_files"] features = ["tera_templates", "diesel_sqlite_pool", "serve"]

View File

@ -14,7 +14,7 @@ use rocket::Rocket;
use rocket::fairing::AdHoc; use rocket::fairing::AdHoc;
use rocket::request::{Form, FlashMessage}; use rocket::request::{Form, FlashMessage};
use rocket::response::{Flash, Redirect}; use rocket::response::{Flash, Redirect};
use rocket_contrib::{Template, databases::database, static_files::StaticFiles}; use rocket_contrib::{templates::Template, databases::database, serve::StaticFiles};
use diesel::SqliteConnection; use diesel::SqliteConnection;
use task::{Task, Todo}; use task::{Task, Todo};

View File

@ -2,18 +2,18 @@
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
#[macro_use] extern crate lazy_static; #[macro_use] extern crate lazy_static;
extern crate uuid;
extern crate rocket_contrib; extern crate rocket_contrib;
extern crate uuid;
use std::collections::HashMap; use std::collections::HashMap;
use rocket_contrib::Uuid; use rocket_contrib::uuid::Uuid;
#[cfg(test)] mod tests; #[cfg(test)] mod tests;
lazy_static! { lazy_static! {
// A small people lookup table for the sake of this example. In a real // A small people lookup table for the sake of this example. In a real
// application this could be a database lookup. Notice that we use the // application this could be a database lookup. Notice that we use the
// uuid::Uuid type here and not the rocket_contrib::Uuid type. // uuid::Uuid type here and not the rocket_contrib::uuid::Uuid type.
static ref PEOPLE: HashMap<uuid::Uuid, &'static str> = { static ref PEOPLE: HashMap<uuid::Uuid, &'static str> = {
let mut m = HashMap::new(); let mut m = HashMap::new();
let lacy_id = uuid::Uuid::parse_str("7f205202-7ba1-4c39-b2fc-3e630722bf9f").unwrap(); let lacy_id = uuid::Uuid::parse_str("7f205202-7ba1-4c39-b2fc-3e630722bf9f").unwrap();
@ -29,7 +29,7 @@ lazy_static! {
#[get("/people/<id>")] #[get("/people/<id>")]
fn people(id: Uuid) -> Result<String, String> { fn people(id: Uuid) -> Result<String, String> {
// Because Uuid implements the Deref trait, we use Deref coercion to convert // Because Uuid implements the Deref trait, we use Deref coercion to convert
// rocket_contrib::Uuid to uuid::Uuid. // rocket_contrib::uuid::Uuid to uuid::Uuid.
Ok(PEOPLE.get(&id) Ok(PEOPLE.get(&id)
.map(|person| format!("We found: {}", person)) .map(|person| format!("We found: {}", person))
.ok_or_else(|| format!("Person not found for UUID: {}", id))?) .ok_or_else(|| format!("Person not found for UUID: {}", id))?)

View File

@ -85,7 +85,7 @@ if [ "$1" = "--contrib" ]; then
msgpack msgpack
tera_templates tera_templates
handlebars_templates handlebars_templates
static_files serve
diesel_postgres_pool diesel_postgres_pool
diesel_sqlite_pool diesel_sqlite_pool
diesel_mysql_pool diesel_mysql_pool