Browse Source

Remove `order` and add `heavier`/`later`

This commit removes the option to sort by order and also removes
`page.next` and `page.previous` variables.  Instead, pages can be sorted
by two methods `date` and `weight`.  The Tera `reverse` filter will
reverse either of those sorts, so the old `order` behavior can be
achieved by using the `reverse` filter with `weight`.

In place of the `previous`/`next` variables, this commit adds the
`page.earlier`/`page.later` variables (which are set when the page is
sorted by date) and the `page.heavier`/`page.lighter` variables (which
are set when the page is sorted by weight).  These variables have the
advantage of not having confusing semantics when the `reverse` filter is
used.
index-subcmd
Daniel Sockwell 6 years ago
parent
commit
c2437cc0eb
14 changed files with 89 additions and 147 deletions
  1. +20
    -10
      components/content/src/page.rs
  2. +54
    -120
      components/content/src/sorting.rs
  3. +0
    -2
      components/front_matter/src/lib.rs
  4. +5
    -5
      components/rebuild/tests/rebuild.rs
  5. +1
    -1
      components/site/src/lib.rs
  6. +1
    -1
      test_site/content/posts/tutorials/devops/_index.md
  7. +1
    -1
      test_site/content/posts/tutorials/devops/docker.md
  8. +1
    -1
      test_site/content/posts/tutorials/devops/nix.md
  9. +1
    -1
      test_site/content/posts/tutorials/programming/_index.md
  10. +1
    -1
      test_site/content/posts/tutorials/programming/python.md
  11. +1
    -1
      test_site/content/posts/tutorials/programming/rust.md
  12. +1
    -1
      test_site/content/rebuild/_index.md
  13. +1
    -1
      test_site/content/rebuild/first.md
  14. +1
    -1
      test_site/content/rebuild/second.md

+ 20
- 10
components/content/src/page.rs View File

