/Core/Text/Template.cs
https://bitbucket.org/jdeselms/magenoco · C# · 155 lines · 119 code · 30 blank · 6 comment · 8 complexity · 42f68d02c92b3155e30e00d1547c428c MD5 · raw file
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Resources;
- using System.Text;
- using System.Text.RegularExpressions;
- using System.Reflection;
- using System.IO;
- using Magenoco.Core.IO;
- using Magenoco.Core.Processor;
- namespace Magenoco.Core.Text
- {
- public class Template
- {
- private readonly string _name;
- private readonly string _text;
- private readonly string[] _appliesTo;
- private readonly Lazy<TextToken[]> _tokens;
- private readonly Lazy<ChildToken[]> _childTokens;
- private readonly Template _fileNameTemplateOrNull;
- private static Regex _tokenRegex;
- private static Regex _childTokenRegex;
- public Template(string name, string appliesTo, string text, Template fileNameTemplateOrNull=null)
- {
- _name = name;
- _appliesTo = appliesTo == null ? new string[0] : appliesTo.Split(',');
- _tokenRegex = new Regex("\\<\\<([a-zA-Z_][a-zA-Z0-9_]*)(\\.[a-zA-Z_][a-zA-Z0-9_]*)?\\>\\>");
- _childTokenRegex = new Regex("{{([a-zA-Z_][a-zA-Z0-9_]*)(\\.[a-zA-Z_][a-zA-Z0-9_]*)?}}");
- _fileNameTemplateOrNull = fileNameTemplateOrNull;
- // Handle escpaing: If you want literal <<, then use \<<.
- // But if you really do want "\<<", then use "\\<<".
- _text = text.Replace("\\\\<<", "~~NOTESCAPED`_`TOKEN~~");
- _text = _text.Replace("\\\\{{", "~~NOTESCAPED`_`CHILD~~");
- _text = _text.Replace("\\<<", "~~ESCAPED`_`TOKEN~~");
- _text = _text.Replace("\\{{", "~~ESCAPED`_`CHILD~~");
- _text = _text.Replace("~~NOTESCAPED`_`TOKEN~~", "\\<<");
- _text = _text.Replace("~~NOTESCAPED`_`CHILD~~", "\\{{");
- _tokens = new Lazy<TextToken[]>(ParseForTokens);
- _childTokens = new Lazy<ChildToken[]>(ParseForChildTokens);
- }
- public TextToken[] Tokens
- {
- get { return _tokens.Value; }
- }
- public ChildToken[] ChildTokens
- {
- get { return _childTokens.Value; }
- }
- public string[] AppliesTo { get { return _appliesTo; } }
- public string Replace(ITokenSource tokenSource, ITemplateSource templateSource, IFileSystem fileSystem=null)
- {
- if (fileSystem == null)
- {
- fileSystem = Defaults.FileSystem;
- }
- string result = _text;
- foreach (var token in Tokens)
- {
- result = result.Replace("<<" + token.ToString() + ">>", tokenSource.GetAttribute(token));
- }
- foreach (var childToken in ChildTokens)
- {
- var template = templateSource.GetTemplate(_name + "." + childToken.TemplateName);
- StringBuilder replacement = new StringBuilder();
- List<ICodeGenerator> childCodeGenerators = new List<ICodeGenerator>();
- foreach (var codeGen in tokenSource.GetCodeGeneratorsForChildren(template._name, template.AppliesTo, templateSource))
- {
- childCodeGenerators.Add(codeGen);
- }
- foreach (var childCodeGen in tokenSource.TransformCodeGeneratorForChildToken(childCodeGenerators, childToken))
- {
- replacement.Append(childCodeGen.GenerateCode(template));
- }
- result = result.Replace(childToken.ToString(), replacement.ToString());
- }
- // Replace the tag with "<<" so that the end result will actually
- // be a token.
- result = result.Replace("~~ESCAPED`_`TOKEN~~", "<<");
- result = result.Replace("~~ESCAPED`_`CHILD~~", "{{");
- // And if we're supposed to write it out to a file, do that too.
- if (_fileNameTemplateOrNull != null)
- {
- string outputPath = _fileNameTemplateOrNull.Replace(tokenSource, templateSource, fileSystem);
- fileSystem.CreateDirectoryIfNotExists(Path.GetDirectoryName(outputPath));
- // .cs File? pretty print for C#.
- if (outputPath.ToLower().EndsWith(".cs"))
- {
- CSharpPrettyPrinter prettyPrinter = new CSharpPrettyPrinter();
- result = prettyPrinter.Prettify(result);
- }
- fileSystem.WriteFile(outputPath, result);
- }
- return result;
- }
- public string GetOutputFileNameOrNull(ITokenSource tokenSource, ITemplateSource templateSource, IFileSystem fileSystem)
- {
- if (_fileNameTemplateOrNull != null)
- {
- return _fileNameTemplateOrNull.Replace(tokenSource, templateSource, fileSystem);
- }
- else
- {
- return null;
- }
- }
- private TextToken[] ParseForTokens()
- {
- HashSet<TextToken> matches = new HashSet<TextToken>();
- foreach (Match match in _tokenRegex.Matches(_text))
- {
- matches.Add(new TextToken(match.Value.Substring(2, match.Value.Length-4)));
- }
- return matches.ToArray();
- }
- private ChildToken[] ParseForChildTokens()
- {
- HashSet<ChildToken> matches = new HashSet<ChildToken>();
- foreach (Match match in _childTokenRegex.Matches(_text))
- {
- matches.Add(new ChildToken(match.Value));
- }
- return matches.OrderBy(t => t).ToArray();
- }
- }
- }