Skip to content
This repository has been archived by the owner on Jun 25, 2020. It is now read-only.

Commit

Permalink
Merge pull request #306 from tditiecher/master
Browse files Browse the repository at this point in the history
Added support for specifying frontmatter defaults in _config.yml
  • Loading branch information
Jérémie Bertrand authored Jul 13, 2016
2 parents 183a3af + 358e159 commit d3b3aa3
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 18 deletions.
33 changes: 16 additions & 17 deletions src/Pretzel.Logic/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,29 @@ public interface IConfiguration
bool TryGetValue(string key, out object value);

IDictionary<string, object> ToDictionary();

IDefaultsConfiguration Defaults { get; }
}


internal sealed class Configuration : IConfiguration
{
private const string ConfigFileName = "_config.yml";
public const string DefaultPermalink = "date";

private IDictionary<string, object> _config;
private IFileSystem _fileSystem;
private string _configFilePath;
private IDefaultsConfiguration _defaultsConfiguration;
private readonly IFileSystem _fileSystem;
private readonly string _configFilePath;

public object this[string key]
{
get
{
return _config[key];
}
}
public object this[string key] => _config[key];

public IDefaultsConfiguration Defaults => _defaultsConfiguration;

internal Configuration()
{
_config = new Dictionary<string, object>();
CheckDefaultConfig();
EnsureDefaults();
}

internal Configuration(IFileSystem fileSystem, string sitePath)
Expand All @@ -44,16 +45,14 @@ internal Configuration(IFileSystem fileSystem, string sitePath)
_configFilePath = _fileSystem.Path.Combine(sitePath, ConfigFileName);
}

private void CheckDefaultConfig()
private void EnsureDefaults()
{
if (!_config.ContainsKey("permalink"))
{
_config.Add("permalink", "date");
}
if (!_config.ContainsKey("date"))
{
_config.Add("date", "2012-01-01");
_config.Add("permalink", DefaultPermalink);
}

_defaultsConfiguration = new DefaultsConfiguration(_config);
}

internal void ReadFromFile()
Expand All @@ -62,7 +61,7 @@ internal void ReadFromFile()
if (_fileSystem.File.Exists(_configFilePath))
{
_config = _fileSystem.File.ReadAllText(_configFilePath).ParseYaml();
CheckDefaultConfig();
EnsureDefaults();
}
}

Expand Down
61 changes: 61 additions & 0 deletions src/Pretzel.Logic/DefaultsConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Collections.Generic;
using System.IO;
using Pretzel.Logic.Extensions;

namespace Pretzel.Logic
{
public interface IDefaultsConfiguration
{
IDictionary<string, object> ForScope(string path);
}

internal sealed class DefaultsConfiguration : IDefaultsConfiguration
{
private readonly IDictionary<string, IDictionary<string, object>> _scopedValues;

public DefaultsConfiguration(IDictionary<string, object> configuration)
{
_scopedValues = new Dictionary<string, IDictionary<string, object>>();
FillScopedValues(configuration);
}

private void FillScopedValues(IDictionary<string, object> configuration)
{
if (!configuration.ContainsKey("defaults")) return;

var defaults = configuration["defaults"] as List<object>;
if (defaults == null) return;

foreach (var item in defaults.ConvertAll(x => x as IDictionary<string, object>))
{
if (item != null && item.ContainsKey("scope") && item.ContainsKey("values"))
{
var scopeDictionary = item["scope"] as IDictionary<string, object>;
if (scopeDictionary != null && scopeDictionary.ContainsKey("path"))
{
var path = (string)scopeDictionary["path"];
var values = item["values"] as IDictionary<string, object>;
_scopedValues.Add(path, values ?? new Dictionary<string, object>());
}
}
}
}

public IDictionary<string, object> ForScope(string path)
{
IDictionary<string, object> result = new Dictionary<string, object>();

if (path == null) return result;

if (path.Length > 0)
{
result = result.Merge(ForScope(Path.GetDirectoryName(path)));
}
if (_scopedValues.ContainsKey(path))
{
result = result.Merge(_scopedValues[path]);
}
return result;
}
}
}
28 changes: 28 additions & 0 deletions src/Pretzel.Logic/Extensions/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;