@@ -44,10 +44,14 @@ pub struct Page {
/// When <!-- more --> is found in the text, will take the content up to that part /// When <!-- more --> is found in the text, will take the content up to that part
/// as summary /// as summary
pub summary: Option<String>, pub summary: Option<String>,
/// The previous page, by whatever sorting is used for the index/section
pub previous: Option<Box<Page>>,
/// The next page, by whatever sorting is used for the index/section
pub next: Option<Box<Page>>,
/// The earlier page, for pages sorted by date
pub earlier: Option<Box<Page>>,
/// The later page, for pages sorted by date
pub later: Option<Box<Page>>,
/// The lighter page, for pages sorted by weight
pub lighter: Option<Box<Page>>,
/// The heavier page, for pages sorted by weight
pub heavier: Option<Box<Page>>,
/// Toc made from the headers of the markdown file /// Toc made from the headers of the markdown file
pub toc: Vec<Header>, pub toc: Vec<Header>,
} }
@@ -68,8 +72,10 @@ impl Page {
components: vec![], components: vec![],
permalink: "".to_string(), permalink: "".to_string(),
summary: None, summary: None,
previous: None,
next: None,
earlier: None,
later: None,
lighter: None,
heavier: None,
toc: vec![], toc: vec![],
} }
} }
@@ -229,8 +235,10 @@ impl Default for Page {
components: vec![], components: vec![],
permalink: "".to_string(), permalink: "".to_string(),
summary: None, summary: None,
previous: None,
next: None,
earlier: None,
later: None,
lighter: None,
heavier: None,
toc: vec![], toc: vec![],
} }
} }
@@ -263,8 +271,10 @@ impl ser::Serialize for Page {
let (word_count, reading_time) = get_reading_analytics(&self.raw_content); let (word_count, reading_time) = get_reading_analytics(&self.raw_content);
state.serialize_field("word_count", &word_count)?; state.serialize_field("word_count", &word_count)?;
state.serialize_field("reading_time", &reading_time)?; state.serialize_field("reading_time", &reading_time)?;
state.serialize_field("previous", &self.previous)?;
state.serialize_field("next", &self.next)?;
state.serialize_field("earlier", &self.earlier)?;
state.serialize_field("later", &self.later)?;
state.serialize_field("lighter", &self.lighter)?;
state.serialize_field("heavier", &self.heavier)?;
state.serialize_field("toc", &self.toc)?; state.serialize_field("toc", &self.toc)?;
state.serialize_field("draft", &self.is_draft())?; state.serialize_field("draft", &self.is_draft())?;
let assets = self.serialize_assets(); let assets = self.serialize_assets();


+ 54
- 120
components/content/src/sorting.rs View File

@@ -7,7 +7,7 @@ use front_matter::SortBy;


/// Sort pages by the given criteria /// Sort pages by the given criteria
/// ///
/// Any pages that doesn't have a the required field when the sorting method is other than none
/// Any pages that doesn't have a required field when the sorting method is other than none
/// will be ignored. /// will be ignored.
pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) { pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
if sort_by == SortBy::None { if sort_by == SortBy::None {
@@ -19,7 +19,6 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
.partition(|page| { .partition(|page| {
match sort_by { match sort_by {
SortBy::Date => page.meta.date.is_some(), SortBy::Date => page.meta.date.is_some(),
SortBy::Order => page.meta.order.is_some(),
SortBy::Weight => page.meta.weight.is_some(), SortBy::Weight => page.meta.weight.is_some(),
_ => unreachable!() _ => unreachable!()
} }
@@ -36,16 +35,6 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {
} }
}) })
}, },
SortBy::Order => {
can_be_sorted.par_sort_unstable_by(|a, b| {
let ord = b.meta.order().cmp(&a.meta.order());
if ord == Ordering::Equal {
a.permalink.cmp(&b.permalink)
} else {
ord
}
})
},
SortBy::Weight => { SortBy::Weight => {
can_be_sorted.par_sort_unstable_by(|a, b| { can_be_sorted.par_sort_unstable_by(|a, b| {
let ord = a.meta.weight().cmp(&b.meta.weight()); let ord = a.meta.weight().cmp(&b.meta.weight());
@@ -64,7 +53,7 @@ pub fn sort_pages(pages: Vec<Page>, sort_by: SortBy) -> (Vec<Page>, Vec<Page>) {


/// Horribly inefficient way to set previous and next on each pages that skips drafts /// Horribly inefficient way to set previous and next on each pages that skips drafts
/// So many clones /// So many clones
pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec<Page> {
pub fn populate_previous_and_next_pages(input: &[Page], sort_by: SortBy) -> Vec<Page> {
let mut res = Vec::with_capacity(input.len()); let mut res = Vec::with_capacity(input.len());


// The input is already sorted // The input is already sorted
@@ -91,9 +80,21 @@ pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec<Page> {


// Remove prev/next otherwise we serialise the whole thing... // Remove prev/next otherwise we serialise the whole thing...
let mut next_page = input[j].clone(); let mut next_page = input[j].clone();
next_page.previous = None;
next_page.next = None;
new_page.next = Some(Box::new(next_page));

match sort_by {
SortBy::Weight => {
next_page.lighter = None;
next_page.heavier = None;
new_page.lighter = Some(Box::new(next_page));
},
SortBy::Date => {
next_page.earlier = None;
next_page.later = None;
new_page.later = Some(Box::new(next_page));
},
SortBy::None => {
}
}
break; break;
} }
} }
@@ -113,9 +114,20 @@ pub fn populate_previous_and_next_pages(input: &[Page]) -> Vec<Page> {


// Remove prev/next otherwise we serialise the whole thing... // Remove prev/next otherwise we serialise the whole thing...
let mut previous_page = input[j].clone(); let mut previous_page = input[j].clone();
previous_page.previous = None;
previous_page.next = None;
new_page.previous = Some(Box::new(previous_page));
match sort_by {
SortBy::Weight => {
previous_page.lighter = None;
previous_page.heavier = None;
new_page.heavier = Some(Box::new(previous_page));
},
SortBy::Date => {
previous_page.earlier = None;
previous_page.later = None;
new_page.earlier = Some(Box::new(previous_page));
},
SortBy::None => {
}
}
break; break;
} }
} }
@@ -137,22 +149,6 @@ mod tests {
Page::new("content/hello.md", front_matter) Page::new("content/hello.md", front_matter)
} }


fn create_page_with_order(order: usize, filename: &str) -> Page {
let mut front_matter = PageFrontMatter::default();
front_matter.order = Some(order);
let mut p = Page::new("content/".to_string() + filename, front_matter);
// Faking a permalink to test sorting with equal order
p.permalink = filename.to_string();
p
}

fn create_draft_page_with_order(order: usize) -> Page {
let mut front_matter = PageFrontMatter::default();
front_matter.order = Some(order);
front_matter.draft = true;
Page::new("content/hello.md", front_matter)
}

fn create_page_with_weight(weight: usize) -> Page { fn create_page_with_weight(weight: usize) -> Page {
let mut front_matter = PageFrontMatter::default(); let mut front_matter = PageFrontMatter::default();
front_matter.weight = Some(weight); front_matter.weight = Some(weight);
@@ -173,37 +169,6 @@ mod tests {
assert_eq!(pages[2].clone().meta.date.unwrap().to_string(), "2017-01-01"); assert_eq!(pages[2].clone().meta.date.unwrap().to_string(), "2017-01-01");
} }


#[test]
fn can_sort_by_order() {
let input = vec![
create_page_with_order(2, "hello.md"),
create_page_with_order(3, "hello2.md"),
create_page_with_order(1, "hello3.md"),
];
let (pages, _) = sort_pages(input, SortBy::Order);
// Should be sorted by order
assert_eq!(pages[0].clone().meta.order.unwrap(), 3);
assert_eq!(pages[1].clone().meta.order.unwrap(), 2);
assert_eq!(pages[2].clone().meta.order.unwrap(), 1);
}

#[test]
fn can_sort_by_order_uses_permalink_to_break_ties() {
let input = vec![
create_page_with_order(3, "b.md"),
create_page_with_order(3, "a.md"),
create_page_with_order(3, "c.md"),
];
let (pages, _) = sort_pages(input, SortBy::Order);
// Should be sorted by order
assert_eq!(pages[0].clone().meta.order.unwrap(), 3);
assert_eq!(pages[0].clone().permalink, "a.md");
assert_eq!(pages[1].clone().meta.order.unwrap(), 3);
assert_eq!(pages[1].clone().permalink, "b.md");
assert_eq!(pages[2].clone().meta.order.unwrap(), 3);
assert_eq!(pages[2].clone().permalink, "c.md");
}

#[test] #[test]
fn can_sort_by_weight() { fn can_sort_by_weight() {
let input = vec![ let input = vec![
@@ -221,25 +186,25 @@ mod tests {
#[test] #[test]
fn can_sort_by_none() { fn can_sort_by_none() {
let input = vec![ let input = vec![
create_page_with_order(2, "a.md"),
create_page_with_order(3, "a.md"),
create_page_with_order(1, "a.md"),
create_page_with_weight(2),
create_page_with_weight(3),
create_page_with_weight(1),
]; ];
let (pages, _) = sort_pages(input, SortBy::None); let (pages, _) = sort_pages(input, SortBy::None);
// Should be sorted by date // Should be sorted by date
assert_eq!(pages[0].clone().meta.order.unwrap(), 2);
assert_eq!(pages[1].clone().meta.order.unwrap(), 3);
assert_eq!(pages[2].clone().meta.order.unwrap(), 1);
assert_eq!(pages[0].clone().meta.weight.unwrap(), 2);
assert_eq!(pages[1].clone().meta.weight.unwrap(), 3);
assert_eq!(pages[2].clone().meta.weight.unwrap(), 1);
} }


#[test] #[test]
fn ignore_page_with_missing_field() { fn ignore_page_with_missing_field() {
let input = vec![ let input = vec![
create_page_with_order(2, "a.md"),
create_page_with_order(3, "a.md"),
create_page_with_weight(2),
create_page_with_weight(3),
create_page_with_date("2019-01-01"), create_page_with_date("2019-01-01"),
]; ];
let (pages, unsorted) = sort_pages(input, SortBy::Order);
let (pages, unsorted) = sort_pages(input, SortBy::Weight);
assert_eq!(pages.len(), 2); assert_eq!(pages.len(), 2);
assert_eq!(unsorted.len(), 1); assert_eq!(unsorted.len(), 1);
} }
@@ -247,54 +212,23 @@ mod tests {
#[test] #[test]
fn can_populate_previous_and_next_pages() { fn can_populate_previous_and_next_pages() {
let input = vec![ let input = vec![
create_page_with_order(1, "a.md"),
create_page_with_order(2, "b.md"),
create_page_with_order(3, "a.md"),
];
let pages = populate_previous_and_next_pages(&input);

assert!(pages[0].clone().next.is_none());
assert!(pages[0].clone().previous.is_some());
assert_eq!(pages[0].clone().previous.unwrap().meta.order.unwrap(), 2);

assert!(pages[1].clone().next.is_some());
assert!(pages[1].clone().previous.is_some());
assert_eq!(pages[1].clone().previous.unwrap().meta.order.unwrap(), 3);
assert_eq!(pages[1].clone().next.unwrap().meta.order.unwrap(), 1);

assert!(pages[2].clone().next.is_some());
assert!(pages[2].clone().previous.is_none());
assert_eq!(pages[2].clone().next.unwrap().meta.order.unwrap(), 2);
}

#[test]
fn can_populate_previous_and_next_pages_skip_drafts() {
let input = vec![
create_draft_page_with_order(0),
create_page_with_order(1, "a.md"),
create_page_with_order(2, "b.md"),
create_page_with_order(3, "c.md"),
create_draft_page_with_order(4),
create_page_with_weight(1),
create_page_with_weight(2),
create_page_with_weight(3),
]; ];
let pages = populate_previous_and_next_pages(&input);

assert!(pages[0].clone().next.is_none());
assert!(pages[0].clone().previous.is_none());

assert!(pages[1].clone().next.is_none());
assert!(pages[1].clone().previous.is_some());
assert_eq!(pages[1].clone().previous.unwrap().meta.order.unwrap(), 2);
let pages = populate_previous_and_next_pages(&input, SortBy::Weight);


assert!(pages[2].clone().next.is_some());
assert!(pages[2].clone().previous.is_some());
assert_eq!(pages[2].clone().previous.unwrap().meta.order.unwrap(), 3);
assert_eq!(pages[2].clone().next.unwrap().meta.order.unwrap(), 1);
assert!(pages[0].clone().lighter.is_none());
assert!(pages[0].clone().heavier.is_some());
assert_eq!(pages[0].clone().heavier.unwrap().meta.weight.unwrap(), 2);


assert!(pages[3].clone().next.is_some());
assert!(pages[3].clone().previous.is_none());
assert_eq!(pages[3].clone().next.unwrap().meta.order.unwrap(), 2);
assert!(pages[1].clone().heavier.is_some());
assert!(pages[1].clone().lighter.is_some());
assert_eq!(pages[1].clone().lighter.unwrap().meta.weight.unwrap(), 1);
assert_eq!(pages[1].clone().heavier.unwrap().meta.weight.unwrap(), 3);


assert!(pages[4].clone().next.is_none());
assert!(pages[4].clone().previous.is_none());
assert!(pages[2].clone().lighter.is_some());
assert!(pages[2].clone().heavier.is_none());
assert_eq!(pages[2].clone().lighter.unwrap().meta.weight.unwrap(), 2);
} }
} }

+ 0
- 2
components/front_matter/src/lib.rs View File

@@ -30,8 +30,6 @@ lazy_static! {
pub enum SortBy { pub enum SortBy {
/// Most recent to oldest /// Most recent to oldest
Date, Date,
/// Lower order comes last
Order,
/// Lower weight comes first /// Lower weight comes first
Weight, Weight,
/// No sorting /// No sorting


+ 5
- 5
components/rebuild/tests/rebuild.rs View File

@@ -2,7 +2,7 @@ extern crate rebuild;
extern crate site; extern crate site;
extern crate tempfile; extern crate tempfile;
extern crate fs_extra; extern crate fs_extra;
use std::env; use std::env;
use std::fs::{remove_dir_all, File}; use std::fs::{remove_dir_all, File};
use std::io::prelude::*; use std::io::prelude::*;
@@ -79,7 +79,7 @@ fn can_rebuild_after_simple_change_to_page_content() {
let file_path = edit_file!(site_path, "content/rebuild/first.md", br#" let file_path = edit_file!(site_path, "content/rebuild/first.md", br#"
+++ +++
title = "first" title = "first"
order = 1
weight = 1
date = 2017-01-01 date = 2017-01-01
+++ +++


@@ -97,7 +97,7 @@ fn can_rebuild_after_title_change_page_global_func_usage() {
let file_path = edit_file!(site_path, "content/rebuild/first.md", br#" let file_path = edit_file!(site_path, "content/rebuild/first.md", br#"
+++ +++
title = "Premier" title = "Premier"
order = 10
weight = 10
date = 2017-01-01 date = 2017-01-01
+++ +++


@@ -115,12 +115,12 @@ fn can_rebuild_after_sort_change_in_section() {
let file_path = edit_file!(site_path, "content/rebuild/_index.md", br#" let file_path = edit_file!(site_path, "content/rebuild/_index.md", br#"
+++ +++
paginate_by = 1 paginate_by = 1
sort_by = "order"
sort_by = "weight"
template = "rebuild.html" template = "rebuild.html"
+++ +++
"#); "#);


let res = after_content_change(&mut site, &file_path); let res = after_content_change(&mut site, &file_path);
assert!(res.is_ok()); assert!(res.is_ok());
assert!(file_contains!(site_path, "public/rebuild/index.html", "<h1>second</h1><h1>first</h1>"));
assert!(file_contains!(site_path, "public/rebuild/index.html", "<h1>first</h1><h1>second</h1>"));
} }

+ 1
- 1
components/site/src/lib.rs View File

@@ -401,7 +401,7 @@ impl Site {
} }
let pages = mem::replace(&mut section.pages, vec![]); let pages = mem::replace(&mut section.pages, vec![]);
let (sorted_pages, cannot_be_sorted_pages) = sort_pages(pages, section.meta.sort_by); let (sorted_pages, cannot_be_sorted_pages) = sort_pages(pages, section.meta.sort_by);
section.pages = populate_previous_and_next_pages(&sorted_pages);
section.pages = populate_previous_and_next_pages(&sorted_pages, section.meta.sort_by);
section.ignored_pages = cannot_be_sorted_pages; section.ignored_pages = cannot_be_sorted_pages;
} }
} }


+ 1
- 1
test_site/content/posts/tutorials/devops/_index.md View File

@@ -1,6 +1,6 @@
+++ +++
title = "DevOps" title = "DevOps"
sort_by = "order"
sort_by = "weight"
redirect_to = "posts/tutorials/devops/docker" redirect_to = "posts/tutorials/devops/docker"
weight = 10 weight = 10
+++ +++

+ 1
- 1
test_site/content/posts/tutorials/devops/docker.md View File

@@ -1,6 +1,6 @@
+++ +++
title = "Docker" title = "Docker"
order = 1
weight = 1
date = 2017-01-01 date = 2017-01-01
+++ +++




+ 1
- 1
test_site/content/posts/tutorials/devops/nix.md View File

@@ -1,6 +1,6 @@
+++ +++
title = "Nix" title = "Nix"
order = 2
weight = 2
date = 2017-01-01 date = 2017-01-01
+++ +++




+ 1
- 1
test_site/content/posts/tutorials/programming/_index.md View File

@@ -1,5 +1,5 @@
+++ +++
title = "Programming" title = "Programming"
sort_by = "order"
sort_by = "weight"
weight = 1 weight = 1
+++ +++

+ 1
- 1
test_site/content/posts/tutorials/programming/python.md View File

@@ -1,6 +1,6 @@
+++ +++
title = "Python tutorial" title = "Python tutorial"
order = 1
weight = 1
date = 2017-01-01 date = 2017-01-01
+++ +++




+ 1
- 1
test_site/content/posts/tutorials/programming/rust.md View File

@@ -1,6 +1,6 @@
+++ +++
title = "Rust" title = "Rust"
order = 2
weight = 2
date = 2017-01-01 date = 2017-01-01
+++ +++




+ 1
- 1
test_site/content/rebuild/_index.md View File

@@ -1,5 +1,5 @@
+++ +++
paginate_by = 1 paginate_by = 1
sort_by = "order"
sort_by = "weight"
template = "rebuild.html" template = "rebuild.html"
+++ +++

+ 1
- 1
test_site/content/rebuild/first.md View File

@@ -1,6 +1,6 @@
+++ +++
title = "first" title = "first"
order = 10
weight = 10
date = 2017-01-01 date = 2017-01-01
+++ +++




+ 1
- 1
test_site/content/rebuild/second.md View File

@@ -1,6 +1,6 @@
+++ +++
title = "second" title = "second"
order = 100
weight = 100
date = 2016-01-01 date = 2016-01-01
+++ +++




Loading…
Cancel
Save