The value of @name is @value.
+//! +//! +//! ``` +//! +//! As seen above, string slices and integers can easily be outputed +//! in the template body, using `@name` where `name` is a parameter of +//! the template. +//! Actually, more complex expressions can be outputed in the same +//! way, as long as the resulting value implements [`ToHtml`]. +//! Rust types that implements [`Display`] automatically implements +//! [`ToHtml`] in such a way that contents are safely escaped for +//! html. +//! +//! ```html +//! @use any::rust::Type; +//! +//! @(name: &str, items: &[Type]) +//! +//! +//!There are no items.
+//! } else { +//!There are @items.len() items.
+//!The user @user.name has email @user.get_email().
+ //!A function result is @function(with, three, arguments).
+ //! ``` + //! + //! Standard function and macros can also be used, e.g. for specific + //! formatting needs: + //! + //! ```text + //!The value is @format!("{:.1}", float_value).
+ //! ``` + //! + //! If more complex expressions are needed, they can be put in + //! parenthesis. + //! + //! ```text + //!The sum @a+3 is @(a+3).
+ //! ``` + //! If `a` is 2, this exapands to: + //! ```text + //!The sum 2+3 is 5.
+ //! ``` + //! + //! Anything is allowed in parenthesis, as long as parenthesis, + //! brackets and string quotes are balanced. + //! Note that this also applies to the parenthesis of a function + //! call or the brackets of an index, so complex things like the + //! following are allowed: + //! + //! ```text + //!Index: @myvec[t.map(|s| s.length()).unwrap_or(0)].
+ //!Argument: @call(a + 3, |t| t.something()).
+ //! ``` + //! + //! An expression ends when parenthesis and brackets are matched + //! and it is followed by something not allowed in an expression. + //! This includes whitespace and e.g. the `<` and `@` characters. + //! If an expression starts with an open parenthesis, the + //! expression ends when that parentheis is closed. + //! That is usefull if an expression is to be emmediatley followed + //! by something that would be allowed in an expression. + //! + //! ```text + //!@arg
+ //!@arg.
+ //!@arg.@arg
+ //!@arg.len()
+ //!@(arg).len()
+ //!@((2_i8 - 3).abs())
@* Note extra parens needed here *@ + //! ``` + //! With `arg = "name"`, the above renders as: + //! ```text + //!name
+ //!name.
+ //!name.name
+ //!4
+ //!name.len()
+ //!1
+ //! ``` +} + +pub mod b_Loops { + //! A ructe `@for` loop works just as a rust `for` loop, + //! iterating over anything that implements `std::iter::IntoIterator`, + //! such as a `Vec` or a slice. + //! + //! # Loops + //! + //! Rust-like loops are supported like this: + //! + //! ```text + //!@n: @item
+ //! } + //! ``` + //! + //! It is also possible to loop over a literal array (which may be + //! an array of tuples), as long as you do it by reference: + //! + //! ```text + //! @for &(name, age) in &[("Rasmus", 44), ("Mike", 36)] { + //!@name is @age years old.
+ //! } + //! ``` +} + +pub mod c_Conditionals { + //! Both `@if` statements with boolean expressions, `@if let` guard + //! statements, and `@match` statements are supported. + //! + //! # Conditionals + //! + //! Rust-like conditionals are supported in a style similar to the loops: + //! + //! ```text + //! @if items.is_empty() { + //!There are no items.
+ //! } + //! ``` + //! + //! Pattern matching let expressions are also supported, as well as an + //! optional else part. + //! + //! ```text + //! @if let Some(foo) = foo { + //!Foo is @foo.
+ //! } else { + //!There is no foo.
+ //! } + //! ``` + //! + //! The condition or let expression should allow anything that would be + //! allowed in the same place in plain rust. + //! As with loops, the things in the curly brackets are ructe template + //! code. + //! + //! ## match + //! + //! Pattern matching using `match` statements are also supported. + //! + //! ```text + //! @match answer { + //! Ok(value) => { + //!The answer is @value.
+ //! } + //! Err(_) => { + //!I don't know the answer.
+ //! } + //! } + //! ``` + //! + //! The let expression and patterns should allow anything that would be + //! allowed in the same place in plain rust. + //! As above, the things in the curly brackets are ructe template code. +} + +pub mod d_Calling_other_templates { + //! The ability to call other templates for from a template makes + //! both "tag libraries" and "base templates" possible with the + //! same syntax. + //! + //! # Calling other templates + //! + //! While rust methods can be called as a simple expression, there is a + //! special syntax for calling other templates: + //! `@:template_name(template_arguments)`. + //! Also, before calling a template, it has to be imported by a `use` + //! statement. + //! Templates are declared in a `templates` module. + //! + //! So, given something like this in `header.rs.html`: + //! + //! ```text + //! @(title: &str) + //! + //! + //!page content ...
+ //! + //! + //! ``` + //! + //! It is also possible to send template blocks as parameters to templates. + //! A structure similar to the above can be created by having something like + //! this in `base_page.rs.html`: + //! + //! ```text + //! @(title: &str, body: Content) + //! + //! + //! + //!page content ...
+ //! }) + //! ``` +} diff --git a/ructe-0.17.0/src/expression.rs b/ructe-0.17.0/src/expression.rs new file mode 100644 index 0000000..a8f6a49 --- /dev/null +++ b/ructe-0.17.0/src/expression.rs @@ -0,0 +1,275 @@ +use crate::parseresult::PResult; +use nom::branch::alt; +use nom::bytes::complete::{escaped, is_a, is_not, tag}; +use nom::character::complete::{alpha1, char, digit1, none_of, one_of}; +use nom::combinator::{map, map_res, not, opt, recognize, value}; +use nom::error::context; //, VerboseError}; +use nom::multi::{fold_many0, many0, separated_list0}; +use nom::sequence::{delimited, pair, preceded, terminated, tuple}; +use std::str::{from_utf8, Utf8Error}; + +pub fn expression(input: &[u8]) -> PResult<&str> { + map_res( + recognize(context( + "Expected rust expression", + tuple(( + map_res(alt((tag("&"), tag("*"), tag(""))), input_to_str), + alt(( + rust_name, + map_res(digit1, input_to_str), + quoted_string, + expr_in_parens, + expr_in_brackets, + )), + fold_many0( + alt(( + preceded(context("separator", tag(".")), expression), + preceded(tag("::"), expression), + expr_in_parens, + expr_in_braces, + expr_in_brackets, + preceded(tag("!"), expr_in_parens), + preceded(tag("!"), expr_in_brackets), + )), + || (), + |_, _| (), + ), + )), + )), + input_to_str, + )(input) +} + +pub fn input_to_str(s: &[u8]) -> Result<&str, Utf8Error> { + from_utf8(s) +} + +pub fn comma_expressions(input: &[u8]) -> PResultThere are no items.
+//! } else { +//!There are @items.len() items.
+//!(&mut self, indir: P) -> Result<()>
+ where
+ P: AsRef (
+ &mut self,
+ path: P,
+ data: &[u8],
+ ) -> Result<&mut Self>
+ where
+ P: AsRef (&mut self, src: P) -> Result<&mut Self>
+ where
+ P: AsRef` tag in
+/// a template. That can be done like this:
+///
+/// ```html
+/// @use super::statics::image_png;
+/// @()
+///
+/// ```
+///
+/// So, what has happened here?
+/// First, assuming the `static` directory in your
+/// `$CARGO_MANIFEST_DIR` contained a file name `image.png`, your
+/// `templates::statics` module (which is reachable as `super::statics`
+/// from inside a template) will contain a
+/// `pub static image_png: StaticFile` which can be imported and used
+/// in both templates and rust code.
+/// A `StaticFile` has a field named `name` which is a `&'static str`
+/// containing the name with the generated hash, `image-SomeHash.png`.
+///
+/// The next step is that a browser actually sends a request for
+/// `/static/image-SomeHash.png` and your server needs to deliver it.
+/// Here, things depend on your web framework, so we start with some
+/// pseudo code.
+/// Full examples for [warp], [gotham], [nickel], and [iron] is
+/// available [in the ructe repository].
+///
+/// [warp]: https://crates.rs/crates/warp
+/// [gotham]: https://crates.rs/crates/gotham
+/// [nickel]: https://crates.rs/crates/nickel
+/// [iron]: https://crates.rs/crates/iron
+/// [in the ructe repository]: https://github.com/kaj/ructe/tree/master/examples
+///
+/// ```ignore
+/// /// A hypothetical web framework calls this each /static/... request,
+/// /// with the name component of the URL as the name argument.
+/// fn serve_static(name: &str) -> Response {
+/// if let Some(data) = StaticFile::get(name) {
+/// Response::Ok(data.content)
+/// } else {
+/// Response::NotFound
+/// }
+/// }
+/// ```
+///
+/// The `StaticFile::get` function returns the `&'static StaticFile`
+/// for a given file name if the file exists.
+/// This is a reference to the same struct that we used by the name
+/// `image_png` in the template.
+/// Besides the `name` field (which will be equal to the argument, or
+/// `get` would not have returned this `StaticFile`), there is a
+/// `content: &'static [u8]` field which contains the actual file
+/// data.
+///
+/// # Content-types
+///
+/// How to get the content type of static files.
+///
+/// Ructe has support for making the content-type of each static
+/// file availiable using the
+/// [mime](https://crates.io/crates/mime) crate.
+/// Since mime version 0.3.0 was a breaking change of how the
+/// `mime::Mime` type was implemented, and both Nickel and Iron
+/// currently require the old version (0.2.x), ructe provides
+/// support for both mime 0.2.x and mime 0.3.x with separate
+/// feature flags.
+///
+/// # Mime 0.2.x
+///
+/// To use the mime 0.2.x support, enable the `mime02` feature and
+/// add mime 0.2.x as a dependency:
+///
+/// ```toml
+/// [build-dependencies]
+/// ructe = { version = "^0.3.2", features = ["mime02"] }
+///
+/// [dependencies]
+/// mime = "~0.2"
+/// ```
+///
+/// A `Mime` as implemented in `mime` version 0.2.x cannot be
+/// created statically, so instead a `StaticFile` provides
+/// `pub fn mime(&self) -> Mime`.
+///
+/// ```
+/// # // Test and doc even without the feature, so mock functionality.
+/// # pub mod templates { pub mod statics {
+/// # pub struct FakeFile;
+/// # impl FakeFile { pub fn mime(&self) -> &'static str { "image/png" } }
+/// # pub static image_png: FakeFile = FakeFile;
+/// # }}
+/// use templates::statics::image_png;
+///
+/// # fn main() {
+/// assert_eq!(format!("Type is {}", image_png.mime()),
+/// "Type is image/png");
+/// # }
+/// ```
+///
+/// # Mime 0.3.x
+///
+/// To use the mime 0.3.x support, enable the `mime3` feature and
+/// add mime 0.3.x as a dependency:
+///
+/// ```toml
+/// [build-dependencies]
+/// ructe = { version = "^0.3.2", features = ["mime03"] }
+///
+/// [dependencies]
+/// mime = "~0.3"
+/// ```
+///
+/// From version 0.3, the `mime` crates supports creating const
+/// static `Mime` objects, so with this feature, a `StaticFile`
+/// simply has a `pub mime: &'static Mime` field.
+///
+/// ```
+/// # // Test and doc even without the feature, so mock functionality.
+/// # pub mod templates { pub mod statics {
+/// # pub struct FakeFile { pub mime: &'static str }
+/// # pub static image_png: FakeFile = FakeFile { mime: "image/png", };
+/// # }}
+/// use templates::statics::image_png;
+///
+/// # fn main() {
+/// assert_eq!(format!("Type is {}", image_png.mime),
+/// "Type is image/png");
+/// # }
+/// ```
+pub struct StaticFiles {
+ /// Rust source file `statics.rs` beeing written.
+ src: Vec