@@ -2,6 +2,7 @@ | |||||
name = "gutenberg" | name = "gutenberg" | ||||
version = "0.1.0" | version = "0.1.0" | ||||
dependencies = [ | dependencies = [ | ||||
"chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | |||||
"clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)", | "clap 2.20.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
@@ -24,6 +24,7 @@ serde_derive = "0.9" | |||||
tera = "0.8" | tera = "0.8" | ||||
slug = "0.1" | slug = "0.1" | ||||
syntect = "1" | syntect = "1" | ||||
chrono = "0.3" | |||||
# Below is for the serve cmd | # Below is for the serve cmd | ||||
staticfile = "0.4" | staticfile = "0.4" | ||||
@@ -5,7 +5,6 @@ use std::time::Duration; | |||||
use std::thread; | use std::thread; | ||||
use iron::{Iron, Request, IronResult, Response, status}; | use iron::{Iron, Request, IronResult, Response, status}; | ||||
use iron::modifiers::Header; | |||||
use mount::Mount; | use mount::Mount; | ||||
use staticfile::Static; | use staticfile::Static; | ||||
use notify::{Watcher, RecursiveMode, watcher}; | use notify::{Watcher, RecursiveMode, watcher}; | ||||
@@ -17,7 +16,7 @@ use errors::{Result}; | |||||
const LIVE_RELOAD: &'static [u8; 37809] = include_bytes!("livereload.js"); | const LIVE_RELOAD: &'static [u8; 37809] = include_bytes!("livereload.js"); | ||||
fn livereload_handler(req: &mut Request) -> IronResult<Response> { | |||||
fn livereload_handler(_: &mut Request) -> IronResult<Response> { | |||||
Ok(Response::with((status::Ok, String::from_utf8(LIVE_RELOAD.to_vec()).unwrap()))) | Ok(Response::with((status::Ok, String::from_utf8(LIVE_RELOAD.to_vec()).unwrap()))) | ||||
} | } | ||||
@@ -3,6 +3,7 @@ use std::collections::HashMap; | |||||
use toml; | use toml; | ||||
use tera::Value; | use tera::Value; | ||||
use chrono::prelude::*; | |||||
use errors::{Result}; | use errors::{Result}; | ||||
@@ -67,6 +68,19 @@ impl FrontMatter { | |||||
Ok(f) | Ok(f) | ||||
} | } | ||||
pub fn parse_date(&self) -> Option<NaiveDateTime> { | |||||
match self.date { | |||||
Some(ref d) => { | |||||
if d.contains("T") { | |||||
DateTime::parse_from_rfc3339(d).ok().and_then(|s| Some(s.naive_local())) | |||||
} else { | |||||
NaiveDate::parse_from_str(d, "%Y-%m-%d").ok().and_then(|s| Some(s.and_hms(0,0,0))) | |||||
} | |||||
}, | |||||
None => None, | |||||
} | |||||
} | |||||
} | } | ||||
@@ -183,6 +197,7 @@ slug = """#; | |||||
let res = FrontMatter::parse(content); | let res = FrontMatter::parse(content); | ||||
assert!(res.is_err()); | assert!(res.is_err()); | ||||
} | } | ||||
#[test] | #[test] | ||||
fn test_errors_on_present_but_empty_url() { | fn test_errors_on_present_but_empty_url() { | ||||
let content = r#" | let content = r#" | ||||
@@ -192,4 +207,34 @@ url = """#; | |||||
let res = FrontMatter::parse(content); | let res = FrontMatter::parse(content); | ||||
assert!(res.is_err()); | assert!(res.is_err()); | ||||
} | } | ||||
#[test] | |||||
fn test_parse_date_yyyy_mm_dd() { | |||||
let content = r#" | |||||
title = "Hello" | |||||
description = "hey there" | |||||
date = "2016-10-10""#; | |||||
let res = FrontMatter::parse(content).unwrap(); | |||||
assert!(res.parse_date().is_some()); | |||||
} | |||||
#[test] | |||||
fn test_parse_date_rfc3339() { | |||||
let content = r#" | |||||
title = "Hello" | |||||
description = "hey there" | |||||
date = "2002-10-02T15:00:00Z""#; | |||||
let res = FrontMatter::parse(content).unwrap(); | |||||
assert!(res.parse_date().is_some()); | |||||
} | |||||
#[test] | |||||
fn test_cant_parse_random_date_format() { | |||||
let content = r#" | |||||
title = "Hello" | |||||
description = "hey there" | |||||
date = "2002/10/12""#; | |||||
let res = FrontMatter::parse(content).unwrap(); | |||||
assert!(res.parse_date().is_none()); | |||||
} | |||||
} | } |
@@ -15,6 +15,7 @@ extern crate tera; | |||||
extern crate glob; | extern crate glob; | ||||
extern crate syntect; | extern crate syntect; | ||||
extern crate slug; | extern crate slug; | ||||
extern crate chrono; | |||||
extern crate staticfile; | extern crate staticfile; | ||||
extern crate iron; | extern crate iron; | ||||
@@ -1,4 +1,5 @@ | |||||
/// A page, can be a blog post or a basic page | /// A page, can be a blog post or a basic page | ||||
use std::cmp::Ordering; | |||||
use std::fs::File; | use std::fs::File; | ||||
use std::io::prelude::*; | use std::io::prelude::*; | ||||
use std::path::Path; | use std::path::Path; | ||||
@@ -176,10 +177,30 @@ impl ser::Serialize for Page { | |||||
} | } | ||||
} | } | ||||
// Order pages by date, no-op for now | |||||
// TODO: impl PartialOrd on Vec<Page> so we can use sort()? | |||||
pub fn order_pages(pages: Vec<Page>) -> Vec<Page> { | |||||
pages | |||||
impl PartialOrd for Page { | |||||
fn partial_cmp(&self, other: &Page) -> Option<Ordering> { | |||||
if self.meta.date.is_none() { | |||||
println!("No self data"); | |||||
return Some(Ordering::Less); | |||||
} | |||||
if other.meta.date.is_none() { | |||||
println!("No other date"); | |||||
return Some(Ordering::Greater); | |||||
} | |||||
let this_date = self.meta.parse_date().unwrap(); | |||||
let other_date = other.meta.parse_date().unwrap(); | |||||
if this_date > other_date { | |||||
return Some(Ordering::Less); | |||||
} | |||||
if this_date < other_date { | |||||
return Some(Ordering::Greater); | |||||
} | |||||
Some(Ordering::Equal) | |||||
} | |||||
} | } | ||||
@@ -118,6 +118,7 @@ impl Site { | |||||
// And finally the index page | // And finally the index page | ||||
let mut context = Context::new(); | let mut context = Context::new(); | ||||
pages.sort_by(|a, b| a.partial_cmp(b).unwrap()); | |||||
context.add("pages", &pages); | context.add("pages", &pages); | ||||
context.add("config", &self.config); | context.add("config", &self.config); | ||||
let index = self.templates.render("index.html", &context)?; | let index = self.templates.render("index.html", &context)?; | ||||