mini-builder-rs

A static website generator.

Programming languages use functions to avoid rewriting similar logic. HTML doesn't have a similar features. This crate provides a simple language that can be inserted into HTML (or really any) files in order to programmatically generate new files.

For example, consider the following HTML: ```html

Page1 Page2 Page3

`` Without a static website generator, this html snippet would have to be copied and pasted into each of the pages with a minor change of whichatag will have theselectedclass. However with a static website generator, this snippet could be stored in a file for examplenavigation.html` and then reused in every page. For example:

navigation.html ```html

Page1 Page2 Page3

```

page1.html html ... {{@ navigation(page = 'page 1')}} ...

Examples

For some code examples check out the examples directory.

Builder

The Builder handles ```rust minibuilderrs::builder::Builder::new( // sources - the source for the pages that will be generated Some("./examples/examplesite/sources".into()), // templates - the partial files that can be referenced // from sources or other templates Some("./examples/examplesite/templates".into()), // generated - where the transformed sources will be placed Some("./examples/examplesite/generated".into()), // variables - a file containing global variables and their values Some("./examples/examplesite/variables".into()), // see minibuilderrs::builder::BuilderOptions Default::default(), ) .unwrap() // variable that will be available for every source and template // (unless shadowed) .addvariable("title", Value::text("Website Title")) .addvariable( "files", Value::List(DATA.iter().map(|x| Value::text(x.0)).collect::>()), ) // functions that can be called from every source and template .addfunction("getfilesize", Box::new(getfile_size) as _) // watch for changes in the sources and templates directories, // updating the generated directory live .watch() .unwrap();

...

fn getfilesize(values: &[Value]) -> Value { if let Some(Value::Text(name)) = values.get(0) { for (filename, filesize) in DATA { if filename == name { return Value::Number(*filesize); } } } Value::None } ```

Sources and Templates

Sources the files that correspond to the output files. Templates are files that are used in order by sources or other templates to generate text. For example if the sources are page_1.html, page_2.html and the templates are navigation.html, and footer.html, then after the site has finished, the output will be the expanded versions of only page_1.html and page_2.html.

Templates are called with the syntax @ template(key1 = value1, ...).

The name of the template is either given explicitly when passed as a string, or is the path of the file relative to the templates directory when it loaded from a file ignoring extensions (for example the template template/sub_dir1/temp1.html name would be sub_dir1/tmp1).

Variables and Functions

Values are defined with the following enum: rust pub enum Value { Number(f32), Bool(bool), Text(String), List(Vec<Value>), None, } Functions are defined by the type: Box<dyn Fn(&[Value]) -> Value + 'static>.

Directives

A directive is a piece of code with the pattern {{...}} that adds logic to plain files. Control flow directives such as if statements use a slightly different pattern: {{# ...}}. The language used inside the directives can be summarized in a few examples: * Expressions: ``html <!-- if the variablesaandb` are defined, they will be added and returned -->

a + b = {{ a + b }}

* If statements: html {{# if page == 'page 1' }} ... {{# elif page == 'page 2'}} ... {{# else }} .... {{#}} * For loops: html {{# for file in files}}

{{ file }}

{{#}} * Ternary: html {# if a != None && b != None}}

a is{{ a > b ? 'greater than : a < b ? 'smaller than' : 'equals to'}} b

{{# else}}

a or b are none

{{#}} * Templates: html {{ useprettyheader ? @ prettyheader : @ normalheader}}

{{@ footer(useprettyfooter = useprettyheader)}} ```