limonite 0.1.0

small blog generator
Documentation
use std::path::Path;
use std::collections::HashMap;
use layout_store::LayoutStore;
use regex::Regex;
use util;

#[derive(Debug)]
pub struct Post {
    title: String,
    slug: String,
    content: String,
    layout: Option<String>,
    date: String,
    seq: u8
}

fn extract_data_from_filename(filename: &str) -> (&str, &str, u8) {
    let re = Regex::new(r"^(\d{4}-\d{2}-\d{2})-(\d{3})-(.+)$").unwrap();
    let cap = re.captures(filename).unwrap();
    let date_str = cap.at(1).unwrap();
    let seq = cap.at(2).unwrap().parse::<u8>().unwrap();
    let slug = cap.at(3).unwrap();
    (date_str, slug, seq)
}

impl Post {

    pub fn new(src: &Path) -> Post {
        let filename = src.file_stem().unwrap().to_str().unwrap();
        let (date_str, slug, seq) = extract_data_from_filename(filename);
        let (front_matter, content) = util::parse_front_matter_and_content(src).unwrap();
        let layout = front_matter.get("layout").cloned();
        let title: String = match front_matter.get("title") {
            Some(t) => t.to_owned(),
            None => slug.to_owned()
        };
        Post {
            title: title,
            slug: slug.to_owned(),
            content: content.to_owned(),
            layout: layout,
            date: date_str.to_owned(),
            seq: seq
        }
    }

    pub fn render(&self, data: HashMap<String, String>) -> String {
        let mut local_data = data.clone();
        local_data.insert("title".to_owned(), self.title());
        let result = util::render_liquid(&self.content, local_data).expect("render failure");
        util::render_markdown(&result)
    }

    pub fn slug(&self) -> String {
        self.slug.clone()
    }

    pub fn layout(&self) -> Option<String> {
        self.layout.clone()
    }

    pub fn title(&self) -> String {
        self.title.clone()
    }
}

#[test]
fn constructs_post_from_filename() {
    let post = Post::new(Path::new("fixtures/003/_posts/2015-10-26-001-merry-xmas.markdown"));
    assert_eq!(post.slug(), "merry-xmas");
    assert_eq!(post.date, "2015-10-26".to_owned());
    assert_eq!(post.seq, 1);
    assert_eq!(post.layout, None);
}

#[test]
fn reads_layout_from_front_matter() {
    let post = Post::new(Path::new("fixtures/005/_posts/2015-10-26-001-merry-xmas.markdown"));
    assert_eq!(post.layout, Some("post".to_owned()));
}

#[test]
fn reads_title_from_front_matter() {
    let post = Post::new(Path::new("fixtures/005/_posts/2015-10-26-001-merry-xmas.markdown"));
    assert_eq!(post.title(), "wild merry xmas!".to_owned());
}

#[test]
fn title_is_taken_from_slug_if_missing() {
    let post = Post::new(Path::new("fixtures/005/_posts/2015-10-26-002-meh.markdown"));
    assert_eq!(post.title(), "meh".to_owned());
}

#[test]
fn renders_post_using_specified_layout() {
    let layout_store = LayoutStore::new(Path::new("fixtures/005/_layouts"));
    let post = Post::new(Path::new("fixtures/005/_posts/2015-10-26-001-merry-xmas.markdown"));
    let post_content = post.render(HashMap::new());
    let output = layout_store.render(&post.layout.unwrap(), post_content, HashMap::new());
    assert_eq!(output, "Main\nPost\n<h1>hello shit</h1>\n\n\n".to_owned());
}

#[test]
fn renders_post_with_both_markdown_and_liquid() {
    let layout_store = LayoutStore::new(Path::new("fixtures/009/_layouts"));
    let post = Post::new(Path::new("fixtures/009/_posts/2015-10-26-001-merry-xmas.markdown"));
    let post_content = post.render(HashMap::new());
    let output = layout_store.render(&post.layout.unwrap(), post_content, HashMap::new());
    assert_eq!(output, "Main\nPost\n<h1>ooh, boo</h1>\n\n\n".to_owned());
}