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
138
139
140
141
142
143
144
extern crate fs_extra;
extern crate handlebars;
extern crate serde;
extern crate serde_json;
extern crate toml;
#[macro_use]
extern crate failure;

use serde_json::value::Value as SerdeJson;
use toml::Value as Toml;
use serde::ser::Serialize;
use handlebars::Handlebars;
use failure::Error;

pub mod template;
pub mod data;
pub mod generate;


/// Rust library for fast prototyping and creating static websites.
/// Use handlebars to handle html parts.
/// Uses json and toml formats for data passed into templates.
/// Flexible design allows to create any type of static website.

/// Creating new project:
/// Create new binary crate with
/// ```
/// cargo new --bin crate_name
/// ```
/// Open crate folder and run
/// curl -s https://raw.githubusercontent.com/jaroslaw-weber/slime/master/init_slime.sh | bash
/// This will download deployment scripts and create some folders.
/// It will also create example files.

/// Wrapper for creating a static websites.
/// Load templates and helps with loading and inserting data into templates.
pub struct Slime<'a> {
    /// cached config
    config: Config<'a>,
    /// cached templates
    templates: Option<Handlebars>,
}

impl<'a> Slime<'a> {
    /// Create new wrapper with custom config.
    pub fn new(config: Config<'a>) -> Slime<'a> {
        Slime {
            config: config,
            templates: None,
        }
    }

    /// Load templates (need to run only once)
    pub fn initialize(&mut self) -> Result<(), Error> {
        let hb: Handlebars = template::load_all(&self.config)?;
        self.templates = Some(hb);
        Ok(())
    }

    /// Load json data from data folder.
    /// Default file extension is ".json" if not specified.
    pub fn load_json_data(&self, file_name: &str) -> Result<SerdeJson, Error> {
        data::load_json(self.config.data_path, file_name)
    }

    /// Load toml data from data folder. 
    /// Default file extension is ".toml" if not specified.
    pub fn load_toml_data(&self, file_name: &str) -> Result<Toml, Error> {
        data::load_toml(self.config.data_path, file_name)
    }


    /// Generate file. If filename has no extension then default extension is added (.html)
    pub fn generate<T: Serialize>(
        &self,
        template: &str,
        file_name: &str,
        data: &T,
    ) -> Result<(), Error> {
        match &self.templates {
            &Some(ref hb) => {
                generate::generate(
                    &hb,
                    template,
                    data,
                    self.config.generated_path,
                    file_name,
                )?;
                Ok(())
            }
            &None => bail!("templates not loaded! use Slime::initialize()"),
        }
    }

}

impl<'a> Default for Slime<'a> {
    fn default() -> Slime<'a> {
        Slime::new(Config::default())
    }
}

/// Folders paths config file.
pub struct Config<'a> {
    data_path: &'a str,
    generated_path: &'a str,
    templates_path: &'a str,
}

impl<'a> Config<'a> {
    pub fn new(data_path: &'a str, generated_path: &'a str, templates_path: &'a str) -> Config<'a> {
        Config {
            data_path: data_path,
            generated_path: generated_path,
            templates_path: templates_path,
        }
    }
}

/// Default folder paths (working with installation script)
impl<'a> Default for Config<'a> {
    fn default() -> Config<'a> {
        Config {
            data_path: "data",
            generated_path: "generated",
            templates_path: "templates",
        }
    }
}

/// does filename has extension in it?
fn has_ext(file_name: &str)-> bool
{
    file_name.contains(".")
}

fn get_filename_with_ext(file_name: &str, extension: &str) -> String
{
    match has_ext(file_name)
    {
        true => file_name.to_string(),
        false => format!("{}.{}", file_name, extension)
    }
}