Skip to content

Commit

Permalink
Modify readme to use cargo readme; Closes #1
Browse files Browse the repository at this point in the history
  • Loading branch information
Atreyagaurav committed Oct 17, 2023
1 parent b4b3c71 commit 2f0323e
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 89 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "string-template-plus"
version = "0.3.5"
version = "0.3.6"
edition = "2021"
authors = ["Gaurav Atreya"]
description = "Render string template with more options"
Expand Down
128 changes: 70 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# Introduction
# string-template-plus

## Introduction

This is a simple template tool that works with variable names and
`HashMap` of `String`. The `Template` can be parsed from `str`
and then you can render it using the variables in `HashMap` and any
shell commands running through `Exec`.
# Features
[`HashMap`] of [`String`]. The [`Template`] can be parsed from [`str`]
and then you can render it using the variables in [`HashMap`] and any
shell commands running through [`Exec`].

## Features
- Parse the template from a `str` that's easy to write,
- Support for alternatives in case some variables are not present,
Use `?` to separate the alternatives, uses whichever it can find first. If `?` is at the end, leaves it blank instead of erroring out.
Expand All @@ -14,13 +18,14 @@ shell commands running through `Exec`.
- Support for any arbitrary commands, etc.
You can keep any command inside `$(` and `)` to run it and use the result in the template. You can use other format elements inside it.
- Support for iterating (incremented with -N) strings with the same template conditions,
- Limited formatting support like UPCASE, downcase, float significant digits, etc.
# Bug
Using transformations with `()` inside a command `$()` is not possible as they are recognized using regex. Need to fix it later.
# Usages
- Limited formatting support like UPCASE, downcase, float significant digits, etc. Look into [`transformers`] for more info.


## Usages
Simple variables:
```rust
let templ = parse_template("hello {name}").unwrap();
#
let templ = Template::parse_template("hello {name}").unwrap();
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("name".into(), "world".into());
let rendered = templ
Expand All @@ -31,9 +36,11 @@ variables: vars,
.unwrap();
assert_eq!(rendered, "hello world");
```

Safe replace, blank if not present, or literal string if not present:
```rust
let templ = parse_template("hello {name?} {lastname?\"User\"}").unwrap();
#
let templ = Template::parse_template("hello {name?} {lastname?\"User\"}").unwrap();
let vars: HashMap<String, String> = HashMap::new();
let rendered = templ
.render(&RenderOptions {
Expand All @@ -43,9 +50,11 @@ variables: vars,
.unwrap();
assert_eq!(rendered, "hello User");
```

Alternate, whichever variable it finds first will be replaced:
```rust
let templ = parse_template("hello {nickname?name}").unwrap();
#
let templ = Template::parse_template("hello {nickname?name}").unwrap();
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("name".into(), "world".into());
let rendered = templ
Expand All @@ -56,9 +65,11 @@ variables: vars,
.unwrap();
assert_eq!(rendered, "hello world");
```

Custom Commands:
```rust
let templ = parse_template("L=$(printf \"%.2f\" {length})").unwrap();
#
let templ = Template::parse_template("L=$(printf \"%.2f\" {length})").unwrap();
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("length".into(), "12.342323".into());
let rendered = templ
Expand All @@ -70,9 +81,11 @@ shell_commands: true,
.unwrap();
assert_eq!(rendered, "L=12.34");
```

You can turn off Custom Commands for safety:
```rust
let templ = parse_template("L=$(printf \"%.2f\" {length})").unwrap();
#
let templ = Template::parse_template("L=$(printf \"%.2f\" {length})").unwrap();
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("length".into(), "12.342323".into());
let rendered = templ
Expand All @@ -82,11 +95,13 @@ variables: vars,
shell_commands: false,
})
.unwrap();
assert_eq!(rendered, "L=$(printf \"%.2f\" 12.342323)");
assert_eq!(rendered, "L=$(printf %.2f 12.342323)");
```

Date Time:
```rust
let templ = parse_template("hello {name} at {%Y-%m-%d}").unwrap();
#
let templ = Template::parse_template("hello {name} at {%Y-%m-%d}").unwrap();
let timefmt = Local::now().format("%Y-%m-%d");
let output = format!("hello world at {}", timefmt);
let mut vars: HashMap<String, String> = HashMap::new();
Expand All @@ -100,34 +115,11 @@ shell_commands: false,
.unwrap();
assert_eq!(rendered, output);
```
# Transformers:

