ryuji_rust/
lib.rs

1//! Ryuji-Rust is an implementation of the Ryuji templating language in Rust.
2pub mod ryuji;
3
4pub use ryuji::{ Renderer, Vars, VarValue, FileExtension };
5
6#[cfg(test)]
7mod tests {
8  use super::*;
9
10  #[test]
11  fn file_extension_coerce() {
12    assert!(ryuji::FileExtension::new("adsf".to_string()).is_err());
13    assert!(ryuji::FileExtension::new("ad.sf".to_string()).is_err());
14    assert!(ryuji::FileExtension::new(".png".to_string()).is_ok());
15    assert_eq!(ryuji::FileExtension::try_from(".py".to_string()).unwrap(), ryuji::FileExtension::new(".py".to_string()).unwrap());
16    assert_eq!(".py".to_string(), String::from(ryuji::FileExtension::new(".py".to_string()).unwrap()));
17  }
18
19  #[test]
20  fn concat_path_test() {
21    assert_eq!(ryuji::Renderer::concat_path(&"abc/".to_string(), &"/tree.html".to_string()), "abc/tree.html".to_string());
22    assert_eq!(ryuji::Renderer::concat_path(&"/abc/".to_string(), &"/tree.html".to_string()), "/abc/tree.html".to_string());
23    assert_eq!(ryuji::Renderer::concat_path(&"abc/".to_string(), &"tree.html".to_string()), "abc/tree.html".to_string());
24    assert_eq!(ryuji::Renderer::concat_path(&"abc".to_string(), &"/tree.html".to_string()), "abc/tree.html".to_string());
25    assert_eq!(ryuji::Renderer::concat_path(&"abc/def".to_string(), &"tree.html".to_string()), "abc/def/tree.html".to_string());
26  }
27
28  #[test]
29  fn sanitize_test() {
30    assert_eq!(ryuji::Renderer::sanitize(&"asdf".to_string()), "asdf".to_string());
31    assert_eq!(ryuji::Renderer::sanitize(&"<script>a</script>".to_string()), "&lt;script&gt;a&lt;/script&gt;".to_string());
32  }
33
34  #[test]
35  fn var_name_legality_test() {
36    assert!(ryuji::Renderer::check_var_name_legality(&"asdf".to_string(), true).is_ok());
37    assert!(ryuji::Renderer::check_var_name_legality(&"random/abc".to_string(), true).is_ok());
38    assert!(ryuji::Renderer::check_var_name_legality(&"cheese.burger.property40".to_string(), true).is_ok());
39    assert!(ryuji::Renderer::check_var_name_legality(&"Dave_Davidson.drunkness.intensity".to_string(), true).is_ok());
40    assert!(ryuji::Renderer::check_var_name_legality(&"Dave_Davidson.drunkness.intensity".to_string(), false).is_err());
41    assert!(ryuji::Renderer::check_var_name_legality(&"+23;.'wow'".to_string(), true).is_err());
42    assert!(ryuji::Renderer::check_var_name_legality(&"test ".to_string(), true).is_err());
43  }
44
45  #[test]
46  fn find_syntax_matches_test() {
47    assert_eq!(ryuji::Renderer::find_syntax_matches(&"[[ test.e ]]\n[[]]\nyay [[ if:yay ]]".to_string()), vec![
48      ryuji::SyntaxMatch {
49        index: 0,
50        content: "[[ test.e ]]".to_string(),
51      },
52      ryuji::SyntaxMatch {
53        index: 22,
54        content: "[[ if:yay ]]".to_string(),
55      },
56    ]);
57    assert_eq!(ryuji::Renderer::find_syntax_matches(&"lorem\n[[ \na ]]\nhello [[ na=me ]]".to_string()), vec![]);
58  }
59
60  #[test]
61  fn variable_test() {
62    let renderer: ryuji::Renderer = ryuji::Renderer::new("templates".to_string(), "components".to_string(), ryuji::FileExtension::new(".html".to_string()).unwrap());
63    let mut vars: ryuji::Vars = std::collections::HashMap::from([
64      ("a".to_string(), ryuji::VarValue::U32(15)),
65      ("b".to_string(), ryuji::VarValue::HashMap(std::collections::HashMap::from([
66        ("c".to_string(), ryuji::VarValue::String("abc".to_string())),
67      ]))),
68      ("d".to_string(), ryuji::VarValue::Bool(false)),
69      ("testing_123".to_string(), ryuji::VarValue::String("a\nb\nc".to_string())),
70      ("img".to_string(), ryuji::VarValue::String("<img/>".to_string())),
71    ]);
72    let rendered: String = renderer.render("[[ a ]]\n<h1>title: [[ b.c ]]</h1>\n<div>\n  <p>[[ d ]]</p>\n  [[ testing_123 ]]\n</div>\n[[ html:img ]][[ img ]]".to_string(), &mut vars, None).unwrap();
73    assert_eq!(rendered, "15\n<h1>title: abc</h1>\n<div>\n  <p>false</p>\n  a\n  b\n  c\n</div>\n<img/>&lt;img/&gt;");
74  }
75
76  #[test]
77  fn if_test() {
78    let renderer: ryuji::Renderer = ryuji::Renderer::new("templates".to_string(), "components".to_string(), ryuji::FileExtension::new(".html".to_string()).unwrap());
79    let mut vars: ryuji::Vars = std::collections::HashMap::from([
80      ("koalas_list".to_string(), ryuji::VarValue::Vec(Vec::new())),
81      ("oak".to_string(), ryuji::VarValue::HashMap(std::collections::HashMap::from([
82        ("is_tree".to_string(), ryuji::VarValue::Bool(true)),
83        ("is_not_tree".to_string(), ryuji::VarValue::Bool(false)),
84      ]))),
85      ("pine".to_string(), ryuji::VarValue::HashMap(std::collections::HashMap::from([
86        ("is_tree".to_string(), ryuji::VarValue::Bool(true)),
87        ("is_not_tree".to_string(), ryuji::VarValue::Bool(false)),
88      ]))),
89      ("dave".to_string(), ryuji::VarValue::HashMap(std::collections::HashMap::from([
90        ("is_tree".to_string(), ryuji::VarValue::Bool(false)),
91        ("is_not_tree".to_string(), ryuji::VarValue::Bool(true)),
92      ]))),
93    ]);
94    let rendered: String = renderer.render("[[ if:koalas_list ]]<p>We have a list of koalas</p>\n[[ endif ]]<p>Dave is [[ if:dave.is_not_tree ]]not a tree[[ endif ]][[ if:dave.is_tree ]]a tree[[ endif ]]</p>\n[[ if:pine.is_tree:oak.is_tree ]]<b>Oak and pine are both trees.</b>[[ endif ]]\n[[ if:dave.is_tree:!oak.is_tree ]]<i>But Dave and Oak are different. One of them is a tree, and one of them is not a tree.</i>[[ endif ]]".to_string(), &mut vars, None).unwrap();
95    assert_eq!(rendered, "<p>Dave is not a tree</p>\n<b>Oak and pine are both trees.</b>\n<i>But Dave and Oak are different. One of them is a tree, and one of them is not a tree.</i>");
96  }
97
98  #[test]
99  fn for_loop_test() {
100    //am lazy so these tests are copied from typescript ryuji's tests, more or less
101    let renderer: ryuji::Renderer = ryuji::Renderer::new("templates".to_string(), "components".to_string(), ryuji::FileExtension::new(".html".to_string()).unwrap());
102
103    //empty for loop test
104    let mut vars_empty: ryuji::Vars = std::collections::HashMap::from([
105      ("loop_over".to_string(), ryuji::VarValue::Vec(Vec::new())),
106    ]);
107    let rendered_empty: String = renderer.render("<ul>\n  [[ for:loop_over ]]a[[ endfor ]]\n</ul>\n<p>[[ for:loop_over:item ]][[ endfor ]]</p>".to_string(), &mut vars_empty, None).unwrap();
108    assert_eq!(rendered_empty, "<ul>\n  \n</ul>\n<p></p>");
109
110    //for loop with more vars and if statement test
111    let mut vars_max: ryuji::Vars = std::collections::HashMap::from([
112      ("trees".to_string(), ryuji::VarValue::Vec(vec![
113        ryuji::VarValue::String("mango".to_string()),
114        ryuji::VarValue::String("oak".to_string()),
115        ryuji::VarValue::String("redwood".to_string()),
116        ryuji::VarValue::String("palm".to_string()),
117      ])),
118    ]);
119    let rendered_if: String = renderer.render("[[ for:trees:tree:index_var:max_var ]][[ index_var ]]/[[ max_var ]] [[ tree ]][[ if:index_var:!max_var ]] [[ endif ]][[ endfor ]]".to_string(), &mut vars_max, None).unwrap();
120    assert_eq!(rendered_if, "0/3 mango 1/3 oak 2/3 redwood 3/3 palm");
121
122    //another for loop with if statement test
123    let mut vars_if2: ryuji::Vars = std::collections::HashMap::from([
124      ("letters".to_string(), ryuji::VarValue::Vec(vec![
125        ryuji::VarValue::HashMap(std::collections::HashMap::from([
126          ("letter".to_string(), ryuji::VarValue::String("a".to_string())),
127          ("show".to_string(), ryuji::VarValue::Bool(true)),
128        ])),
129        ryuji::VarValue::HashMap(std::collections::HashMap::from([
130          ("letter".to_string(), ryuji::VarValue::String("b".to_string())),
131          ("show".to_string(), ryuji::VarValue::Bool(false)),
132        ])),
133        ryuji::VarValue::HashMap(std::collections::HashMap::from([
134          ("letter".to_string(), ryuji::VarValue::String("c".to_string())),
135          ("show".to_string(), ryuji::VarValue::Bool(true)),
136        ])),
137        ryuji::VarValue::HashMap(std::collections::HashMap::from([
138          ("letter".to_string(), ryuji::VarValue::String("d".to_string())),
139          ("show".to_string(), ryuji::VarValue::Bool(false)),
140        ])),
141      ])),
142    ]);
143    let rendered_if2: String = renderer.render("[[ for:letters:letter ]][[ if:letter.show ]]<p>[[ letter.letter ]]</p>[[ endif ]][[ endfor ]]".to_string(), &mut vars_if2, None).unwrap();
144    assert_eq!(rendered_if2, "<p>a</p><p>c</p>");
145
146    //nested for loop test
147    let mut vars_nested: ryuji::Vars = std::collections::HashMap::from([
148      ("numbers".to_string(), ryuji::VarValue::Vec(vec![
149        ryuji::VarValue::U32(1),
150        ryuji::VarValue::U32(2),
151        ryuji::VarValue::U32(3),
152      ])),
153    ]);
154    let rendered_nested: String = renderer.render("[[ for:numbers:i ]].[[ i ]].[[ for:numbers:j ]][[ j ]][[ endfor ]][[ endfor ]]".to_string(), &mut vars_nested, None).unwrap();
155    assert_eq!(rendered_nested, ".1.123.2.123.3.123");
156  }
157}