Skip to content

Instantly share code, notes, and snippets.

@Geobert
Created October 2, 2017 19:10
Show Gist options
  • Save Geobert/84e2d4962ca7e5a77f3a9dfe40ac372a to your computer and use it in GitHub Desktop.
Save Geobert/84e2d4962ca7e5a77f3a9dfe40ac372a to your computer and use it in GitHub Desktop.
use datetime;
use serde_yaml;
use liquid;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use super::super::document::{read_file, split_document};
use frontmatter::FrontmatterBuilder;
use error::{ErrorKind, Result};
#[derive(Debug, Default, Clone, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
struct JkPostFrontmatter {
pub layout: Option<String>,
pub permalink: Option<String>,
pub published: bool,
pub date: Option<datetime::DateTime>,
pub category: Option<String>,
pub categories: Option<Vec<String>>,
pub tags: Option<Vec<String>>,
pub title: String,
pub excerpt: Option<String>,
pub path: String,
pub custom: liquid::Object,
}
impl From<JkPostFrontmatter> for FrontmatterBuilder {
fn from(jekyll: JkPostFrontmatter) -> Self {
let builder = FrontmatterBuilder::new()
.merge_title(jekyll.title)
.merge_layout(jekyll.layout)
.merge_published_date(jekyll.date)
.merge_description(jekyll.excerpt)
.merge_path(jekyll.path)
.merge_custom(jekyll.custom);
if let Some(cat) = jekyll.category {
builder.merge_categories(vec![cat])
} else if let Some(categories) = jekyll.categories {
builder.merge_categories(categories)
} else {
builder
}
// TODO merge tags when cobalt's frontmatter allows it
}
}
#[derive(Debug, Default, Clone, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct JkDocument {
pub front: Option<String>,
pub content: Option<String>,
}
impl JkDocument {
pub fn parse_string(doc: String) -> Result<JkDocument> {
let (front, content) = split_document(&doc)?;
if front != None {
Err(ErrorKind::MissingFrontStart.into())
} else {
match split_document(&content)? {
(None, _) => Err(ErrorKind::MissingFrontmatter.into()),
(Some(front), content) => Ok(JkDocument {
front: Some(front.to_owned()),
content: Some(content.to_owned()),
}),
}
}
}
pub fn parse(source_file: &Path) -> Result<JkDocument> {
let doc: String = read_file(source_file)?;
JkDocument::parse_string(doc)
}
pub fn convert_front(front: &str) -> Result<String> {
let front_yaml: JkPostFrontmatter = serde_yaml::from_str(front)?;
let front_builder: FrontmatterBuilder = front_yaml.into();
let front = front_builder.build()?;
Ok(serde_yaml::to_string(&front)?)
}
pub fn convert(source_file: &Path, dest_file: &Path) -> Result<()> {
let doc = JkDocument::parse(source_file)?;
let front = JkDocument::convert_front(&doc.front.unwrap())?;
let mut dest = File::create(dest_file)?;
let converted = format!("{}---\n{}", &front, &doc.content.unwrap());
dest.write_all(converted.as_bytes())?;
Ok(())
}
}
#[cfg(test)]
mod test {
use super::*;
use error::{ErrorKind, Result};
fn get_correct_cb_front() -> &'static str {
r#"title: test_post
published_date: 2017-05-03T20:55:07+00:00
layout: post
path: /2017/05/03/test_post/
categories:
- cat1
- cat2
"#
}
fn get_correct_jk_front() -> &'static str {
r#"id: 33
title: test_post
date: 2017-05-03T20:55:07+00:00
author: TheAuthor
layout: post
guid: http://url.com/?p=33
permalink: /2017/05/03/test_post/
categories:
- cat1
- cat2
tags:
- tag1
- tag2
- tag3
"#
}
fn get_correct_content() -> &'static str {
"the content\n"
}
#[test]
fn parse_string_ok() {
let correct_front = get_correct_jk_front();
let correct_content = get_correct_content();
let correct_doc = format!("---\n{}---\n{}", correct_front, correct_content);
let res = JkDocument::parse_string(correct_doc);
assert!(res.is_ok());
let doc = res.unwrap();
assert_eq!(doc.content.unwrap(), correct_content);
assert_eq!(doc.front.unwrap(), correct_front);
}
#[test]
fn parse_string_no_front() {
let res = JkDocument::parse_string(get_correct_content().to_owned());
assert!(res.is_err());
//assert_eq!(res.unwrap_err(), ErrorKind::MissingFrontmatter);
}
#[test]
fn parse_string_no_front_starter() {
let correct_front = get_correct_jk_front();
let correct_content = get_correct_content();
let correct_doc = format!("{}---\n{}", correct_front, correct_content);
let res = JkDocument::parse_string(correct_doc);
assert!(res.is_err());
//assert_eq!(res.unwrap_err(), ErrorKind::MissingFrontStart);
}
#[test]
fn convert_front_ok() {
let correct_front = get_correct_jk_front();
let res = JkDocument::convert_front(correct_front);
match res {
Err(e) => println!("error convert: {:#?}", e),
Ok(converted) => assert_eq!(converted, get_correct_cb_front()),
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment