templito/funcs/
mod.rs

1//! The section about making providing functions for the templates
2
3use crate::*;
4use func_man::*;
5use std::path::PathBuf;
6
7mod bools;
8mod bytes;
9mod exec;
10mod folder;
11mod format;
12mod free_file;
13mod lists;
14mod maps;
15pub mod math;
16mod path;
17mod random;
18mod strings;
19mod svg;
20mod table;
21mod write;
22
23pub trait WithFuncs: Sized {
24    fn with_f<K: Into<String>>(self, k: K, f: Box<TFunc>, d: &'static str) -> Self;
25    fn with_fn<K: Into<String>>(self, k: K, f: TFn, d: &'static str) -> Self {
26        self.with_f(k, Box::new(f), d)
27    }
28
29    fn with_defaults(self) -> Self {
30        self.with_bools()
31            .with_strings()
32            .with_math()
33            .with_path()
34            .with_lists()
35            .with_maps()
36            .with_format()
37            .with_rand()
38            .with_bytes()
39            .with_svg()
40    }
41
42    fn with_bytes(self) -> Self {
43        self.with_fn(
44            "as_base64",
45            bytes::as_base64,
46            "(int)->string: Convert a number to base 64",
47        )
48        .with_fn(
49            "from_base64",
50            bytes::from_base64,
51            "(string)->int:Convert a to a number from base 64 string ",
52        )
53    }
54
55    fn with_rand(self) -> Self {
56        self.with_fn(
57            "rand",
58            random::get_rand,
59            "(?min,max)->int|(list)->value : Get a random number or item from list",
60        )
61    }
62    fn with_svg(self) -> Self {
63        self.with_fn(
64            "xy",
65            svg::xy,
66            "(x,y,?units)->string : set svg x and y values",
67        )
68        .with_fn(
69            "xywh",
70            svg::xywh,
71            "(x,y,w,h,?units)->string : set svg x,y,width and hight values",
72        )
73        .with_fn(
74            "cxyrr",
75            svg::cxyrr,
76            "(cx,cy,rx,ry,?units)->string : set svg ellipse values",
77        )
78        .with_fn(
79            "xy12",
80            svg::xy12,
81            "(x,y,x2,y2,?units)->string : set svg x,y,x2 and y2 values",
82        )
83        .with_fn(
84            "fl_stk",
85            svg::fl_stk,
86            "(fill_color,stroke_color,stroke_width)->string : set svg fill and stroke values",
87        )
88        .with_fn(
89            "xml_esc",
90            svg::xml_esc,
91            "(string)->string : escape an xml string",
92        )
93        .with_fn(
94            "font",
95            svg::font,
96            "(size,?name,?units)->string : set svg font",
97        )
98    }
99    fn with_maps(self) -> Self {
100        self.with_fn(
101            "map",
102            maps::map,
103            "(key,value,key,value, ...)->map : build map from list of key value pairs",
104        )
105    }
106
107    fn with_format(self) -> Self {
108        self.with_fn(
109            "r_json",
110            format::r_json,
111            "(string)->value : read json data to value, normally a map",
112        )
113        .with_fn(
114            "r_card",
115            format::r_card,
116            "(string)->map : read card_format data to list of values",
117        )
118        .with_fn(
119            "w_json",
120            format::w_json,
121            "(value)->string : json output of data",
122        )
123    }
124
125    fn with_lists(self) -> Self {
126        self.with_fn(
127            "list",
128            lists::list,
129            "(arg ...)->list<arg> : convert args to a single list",
130        )
131        .with_fn(
132            "sort",
133            lists::sort,
134            "(list ...)->list : combine lists and sort final list on simple value",
135        )
136        .with_fn(
137            "append",
138            lists::append,
139            "(list ...)->list : join all list args to single list",
140        )
141        .with_fn(
142            "sort_on",
143            lists::sort_on,
144            "(list, criteria...)->list : sort list by *criteria*",
145        )
146        .with_fn(
147            "bin_search",
148            lists::bin_search,
149            "(list, criteria)->index : search sorted list for comparator must match sort *criteria*",
150        )
151        .with_fn(
152            "bin_get",
153            lists::bin_get,
154            "(list, criteria)->value : search sorted list for comparator must match sort *criteria*",
155        )
156            .with_fn(
157                "index_of",
158                lists::index_of,
159                "(item,list)->uint/null : if item in list, returns index, else returns null"
160            )
161        .with_fn(
162            "get",
163            lists::get,
164            "(list,index)->value : get item from list by index (list,index)->value",
165        )
166        .with_fn(
167            "filter",
168            lists::filter,
169            "filter list by criteria (list,criteria)->list",
170        )
171        .with_fn("len", lists::len, "(list)->int : Length of the list")
172        .with_fn(
173            "slice",
174            lists::slice,
175            "(list|string, start,?end)->list|string : take a section of a list",
176        )
177        .with_fn(
178            "groups",
179            lists::groups,
180            "(int,list)->list<list> : break a list into groups of the given size",
181        )
182    }
183
184    fn with_strings(self) -> Self {
185        self.with_fn(
186            "cat",
187            strings::cat,
188            "(string...)->string : Concatenate strings",
189        )
190        .with_fn(
191            "md",
192            strings::md,
193            "(string)->string process a string as markdown",
194        )
195        .with_fn(
196            "table",
197            strings::table,
198            "use *table notation* to create an html table",
199        )
200        .with_fn(
201            "split",
202            strings::split,
203            "(string,splitter)->list<string> : split string on splitter",
204        )
205        .with_fn(
206            "string_from_ints",
207            strings::string_from_ints,
208            "(int...)->string : convert the ints to char and combine as a string",
209        )
210        .with_fn(
211            "str_contains",
212            strings::contains,
213            "(haystack,needle...)->bool, does the haystack contain any of the needles",
214        )
215        .with_fn(
216            "str_replace",
217            strings::replace,
218            "(string,needle,replacement)->string : Replace all copies of needle with replacement",
219        )
220        .with_fn("str_replace_n", strings::replace_n,"(string, needle,replacement,?n)->string : Replace n or 1 copies of needle with replacement")
221        .with_fn("html_esc", strings::html_esc,"(string)->string : sanitize input against html security")
222        .with_fn("regex", strings::regex,"(string,regex)->bool : Does the string match the regex")
223        .with_fn("word_wrap", strings::word_wrap,"(string,width)->[]string : Make new string with words wrapped.  \\n is auto break, otherwise wrap on width")
224        .with_fn("debug", strings::debug,"(value ...)->() : print something to the log")
225    }
226
227    fn with_math(self) -> Self {
228        self.with_fn(
229            "add",
230            math::add,
231            "(number...)->number : Sum all the numbers",
232        )
233        .with_fn(
234            "sub",
235            math::sub,
236            "(up,down...)->number : Subtract all downs from up",
237        )
238        .with_fn(
239            "mul",
240            math::mul,
241            "(number...)->number : Multiply all the numbers",
242        )
243        .with_fn("div", math::div,"(top,bottom)->number : Divide the top by the bottom, if both are integers then result will be an integer")
244        .with_fn("mod", math::modulo,"(top,bottom...)->int : Top Modulo Bottom")
245        .with_fn("min", math::min,"(number...)->number : The lowest of the numbers")
246        .with_fn("max", math::max,"(number...)->number : The highest of the numbers")
247    }
248
249    fn with_bools(self) -> Self {
250        self.with_fn("eq", bools::eq, "(A,B...)->bool : Does A equal all the B's")
251            .with_fn(
252                "neq",
253                bools::neq,
254                "(A,B...)->bool : Is A different to all the B's",
255            )
256            .with_fn(
257                "eq_any",
258                bools::eq_any,
259                "(A,B...)->bool : Does A equal any of the B's",
260            )
261            .with_fn(
262                "gt",
263                bools::gt,
264                "(A,B...)->bool : Is A greater than all the B's",
265            )
266            .with_fn(
267                "gte",
268                bools::gte,
269                "(A,B...)->bool : Is A greater than or equal to all the B's",
270            )
271            .with_fn(
272                "lt",
273                bools::lt,
274                "(A,B...)->bool : Is a Less than all the B's",
275            )
276            .with_fn(
277                "lte",
278                bools::lte,
279                "(A,B...)->bool : Is a Less than or equal to all the B's",
280            )
281            .with_fn("and", bools::and, "(A...)->bool : Are all the values true")
282            .with_fn(
283                "nand",
284                bools::nand,
285                "(A...)->bool : False if all values are true, with one are, equivilent to not",
286            )
287            .with_fn(
288                "or",
289                bools::or,
290                "(A...)->bool : True if any values are true",
291            )
292            .with_fn(
293                "nor",
294                bools::nor,
295                "(A...)->bool : False if any values are true",
296            )
297            .with_fn(
298                "type_of",
299                bools::type_of,
300                "(value)->string : The type of the value",
301            )
302            .with_fn(
303                "is_null",
304                bools::is_null,
305                "(value)->bool : Is the value null",
306            )
307            .with_fn(
308                "is_num",
309                bools::is_num,
310                "(value)->bool : Is the value a number",
311            )
312    }
313
314    fn with_path(self) -> Self {
315        self.with_fn("parent", path::parent, "(path)->path : The parent path")
316            .with_fn("join", path::join, "(path...)->path : Join paths")
317            .with_fn(
318                "bread_crumbs",
319                path::bread_crumbs,
320                "(path)->list<path> : A list of paths for each parent of this path",
321            )
322            .with_fn(
323                "base_name",
324                path::base_name,
325                "(path)->string : Return file name within the folder Panics on empty",
326            )
327            .with_fn(
328                "base_name_sure",
329                path::base_name_sure,
330                "(path)->string : Return file name within the folder empty string on empty",
331            )
332            .with_fn(
333                "join_with",
334                path::join_with,
335                "(string,[]string)->string: Join the list into a string using the first param as a separator)",
336            )
337            .with_fn(
338                "with_ext",
339                path::with_ext,
340                "(path,ext)->path : replaces the current exstension an extension to a path,ext should not have a dot ",
341            )
342            .with_fn("stem", path::stem,"(path)->string : basename without extension")
343            .with_fn("full_stem", path::full_stem,"(path)->path : file path without extension")
344    }
345
346    fn with_folder_lock<P: Into<PathBuf>>(self, pb: P) -> Self {
347        let pb: PathBuf = pb.into();
348        self.with_f(
349            "dir",
350            folder::dir(pb.clone()),
351            "(path)->list<string> : Locked to folder : List files in folder",
352        )
353        .with_f(
354            "file",
355            folder::file(pb.clone()),
356            "(path)->string : Locked to folder : return a files string",
357        )
358        .with_f(
359            "file_bytes",
360            folder::file_bytes(pb.clone()),
361            "(path)->bytes : Locked to folder : read file as bytes",
362        )
363        .with_f(
364            "is_file",
365            folder::is_file(pb.clone()),
366            "(path)->bool : Locked to folder : Does path point to file",
367        )
368        .with_f(
369            "is_dir",
370            folder::is_dir(pb.clone()),
371            "(path)->bool : Locked to folder : Does path point to directory",
372        )
373        .with_f(
374            "scan_dir",
375            folder::scan_dir(pb.clone()),
376            "(path)->list<map> : Locked to folder :recursively scan directory",
377        )
378        .with_f(
379            "file_img_dimensions",
380            folder::file_img_dimensions(pb.clone()),
381            "(path)->map<x,y> : Locked to folder : Read img file dimensions without reading whole file"
382
383            ,
384        )
385    }
386
387    fn with_free_files(self) -> Self {
388        self.with_fn(
389            "dir",
390            free_file::dir,
391            "(path)->list : List the contents of a directory",
392        )
393        .with_fn(
394            "file",
395            free_file::file,
396            "(path)->string : The contents of a text file",
397        )
398        .with_fn(
399            "file_bytes",
400            free_file::file_bytes,
401            "(path)->bytes : The byte contents of a file",
402        )
403        .with_fn(
404            "is_file",
405            free_file::is_file,
406            "(path)->bool : Dows the path point to a file",
407        )
408        .with_fn(
409            "is_dir",
410            free_file::is_dir,
411            "(path)->bool : Does the path point to a Directory",
412        )
413        .with_fn(
414            "scan_dir",
415            free_file::scan_dir,
416            "(path)->list : recursive list of folder ",
417        )
418        .with_fn(
419            "file_img_dimensions",
420            free_file::file_img_dimensions,
421            "(path)->map<w,h> : get width and height of an image file without reading the whole file",
422        )
423        .with_fn("write", free_file::write ,"(path,contents ...)->bool : Write the contents to the file",)
424    }
425
426    fn with_exec(self) -> Self {
427        self.with_fn(
428            "exec",
429            exec::exec,
430            "(command,arg...)->string : Run the command and return the string result",
431        )
432        .with_fn(
433            "exec_stdin",
434            exec::exec_stdin,
435            "(command,stdin,arg...)->string : Run the command with stdin piped to it's std in",
436        )
437        .with_fn(
438            "env",
439            exec::env,
440            "(var_name,default)->string : read environment variable, if not found, use default",
441        )
442    }
443
444    fn with_write_lock<P: Into<PathBuf>>(self, pb: P) -> Self {
445        let pb: PathBuf = pb.into();
446        self.with_f(
447            "write",
448            write::write(pb.clone()),
449            "(rel_path,contents)->() : write locked within specific folder",
450        )
451    }
452}
453
454impl<FA: FuncAdder> WithFuncs for FA {
455    fn with_f<K: Into<String>>(self, k: K, f: Box<TFunc>, d: &'static str) -> Self {
456        self.with_func(k, f, d)
457    }
458}