This repository has been archived by the owner on Jun 25, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 162
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jérémie Bertrand
committed
Mar 11, 2015
1 parent
26aa76a
commit 01c7dbc
Showing
8 changed files
with
350 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.ComponentModel.Composition; | ||
using System.Globalization; | ||
using System.IO; | ||
using System.Linq; | ||
using System.Text.RegularExpressions; | ||
|
||
namespace Pretzel.Logic.Templating.Context | ||
{ | ||
[Export] | ||
public sealed class LinkHelper | ||
{ | ||
private static readonly Regex TimestampAndTitleFromPathRegex = new Regex(@"\\(?:(?<timestamp>\d+-\d+-\d+)-)?(?<title>[^\\]*)\.[^\.]+$", RegexOptions.Compiled); | ||
private static readonly Regex CategoryRegex = new Regex(@":category(\d*)", RegexOptions.Compiled); | ||
private static readonly Regex SlashesRegex = new Regex(@"/{1,}", RegexOptions.Compiled); | ||
|
||
private static readonly string[] HtmlExtensions = new[] { ".markdown", ".mdown", ".mkdn", ".mkd", ".md", ".textile" }; | ||
|
||
private static readonly Dictionary<string, string> BuiltInPermalinks = new Dictionary<string, string> | ||
{ | ||
{ "date", "/:categories/:year/:month/:day/:title.html" }, | ||
{ "pretty", "/:categories/:year/:month/:day/:title/" }, | ||
{ "ordinal", "/:categories/:year/:y_day/:title.html" }, | ||
{ "none", "/:categories/:title.html" }, | ||
}; | ||
|
||
// http://jekyllrb.com/docs/permalinks/ | ||
public string EvaluatePermalink(string permalink, Page page) | ||
{ | ||
if (BuiltInPermalinks.ContainsKey(permalink)) | ||
{ | ||
permalink = BuiltInPermalinks[permalink]; | ||
} | ||
|
||
permalink = permalink.Replace(":categories", string.Join("/", page.Categories.ToArray())); | ||
permalink = permalink.Replace(":dashcategories", string.Join("-", page.Categories.ToArray())); | ||
permalink = permalink.Replace(":year", page.Date.Year.ToString(CultureInfo.InvariantCulture)); | ||
permalink = permalink.Replace(":month", page.Date.ToString("MM")); | ||
permalink = permalink.Replace(":day", page.Date.ToString("dd")); | ||
permalink = permalink.Replace(":title", GetTitle(page.File)); | ||
permalink = permalink.Replace(":y_day", page.Date.DayOfYear.ToString("000")); | ||
permalink = permalink.Replace(":short_year", page.Date.ToString("yy")); | ||
permalink = permalink.Replace(":i_month", page.Date.Month.ToString()); | ||
permalink = permalink.Replace(":i_day", page.Date.Day.ToString()); | ||
|
||
if (permalink.Contains(":category")) | ||
{ | ||
var matches = CategoryRegex.Matches(permalink); | ||
if (matches != null && matches.Count > 0) | ||
{ | ||
foreach (Match match in matches) | ||
{ | ||
var replacementValue = string.Empty; | ||
int categoryIndex; | ||
if (match.Success) | ||
{ | ||
if (int.TryParse(match.Groups[1].Value, out categoryIndex) && categoryIndex > 0) | ||
{ | ||
replacementValue = page.Categories.Skip(categoryIndex - 1).FirstOrDefault(); | ||
} | ||
else if (page.Categories.Any()) | ||
{ | ||
replacementValue = page.Categories.First(); | ||
} | ||
} | ||
|
||
permalink = permalink.Replace(match.Value, replacementValue); | ||
} | ||
} | ||
} | ||
|
||
permalink = SlashesRegex.Replace(permalink, "/"); | ||
|
||
return permalink; | ||
} | ||
|
||
public string EvaluateLink(SiteContext context, Page page) | ||
{ | ||
var directory = Path.GetDirectoryName(page.Filepath); | ||
var relativePath = directory.Replace(context.OutputFolder, string.Empty); | ||
var fileExtension = Path.GetExtension(page.Filepath); | ||
|
||
if (HtmlExtensions.Contains(fileExtension, StringComparer.InvariantCultureIgnoreCase)) | ||
{ | ||
fileExtension = ".html"; | ||
} | ||
|
||
var link = relativePath.Replace('\\', '/').TrimStart('/') + "/" + GetPageTitle(page.Filepath) + fileExtension; | ||
if (!link.StartsWith("/")) | ||
{ | ||
link = "/" + link; | ||
} | ||
|
||
return link; | ||
} | ||
|
||
public string GetTitle(string file) | ||
{ | ||
return TimestampAndTitleFromPathRegex.Match(file).Groups["title"].Value; | ||
} | ||
|
||
private string GetPageTitle(string file) | ||
{ | ||
return Path.GetFileNameWithoutExtension(file); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
using Pretzel.Logic.Templating.Context; | ||
using System; | ||
using System.Linq; | ||
using Xunit; | ||
using Xunit.Extensions; | ||
|
||
namespace Pretzel.Tests.Templating.Context | ||
{ | ||
public class LinkHelperTest | ||
{ | ||
public LinkHelper LinkHelper { get; private set; } | ||
|
||
public LinkHelperTest() | ||
{ | ||
LinkHelper = new LinkHelper(); | ||
} | ||
|
||
[Fact] | ||
public void GetTitle_returns_original_value_when_no_timestamp() | ||
{ | ||
var result = LinkHelper.GetTitle(@"C:\temp\foobar_baz.md"); | ||
Assert.Equal("foobar_baz", result); | ||
} | ||
|
||
[Fact] | ||
public void GetTitle_returns_strips_timestamp() | ||
{ | ||
var result = LinkHelper.GetTitle(@"C:\temp\2012-01-03-foobar_baz.md"); | ||
Assert.Equal("foobar_baz", result); | ||
} | ||
|
||
[Fact] | ||
public void GetTitle_preserves_dash_separated_values_that_arent_timestamps() | ||
{ | ||
var result = LinkHelper.GetTitle(@"C:\temp\foo-bar-baz-qak-foobar_baz.md"); | ||
Assert.Equal("foo-bar-baz-qak-foobar_baz", result); | ||
} | ||
|
||
[InlineData(@"C:\TestSite\_site\about.md", "/about.html")] | ||
[InlineData(@"C:\TestSite\_site\about.mkd", "/about.html")] | ||
[InlineData(@"C:\TestSite\_site\about.mkdn", "/about.html")] | ||
[InlineData(@"C:\TestSite\_site\about.mdown", "/about.html")] | ||
[InlineData(@"C:\TestSite\_site\about.markdown", "/about.html")] | ||
[InlineData(@"C:\TestSite\_site\about.textile", "/about.html")] | ||
[InlineData(@"C:\TestSite\_site\rss.xml", "/rss.xml")] | ||
[InlineData(@"C:\TestSite\_site\relativepath\about.md", "/relativepath/about.html")] | ||
[Theory] | ||
public void EvaluateLink_url_is_well_formatted(string filePath, string expectedUrl) | ||
{ | ||
var siteContext = new SiteContext { OutputFolder = @"C:\TestSite\_site" }; | ||
var page = new Page { Filepath = filePath }; | ||
|
||
Assert.Equal(expectedUrl, LinkHelper.EvaluateLink(siteContext, page)); | ||
} | ||
|
||
[InlineData("date", "/cat1/cat2/2015/03/09/foobar-baz.html", "cat1,cat2")] | ||
[InlineData("date", "/2015/03/09/foobar-baz.html", "")] | ||
[InlineData("/:dashcategories/:year/:month/:day/:title.html", "/cat1-cat2/2015/03/09/foobar-baz.html", "cat1,cat2")] | ||
[InlineData("/:dashcategories/:year/:month/:day/:title.html", "/2015/03/09/foobar-baz.html", "")] | ||
[InlineData("pretty", "/cat1/cat2/2015/03/09/foobar-baz/", "cat1,cat2")] | ||
[InlineData("ordinal", "/cat1/cat2/2015/068/foobar-baz.html", "cat1,cat2")] | ||
[InlineData("none", "/cat1/cat2/foobar-baz.html", "cat1,cat2")] | ||
[InlineData("/:categories/:short_year/:i_month/:i_day/:title.html", "/cat1/cat2/15/3/9/foobar-baz.html", "cat1,cat2")] | ||
[InlineData("/:category/:title.html", "/cat1/foobar-baz.html", "cat1,cat2")] | ||
[InlineData("/:category/:title.html", "/foobar-baz.html", "")] | ||
[InlineData("/:category1/:title.html", "/cat1/foobar-baz.html", "cat1,cat2")] | ||
[InlineData("/:category2/:title.html", "/cat2/foobar-baz.html", "cat1,cat2")] | ||
[InlineData("/:category3/:title.html", "/foobar-baz.html", "cat1,cat2")] | ||
[Theory] | ||
public void EvaluatePermalink_url_is_well_formatted(string permalink, string expectedUrl, string categories) | ||
{ | ||
var page = new Page | ||
{ | ||
Categories = categories == null ? Enumerable.Empty<string>() : categories.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), | ||
Date = new DateTime(2015, 03, 09), | ||
File = @"C:\temp\2015-03-09-foobar-baz.md" | ||
}; | ||
|
||
Assert.Equal(expectedUrl, LinkHelper.EvaluatePermalink(permalink, page)); | ||
} | ||
} | ||
} |
Oops, something went wrong.