## Transformers:
Although there is no format strings, there are transformer functions that can format for a bit. I'm planning to add more format functions as the need arises.
```rust
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("length".into(), "120.1234".into());
vars.insert("name".into(), "joHN".into());
vars.insert("job".into(), "assistant manager of company".into());
let options = RenderOptions {
variables: vars,
..Default::default()
};
let cases = [
("L={length}", "L=120.1234"),
("L={length:calc(+100)}", "L=220.1234"),
("L={length:f(.2)} ({length:f(3)})", "L=120.12 (120.123)"),
("hi {name:case(up)}", "hi JOHN"),
(
"hi {name:case(proper)}, {job:case(title)}",
"hi John, Assistant Manager of Company",
),
("hi {name:case(down)}", "hi john"),
];
for (t, r) in cases {
let templ = parse_template(t).unwrap();
let rendered = templ.render(&options).unwrap();
assert_eq!(rendered, r);
}
```

To apply a tranformer to a variable provide it after [`VAR_TRANSFORM_SEP_CHAR`] (currently ":") to a variable template.

There are a few transformers available:

Expand All @@ -138,31 +130,51 @@ There are a few transformers available:
| case [`string_case`] | down | downcase a string | {"nA":case(down)} ⇒ na |
| case [`string_case`] | proper | Upcase the first letter | {"nA":case(proper)} ⇒ Na |
| case [`string_case`] | title | Title Case the string | {"na":case(title)} ⇒ Na |
| calc | [+-*/^]N | Airthmatic calculation | {"1":calc(+1*2^2)} ⇒ 16 |
| calc | [+-*/^]N | Airthmatic calculation | {"1":calc(+1,-1)} ⇒ 2,0 |
| calc | [+-*\/^]N | Airthmatic calculation | {"1":calc(+1*2^2)} ⇒ 16 |
| calc | [+-*\/^]N | Airthmatic calculation | {"1":calc(+1,-1)} ⇒ 2,0 |
| count | str | count str occurance | {"nata":count(a)} ⇒ 2 |
| repl [`replace`] | str1,str2 | replace str1 by str2 | {"nata":rep(a,o)} ⇒ noto |
| q [`quote`] | [str1] | quote with str1, or "" | {"nata":q()} ⇒ "noto" |
| take | str,N | take Nth group sep by str| {"nata":take(a,2)} ⇒ "t" |
| trim | str | trim the string with str | {"nata":trim(a)} ⇒ "nat" |

You can chain transformers ones after another for combined actions. For example, `count( ):calc(+1)` will give you total number of words in a sentence.
You can chain transformers ones after another for combined actions. For example, `count( ):calc(+1)` will give you total number of words in a sentence.

# Render Iter
Makes a `RenderIter<'a>` that can generate incremented strings from the given `Template` and the `RenderOptions`. The Iterator will have `-N` appended where N is the number representing the number of instance.
Examples are in individual functions in [`transformers`].

```rust
let templ = parse_template("hello {name}").unwrap();
#
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("name".into(), "world".into());
vars.insert("length".into(), "120.1234".into());
vars.insert("name".into(), "joHN".into());
vars.insert("job".into(), "assistant manager of company".into());
let options = RenderOptions {
variables: vars,
..Default::default()
};
let mut names = options.render_iter(&templ);
assert_eq!("hello world-1", names.next().unwrap());
assert_eq!("hello world-2", names.next().unwrap());
assert_eq!("hello world-3", names.next().unwrap());
variables: vars,
..Default::default()
};
let cases = [
("L={length}", "L=120.1234"),
("L={length:calc(+100)}", "L=220.1234"),
("L={length:f(.2)} ({length:f(3)})", "L=120.12 (120.123)"),
("hi {name:case(up)}", "hi JOHN"),
(
"hi {name:case(proper)}, {job:case(title)}",
"hi John, Assistant Manager of Company",
),
("hi {name:case(down)}", "hi john"),
];

for (t, r) in cases {
let templ = Template::parse_template(t).unwrap();
let rendered = templ.render(&options).unwrap();
assert_eq!(rendered, r);
}
```

# Limitations
## Limitations
- You cannot use positional arguments in this template system, only named ones. `{}` will be replaced with empty string. Although you can use `"0"`, `"1"`, etc as variable names in the template and the render options variables.
- I haven't tested variety of names, although they should work try to keep the names identifier friendly.
- Currently doesn't have format specifiers, for now you can use the command options with `printf` bash command to format things the way you want, or use the transformers which have limited formatting capabilities.
Like a template `this is $(printf "%05.2f" {weight}) kg.` should be rendered with the correct float formatting.

