Parse date only once for pages

This commit is contained in:
Vincent Prouillet 2018-09-21 09:40:52 +02:00
parent 69dce561c8
commit 9461769bcc
5 changed files with 32 additions and 14 deletions

1
Cargo.lock generated
View file

@ -250,6 +250,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View file

@ -8,7 +8,7 @@ tera = "0.11"
serde = "1" serde = "1"
slug = "0.1" slug = "0.1"
rayon = "1" rayon = "1"
chrono = "0.4" chrono = { version = "0.4", features = ["serde"] }
errors = { path = "../errors" } errors = { path = "../errors" }
config = { path = "../config" } config = { path = "../config" }

View file

@ -3,7 +3,6 @@ use std::collections::HashMap;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::result::Result as StdResult; use std::result::Result as StdResult;
use chrono::Datelike;
use tera::{Tera, Context as TeraContext}; use tera::{Tera, Context as TeraContext};
use serde::ser::{SerializeStruct, self}; use serde::ser::{SerializeStruct, self};
use slug::slugify; use slug::slugify;
@ -263,11 +262,10 @@ impl ser::Serialize for Page {
state.serialize_field("title", &self.meta.title)?; state.serialize_field("title", &self.meta.title)?;
state.serialize_field("description", &self.meta.description)?; state.serialize_field("description", &self.meta.description)?;
state.serialize_field("date", &self.meta.date)?; state.serialize_field("date", &self.meta.date)?;
if let Some(chrono_datetime) = self.meta.date() { if let Some(d) = self.meta.datetime_tuple {
let d = chrono_datetime.date(); state.serialize_field("year", &d.0)?;
state.serialize_field("year", &d.year())?; state.serialize_field("month", &d.1)?;
state.serialize_field("month", &d.month())?; state.serialize_field("day", &d.2)?;
state.serialize_field("day", &d.day())?;
} else { } else {
state.serialize_field::<Option<usize>>("year", &None)?; state.serialize_field::<Option<usize>>("year", &None)?;
state.serialize_field::<Option<usize>>("month", &None)?; state.serialize_field::<Option<usize>>("month", &None)?;

View file

@ -11,7 +11,7 @@ use front_matter::SortBy;
/// To remove if `sort_pages` is changed to work on borrowed values /// To remove if `sort_pages` is changed to work on borrowed values
/// This cannot be used in `sort_pages` currently as it takes &&Page instead of &Page /// This cannot be used in `sort_pages` currently as it takes &&Page instead of &Page
pub fn sort_pages_by_date(a: &&Page, b: &&Page) -> Ordering { pub fn sort_pages_by_date(a: &&Page, b: &&Page) -> Ordering {
let ord = b.meta.date().unwrap().cmp(&a.meta.date().unwrap()); let ord = b.meta.datetime.unwrap().cmp(&a.meta.datetime.unwrap());
if ord == Ordering::Equal { if ord == Ordering::Equal {
a.permalink.cmp(&b.permalink) a.permalink.cmp(&b.permalink)
} else { } else {
@ -33,7 +33,7 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
.into_par_iter() .into_par_iter()
.partition(|page| { .partition(|page| {
match sort_by { match sort_by {
SortBy::Date => page.meta.date.is_some(), SortBy::Date => page.meta.datetime.is_some(),
SortBy::Weight => page.meta.weight.is_some(), SortBy::Weight => page.meta.weight.is_some(),
_ => unreachable!() _ => unreachable!()
} }
@ -42,7 +42,7 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
match sort_by { match sort_by {
SortBy::Date => { SortBy::Date => {
can_be_sorted.par_sort_unstable_by(|a, b| { can_be_sorted.par_sort_unstable_by(|a, b| {
let ord = b.meta.date().unwrap().cmp(&a.meta.date().unwrap()); let ord = b.meta.datetime.unwrap().cmp(&a.meta.datetime.unwrap());
if ord == Ordering::Equal { if ord == Ordering::Equal {
a.permalink.cmp(&b.permalink) a.permalink.cmp(&b.permalink)
} else { } else {
@ -159,6 +159,7 @@ mod tests {
fn create_page_with_date(date: &str) -> Page { fn create_page_with_date(date: &str) -> Page {
let mut front_matter = PageFrontMatter::default(); let mut front_matter = PageFrontMatter::default();
front_matter.date = Some(date.to_string()); front_matter.date = Some(date.to_string());
front_matter.date_to_datetime();
Page::new("content/hello.md", front_matter) Page::new("content/hello.md", front_matter)
} }

View file

@ -62,7 +62,7 @@ fn fix_toml_dates(table: Map<String, Value>) -> Value {
/// The front matter of every page /// The front matter of every page
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(default)] #[serde(default)]
pub struct PageFrontMatter { pub struct PageFrontMatter {
/// <title> of the page /// <title> of the page
@ -72,6 +72,12 @@ pub struct PageFrontMatter {
/// Date if we want to order pages (ie blog post) /// Date if we want to order pages (ie blog post)
#[serde(default, deserialize_with = "from_toml_datetime")] #[serde(default, deserialize_with = "from_toml_datetime")]
pub date: Option<String>, pub date: Option<String>,
/// Chrono converted datetime
#[serde(default, skip_deserializing)]
pub datetime: Option<NaiveDateTime>,
/// The converted date into a (year, month, day) tuple
#[serde(default, skip_deserializing)]
pub datetime_tuple: Option<(i32, u32, u32)>,
/// Whether this page is a draft and should be ignored for pagination etc /// Whether this page is a draft and should be ignored for pagination etc
pub draft: bool, pub draft: bool,
/// The page slug. Will be used instead of the filename if present /// The page slug. Will be used instead of the filename if present
@ -124,12 +130,16 @@ impl PageFrontMatter {
Value::Object(o) => o, Value::Object(o) => o,
_ => unreachable!("Got something other than a table in page extra"), _ => unreachable!("Got something other than a table in page extra"),
}; };
f.date_to_datetime();
Ok(f) Ok(f)
} }
/// Converts the TOML datetime to a Chrono naive datetime /// Converts the TOML datetime to a Chrono naive datetime
pub fn date(&self) -> Option<NaiveDateTime> { /// Also grabs the year/month/day tuple that will be used in serialization
if let Some(ref d) = self.date { pub fn date_to_datetime(&mut self) {
self.datetime = if let Some(ref d) = self.date {
if d.contains('T') { if d.contains('T') {
DateTime::parse_from_rfc3339(&d).ok().and_then(|s| Some(s.naive_local())) DateTime::parse_from_rfc3339(&d).ok().and_then(|s| Some(s.naive_local()))
} else { } else {
@ -137,7 +147,13 @@ impl PageFrontMatter {
} }
} else { } else {
None None
} };
self.datetime_tuple = if let Some(ref dt) = self.datetime {
Some((dt.year(), dt.month(), dt.day()))
} else {
None
};
} }
pub fn order(&self) -> usize { pub fn order(&self) -> usize {
@ -155,6 +171,8 @@ impl Default for PageFrontMatter {
title: None, title: None,
description: None, description: None,
date: None, date: None,
datetime: None,
datetime_tuple: None,
draft: false, draft: false,
slug: None, slug: None,
path: None, path: None,