You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

site.rs 4.0KB

Fix clippy warnings (#744) Clippy is returning some warnings. Let's fix or explicitly ignore them. In particular: - In `components/imageproc/src/lib.rs`, we implement `Hash` explicitly but derive `PartialEq`. We need to maintain the property that two keys being equal implies the hashes of those two keys are equal. Our `Hash` implementations preserve this, so we'll explicitly ignore the warnings. - In `components/site/src/lib.rs`, we were calling `.into()` on some values that are already of the correct type. - In `components/site/src/lib.rs`, we were using `.map(|x| *x)` in iterator chains to remove a level of indirection; we can instead say `.copied()` (introduced in Rust v1.36) or `.cloned()`. Using `.copied` here is better from a type-checking point of view, but we'll use `.cloned` for now as Rust v1.36 was only recently released. - In `components/templates/src/filters.rs` and `components/utils/src/site.rs`, we were taking `HashMap`s as function arguments but not generically accepting alternate `Hasher` implementations. - In `src/cmd/check.rs`, we use `env::current_dir()` as a default value, but our use of `unwrap_or` meant that we would always retrieve the current directory even when not needed. - In `components/errors/src/lib.rs`, we can use `if let` rather than `match`. - In `components/library/src/content/page.rs`, we can collapse a nested conditional into `else if let ...`. - In `components/library/src/sorting.rs`, a function takes `&&Page` arguments. Clippy warns about this for efficiency reasons, but we're doing it here to match a particular sorting API, so we'll explicitly ignore the warning.
4 years ago
Fix clippy warnings (#744) Clippy is returning some warnings. Let's fix or explicitly ignore them. In particular: - In `components/imageproc/src/lib.rs`, we implement `Hash` explicitly but derive `PartialEq`. We need to maintain the property that two keys being equal implies the hashes of those two keys are equal. Our `Hash` implementations preserve this, so we'll explicitly ignore the warnings. - In `components/site/src/lib.rs`, we were calling `.into()` on some values that are already of the correct type. - In `components/site/src/lib.rs`, we were using `.map(|x| *x)` in iterator chains to remove a level of indirection; we can instead say `.copied()` (introduced in Rust v1.36) or `.cloned()`. Using `.copied` here is better from a type-checking point of view, but we'll use `.cloned` for now as Rust v1.36 was only recently released. - In `components/templates/src/filters.rs` and `components/utils/src/site.rs`, we were taking `HashMap`s as function arguments but not generically accepting alternate `Hasher` implementations. - In `src/cmd/check.rs`, we use `env::current_dir()` as a default value, but our use of `unwrap_or` meant that we would always retrieve the current directory even when not needed. - In `components/errors/src/lib.rs`, we can use `if let` rather than `match`. - In `components/library/src/content/page.rs`, we can collapse a nested conditional into `else if let ...`. - In `components/library/src/sorting.rs`, a function takes `&&Page` arguments. Clippy warns about this for efficiency reasons, but we're doing it here to match a particular sorting API, so we'll explicitly ignore the warning.
4 years ago
Fix clippy warnings (#744) Clippy is returning some warnings. Let's fix or explicitly ignore them. In particular: - In `components/imageproc/src/lib.rs`, we implement `Hash` explicitly but derive `PartialEq`. We need to maintain the property that two keys being equal implies the hashes of those two keys are equal. Our `Hash` implementations preserve this, so we'll explicitly ignore the warnings. - In `components/site/src/lib.rs`, we were calling `.into()` on some values that are already of the correct type. - In `components/site/src/lib.rs`, we were using `.map(|x| *x)` in iterator chains to remove a level of indirection; we can instead say `.copied()` (introduced in Rust v1.36) or `.cloned()`. Using `.copied` here is better from a type-checking point of view, but we'll use `.cloned` for now as Rust v1.36 was only recently released. - In `components/templates/src/filters.rs` and `components/utils/src/site.rs`, we were taking `HashMap`s as function arguments but not generically accepting alternate `Hasher` implementations. - In `src/cmd/check.rs`, we use `env::current_dir()` as a default value, but our use of `unwrap_or` meant that we would always retrieve the current directory even when not needed. - In `components/errors/src/lib.rs`, we can use `if let` rather than `match`. - In `components/library/src/content/page.rs`, we can collapse a nested conditional into `else if let ...`. - In `components/library/src/sorting.rs`, a function takes `&&Page` arguments. Clippy warns about this for efficiency reasons, but we're doing it here to match a particular sorting API, so we'll explicitly ignore the warning.
4 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. use std::collections::HashMap;
  2. use std::hash::BuildHasher;
  3. use unicode_segmentation::UnicodeSegmentation;
  4. use errors::{bail, Result};
  5. /// Get word count and estimated reading time
  6. pub fn get_reading_analytics(content: &str) -> (usize, usize) {
  7. let word_count: usize = content.unicode_words().count();
  8. // https://help.medium.com/hc/en-us/articles/214991667-Read-time
  9. // 275 seems a bit too high though
  10. (word_count, ((word_count + 199) / 200))
  11. }
  12. #[derive(Debug, PartialEq, Clone)]
  13. pub struct ResolvedInternalLink {
  14. pub permalink: String,
  15. // The 2 fields below are only set when there is an anchor
  16. // as we will need that to check if it exists after the markdown rendering is done
  17. pub md_path: Option<String>,
  18. pub anchor: Option<String>,
  19. }
  20. /// Resolves an internal link (of the `@/posts/something.md#hey` sort) to its absolute link and
  21. /// returns the path + anchor as well
  22. pub fn resolve_internal_link<S: BuildHasher>(
  23. link: &str,
  24. permalinks: &HashMap<String, String, S>,
  25. ) -> Result<ResolvedInternalLink> {
  26. // First we remove the ./ since that's zola specific
  27. let clean_link = link.replacen("@/", "", 1);
  28. // Then we remove any potential anchor
  29. // parts[0] will be the file path and parts[1] the anchor if present
  30. let parts = clean_link.split('#').collect::<Vec<_>>();
  31. match permalinks.get(parts[0]) {
  32. Some(p) => {
  33. if parts.len() > 1 {
  34. Ok(ResolvedInternalLink {
  35. permalink: format!("{}#{}", p, parts[1]),
  36. md_path: Some(parts[0].to_string()),
  37. anchor: Some(parts[1].to_string()),
  38. })
  39. } else {
  40. Ok(ResolvedInternalLink { permalink: p.to_string(), md_path: None, anchor: None })
  41. }
  42. }
  43. None => bail!(format!("Relative link {} not found.", link)),
  44. }
  45. }
  46. #[cfg(test)]
  47. mod tests {
  48. use std::collections::HashMap;
  49. use super::{get_reading_analytics, resolve_internal_link};
  50. #[test]
  51. fn can_resolve_valid_internal_link() {
  52. let mut permalinks = HashMap::new();
  53. permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string());
  54. let res = resolve_internal_link("@/pages/about.md", &permalinks).unwrap();
  55. assert_eq!(res.permalink, "https://vincent.is/about");
  56. }
  57. #[test]
  58. fn can_resolve_valid_root_internal_link() {
  59. let mut permalinks = HashMap::new();
  60. permalinks.insert("about.md".to_string(), "https://vincent.is/about".to_string());
  61. let res = resolve_internal_link("@/about.md", &permalinks).unwrap();
  62. assert_eq!(res.permalink, "https://vincent.is/about");
  63. }
  64. #[test]
  65. fn can_resolve_internal_links_with_anchors() {
  66. let mut permalinks = HashMap::new();
  67. permalinks.insert("pages/about.md".to_string(), "https://vincent.is/about".to_string());
  68. let res = resolve_internal_link("@/pages/about.md#hello", &permalinks).unwrap();
  69. assert_eq!(res.permalink, "https://vincent.is/about#hello");
  70. assert_eq!(res.md_path, Some("pages/about.md".to_string()));
  71. assert_eq!(res.anchor, Some("hello".to_string()));
  72. }
  73. #[test]
  74. fn errors_resolve_inexistant_internal_link() {
  75. let res = resolve_internal_link("@/pages/about.md#hello", &HashMap::new());
  76. assert!(res.is_err());
  77. }
  78. #[test]
  79. fn reading_analytics_empty_text() {
  80. let (word_count, reading_time) = get_reading_analytics(" ");
  81. assert_eq!(word_count, 0);
  82. assert_eq!(reading_time, 0);
  83. }
  84. #[test]
  85. fn reading_analytics_short_text() {
  86. let (word_count, reading_time) = get_reading_analytics("Hello World");
  87. assert_eq!(word_count, 2);
  88. assert_eq!(reading_time, 1);
  89. }
  90. #[test]
  91. fn reading_analytics_long_text() {
  92. let mut content = String::new();
  93. for _ in 0..1000 {
  94. content.push_str(" Hello world");
  95. }
  96. let (word_count, reading_time) = get_reading_analytics(&content);
  97. assert_eq!(word_count, 2000);
  98. assert_eq!(reading_time, 10);
  99. }
  100. }