diff options
author | Lars Wirzenius <liw@liw.fi> | 2022-08-05 06:36:14 +0300 |
---|---|---|
committer | Lars Wirzenius <liw@liw.fi> | 2022-08-05 14:08:53 +0300 |
commit | a855f665873d34d7797785fef0e88bf3e497af01 (patch) | |
tree | f9d6de02b882b27e5157f6ff8c646ca252132054 | |
parent | d6eabfc585e6dff203d7ee4795d7b0e19093fbb7 (diff) | |
download | riki-a855f665873d34d7797785fef0e88bf3e497af01.tar.gz |
feat: data type for names for files, pages in the site
A "Name" knows its source and destination file paths, and so on.
Sponsored-by: author
-rw-r--r-- | src/lib.rs | 1 | ||||
-rw-r--r-- | src/name.rs | 185 |
2 files changed, 186 insertions, 0 deletions
@@ -7,6 +7,7 @@ //! little slow. This care implements a subset of the functionality of //! ikiwiki in Rust, for speed. +pub mod name; pub mod directive; pub mod error; pub mod html; diff --git a/src/name.rs b/src/name.rs new file mode 100644 index 0000000..44328b1 --- /dev/null +++ b/src/name.rs @@ -0,0 +1,185 @@ +use crate::util::{join_subpath, make_path_absolute, make_path_relative_to}; +use std::fmt; +use std::path::{Path, PathBuf}; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Name { + is_wikitext: bool, + src: PathBuf, + dest: PathBuf, + page: PathBuf, + page_name: String, +} + +impl Name { + fn new(is_wikitext: bool, src: PathBuf, dest: PathBuf, page: PathBuf) -> Self { + Self { + is_wikitext, + src, + dest, + page: page.clone(), + page_name: page.to_string_lossy().into(), + } + } + + pub fn is_wikitext_page(&self) -> bool { + self.is_wikitext + } + + pub fn source_path(&self) -> &Path { + &self.src + } + + pub fn destination_path(&self) -> &Path { + &self.dest + } + + pub fn page_path(&self) -> &Path { + &self.page + } + + pub fn page_name(&self) -> &str { + &self.page_name + } +} + +impl PartialEq<Name> for &Name { + fn eq(&self, other: &Name) -> bool { + self.src == other.src + } +} + +impl fmt::Display for Name { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + write!(f, "{}", self.src.display()) + } +} + +pub struct NameBuilder { + srcdir: PathBuf, + destdir: PathBuf, +} + +impl NameBuilder { + pub fn new(srcdir: &Path, destdir: &Path) -> Self { + Self { + srcdir: srcdir.into(), + destdir: destdir.into(), + } + } + + fn name(&self, path: &Path, ext: Option<&str>) -> Name { + assert!(path.starts_with(&self.srcdir)); + let src = path.into(); + let relative = make_path_relative_to(&self.srcdir, path); + let dest = join_subpath(&self.destdir, &relative); + let page = make_path_absolute(&relative); + if let Some(ext) = ext { + Name::new(true, src, dest.with_extension(ext), page.with_extension("")) + } else { + Name::new(false, src, dest, page) + } + } + + pub fn page(&self, path: &Path) -> Name { + self.name(path, Some("html")) + } + + pub fn file(&self, path: &Path) -> Name { + self.name(path, None) + } +} + +#[derive(Default, Debug)] +pub struct Names { + names: Vec<Name>, +} + +impl Names { + pub fn insert(&mut self, name: Name) { + self.names.push(name); + } + + pub fn iter(&self) -> impl Iterator<Item = &Name> { + self.names.iter() + } + + pub fn source_paths(&self) -> impl Iterator<Item = &PathBuf> { + self.names.iter().map(|name| &name.src) + } + + pub fn pages(&self) -> impl Iterator<Item = &Name> { + self.names.iter().filter(|name| name.is_wikitext_page()) + } + + pub fn files(&self) -> impl Iterator<Item = &Name> { + self.names.iter().filter(|name| !name.is_wikitext_page()) + } + + pub fn get_source_path(&self, path: &Path) -> Option<&Name> { + self.names.iter().find(|name| name.src == path) + } + + pub fn get_page_path(&self, path: &Path) -> Option<&Name> { + self.names.iter().find(|name| name.page == path) + } +} + +#[cfg(test)] +mod test { + use super::{Name, NameBuilder, Names}; + use std::path::Path; + + fn builder() -> NameBuilder { + NameBuilder::new(Path::new("/src"), Path::new("/dest")) + } + + #[test] + fn builds_page_name() { + let name = builder().page(Path::new("/src/foo/bar.mdwn")); + assert_eq!(name.source_path(), Path::new("/src/foo/bar.mdwn")); + assert_eq!(name.destination_path(), Path::new("/dest/foo/bar.html")); + assert_eq!(name.page_path(), Path::new("/foo/bar")); + assert_eq!(name.page_name(), "/foo/bar"); + } + + #[test] + fn builds_file_name() { + let name = builder().file(Path::new("/src/foo/bar.jpg")); + assert_eq!(name.source_path(), Path::new("/src/foo/bar.jpg")); + assert_eq!(name.destination_path(), Path::new("/dest/foo/bar.jpg")); + assert_eq!(name.page_path(), Path::new("/foo/bar.jpg")); + assert_eq!(name.page_name(), "/foo/bar.jpg"); + } + + #[test] + fn names_is_empty_by_default() { + let names = Names::default(); + assert!(names.names.is_empty()); + } + + #[test] + fn names_remembers_inserted() { + let mut names = Names::default(); + let name = builder().page(Path::new("/src/foo/bar.mdwn")); + names.insert(name.clone()); + assert_eq!( + names.get_source_path(Path::new("/src/foo/bar.mdwn")), + Some(&name) + ); + assert_eq!(names.get_page_path(Path::new("/foo/bar")), Some(&name)); + } + + #[test] + fn names_remembers_inserted_pages_and_files() { + let mut names = Names::default(); + let page = builder().page(Path::new("/src/foo/bar.mdwn")); + let file = builder().file(Path::new("/src/foo/bar.jpg")); + names.insert(page.clone()); + names.insert(file.clone()); + let pages: Vec<&Name> = names.pages().collect(); + let files: Vec<&Name> = names.files().collect(); + assert_eq!(pages, vec![page],); + assert_eq!(files, vec![file],); + } +} |