PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/SharpTAL/Template.cs

https://bitbucket.org/rlacko/sharptal
C# | 241 lines | 182 code | 27 blank | 32 comment | 41 complexity | 047b364e9a5ab16ffa861ff991841b4c MD5 | raw file
Possible License(s): Apache-2.0
  1. //
  2. // Template.cs
  3. //
  4. // Author:
  5. // Roman Lacko (backup.rlacko@gmail.com)
  6. //
  7. // Copyright (c) 2010 - 2013 Roman Lacko
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining
  10. // a copy of this software and associated documentation files (the
  11. // "Software"), to deal in the Software without restriction, including
  12. // without limitation the rights to use, copy, modify, merge, publish,
  13. // distribute, sublicense, and/or sell copies of the Software, and to
  14. // permit persons to whom the Software is furnished to do so, subject to
  15. // the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be
  18. // included in all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. //
  28. namespace SharpTAL
  29. {
  30. using System;
  31. using System.Collections;
  32. using System.Collections.Generic;
  33. using System.Reflection;
  34. using System.IO;
  35. using System.Globalization;
  36. using SharpTAL.TemplateProgram;
  37. using SharpTAL.TemplateCache;
  38. public class Template : ITemplate
  39. {
  40. private static ITemplateCache defaultTemplateCache = new MemoryTemplateCache();
  41. protected string body;
  42. protected Dictionary<string, Type> globalsTypes;
  43. protected List<Assembly> referencedAssemblies;
  44. protected ITemplateCache templateCache;
  45. protected TemplateInfo templateInfo;
  46. public CultureInfo Culture { get; set; }
  47. public ITemplateCache TemplateCache
  48. {
  49. set
  50. {
  51. templateInfo = null;
  52. templateCache = value;
  53. }
  54. get
  55. {
  56. return templateCache ?? defaultTemplateCache;
  57. }
  58. }
  59. public Template(string body) :
  60. this(body, null, null)
  61. {
  62. }
  63. public Template(string body, Dictionary<string, Type> globalsTypes) :
  64. this(body, globalsTypes, null)
  65. {
  66. }
  67. public Template(string body, List<Assembly> referencedAssemblies) :
  68. this(body, null, referencedAssemblies)
  69. {
  70. }
  71. public Template(string body, Dictionary<string, Type> globalsTypes, List<Assembly> referencedAssemblies)
  72. {
  73. this.body = body;
  74. this.globalsTypes = globalsTypes;
  75. this.referencedAssemblies = referencedAssemblies;
  76. this.templateCache = defaultTemplateCache;
  77. this.Culture = CultureInfo.InvariantCulture;
  78. }
  79. #region ITemplate interface implementation
  80. public void Compile()
  81. {
  82. Recompile(null);
  83. }
  84. public string Render(Dictionary<string, object> globals)
  85. {
  86. using (MemoryStream outputStream = new MemoryStream())
  87. {
  88. using (StreamWriter outputWriter = new StreamWriter(outputStream))
  89. {
  90. Render(outputWriter, globals);
  91. outputWriter.Flush();
  92. outputStream.Position = 0;
  93. StreamReader reader = new StreamReader(outputStream);
  94. string result = reader.ReadToEnd();
  95. return result;
  96. }
  97. }
  98. }
  99. public void Render(StreamWriter outputWriter, Dictionary<string, object> globals)
  100. {
  101. CompileCheck(globals);
  102. try
  103. {
  104. IRenderContext context = new RenderContext();
  105. foreach (var item in globals)
  106. context[item.Key] = item.Value;
  107. context["__FormatResult"] = new Func<object, string>(FormatResult);
  108. context["__IsFalseResult"] = new Func<object, bool>(IsFalseResult);
  109. if (!context.ContainsKey("repeat"))
  110. context["repeat"] = new RepeatDictionary();
  111. // TODO: add template "macros" to context
  112. templateInfo.RenderMethod.Invoke(null, new object[] { outputWriter, context });
  113. }
  114. catch (TargetInvocationException ex)
  115. {
  116. throw new RenderTemplateException(templateInfo, ex.InnerException.Message, ex.InnerException);
  117. }
  118. catch (Exception ex)
  119. {
  120. throw new RenderTemplateException(templateInfo, ex.Message, ex);
  121. }
  122. }
  123. #endregion
  124. protected virtual string DefaultExpressionType
  125. {
  126. get { return "csharp"; }
  127. }
  128. protected virtual string FormatResult(object result)
  129. {
  130. IFormattable formattable = result as IFormattable;
  131. string resultValue = "";
  132. if (formattable != null)
  133. resultValue = formattable.ToString("", Culture);
  134. else
  135. resultValue = result.ToString();
  136. return resultValue;
  137. }
  138. protected virtual bool IsFalseResult(object obj)
  139. {
  140. if (obj == null)
  141. {
  142. // Value was Nothing
  143. return true;
  144. }
  145. if (obj is bool)
  146. {
  147. return ((bool)obj) == false;
  148. }
  149. if (obj is int)
  150. {
  151. return ((int)obj) == 0;
  152. }
  153. if (obj is float)
  154. {
  155. return ((float)obj) == 0;
  156. }
  157. if (obj is double)
  158. {
  159. return ((double)obj) == 0;
  160. }
  161. if (obj is string)
  162. {
  163. return string.IsNullOrEmpty(((string)obj));
  164. }
  165. if (obj is IEnumerable)
  166. {
  167. return ((IEnumerable)obj).GetEnumerator().MoveNext() == false;
  168. }
  169. // Everything else is true, so we return false!
  170. return false;
  171. }
  172. void CompileCheck(Dictionary<string, object> globals)
  173. {
  174. // First time compile
  175. if (templateInfo == null)
  176. {
  177. Recompile(globals);
  178. return;
  179. }
  180. if (globals == null && globalsTypes == null)
  181. return;
  182. // Compare globals and globalsTypes
  183. if ((globals == null && globalsTypes != null) ||
  184. (globals != null && globalsTypes == null) ||
  185. (globals != null && globalsTypes != null && globals.Count != globalsTypes.Count))
  186. {
  187. Recompile(globals);
  188. return;
  189. }
  190. foreach (string varName in globalsTypes.Keys)
  191. {
  192. if (globals.ContainsKey(varName) == false ||
  193. globals[varName].GetType() != globalsTypes[varName])
  194. {
  195. Recompile(globals);
  196. return;
  197. }
  198. }
  199. }
  200. void Recompile(Dictionary<string, object> globals)
  201. {
  202. if (globals != null && globals.Count > 0)
  203. {
  204. globalsTypes = new Dictionary<string, Type>();
  205. foreach (string name in globals.Keys)
  206. {
  207. object obj = globals[name];
  208. globalsTypes.Add(name, obj != null ? obj.GetType() : null);
  209. }
  210. }
  211. templateInfo = templateCache.CompileTemplate(body, globalsTypes, referencedAssemblies);
  212. }
  213. }
  214. }