2017-05-15 03:23:19 +00:00
|
|
|
use std::fs::read_dir;
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
|
|
|
|
/// Looks into the current folder for the path and see if there's anything that is not a .md
|
|
|
|
/// file. Those will be copied next to the rendered .html file
|
|
|
|
pub fn find_related_assets(path: &Path) -> Vec<PathBuf> {
|
|
|
|
let mut assets = vec![];
|
|
|
|
|
|
|
|
for entry in read_dir(path).unwrap().filter_map(|e| e.ok()) {
|
|
|
|
let entry_path = entry.path();
|
|
|
|
if entry_path.is_file() {
|
|
|
|
match entry_path.extension() {
|
|
|
|
Some(e) => match e.to_str() {
|
|
|
|
Some("md") => continue,
|
|
|
|
_ => assets.push(entry_path.to_path_buf()),
|
|
|
|
},
|
|
|
|
None => continue,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assets
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get word count and estimated reading time
|
|
|
|
pub fn get_reading_analytics(content: &str) -> (usize, usize) {
|
|
|
|
// Only works for latin language but good enough for a start
|
|
|
|
let word_count: usize = content.split_whitespace().count();
|
|
|
|
|
|
|
|
// https://help.medium.com/hc/en-us/articles/214991667-Read-time
|
|
|
|
// 275 seems a bit too high though
|
|
|
|
(word_count, (word_count / 200))
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-05-15 07:26:11 +00:00
|
|
|
/// Takes a full path to a .md and returns only the components after the first `content` directory
|
|
|
|
/// Will not return the filename as last component
|
|
|
|
pub fn find_content_components<P: AsRef<Path>>(path: P) -> Vec<String> {
|
|
|
|
let path = path.as_ref();
|
|
|
|
let mut is_in_content = false;
|
|
|
|
let mut components = vec![];
|
|
|
|
|
|
|
|
for section in path.parent().unwrap().components() {
|
|
|
|
let component = section.as_ref().to_string_lossy();
|
|
|
|
|
|
|
|
if is_in_content {
|
|
|
|
components.push(component.to_string());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if component == "content" {
|
|
|
|
is_in_content = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
components
|
|
|
|
}
|
|
|
|
|
2017-05-15 03:23:19 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use std::fs::File;
|
|
|
|
|
|
|
|
use tempdir::TempDir;
|
|
|
|
|
2017-05-15 07:26:11 +00:00
|
|
|
use super::{find_related_assets, find_content_components, get_reading_analytics};
|
2017-05-15 03:23:19 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn can_find_related_assets() {
|
|
|
|
let tmp_dir = TempDir::new("example").expect("create temp dir");
|
|
|
|
File::create(tmp_dir.path().join("index.md")).unwrap();
|
|
|
|
File::create(tmp_dir.path().join("example.js")).unwrap();
|
|
|
|
File::create(tmp_dir.path().join("graph.jpg")).unwrap();
|
|
|
|
File::create(tmp_dir.path().join("fail.png")).unwrap();
|
|
|
|
|
|
|
|
let assets = find_related_assets(tmp_dir.path());
|
|
|
|
assert_eq!(assets.len(), 3);
|
|
|
|
assert_eq!(assets.iter().filter(|p| p.extension().unwrap() != "md").count(), 3);
|
|
|
|
assert_eq!(assets.iter().filter(|p| p.file_name().unwrap() == "example.js").count(), 1);
|
|
|
|
assert_eq!(assets.iter().filter(|p| p.file_name().unwrap() == "graph.jpg").count(), 1);
|
|
|
|
assert_eq!(assets.iter().filter(|p| p.file_name().unwrap() == "fail.png").count(), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn reading_analytics_short_text() {
|
|
|
|
let (word_count, reading_time) = get_reading_analytics("Hello World");
|
|
|
|
assert_eq!(word_count, 2);
|
|
|
|
assert_eq!(reading_time, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn reading_analytics_long_text() {
|
|
|
|
let mut content = String::new();
|
|
|
|
for _ in 0..1000 {
|
|
|
|
content.push_str(" Hello world");
|
|
|
|
}
|
|
|
|
let (word_count, reading_time) = get_reading_analytics(&content);
|
|
|
|
assert_eq!(word_count, 2000);
|
|
|
|
assert_eq!(reading_time, 10);
|
|
|
|
}
|
2017-05-15 07:26:11 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn can_find_content_components() {
|
|
|
|
let res = find_content_components("/home/vincent/code/site/content/posts/tutorials/python.md");
|
|
|
|
assert_eq!(res, ["posts".to_string(), "tutorials".to_string()]);
|
|
|
|
}
|
2017-05-15 03:23:19 +00:00
|
|
|
}
|