From db4def63dccc1b87b2ca6d4c54dcef6aa9b6593e Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Thu, 25 Oct 2018 16:22:00 +0200 Subject: [PATCH] Set date from filename Fix #396 --- CHANGELOG.md | 1 + Cargo.lock | 2 + components/library/Cargo.toml | 2 + components/library/src/content/page.rs | 59 +++++++++++++++++++++- components/library/src/lib.rs | 3 ++ docs/content/documentation/content/page.md | 5 ++ 6 files changed, 70 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d769038c..c5065695 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ sections up to the index to be used with the `get_section` Tera function - `serve` will now try to find other ports than 1111 rather than panicking - Ensure content directory exists before rendering aliases - Do not include drafts in pagination +- Pages filenames starting by a date will now use that date as page date if there isn't one defined in frontmatter ## 0.4.2 (2018-09-03) diff --git a/Cargo.lock b/Cargo.lock index c416b57d..0c7231f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1080,7 +1080,9 @@ dependencies = [ "errors 0.1.0", "front_matter 0.1.0", "globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "rendering 0.1.0", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/library/Cargo.toml b/components/library/Cargo.toml index 68f2b1e7..1391189b 100644 --- a/components/library/Cargo.toml +++ b/components/library/Cargo.toml @@ -11,6 +11,8 @@ tera = "0.11" serde = "1" serde_derive = "1" slug = "0.1" +regex = "1" +lazy_static = "1" front_matter = { path = "../front_matter" } config = { path = "../config" } diff --git a/components/library/src/content/page.rs b/components/library/src/content/page.rs index 6bc5564c..831f3aae 100644 --- a/components/library/src/content/page.rs +++ b/components/library/src/content/page.rs @@ -5,6 +5,7 @@ use std::path::{Path, PathBuf}; use tera::{Tera, Context as TeraContext}; use slug::slugify; use slotmap::{Key}; +use regex::Regex; use errors::{Result, ResultExt}; use config::Config; @@ -18,6 +19,11 @@ use library::Library; use content::file_info::FileInfo; use content::ser::SerializingPage; +lazy_static! { + // Check whether a string starts with yyyy-mm-dd{-,_} + static ref DATE_IN_FILENAME: Regex = Regex::new(r"^^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))(_|-)").unwrap(); +} + #[derive(Clone, Debug, PartialEq)] pub struct Page { @@ -103,10 +109,20 @@ impl Page { pub fn parse(file_path: &Path, content: &str, config: &Config) -> Result { let (meta, content) = split_page_content(file_path, content)?; let mut page = Page::new(file_path, meta); + page.raw_content = content; let (word_count, reading_time) = get_reading_analytics(&page.raw_content); page.word_count = Some(word_count); page.reading_time = Some(reading_time); + + let mut has_date_in_name = false; + if DATE_IN_FILENAME.is_match(&page.file.name) { + has_date_in_name = true; + if page.meta.date.is_none() { + page.meta.date = Some(page.file.name[..10].to_string()); + } + } + page.slug = { if let Some(ref slug) = page.meta.slug { slug.trim().to_string() @@ -114,10 +130,15 @@ impl Page { if let Some(parent) = page.file.path.parent() { slugify(parent.file_name().unwrap().to_str().unwrap()) } else { - slugify(page.file.name.clone()) + slugify(&page.file.name) } } else { - slugify(page.file.name.clone()) + if has_date_in_name { + // skip the date + the {_,-} + slugify(&page.file.name[11..]) + } else { + slugify(&page.file.name) + } } }; @@ -499,4 +520,38 @@ Hello world assert_eq!(page.assets.len(), 1); assert_eq!(page.assets[0].file_name().unwrap().to_str(), Some("graph.jpg")); } + + #[test] + fn can_get_date_from_filename() { + let config = Config::default(); + let content = r#" ++++ ++++ +Hello world +"#.to_string(); + let res = Page::parse(Path::new("2018-10-08_hello.md"), &content, &config); + assert!(res.is_ok()); + let page = res.unwrap(); + + assert_eq!(page.meta.date, Some("2018-10-08".to_string())); + assert_eq!(page.slug, "hello"); + } + + #[test] + fn frontmatter_date_override_filename_date() { + + let config = Config::default(); + let content = r#" ++++ +date = 2018-09-09 ++++ +Hello world +"#.to_string(); + let res = Page::parse(Path::new("2018-10-08_hello.md"), &content, &config); + assert!(res.is_ok()); + let page = res.unwrap(); + + assert_eq!(page.meta.date, Some("2018-09-09".to_string())); + assert_eq!(page.slug, "hello"); + } } diff --git a/components/library/src/lib.rs b/components/library/src/lib.rs index 3594d0cb..7a0e3284 100644 --- a/components/library/src/lib.rs +++ b/components/library/src/lib.rs @@ -6,6 +6,9 @@ extern crate serde_derive; extern crate chrono; extern crate slotmap; extern crate rayon; +#[macro_use] +extern crate lazy_static; +extern crate regex; #[cfg(test)] extern crate tempfile; diff --git a/docs/content/documentation/content/page.md b/docs/content/documentation/content/page.md index 274e7760..a1c7bd88 100644 --- a/docs/content/documentation/content/page.md +++ b/docs/content/documentation/content/page.md @@ -16,6 +16,10 @@ create a **page** at `[base_url]/about`). If the file is given any name *other* than `index.md` or `_index.md`, then it will create a page with that name (without the `.md`). So naming a file in the root of your content directory `about.md` would also create a page at `[base_url]/about`. +Another exception to that rule is that a filename starting with a YYYY-mm-dd date followed by +an underscore (`_`) or a dash (`-`) will use that date as the page date, unless already set +in the front-matter. The page name will be anything after `_`/`-` so a filename like `2018-10-10-hello-world.md` will +be available at `[base_url]/hello-world` As you can see, creating an `about.md` file is exactly equivalent to creating an `about/index.md` file. The only difference between the two methods is that creating @@ -42,6 +46,7 @@ description = "" # Do not wrap dates in quotes, the line below only indicates that there is no default date. # If the section variable `sort_by` is set to `date`, then any page that lacks a `date` # will not be rendered. +# Setting this overrides a date set in the filename. date = # The weight as defined in the Section page