1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! The point in this Library is to provide useful helper methods for cases where you really do
//! need the templates to be capable.
//! My personal use case was to be able to generate specific svg layouts from numbers in card
//! files. This meant doing more maths in the template than is common.
//! I've broken up the helpers roughly by subject so it should be easy to find the ones you need.
//!
//! The simplest way to use this is to import the trait and call with_all on a template.
//! ```rust
//! use gtmpl::{Template,Context};
//! use gtmpl_value::{Value,Number};
//!
//! use gtmpl_helpers::THelper;
//! let mut t = Template::default().with_all();
//! t.parse(r#"<rect {{xywh (mul . 5) (add . 11) 40 20 "px"}}/>"#);
//!
//! let s = t.q_render(4).unwrap();
//! assert_eq!(s,r#"<rect x="20px" y="15px" width="40px" height="20px" />"#.to_string())
//!
//! ```
//!
//! I wanted to keep the demo function simple, but q render works with anything that impls
//! Into for Value And these can of course be Gtmpl Derived like most things.
//! However that is tricky to demo in a doctest.
//!
//!

use gtmpl::{Context, Template};
use gtmpl_value::Value;

/// Functions like add and mul
pub mod math;

/// Functions that help with ranging
/// is_list checks you have a list returning bool
/// as_list creates a list from whatever you give it
/// safe_len returns a length for lists maps and strings, else 0
pub mod range;

/// Provides the selction uptions like b_sel (basically a turnary) and match
pub mod select;

/// String functions like ccat (concat) and sep( Separate with )
pub mod string;

/// Domain specific svg methods for creating trickier shapes.
pub mod svg;

/// Executors for other programs Not included in all because of security issues.
/// While there is a use case for including them, it these helpers should not be added lightly to
/// your application, especially not to web facing systems.
pub mod exec;

/// This trait exists to give methods to the Template object directly.
/// It is not intended to be applied to anything else.
/// By "use"ing this trait, you gain the ability to write "with_svg()" or "with_all()
/// and gain the appropriate helpers for your template
/// q_render is also included to make it slightly easier to render a template.
/// Rather than having to perform Context::from().unwrap() yourself
pub trait THelper: Sized {
    fn push_helper(self, fname: &str, f: fn(&[Value]) -> Result<Value, String>) -> Self;
    fn render_me(&self, c: &Context) -> Result<String, String>;

    fn q_render<V: Into<Value>>(&self, v: V) -> Result<String, String> {
        let c = Context::from(Value::from(v))?;
        self.render_me(&c)
    }

    //fn q_render<T:Into<Value>(&self)
    fn with_math(self) -> Self {
        self.push_helper("add", math::add)
            .push_helper("mul", math::mul)
            .push_helper("sub", math::sub)
            .push_helper("div", math::div)
            .push_helper("idiv", math::idiv)
            .push_helper("mod", math::imod)
    }

    fn with_range(self) -> Self {
        self.push_helper("is_list", range::is_list)
            .push_helper("as_list", range::as_list)
            .push_helper("safe_len", range::safe_len)
            .push_helper("num_range", range::num_range)
            .push_helper("sort_on", range::sort_on)
            .push_helper("to_json", range::to_json)
    }

    fn with_select(self) -> Self {
        self.push_helper("b_sel", select::b_sel)
            .push_helper("match", select::v_match)
            .push_helper("has", select::has)
            .push_helper("first", select::first)
    }

    fn with_string(self) -> Self {
        self.push_helper("ccat", string::ccat)
            .push_helper("sep", string::sep)
            .push_helper("wrap", string::wrap)
            .push_helper("markdown", string::markdown)
    }

    fn with_svg(self) -> Self {
        self.push_helper("xywh", svg::xywh)
            .push_helper("xy", svg::xy)
            .push_helper("fl_stk", svg::fl_stk)
            .push_helper("font", svg::font)
            .push_helper("xml_es", svg::xml_es)
    }

    #[deprecated(since = "0.1.2", note = "please use `with_defaults` instead")]
    fn with_all(self) -> Self {
        self.with_defaults()
    }

    fn with_defaults(self) -> Self {
        self.with_string()
            .with_math()
            .with_range()
            .with_select()
            .with_svg()
    }

    ///This is not included in the "with_defaults" option to make sure you know you have added
    ///it, as it would be dangerous to use in any web facing programs
    fn with_exec(self) -> Self {
        self.push_helper("exec", exec::exec)
    }
}

impl THelper for Template {
    fn push_helper(mut self, fname: &str, f: fn(&[Value]) -> Result<Value, String>) -> Self {
        self.add_func(fname, f);
        self
    }
    fn render_me(&self, c: &Context) -> Result<String, String> {
        self.render(c)
    }
}