License: GPL-3.0-only
30 changes: 26 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ shell commands running through [`Exec`].
- Support for any arbitrary commands, etc.
You can keep any command inside `$(` and `)` to run it and use the result in the template. You can use other format elements inside it.
- Support for iterating (incremented with -N) strings with the same template conditions,
- Limited formatting support like UPCASE, downcase, float significant digits, etc.
- Limited formatting support like UPCASE, downcase, float significant digits, etc. Look into [`transformers`] for more info.
# Bug
Using transformations with `()` inside a command `$()` is not possible as they are recognized using regex. Need to fix it later.
# Usages
Simple variables:
Expand Down Expand Up @@ -160,8 +158,32 @@ shell_commands: false,
# }
```
Transformers:
# Transformers:
Although there is no format strings, there are transformer functions that can format for a bit. I'm planning to add more format functions as the need arises.
To apply a tranformer to a variable provide it after [`VAR_TRANSFORM_SEP_CHAR`] (currently ":") to a variable template.
There are a few transformers available:
| Transformer | Arguments | Function | Example |
|----------------------|-----------|--------------------------|--------------------------|
| f [`format_float`] | [.]N | only N number of decimal | {"1.12":f(.1)} ⇒ 1.1 |
| case [`string_case`] | up | UPCASE a string | {"na":case(up)} ⇒ NA |
| case [`string_case`] | down | downcase a string | {"nA":case(down)} ⇒ na |
| case [`string_case`] | proper | Upcase the first letter | {"nA":case(proper)} ⇒ Na |
| case [`string_case`] | title | Title Case the string | {"na":case(title)} ⇒ Na |
| calc | [+-*\/^]N | Airthmatic calculation | {"1":calc(+1*2^2)} ⇒ 16 |
| calc | [+-*\/^]N | Airthmatic calculation | {"1":calc(+1,-1)} ⇒ 2,0 |
| count | str | count str occurance | {"nata":count(a)} ⇒ 2 |
| repl [`replace`] | str1,str2 | replace str1 by str2 | {"nata":rep(a,o)} ⇒ noto |
| q [`quote`] | [str1] | quote with str1, or "" | {"nata":q()} ⇒ "noto" |
| take | str,N | take Nth group sep by str| {"nata":take(a,2)} ⇒ "t" |
| trim | str | trim the string with str | {"nata":trim(a)} ⇒ "nat" |
You can chain transformers ones after another for combined actions. For example, `count( ):calc(+1)` will give you total number of words in a sentence.
Examples are in individual functions in [`transformers`].
```rust
# use std::error::Error;
# use std::collections::HashMap;
Expand Down
30 changes: 4 additions & 26 deletions src/transformers.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,4 @@
/*! Transformers for the template
To apply a tranformer to a variable provide it after [`VAR_TRANSFORM_SEP_CHAR`] (currently ":") to a variable template.
There are a few transformers available:
| Transformer | Arguments | Function | Example |
|----------------------|-----------|--------------------------|--------------------------|
| f [`format_float`] | [.]N | only N number of decimal | {"1.12":f(.1)} ⇒ 1.1 |
| case [`string_case`] | up | UPCASE a string | {"na":case(up)} ⇒ NA |
| case [`string_case`] | down | downcase a string | {"nA":case(down)} ⇒ na |
| case [`string_case`] | proper | Upcase the first letter | {"nA":case(proper)} ⇒ Na |
| case [`string_case`] | title | Title Case the string | {"na":case(title)} ⇒ Na |
| calc | [+-*\/^]N | Airthmatic calculation | {"1":calc(+1*2^2)} ⇒ 16 |
| calc | [+-*\/^]N | Airthmatic calculation | {"1":calc(+1,-1)} ⇒ 2,0 |
| count | str | count str occurance | {"nata":count(a)} ⇒ 2 |
| repl [`replace`] | str1,str2 | replace str1 by str2 | {"nata":rep(a,o)} ⇒ noto |
| q [`quote`] | [str1] | quote with str1, or "" | {"nata":q()} ⇒ "noto" |
| take | str,N | take Nth group sep by str| {"nata":take(a,2)} ⇒ "t" |
| trim | str | trim the string with str | {"nata":trim(a)} ⇒ "nat" |
You can chain transformers ones after another for combined actions. For example, `count( ):calc(+1)` will give you total number of words in a sentence.
Examples are in individual functions.
*/
/// Transformers for the template
use std::ops::{Bound, RangeBounds};

use crate::errors::TransformerError;
Expand All @@ -32,7 +8,7 @@ use regex::Regex;
use titlecase::titlecase;

/// Applies any tranformations to the variable, you can chain the
/// transformers Called whenever you use [`VAR_TRANSFORM_SEP_CHAR`] to
/// transformers called whenever you use [`VAR_TRANSFORM_SEP_CHAR`] to
/// provide a transformer in the template.
pub fn apply_tranformers(val: &str, transformations: &str) -> Result<String, TransformerError> {
let mut val: String = val.to_string();
Expand All @@ -59,6 +35,8 @@ pub fn apply_tranformers(val: &str, transformations: &str) -> Result<String, Tra
"count" => count(&val, args)?,
"repl" => replace(&val, args)?,
"take" => take(&val, args)?,
"trim" => trim(&val, args)?,
"q" => quote(&val, args)?,
_ => {
return Err(TransformerError::UnknownTranformer(
name.to_string(),
Expand Down

0 comments on commit 2f0323e

Please sign in to comment.