namespace Pretzel.Logic.Extensions
{
/// <summary>
/// Dictionary extension methods.
/// </summary>
public static class DictionaryExtensions
{
/// <summary>
/// Merges two dictionaries on top of each other and returns a new dictionary.
/// Values from the second override the original values when the key is already present.
/// Values from the second will be added when the key is not present in the first.
/// </summary>
public static IDictionary<TKey, TValue> Merge<TKey, TValue>(this IDictionary<TKey, TValue> first, IDictionary<TKey, TValue> second)
{
var result = new Dictionary<TKey,TValue>(first);
if (second != null)
{
foreach (var key in second.Keys)
{
result[key] = second[key];
}
}
return result;
}
}
}
2 changes: 2 additions & 0 deletions src/Pretzel.Logic/Pretzel.Logic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
<Compile Include="Commands\CommandParameters.cs" />
<Compile Include="Commands\BaseParameters.cs" />
<Compile Include="Configuration.cs" />
<Compile Include="DefaultsConfiguration.cs" />
<Compile Include="Exceptions\PageProcessingException.cs" />
<Compile Include="Extensibility\Extensions\AzureHostSupport.cs" />
<Compile Include="Extensibility\Extensions\CommonMarkEngine.cs" />
Expand All @@ -105,6 +106,7 @@
<Compile Include="Extensibility\IBeforeProcessingTransform.cs" />
<Compile Include="Extensibility\ITag.cs" />
<Compile Include="Extensibility\TagFactoryBase.cs" />
<Compile Include="Extensions\DictionaryExtensions.cs" />
<Compile Include="Extensions\IAssembly.cs" />
<Compile Include="Extensions\Logger.cs" />
<Compile Include="Extensions\Sitemap.cs" />
Expand Down
6 changes: 5 additions & 1 deletion src/Pretzel.Logic/Templating/Context/SiteContextGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,11 @@ private Page CreatePage(SiteContext context, IConfiguration config, string file,
if (pageCache.ContainsKey(file))
return pageCache[file];
var content = SafeReadContents(file);
var header = content.YamlHeader();

var relativePath = MapToOutputPath(context, file);
var scopedDefaults = context.Config.Defaults.ForScope(relativePath);

var header = scopedDefaults.Merge(content.YamlHeader());

if (header.ContainsKey("published") && header["published"].ToString().ToLower() == "false")
{
Expand Down
14 changes: 14 additions & 0 deletions src/Pretzel.Tests/ConfigurationMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,19 @@ public IDictionary<string, object> ToDictionary()
{
return new Dictionary<string, object>(_config);
}

public IDefaultsConfiguration Defaults
{
get { return new DefaultsConfigurationMock(); }
}
}

internal class DefaultsConfigurationMock : IDefaultsConfiguration
{
public IDictionary<string, object> ForScope(string path)
{
return new Dictionary<string, object>();
}
}

}
83 changes: 83 additions & 0 deletions src/Pretzel.Tests/ConfigurationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System;
using System.IO.Abstractions.TestingHelpers;
using Pretzel.Logic;
using Pretzel.Logic.Extensions;
using Xunit;

namespace Pretzel.Tests
{
public class ConfigurationTests
{
private readonly Configuration _sut;

private const string SampleConfig = @"
pretzel:
engine: liquid
title: 'Site Title'
defaults:
-
scope:
path: ''
values:
author: 'default-author'
-
scope:
path: '_posts'
values:
layout: 'post'
author: 'posts-specific-author'
-
scope:
path: '_posts\2016'
values:
layout: 'post-layout-for-2016'
";

public ConfigurationTests()
{
var fileSystem = new MockFileSystem();
fileSystem.AddFile(@"C:\WebSite\_config.yml", new MockFileData(SampleConfig));

_sut = new Configuration(fileSystem, @"C:\WebSite");
_sut.ReadFromFile();
}

[Fact]
public void Indexer_should_correctly_return_the_value()
{
Assert.Equal("Site Title", _sut["title"]);
}

[Fact]
public void Permalinks_should_be_added_with_default_value_if_not_specified_in_file()
{
Assert.Equal(Configuration.DefaultPermalink, _sut["permalink"]);
}

[Fact]
public void DefaultsForScope_should_layer_the_most_specific_scope_on_top()
{
var defaults = _sut.Defaults.ForScope(@"_posts\2016");

Assert.Equal("post-layout-for-2016", defaults["layout"]);
}

[Fact]
public void DefaultsForScope_should_take_value_from_less_specific_when_not_found_in_most_specific()
{
var defaults = _sut.Defaults.ForScope(@"_posts\2016");

Assert.Equal("posts-specific-author", defaults["author"]);
}

[Fact]
public void DefaultsForScope_should_fallback_to_value_from_empty_path_when_given_path_not_found()
{
var defaults = _sut.Defaults.ForScope("_nonexisting");

Assert.Equal("default-author", defaults["author"]);
}
}
}
48 changes: 48 additions & 0 deletions src/Pretzel.Tests/Extensions/DictionaryExtensionTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.Collections.Generic;
using Pretzel.Logic.Extensions;
using Xunit;

namespace Pretzel.Tests.Extensions
{
public class DictionaryExtensionTests
{
[Fact]
public void Merge_two_dictionaries_returns_new_merged_dictionary()
{
var first = new Dictionary<string, string>
{
{ "A", "a-first" },
{ "B", "b-first" },
};
var second = new Dictionary<string, string>
{
{ "A", "a-second" },
{ "C", "c-second" },
};

var merged = first.Merge(second);

Assert.Equal(3, merged.Count);
Assert.Equal("a-second", merged["A"]);
Assert.Equal("b-first", merged["B"]);
Assert.Equal("c-second", merged["C"]);
}

[Fact]
public void Merge_with_null_returns_copy_of_first()
{
var first = new Dictionary<string, string>
{
{ "A", "a-first" },
{ "B", "b-first" },
};

var merged = first.Merge(null);

Assert.NotSame(merged, first);
Assert.Equal(2, merged.Count);
Assert.Equal("a-first", merged["A"]);
Assert.Equal("b-first", merged["B"]);
}
}
}
2 changes: 2 additions & 0 deletions src/Pretzel.Tests/Pretzel.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,11 @@
<Compile Include="Commands\BaseParameterTests.cs" />
<Compile Include="Commands\CommandExtensions.cs" />
<Compile Include="ConfigurationMock.cs" />
<Compile Include="ConfigurationTests.cs" />
<Compile Include="Extensibility\Extensions\AzureHostSupportTest.cs" />
<Compile Include="Extensibility\Extensions\VirtualDirectorySupportTests.cs" />
<Compile Include="Extensibility\Extensions\WebSequenceDiagramsTests.cs" />
<Compile Include="Extensions\DictionaryExtensionTests.cs" />
<Compile Include="Extensions\SitemapTest.cs" />
<Compile Include="Extensions\StringExtensionsTest.cs" />
<Compile Include="Import\BloggerImportTests.cs" />
Expand Down
Loading

0 comments on commit d3b3aa3

Please sign in to comment.