From ef2c5bc35c537110e4697e8dfb55e6875a63bb66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Bertrand?= Date: Thu, 5 Nov 2015 16:05:14 +0100 Subject: [PATCH 1/2] Fix post_url tag Add a TagFactoryBase class which provide SiteContext for Tags which need it. --- libs/DotLiquid.dll | Bin 0 -> 92672 bytes .../Extensibility/Extensions/PostUrlTag.cs | 55 ++++++++++++++---- src/Pretzel.Logic/Extensibility/ITag.cs | 4 +- .../Extensibility/TagFactoryBase.cs | 39 +++++++++++++ src/Pretzel.Logic/Pretzel.Logic.csproj | 3 +- .../Templating/Jekyll/LiquidEngine.cs | 14 ++++- .../Templating/JekyllEngineBase.cs | 7 ++- .../Templating/Razor/ExtensibleTemplate.cs | 23 ++++++-- .../Templating/Razor/RazorSiteEngine.cs | 21 ++++++- src/Pretzel.Tests/Pretzel.Tests.csproj | 2 +- .../Templating/Jekyll/LiquidEngineTests.cs | 22 +++---- .../Templating/Razor/RazorEngineTests.cs | 9 +-- src/Pretzel/Pretzel.csproj | 2 +- 13 files changed, 159 insertions(+), 42 deletions(-) create mode 100644 libs/DotLiquid.dll create mode 100644 src/Pretzel.Logic/Extensibility/TagFactoryBase.cs diff --git a/libs/DotLiquid.dll b/libs/DotLiquid.dll new file mode 100644 index 0000000000000000000000000000000000000000..69c42cec8271c18246426c30ef5d95ba1e2a9b04 GIT binary patch literal 92672 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 X{~->H7^)Om*W(Q4|NQ;G$ASM1{)UCQ literal 0 HcmV?d00001 diff --git a/src/Pretzel.Logic/Extensibility/Extensions/PostUrlTag.cs b/src/Pretzel.Logic/Extensibility/Extensions/PostUrlTag.cs index d80631637..c0a7b9fb3 100644 --- a/src/Pretzel.Logic/Extensibility/Extensions/PostUrlTag.cs +++ b/src/Pretzel.Logic/Extensibility/Extensions/PostUrlTag.cs @@ -1,34 +1,69 @@ using DotLiquid; using System.Collections.Generic; using System.IO; +using Pretzel.Logic.Templating.Context; +using System.Linq; +using Pretzel.Logic.Exceptions; namespace Pretzel.Logic.Extensibility.Extensions { - public class PostUrlTag : Tag, ITag + public class PostUrlTag : DotLiquid.Tag, ITag { - private string postFileName; + private string _postFileName; + private SiteContext _siteContext; public new string Name { get { return "PostUrl"; } } + + public PostUrlTag(SiteContext siteContext) + { + _siteContext = siteContext; + } - public static string PostUrl(string input) + public string PostUrl(string postFileName) { - var permalink = input.Replace(".md", ""); - permalink = permalink.Replace(".mdown", ""); - permalink = permalink.Replace("-", "/"); - permalink += ".html"; + // get Page + var page = _siteContext.Posts.FirstOrDefault(p => p.File.Contains(postFileName)); + if (page == null) + { + page = _siteContext.Pages.FirstOrDefault(p => p.File.Contains(postFileName)); + } + + if (page == null) + { + throw new PageProcessingException(string.Format("PostUrl: no post/page found for '{0}'.", postFileName), null); + } + + var url = page.Url; + + if (url.EndsWith("/")) + { + url += "index.html"; + } - return permalink; + return url; } public override void Initialize(string tagName, string markup, List tokens) { base.Initialize(tagName, markup, tokens); - postFileName = markup.Trim(); + _postFileName = markup.Trim(); } public override void Render(Context context, TextWriter result) + { + result.Write(PostUrl(_postFileName)); + } + } + + public class PostUrlTagFactory : TagFactoryBase + { + public PostUrlTagFactory() + : base("PostUrl") + { } + + internal override ITag CreateTag() { - result.Write(PostUrl(postFileName)); + return new PostUrlTag(SiteContext); } } } diff --git a/src/Pretzel.Logic/Extensibility/ITag.cs b/src/Pretzel.Logic/Extensibility/ITag.cs index 645e1a613..78366a0fd 100644 --- a/src/Pretzel.Logic/Extensibility/ITag.cs +++ b/src/Pretzel.Logic/Extensibility/ITag.cs @@ -1,8 +1,6 @@ -using System.ComponentModel.Composition; - + namespace Pretzel.Logic.Extensibility { - [InheritedExport] public interface ITag : IName { } diff --git a/src/Pretzel.Logic/Extensibility/TagFactoryBase.cs b/src/Pretzel.Logic/Extensibility/TagFactoryBase.cs new file mode 100644 index 000000000..7c7576a37 --- /dev/null +++ b/src/Pretzel.Logic/Extensibility/TagFactoryBase.cs @@ -0,0 +1,39 @@ +using Pretzel.Logic.Extensions; +using Pretzel.Logic.Templating.Context; +using System.ComponentModel.Composition; + +namespace Pretzel.Logic.Extensibility +{ + [InheritedExport] + public abstract class TagFactoryBase : DotLiquid.ITagFactory + { + private string _tageName; + + protected SiteContext SiteContext { get; private set; } + + public TagFactoryBase(string tagName) + { + _tageName = tagName.ToUnderscoreCase(); + } + + public string TagName + { + get + { + return _tageName; + } + } + + public DotLiquid.Tag Create() + { + return (DotLiquid.Tag)CreateTag(); + } + + internal abstract ITag CreateTag(); + + internal void Initialize(SiteContext siteContext) + { + SiteContext = siteContext; + } + } +} diff --git a/src/Pretzel.Logic/Pretzel.Logic.csproj b/src/Pretzel.Logic/Pretzel.Logic.csproj index ef1ecb973..181fce6e6 100644 --- a/src/Pretzel.Logic/Pretzel.Logic.csproj +++ b/src/Pretzel.Logic/Pretzel.Logic.csproj @@ -50,7 +50,7 @@ False - ..\packages\DotLiquid.1.8.0\lib\NET45\DotLiquid.dll + ..\..\libs\DotLiquid.dll False @@ -100,6 +100,7 @@ + diff --git a/src/Pretzel.Logic/Templating/Jekyll/LiquidEngine.cs b/src/Pretzel.Logic/Templating/Jekyll/LiquidEngine.cs index f61d12e1b..bacf22270 100644 --- a/src/Pretzel.Logic/Templating/Jekyll/LiquidEngine.cs +++ b/src/Pretzel.Logic/Templating/Jekyll/LiquidEngine.cs @@ -24,7 +24,7 @@ public LiquidEngine() protected override void PreProcess() { contextDrop = new SiteContextDrop(Context); - + Template.FileSystem = new Includes(Context.SourceFolder, FileSystem); if (Filters != null) @@ -40,8 +40,16 @@ protected override void PreProcess() foreach (var tag in Tags) { - var registerTagGenericMethod = registerTagMethod.MakeGenericMethod(new[] { tag.GetType() }); - registerTagGenericMethod.Invoke(null, new[] { tag.Name.ToUnderscoreCase() }); + var registerTagGenericMethod = registerTagMethod.MakeGenericMethod(new[] { tag.GetType() }); + registerTagGenericMethod.Invoke(null, new[] { tag.Name.ToUnderscoreCase() }); + } + } + if(TagFactories!=null) + { + foreach (var tagFactory in TagFactories) + { + tagFactory.Initialize(Context); + Template.RegisterTagFactory(tagFactory); } } } diff --git a/src/Pretzel.Logic/Templating/JekyllEngineBase.cs b/src/Pretzel.Logic/Templating/JekyllEngineBase.cs index 61432ce36..98145b253 100644 --- a/src/Pretzel.Logic/Templating/JekyllEngineBase.cs +++ b/src/Pretzel.Logic/Templating/JekyllEngineBase.cs @@ -30,6 +30,9 @@ public abstract class JekyllEngineBase : ISiteEngine [ImportMany] public IEnumerable Tags { get; set; } + [ImportMany] + public IEnumerable TagFactories { get; set; } + public abstract void Initialize(); protected abstract void PreProcess(); @@ -151,7 +154,7 @@ private void ProcessFile(string outputDirectory, Page page, Page previous, Page throw new PageProcessingException(message, ex); } - Console.WriteLine(@"Failed to process {0}, see inner exception for more details", context.OutputPath); + Console.WriteLine(@"Failed to process {0}: {1}", context.OutputPath, ex); continue; } @@ -198,7 +201,7 @@ private void ProcessFile(string outputDirectory, Page page, Page previous, Page throw new PageProcessingException(message, ex); } - Console.WriteLine(@"Failed to process {0}, see inner exception for more details", context.OutputPath); + Console.WriteLine(@"Failed to process {0}: {1}", context.OutputPath, ex); continue; } diff --git a/src/Pretzel.Logic/Templating/Razor/ExtensibleTemplate.cs b/src/Pretzel.Logic/Templating/Razor/ExtensibleTemplate.cs index b7ab809bc..3a04c9f72 100644 --- a/src/Pretzel.Logic/Templating/Razor/ExtensibleTemplate.cs +++ b/src/Pretzel.Logic/Templating/Razor/ExtensibleTemplate.cs @@ -1,5 +1,6 @@ using Pretzel.Logic.Extensibility; using RazorEngine.Templating; +using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; @@ -49,17 +50,27 @@ public ITemplate CreateInstance(InstanceContext context) } } - public class ExtensibleProxy : DynamicObject where T : IName + public class ExtensibleProxy : DynamicObject where T : class, IName { - private readonly Dictionary extensibleMethods; + private readonly Dictionary> extensibleMethods; public ExtensibleProxy(IEnumerable extensibleMethods) { this.extensibleMethods = extensibleMethods == null ? - new Dictionary() : + new Dictionary>() : extensibleMethods.ToDictionary( x => x.Name, - x => x.GetType().GetMethod(x.Name) + x => { + var method = x.GetType().GetMethod(x.Name); + if(method.IsStatic) + { + return new Tuple((T)null, method); + } + else + { + return new Tuple(x, method); + } + } ); } @@ -70,10 +81,10 @@ public override IEnumerable GetDynamicMemberNames() public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { - MethodInfo extensibleMethod; + Tuple extensibleMethod; if (extensibleMethods.TryGetValue(binder.Name, out extensibleMethod)) { - result = extensibleMethod.Invoke(null, args); + result = extensibleMethod.Item2.Invoke(extensibleMethod.Item1, args); return true; } diff --git a/src/Pretzel.Logic/Templating/Razor/RazorSiteEngine.cs b/src/Pretzel.Logic/Templating/Razor/RazorSiteEngine.cs index 7dab7a324..779549377 100644 --- a/src/Pretzel.Logic/Templating/Razor/RazorSiteEngine.cs +++ b/src/Pretzel.Logic/Templating/Razor/RazorSiteEngine.cs @@ -7,6 +7,9 @@ using System.ComponentModel.Composition; using System.IO; using System.Text.RegularExpressions; +using System.Linq; +using Pretzel.Logic.Extensibility; +using System.Collections.Generic; namespace Pretzel.Logic.Templating.Razor { @@ -18,6 +21,8 @@ public class RazorSiteEngine : JekyllEngineBase private string includesPath; + private List _allTags = new List(); + public override void Initialize() { } @@ -25,6 +30,20 @@ public override void Initialize() protected override void PreProcess() { includesPath = Path.Combine(Context.SourceFolder, "_includes"); + + if (Tags != null) + { + _allTags.AddRange(Tags); + } + + if (TagFactories != null) + { + _allTags.AddRange(TagFactories.Select(factory => + { + factory.Initialize(Context); + return factory.CreateTag(); + })); + } } protected override string[] LayoutExtensions @@ -39,7 +58,7 @@ protected override string RenderTemplate(string content, PageContext pageData) TemplateManager = new IncludesResolver(FileSystem, includesPath), BaseTemplateType = typeof(ExtensibleTemplate<>) }; - serviceConfiguration.Activator = new ExtensibleActivator(serviceConfiguration.Activator, Filters, Tags); + serviceConfiguration.Activator = new ExtensibleActivator(serviceConfiguration.Activator, Filters, _allTags); Engine.Razor = RazorEngineService.Create(serviceConfiguration); content = Regex.Replace(content, "

(@model .*?)

", "$1"); diff --git a/src/Pretzel.Tests/Pretzel.Tests.csproj b/src/Pretzel.Tests/Pretzel.Tests.csproj index ec313d02b..5f9d57dee 100644 --- a/src/Pretzel.Tests/Pretzel.Tests.csproj +++ b/src/Pretzel.Tests/Pretzel.Tests.csproj @@ -46,7 +46,7 @@
False - ..\packages\DotLiquid.1.8.0\lib\NET45\DotLiquid.dll + ..\..\libs\DotLiquid.dll False diff --git a/src/Pretzel.Tests/Templating/Jekyll/LiquidEngineTests.cs b/src/Pretzel.Tests/Templating/Jekyll/LiquidEngineTests.cs index 19af15efe..31e286c2a 100644 --- a/src/Pretzel.Tests/Templating/Jekyll/LiquidEngineTests.cs +++ b/src/Pretzel.Tests/Templating/Jekyll/LiquidEngineTests.cs @@ -763,13 +763,15 @@ public override void When() [Fact] public void File_With_Bad_Liquid_Format_Should_Be_Traced() { + const string ExpectedStartFile = @"Failed to process C:\website\_site\BadFormat.html: DotLiquid.Exceptions.SyntaxException: Variable '{{}' was not properly terminated with regexp: (?-mix:\}\})"; + using (StringWriter sw = new StringWriter()) { Console.SetOut(sw); Subject.Process(Context, true); - Assert.Equal(@"Failed to process C:\website\_site\BadFormat.html, see inner exception for more details" + Environment.NewLine, sw.ToString()); + Assert.StartsWith(ExpectedStartFile, sw.ToString()); } Assert.False(FileSystem.AllFiles.Contains(@"C:\website\_site\BadFormat.html")); } @@ -930,8 +932,8 @@ public void The_Output_Should_Not_Have_The_Comment() public class Given_Page_Has_PostUrlBlock : BakingEnvironment { - private const string PageContents = "---\r\n layout: nil \r\n---\r\n\r\n

{% post_url post-title.md %}

"; - private const string ExpectedfileContents = "

post/title.html

"; + private const string PageContents = "---\r\n layout: nil \r\n---\r\n\r\n

{% post_url index.md %}

"; + private const string ExpectedfileContents = "

/index.html

"; public override LiquidEngine Given() { @@ -944,7 +946,7 @@ public override void When() var generator = GetSiteContextGenerator(FileSystem); var context = generator.BuildContext(@"C:\website\", @"C:\website\_site", false); Subject.FileSystem = FileSystem; - Subject.Tags = new List { new PostUrlTag() }; + Subject.TagFactories = new List { new PostUrlTagFactory() }; Subject.Process(context); } @@ -1227,8 +1229,8 @@ public class Given_LiquidEngine_Is_Initialized : BakingEnvironment { private const string HighlightPageContents = "---\r\n layout: nil \r\n---\r\n\r\n{% highlight %}a word{% endhighlight %}"; private const string HighlightExpectedfileContents = "

a word

"; - private const string PostUrlPageContents = "---\r\n layout: nil \r\n---\r\n\r\n{% post_url post-title.md %}"; - private const string PostUrlExpectedfileContents = "

post/title.html

"; + private const string PostUrlPageContents = "---\r\n layout: nil \r\n---\r\n\r\n{% post_url NumberOfWords.md %}"; + private const string PostUrlExpectedfileContents = "

/NumberOfWords.html

"; private const string CgiEscapePageContents = "---\r\n layout: nil \r\n---\r\n\r\n{{ 'foo,bar;baz?' | cgi_escape }}"; private const string CgiEscapeExpectedfileContents = "

foo%2Cbar%3Bbaz%3F

"; private const string UriEscapePageContents = "---\r\n layout: nil \r\n---\r\n\r\n{{ 'foo, bar \\baz?' | uri_escape }}"; @@ -1242,7 +1244,6 @@ public override LiquidEngine Given() { var engine = new LiquidEngine(); engine.Initialize(); - engine.Tags = new List { new PostUrlTag() }; return engine; } @@ -1257,6 +1258,7 @@ public override void When() var generator = GetSiteContextGenerator(FileSystem); var context = generator.BuildContext(@"C:\website\", @"C:\website\_site", false); Subject.FileSystem = FileSystem; + Subject.TagFactories = new List { new PostUrlTagFactory() }; Subject.Process(context); } @@ -1505,14 +1507,13 @@ public void The_File_Is_Generated_With_Index_Name() public class Given_Page_Has_Liquid_Tag_And_Block_With_Underscores : BakingEnvironment { - private const string PageContents = "---\r\n layout: nil \r\n---\r\n\r\n_any_ word {% highlight %}a word{% endhighlight %}\r\n{% post_url post-title.md %}\r\n{{ 'This is a test' | number_of_words }}"; - private const string ExpectedfileContents = "

any word

a word
post/title.html4

"; + private const string PageContents = "---\r\n layout: nil \r\n---\r\n\r\n_any_ word {% highlight %}a word{% endhighlight %}\r\n{% post_url index.md %}\r\n{{ 'This is a test' | number_of_words }}"; + private const string ExpectedfileContents = "

any word

a word
/index.html4

"; public override LiquidEngine Given() { var engine = new LiquidEngine(); engine.Initialize(); - engine.Tags = new List { new PostUrlTag() }; return engine; } @@ -1522,6 +1523,7 @@ public override void When() var generator = GetSiteContextGenerator(FileSystem); var context = generator.BuildContext(@"C:\website\", @"C:\website\_site", false); Subject.FileSystem = FileSystem; + Subject.TagFactories = new List { new PostUrlTagFactory() }; Subject.Process(context); } diff --git a/src/Pretzel.Tests/Templating/Razor/RazorEngineTests.cs b/src/Pretzel.Tests/Templating/Razor/RazorEngineTests.cs index 4b3b66711..7715ce7ca 100644 --- a/src/Pretzel.Tests/Templating/Razor/RazorEngineTests.cs +++ b/src/Pretzel.Tests/Templating/Razor/RazorEngineTests.cs @@ -30,7 +30,7 @@ private void ProcessContents(string layout, string content, Dictionary"; + const string templateContents = "@Raw(Model.Content) @Tag.PostUrl(\"index.cshtml\")"; const string pageContents = "

Hello

"; - const string expected = "

Hello

post/title.html"; - Subject.Tags = new ITag[] { new PostUrlTag() }; + const string expected = "

Hello

/index.html"; + + Subject.TagFactories = new List { new PostUrlTagFactory() }; // act ProcessContents(templateContents, pageContents, new Dictionary()); diff --git a/src/Pretzel/Pretzel.csproj b/src/Pretzel/Pretzel.csproj index 1d70e18a2..48a35b95a 100644 --- a/src/Pretzel/Pretzel.csproj +++ b/src/Pretzel/Pretzel.csproj @@ -43,7 +43,7 @@ - ..\packages\DotLiquid.1.8.0\lib\NET45\DotLiquid.dll + ..\..\libs\DotLiquid.dll ..\packages\Firefly.0.6.3\lib\Firefly.dll From 4d134809e515c9e1a00874f274eb6d272727e010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Bertrand?= Date: Mon, 9 Nov 2015 06:53:34 +0100 Subject: [PATCH 2/2] Fix CreateTag method not public And add tests --- .../Extensibility/Extensions/PostUrlTag.cs | 2 +- .../Extensibility/TagFactoryBase.cs | 2 +- .../Templating/Jekyll/LiquidEngineTests.cs | 65 ++++++++++++++++++ .../Templating/Razor/RazorEngineTests.cs | 66 +++++++++++++++++++ src/Pretzel/Program.cs | 12 +++- 5 files changed, 143 insertions(+), 4 deletions(-) diff --git a/src/Pretzel.Logic/Extensibility/Extensions/PostUrlTag.cs b/src/Pretzel.Logic/Extensibility/Extensions/PostUrlTag.cs index c0a7b9fb3..df5c71558 100644 --- a/src/Pretzel.Logic/Extensibility/Extensions/PostUrlTag.cs +++ b/src/Pretzel.Logic/Extensibility/Extensions/PostUrlTag.cs @@ -61,7 +61,7 @@ public PostUrlTagFactory() : base("PostUrl") { } - internal override ITag CreateTag() + public override ITag CreateTag() { return new PostUrlTag(SiteContext); } diff --git a/src/Pretzel.Logic/Extensibility/TagFactoryBase.cs b/src/Pretzel.Logic/Extensibility/TagFactoryBase.cs index 7c7576a37..90ee333c1 100644 --- a/src/Pretzel.Logic/Extensibility/TagFactoryBase.cs +++ b/src/Pretzel.Logic/Extensibility/TagFactoryBase.cs @@ -29,7 +29,7 @@ public DotLiquid.Tag Create() return (DotLiquid.Tag)CreateTag(); } - internal abstract ITag CreateTag(); + public abstract ITag CreateTag(); internal void Initialize(SiteContext siteContext) { diff --git a/src/Pretzel.Tests/Templating/Jekyll/LiquidEngineTests.cs b/src/Pretzel.Tests/Templating/Jekyll/LiquidEngineTests.cs index cfc83214a..45e4e99b1 100644 --- a/src/Pretzel.Tests/Templating/Jekyll/LiquidEngineTests.cs +++ b/src/Pretzel.Tests/Templating/Jekyll/LiquidEngineTests.cs @@ -2124,5 +2124,70 @@ public void Mkd_File_Should_Be_Rendered() Assert.Equal("

Title

", FileSystem.File.ReadAllText(@"D:\Result\_site\2012\01\04\SomeFile.html")); } } + public class Given_Engine_Has_Custom_TagFactory : BakingEnvironment + { + private const string ConfigContents = "---\r\n title: Site Title\r\n---"; + private const string PageContent = "---\r\n \r\n---\r\n{% custom %}"; + private const string ExpectedPageContents = "

custom tag: Site Title

"; + + public override LiquidEngine Given() + { + return new LiquidEngine(); + } + + public override void When() + { + FileSystem.AddFile(@"C:\website\_config.yml", new MockFileData(ConfigContents)); + FileSystem.AddFile(@"C:\website\index.md", new MockFileData(PageContent)); + var generator = GetSiteContextGenerator(FileSystem); + var context = generator.BuildContext(@"C:\website\", @"C:\website\_site", false); + Subject.FileSystem = FileSystem; + + Subject.TagFactories = new List { new CustomTagFactory() }; + + Subject.Process(context); + } + + [Fact] + public void Page_should_contain_custom_tag() + { + Assert.Equal(ExpectedPageContents, FileSystem.File.ReadAllText(@"C:\website\_site\index.html").RemoveWhiteSpace()); + } + + public class CustomTag : DotLiquid.Tag, ITag + { + private SiteContext _siteContext; + + public new string Name { get { return "Custom"; } } + + public CustomTag(SiteContext siteContext) + { + _siteContext = siteContext; + } + + public string Custom() + { + return string.Format("custom tag: {0}", _siteContext.Config["title"]); + } + + public override void Render(DotLiquid.Context context, TextWriter result) + { + result.WriteLine(Custom()); + } + } + + public class CustomTagFactory : TagFactoryBase + { + public CustomTagFactory():base("Custom") + { + + } + + public override ITag CreateTag() + { + return new CustomTag(this.SiteContext); + } + } + } } } diff --git a/src/Pretzel.Tests/Templating/Razor/RazorEngineTests.cs b/src/Pretzel.Tests/Templating/Razor/RazorEngineTests.cs index 94830c7a9..2101da303 100644 --- a/src/Pretzel.Tests/Templating/Razor/RazorEngineTests.cs +++ b/src/Pretzel.Tests/Templating/Razor/RazorEngineTests.cs @@ -309,4 +309,70 @@ public void Posts_Properly_Paginated() FileSystem.File.ReadAllText(@"C:\website\_site\blog\page4\index.html").RemoveWhiteSpace()); } } + + public class Given_Engine_Has_Custom_TagFactory : BakingEnvironment + { + private const string ConfigContents = "---\r\n title: Site Title\r\n---"; + private const string PageContent = "---\r\n \r\n---\r\n@Tag.Custom()"; + private const string ExpectedPageContents = "

custom tag: Site Title

"; + + public override RazorSiteEngine Given() + { + return new RazorSiteEngine(); + } + + public override void When() + { + FileSystem.AddFile(@"C:\website\_config.yml", new MockFileData(ConfigContents)); + FileSystem.AddFile(@"C:\website\index.md", new MockFileData(PageContent)); + var generator = new SiteContextGenerator(FileSystem, new LinkHelper()); + var context = generator.BuildContext(@"C:\website\", @"C:\website\_site", false); + Subject.FileSystem = FileSystem; + + Subject.TagFactories = new List { new CustomTagFactory() }; + + Subject.Process(context); + } + + [Fact] + public void Page_should_contain_custom_tag() + { + Assert.Equal(ExpectedPageContents, FileSystem.File.ReadAllText(@"C:\website\_site\index.html").RemoveWhiteSpace()); + } + + public class CustomTag : DotLiquid.Tag, ITag + { + private SiteContext _siteContext; + + public new string Name { get { return "Custom"; } } + + public CustomTag(SiteContext siteContext) + { + _siteContext = siteContext; + } + + public string Custom() + { + return string.Format("custom tag: {0}", _siteContext.Config["title"]); + } + + public override void Render(DotLiquid.Context context, TextWriter result) + { + result.WriteLine(Custom()); + } + } + + public class CustomTagFactory : TagFactoryBase + { + public CustomTagFactory() : base("Custom") + { + + } + + public override ITag CreateTag() + { + return new CustomTag(this.SiteContext); + } + } + } } diff --git a/src/Pretzel/Program.cs b/src/Pretzel/Program.cs index 397a30375..272410e03 100644 --- a/src/Pretzel/Program.cs +++ b/src/Pretzel/Program.cs @@ -1,7 +1,6 @@ using NDesk.Options; using Pretzel.Commands; using Pretzel.Logic.Commands; -using Pretzel.Logic.Extensibility; using Pretzel.Logic.Extensions; using System; using System.ComponentModel.Composition; @@ -134,7 +133,16 @@ private void AddScriptCs(AggregateCatalog mainCatalog, string pluginsPath) var scriptCsCatalogMethod = factoryType.GetMethod("CreateScriptCsCatalog"); if (scriptCsCatalogMethod != null) { - var catalog = (ComposablePartCatalog)scriptCsCatalogMethod.Invoke(null, new object[] { pluginsPath, new[] { typeof(DotLiquid.Tag), typeof(ITag) } }); + var catalog = (ComposablePartCatalog)scriptCsCatalogMethod.Invoke(null, new object[] + { + pluginsPath, + new[] + { + typeof(DotLiquid.Tag), + typeof(Logic.Extensibility.ITag), + typeof(Logic.Templating.Context.SiteContext) + } + }); mainCatalog.Catalogs.Add(catalog); } else