Unfortunately, I've not had as much time to devote to this for a while. There are also a lot of weird cases that aren't too well defined or that the Ruby implementation shines through that also have me dissatisfied with Liquid. That and wanting to make it easier to extend with an embedded language. A way to solve this and my annoyance is to create a template language using an existing embedded language. I'm tempted by koto because it already has something like `|` operator (`->`) and isn't just "Rust, but embeddable" (Rust is an implementation detail; it shouldn't bleed through).
Conformant: Incompatibilities with strict shopify/liquid are bugs to be fixed.
Flexible: Liquid embraces variants for different domains and we want to follow in that spirit.
Performant: Do the best we can within what is conformant.
This has potential to replace Github Pages ruby-based Jekyll+Liquid, which is unusably slow on iOS without JIT.Compiled cobalt with liquid-rust on iSH is fast enough for static blog publishing and browser-based offline site preview on iOS/iPadOS, https://news.ycombinator.com/item?id=46220227
``` Performant. Do the best we can within what is conformant. ```
Would be great to have benchmarks like ops/second
For an overview of liquid itself, see https://shopify.github.io/liquid/
For a greenfield site where Jekyll/Liquid compatibility is not beneficial, Zola may be an option, https://github.com/getzola/zola
Liquid templating for Rust
Goals:
Example applications using liquid-rust:
To include liquid in your project add the following to your Cargo.toml:
$ cargo add liquid
Example:
let template = liquid::ParserBuilder::with_stdlib()
.build().unwrap()
.parse("Liquid! {{num | minus: 2}}").unwrap();
let globals = liquid::object!({
"num": 4f64
});
let output = template.render(&globals).unwrap();
assert_eq!(output, "Liquid! 2".to_string());
You can find a reference on Liquid syntax here.
By default, liquid-rust has no filters, tags, or blocks. You can enable the
default set or pick and choose which to add to suit your application.
Creating your own filters is very easy. Filters are simply functions or
closures that take an input Value and a Vec<Value> of optional arguments
and return a Value to be rendered or consumed by chained filters.
See
filters/
for what a filter implementation looks like. You can then register it by
calling liquid::ParserBuilder::filter.
Tags are made up of two parts, the initialization and the rendering.
Initialization happens when the parser hits a Liquid tag that has your
designated name. You will have to specify a function or closure that will
then return a Renderable object to do the rendering.
See
include_tag.rs
for what a tag implementation looks like. You can then register it by calling liquid::ParserBuilder::tag.
Blocks work very similar to Tags. The only difference is that blocks contain other
markup, which is why block initialization functions take another argument, a list
of Elements that are inside the specified block.
See
comment_block.rs
for what a block implementation looks like. You can then register it by
calling liquid::ParserBuilder::block.
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions.