Add get_taxonomy_url global_fn

And fix bug with taxonomies urls
This commit is contained in:
Vincent Prouillet 2017-11-16 18:08:06 +01:00
parent 8759323a16
commit 322d2f30fb
9 changed files with 125 additions and 1504 deletions

View file

@ -1,5 +1,10 @@
# Changelog
## 0.2.3 (unreleased)
- Add `get_taxonomy_url` to retrieve the permalink of a tag/category
- Fix bug when generating permalinks for taxonomies
## 0.2.2 (2017-11-01)
- Fix shortcodes without arguments being ignored

1452
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -120,6 +120,8 @@ impl Config {
format!("{}{}{}", self.base_url, &path[1..], trailing_bit)
} else if self.base_url.ends_with('/') {
format!("{}{}{}", self.base_url, path, trailing_bit)
} else if path.starts_with('/') {
format!("{}{}{}", self.base_url, path, trailing_bit)
} else {
format!("{}/{}{}", self.base_url, path, trailing_bit)
}
@ -272,6 +274,13 @@ hello = "world"
assert_eq!(config.make_permalink("/hello"), "http://vincent.is/hello/");
}
#[test]
fn can_make_url_with_localhost() {
let mut config = Config::default();
config.base_url = "http://127.0.0.1:1111".to_string();
assert_eq!(config.make_permalink("/tags/rust"), "http://127.0.0.1:1111/tags/rust/");
}
#[test]
fn can_merge_with_theme_data_and_preserve_config_value() {
let config_str = r#"

View file

@ -251,6 +251,10 @@ impl Site {
pub fn register_tera_global_fns(&mut self) {
self.tera.register_global_function("get_page", global_fns::make_get_page(&self.pages));
self.tera.register_global_function("get_section", global_fns::make_get_section(&self.sections));
self.tera.register_global_function(
"get_taxonomy_url",
global_fns::make_get_taxonomy_url(self.tags.clone(), self.categories.clone())
);
self.tera.register_global_function(
"get_url",
global_fns::make_get_url(self.permalinks.clone(), self.config.clone())

View file

@ -44,7 +44,7 @@ impl TaxonomyItem {
let (mut pages, ignored_pages) = sort_pages(pages, SortBy::Date);
let slug = slugify(name);
let permalink = {
let kind_path = if kind == TaxonomyKind::Tags { "tag" } else { "category" };
let kind_path = if kind == TaxonomyKind::Tags { "tags" } else { "categories" };
config.make_permalink(&format!("/{}/{}", kind_path, slug))
};

View file

@ -13,3 +13,4 @@ errors = { path = "../errors" }
utils = { path = "../utils" }
content = { path = "../content" }
config = { path = "../config" }
taxonomies = { path = "../taxonomies" }

View file

@ -6,8 +6,21 @@ use tera::{GlobalFn, Value, from_value, to_value, Result};
use content::{Page, Section};
use config::Config;
use utils::site::resolve_internal_link;
use taxonomies::Taxonomy;
macro_rules! required_string_arg {
($e: expr, $err: expr) => {
match $e {
Some(v) => match from_value::<String>(v.clone()) {
Ok(u) => u,
Err(_) => return Err($err.into())
},
None => return Err($err.into())
};
};
}
pub fn make_get_page(all_pages: &HashMap<PathBuf, Page>) -> GlobalFn {
let mut pages = HashMap::new();
for page in all_pages.values() {
@ -15,17 +28,10 @@ pub fn make_get_page(all_pages: &HashMap<PathBuf, Page>) -> GlobalFn {
}
Box::new(move |args| -> Result<Value> {
match args.get("path") {
Some(val) => match from_value::<String>(val.clone()) {
Ok(v) => {
match pages.get(&v) {
Some(p) => Ok(to_value(p).unwrap()),
None => Err(format!("Page `{}` not found.", v).into())
}
},
Err(_) => Err(format!("`get_page` received path={:?} but it requires a string", val).into()),
},
None => Err("`get_page` requires a `path` argument.".into()),
let path = required_string_arg!(args.get("path"), "`get_page` requires a `path` argument with a string value");
match pages.get(&path) {
Some(p) => Ok(to_value(p).unwrap()),
None => Err(format!("Page `{}` not found.", path).into())
}
})
}
@ -37,17 +43,10 @@ pub fn make_get_section(all_sections: &HashMap<PathBuf, Section>) -> GlobalFn {
}
Box::new(move |args| -> Result<Value> {
match args.get("path") {
Some(val) => match from_value::<String>(val.clone()) {
Ok(v) => {
match sections.get(&v) {
Some(p) => Ok(to_value(p).unwrap()),
None => Err(format!("Section `{}` not found.", v).into())
}
},
Err(_) => Err(format!("`get_section` received path={:?} but it requires a string", val).into()),
},
None => Err("`get_section` requires a `path` argument.".into()),
let path = required_string_arg!(args.get("path"), "`get_section` requires a `path` argument with a string value");
match sections.get(&path) {
Some(p) => Ok(to_value(p).unwrap()),
None => Err(format!("Section `{}` not found.", path).into())
}
})
}
@ -59,51 +58,67 @@ pub fn make_get_url(permalinks: HashMap<String, String>, config: Config) -> Glob
.map_or(false, |c| {
from_value::<bool>(c.clone()).unwrap_or(false)
});
let trailing_slash = args
.get("trailing_slash")
.map_or(true, |c| {
from_value::<bool>(c.clone()).unwrap_or(true)
});
match args.get("path") {
Some(val) => match from_value::<String>(val.clone()) {
Ok(v) => {
// Internal link
if v.starts_with("./") {
match resolve_internal_link(&v, &permalinks) {
Ok(url) => Ok(to_value(url).unwrap()),
Err(_) => Err(format!("Could not resolve URL for link `{}` not found.", v).into())
}
} else {
// anything else
let mut permalink = config.make_permalink(&v);
if !trailing_slash && permalink.ends_with("/") {
permalink.pop(); // Removes the slash
}
if cachebust {
permalink = format!("{}?t={}", permalink, config.build_timestamp.unwrap());
}
Ok(to_value(permalink).unwrap())
}
},
Err(_) => Err(format!("`get_url` received path={:?} but it requires a string", val).into()),
},
None => Err("`get_url` requires a `path` argument.".into()),
let path = required_string_arg!(args.get("path"), "`get_url` requires a `path` argument with a string value");
if path.starts_with("./") {
match resolve_internal_link(&path, &permalinks) {
Ok(url) => Ok(to_value(url).unwrap()),
Err(_) => Err(format!("Could not resolve URL for link `{}` not found.", path).into())
}
} else {
// anything else
let mut permalink = config.make_permalink(&path);
if !trailing_slash && permalink.ends_with("/") {
permalink.pop(); // Removes the slash
}
if cachebust {
permalink = format!("{}?t={}", permalink, config.build_timestamp.unwrap());
}
Ok(to_value(permalink).unwrap())
}
})
}
pub fn make_get_taxonomy_url(tags: Option<Taxonomy>, categories: Option<Taxonomy>) -> GlobalFn {
Box::new(move |args| -> Result<Value> {
let kind = required_string_arg!(args.get("kind"), "`get_taxonomy_url` requires a `kind` argument with a string value");
let name = required_string_arg!(args.get("name"), "`get_taxonomy_url` requires a `name` argument with a string value");
let container = match kind.as_ref() {
"tag" => &tags,
"category" => &categories,
_ => return Err("`get_taxonomy_url` can only get `tag` or `category` for the `kind` argument".into()),
};
if let Some(ref c) = *container {
for item in &c.items {
if item.name == name {
return Ok(to_value(item.permalink.clone()).unwrap());
}
}
bail!("`get_taxonomy_url`: couldn't find `{}` in `{}` taxonomy", name, kind);
} else {
bail!("`get_taxonomy_url` tried to get a taxonomy of kind `{}` but there isn't any", kind);
}
})
}
#[cfg(test)]
mod tests {
use super::make_get_url;
use super::{make_get_url, make_get_taxonomy_url};
use std::collections::HashMap;
use tera::to_value;
use config::Config;
use taxonomies::{Taxonomy, TaxonomyKind, TaxonomyItem};
#[test]
@ -115,7 +130,7 @@ mod tests {
args.insert("cachebust".to_string(), to_value(true).unwrap());
assert_eq!(static_fn(args).unwrap(), "http://a-website.com/app.css/?t=1");
}
#[test]
fn can_remove_trailing_slashes() {
let config = Config::default();
@ -125,7 +140,7 @@ mod tests {
args.insert("trailing_slash".to_string(), to_value(false).unwrap());
assert_eq!(static_fn(args).unwrap(), "http://a-website.com/app.css");
}
#[test]
fn can_remove_slashes_and_cachebust() {
let config = Config::default();
@ -145,4 +160,30 @@ mod tests {
args.insert("path".to_string(), to_value("app.css").unwrap());
assert_eq!(static_fn(args).unwrap(), "http://a-website.com/app.css/");
}
#[test]
fn can_get_tag_url() {
let tag = TaxonomyItem::new(
"Prog amming",
TaxonomyKind::Tags,
&Config::default(),
vec![],
);
let tags = Taxonomy {
kind: TaxonomyKind::Tags,
items: vec![tag],
};
let static_fn = make_get_taxonomy_url(Some(tags), None);
// can find it correctly
let mut args = HashMap::new();
args.insert("kind".to_string(), to_value("tag").unwrap());
args.insert("name".to_string(), to_value("Prog amming").unwrap());
assert_eq!(static_fn(args).unwrap(), "http://a-website.com/tag/prog-amming/");
// and errors if it can't find it
let mut args = HashMap::new();
args.insert("kind".to_string(), to_value("tag").unwrap());
args.insert("name".to_string(), to_value("random").unwrap());
assert!(static_fn(args).is_err());
}
}

View file

@ -5,10 +5,12 @@ extern crate tera;
extern crate base64;
extern crate pulldown_cmark;
#[macro_use]
extern crate errors;
extern crate utils;
extern crate content;
extern crate config;
extern crate taxonomies;
pub mod filters;
pub mod global_fns;

View file

@ -79,3 +79,14 @@ when dealing with certain hosting providers. An example is:
In the case of non-internal links, you can also add a cachebust of the format `?t=1290192` at the end of a URL
by passing `cachebust=true` to the `get_url` function.
### ` get_taxonomy_url`
Gets the permalink for the tag or category given.
```jinja2
{% set url = get_taxonomy_url(kind="category", name=page.category) %}
```
The `name` will almost come from a variable but in case you want to do it manually,
the value should be the same as the one in the front-matter, not the slugified version.