Browse Source

Add get_taxonomy_url global_fn

And fix bug with taxonomies urls
index-subcmd
Vincent Prouillet 7 years ago
parent
commit
322d2f30fb
9 changed files with 126 additions and 1505 deletions
  1. +5
    -0
      CHANGELOG.md
  2. +0
    -1452
      Cargo.lock
  3. +9
    -0
      components/config/src/lib.rs
  4. +4
    -0
      components/site/src/lib.rs
  5. +1
    -1
      components/taxonomies/src/lib.rs
  6. +1
    -0
      components/templates/Cargo.toml
  7. +93
    -52
      components/templates/src/global_fns.rs
  8. +2
    -0
      components/templates/src/lib.rs
  9. +11
    -0
      docs/content/documentation/templates/overview.md

+ 5
- 0
CHANGELOG.md 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


+ 0
- 1452
Cargo.lock
File diff suppressed because it is too large
View File


+ 9
- 0
components/config/src/lib.rs 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#"


+ 4
- 0
components/site/src/lib.rs 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())


+ 1
- 1
components/taxonomies/src/lib.rs 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))
};



+ 1
- 0
components/templates/Cargo.toml View File

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

+ 93
- 52
components/templates/src/global_fns.rs 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());
}
}

+ 2
- 0
components/templates/src/lib.rs 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;


+ 11
- 0
docs/content/documentation/templates/overview.md 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.

Loading…
Cancel
Save