/src/DotLiquid/StandardFilters.cs

https://github.com/RevCBH/dotliquid · C# · 567 lines · 301 code · 57 blank · 209 comment · 42 complexity · e10e359eca94a30801cf6b60b9dd713b MD5 · raw file

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Globalization;
  5. #if !NET35
  6. using System.Net;
  7. #endif
  8. using System.Linq;
  9. using System.Linq.Expressions;
  10. using System.Text.RegularExpressions;
  11. #if NET35
  12. using System.Web;
  13. #endif
  14. using DotLiquid.Util;
  15. namespace DotLiquid
  16. {
  17. public static class StandardFilters
  18. {
  19. /// <summary>
  20. /// Return the size of an array or of an string
  21. /// </summary>
  22. /// <param name="input"></param>
  23. /// <returns></returns>
  24. public static int Size(object input)
  25. {
  26. if (input is string)
  27. return ((string) input).Length;
  28. if (input is IEnumerable)
  29. return ((IEnumerable) input).Cast<object>().Count();
  30. return 0;
  31. }
  32. /// <summary>
  33. /// convert a input string to DOWNCASE
  34. /// </summary>
  35. /// <param name="input"></param>
  36. /// <returns></returns>
  37. public static string Downcase(string input)
  38. {
  39. return input == null ? input : input.ToLower();
  40. }
  41. /// <summary>
  42. /// convert a input string to UPCASE
  43. /// </summary>
  44. /// <param name="input"></param>
  45. /// <returns></returns>
  46. public static string Upcase(string input)
  47. {
  48. return input == null
  49. ? input
  50. : input.ToUpper();
  51. }
  52. /// <summary>
  53. /// capitalize words in the input sentence
  54. /// </summary>
  55. /// <param name="input"></param>
  56. /// <returns></returns>
  57. public static string Capitalize(string input)
  58. {
  59. if (input.IsNullOrWhiteSpace())
  60. return input;
  61. return string.IsNullOrEmpty(input)
  62. ? input
  63. : CultureInfo.CurrentCulture.TextInfo.ToTitleCase(input);
  64. }
  65. public static string Escape(string input)
  66. {
  67. if (string.IsNullOrEmpty(input))
  68. return input;
  69. try
  70. {
  71. #if NET35
  72. return HttpUtility.HtmlEncode(input);
  73. #else
  74. return WebUtility.HtmlEncode(input);
  75. #endif
  76. }
  77. catch
  78. {
  79. return input;
  80. }
  81. }
  82. public static string H(string input)
  83. {
  84. return Escape(input);
  85. }
  86. #if NET35
  87. /// <summary>
  88. /// Truncates a string down to 15 characters
  89. /// </summary>
  90. /// <param name="input"></param>
  91. /// <returns></returns>
  92. public static string Truncate(string input)
  93. {
  94. return Truncate(input, 15, "...");
  95. }
  96. /// <summary>
  97. /// Truncates a string down to <paramref name="length"/> characters
  98. /// </summary>
  99. /// <param name="input"></param>
  100. /// <param name="length"></param>
  101. /// <returns></returns>
  102. public static string Truncate(string input, int length)
  103. {
  104. return Truncate(input, length, "...");
  105. }
  106. /// <summary>
  107. /// Truncates a string down to x characters
  108. /// </summary>
  109. /// <param name="input"></param>
  110. /// <param name="length"></param>
  111. /// <param name="truncateString"></param>
  112. /// <returns></returns>
  113. public static string Truncate(string input, int length, string truncateString)
  114. #else
  115. /// <summary>
  116. /// Truncates a string down to x characters
  117. /// </summary>
  118. /// <param name="input"></param>
  119. /// <param name="length"></param>
  120. /// <param name="truncateString"></param>
  121. /// <returns></returns>
  122. public static string Truncate(string input, int length = 50, string truncateString = "...")
  123. #endif
  124. {
  125. if (string.IsNullOrEmpty(input))
  126. return input;
  127. int l = length - truncateString.Length;
  128. return input.Length > length
  129. ? input.Substring(0, l < 0 ? 0 : l) + truncateString
  130. : input;
  131. }
  132. #if NET35
  133. public static string TruncateWords(string input)
  134. {
  135. return TruncateWords(input, 15);
  136. }
  137. public static string TruncateWords(string input, int words)
  138. {
  139. return TruncateWords(input, words, "...");
  140. }
  141. public static string TruncateWords(string input, int words, string truncateString)
  142. #else
  143. public static string TruncateWords(string input, int words = 15, string truncateString = "...")
  144. #endif
  145. {
  146. if (string.IsNullOrEmpty(input))
  147. return input;
  148. var wordList = input.Split(' ').ToList();
  149. int l = words < 0 ? 0 : words;
  150. return wordList.Count > l
  151. ? string.Join(" ", wordList.Take(l).ToArray()) + truncateString
  152. : input;
  153. }
  154. public static string StripHtml(string input)
  155. {
  156. return input.IsNullOrWhiteSpace()
  157. ? input
  158. : Regex.Replace(input, @"<.*?>", string.Empty);
  159. }
  160. /// <summary>
  161. /// Remove all newlines from the string
  162. /// </summary>
  163. /// <param name="input"></param>
  164. /// <returns></returns>
  165. public static string StripNewlines(string input)
  166. {
  167. return input.IsNullOrWhiteSpace()
  168. ? input
  169. : Regex.Replace(input, Environment.NewLine, string.Empty);
  170. }
  171. #if NET35
  172. /// <summary>
  173. /// Join elements of the array with a certain character between them
  174. /// </summary>
  175. /// <param name="input"></param>
  176. /// <returns></returns>
  177. public static string Join(IEnumerable input)
  178. {
  179. return Join(input, " ");
  180. }
  181. /// <summary>
  182. /// Join elements of the array with a certain character between them
  183. /// </summary>
  184. /// <param name="input"></param>
  185. /// <param name="glue"></param>
  186. /// <returns></returns>
  187. public static string Join(IEnumerable input, string glue)
  188. #else
  189. /// <summary>
  190. /// Join elements of the array with a certain character between them
  191. /// </summary>
  192. /// <param name="input"></param>
  193. /// <param name="glue"></param>
  194. /// <returns></returns>
  195. public static string Join(IEnumerable input, string glue = " ")
  196. #endif
  197. {
  198. if (input == null)
  199. return null;
  200. IEnumerable<object> castInput = input.Cast<object>();
  201. #if NET35
  202. return string.Join(glue, castInput.Select(o => o.ToString()).ToArray());
  203. #else
  204. return string.Join(glue, castInput);
  205. #endif
  206. }
  207. #if NET35
  208. /// <summary>
  209. /// Sort elements of the array
  210. /// provide optional property with which to sort an array of hashes or drops
  211. /// </summary>
  212. /// <param name="input"></param>
  213. /// <returns></returns>
  214. public static IEnumerable Sort(object input)
  215. {
  216. return Sort(input, null);
  217. }
  218. /// <summary>
  219. /// Sort elements of the array
  220. /// provide optional property with which to sort an array of hashes or drops
  221. /// </summary>
  222. /// <param name="input"></param>
  223. /// <param name="property"></param>
  224. /// <returns></returns>
  225. public static IEnumerable Sort(object input, string property)
  226. #else
  227. /// <summary>
  228. /// Sort elements of the array
  229. /// provide optional property with which to sort an array of hashes or drops
  230. /// </summary>
  231. /// <param name="input"></param>
  232. /// <param name="property"></param>
  233. /// <returns></returns>
  234. public static IEnumerable Sort(object input, string property = null)
  235. #endif
  236. {
  237. List<object> ary;
  238. if (input is IEnumerable)
  239. ary = ((IEnumerable) input).Flatten().Cast<object>().ToList();
  240. else
  241. ary = new List<object>(new[] { input });
  242. if (!ary.Any())
  243. return ary;
  244. if (string.IsNullOrEmpty(property))
  245. ary.Sort();
  246. else if ((ary.All(o => o is IDictionary)) && ((IDictionary) ary.First()).Contains(property))
  247. ary.Sort((a, b) => Comparer.Default.Compare(((IDictionary) a)[property], ((IDictionary) b)[property]));
  248. else if (ary.All(o => o.RespondTo(property)))
  249. ary.Sort((a, b) => Comparer.Default.Compare(a.Send(property), b.Send(property)));
  250. return ary;
  251. }
  252. /// <summary>
  253. /// Map/collect on a given property
  254. /// </summary>
  255. /// <param name="input"></param>
  256. /// <param name="property"></param>
  257. /// <returns></returns>
  258. public static IEnumerable Map(IEnumerable input, string property)
  259. {
  260. List<object> ary = input.Cast<object>().ToList();
  261. if (!ary.Any())
  262. return ary;
  263. if ((ary.All(o => o is IDictionary)) && ((IDictionary) ary.First()).Contains(property))
  264. return ary.Select(e => ((IDictionary) e)[property]);
  265. if (ary.All(o => o.RespondTo(property)))
  266. return ary.Select(e => e.Send(property));
  267. return ary;
  268. }
  269. #if NET35
  270. /// <summary>
  271. /// Replace occurrences of a string with another
  272. /// </summary>
  273. /// <param name="input"></param>
  274. /// <param name="string"></param>
  275. /// <returns></returns>
  276. public static string Replace(string input, string @string)
  277. {
  278. return Replace(input, @string, " ");
  279. }
  280. /// <summary>
  281. /// Replace occurrences of a string with another
  282. /// </summary>
  283. /// <param name="input"></param>
  284. /// <param name="string"></param>
  285. /// <param name="replacement"></param>
  286. /// <returns></returns>
  287. public static string Replace(string input, string @string, string replacement)
  288. #else
  289. /// <summary>
  290. /// Replace occurrences of a string with another
  291. /// </summary>
  292. /// <param name="input"></param>
  293. /// <param name="string"></param>
  294. /// <param name="replacement"></param>
  295. /// <returns></returns>
  296. public static string Replace(string input, string @string, string replacement = "")
  297. #endif
  298. {
  299. if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(@string))
  300. return input;
  301. return string.IsNullOrEmpty(input)
  302. ? input
  303. : Regex.Replace(input, @string, replacement);
  304. }
  305. #if NET35
  306. /// <summary>
  307. /// Replace the first occurence of a string with another
  308. /// </summary>
  309. /// <param name="input"></param>
  310. /// <param name="string"></param>
  311. /// <param name="replacement"></param>
  312. /// <returns></returns>
  313. public static string ReplaceFirst(string input, string @string)
  314. {
  315. return ReplaceFirst(input, @string, "");
  316. }
  317. /// <summary>
  318. /// Replace the first occurence of a string with another
  319. /// </summary>
  320. /// <param name="input"></param>
  321. /// <param name="string"></param>
  322. /// <param name="replacement"></param>
  323. /// <returns></returns>
  324. public static string ReplaceFirst(string input, string @string, string replacement)
  325. #else
  326. /// <summary>
  327. /// Replace the first occurence of a string with another
  328. /// </summary>
  329. /// <param name="input"></param>
  330. /// <param name="string"></param>
  331. /// <param name="replacement"></param>
  332. /// <returns></returns>
  333. public static string ReplaceFirst(string input, string @string, string replacement = "")
  334. #endif
  335. {
  336. if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(@string))
  337. return input;
  338. bool doneReplacement = false;
  339. return Regex.Replace(input, @string, m =>
  340. {
  341. if (doneReplacement)
  342. return m.Value;
  343. doneReplacement = true;
  344. return replacement;
  345. });
  346. }
  347. /// <summary>
  348. /// Remove a substring
  349. /// </summary>
  350. /// <param name="input"></param>
  351. /// <param name="string"></param>
  352. /// <returns></returns>
  353. public static string Remove(string input, string @string)
  354. {
  355. return input.IsNullOrWhiteSpace()
  356. ? input
  357. : input.Replace(@string, string.Empty);
  358. }
  359. /// <summary>
  360. /// Remove the first occurrence of a substring
  361. /// </summary>
  362. /// <param name="input"></param>
  363. /// <param name="string"></param>
  364. /// <returns></returns>
  365. public static string RemoveFirst(string input, string @string)
  366. {
  367. return input.IsNullOrWhiteSpace()
  368. ? input
  369. : ReplaceFirst(input, @string, string.Empty);
  370. }
  371. /// <summary>
  372. /// Add one string to another
  373. /// </summary>
  374. /// <param name="input"></param>
  375. /// <param name="string"></param>
  376. /// <returns></returns>
  377. public static string Append(string input, string @string)
  378. {
  379. return input == null
  380. ? input
  381. : input + @string;
  382. }
  383. /// <summary>
  384. /// Prepend a string to another
  385. /// </summary>
  386. /// <param name="input"></param>
  387. /// <param name="string"></param>
  388. /// <returns></returns>
  389. public static string Prepend(string input, string @string)
  390. {
  391. return input == null
  392. ? input
  393. : @string + input;
  394. }
  395. /// <summary>
  396. /// Add <br /> tags in front of all newlines in input string
  397. /// </summary>
  398. /// <param name="input"></param>
  399. /// <returns></returns>
  400. public static string NewlineToBr(string input)
  401. {
  402. return input.IsNullOrWhiteSpace()
  403. ? input
  404. : Regex.Replace(input, Environment.NewLine, "<br />" + Environment.NewLine);
  405. }
  406. /// <summary>
  407. /// Formats a date using a .NET date format string
  408. /// </summary>
  409. /// <param name="input"></param>
  410. /// <param name="format"></param>
  411. /// <returns></returns>
  412. public static string Date(object input, string format)
  413. {
  414. if (input == null)
  415. return null;
  416. if (format.IsNullOrWhiteSpace())
  417. return input.ToString();
  418. DateTime date;
  419. return DateTime.TryParse(input.ToString(), out date)
  420. ? Liquid.UseRubyDateFormat ? date.ToStrFTime(format) : date.ToString(format)
  421. : input.ToString();
  422. }
  423. /// <summary>
  424. /// Get the first element of the passed in array
  425. ///
  426. /// Example:
  427. /// {{ product.images | first | to_img }}
  428. /// </summary>
  429. /// <param name="array"></param>
  430. /// <returns></returns>
  431. public static object First(IEnumerable array)
  432. {
  433. if (array == null)
  434. return null;
  435. return array.Cast<object>().FirstOrDefault();
  436. }
  437. /// <summary>
  438. /// Get the last element of the passed in array
  439. ///
  440. /// Example:
  441. /// {{ product.images | last | to_img }}
  442. /// </summary>
  443. /// <param name="array"></param>
  444. /// <returns></returns>
  445. public static object Last(IEnumerable array)
  446. {
  447. if (array == null)
  448. return null;
  449. return array.Cast<object>().LastOrDefault();
  450. }
  451. /// <summary>
  452. /// Addition
  453. /// </summary>
  454. /// <param name="input"></param>
  455. /// <param name="operand"></param>
  456. /// <returns></returns>
  457. public static object Plus(object input, object operand)
  458. {
  459. return input is string
  460. ? string.Concat(input, operand)
  461. : DoMathsOperation(input, operand, Expression.Add);
  462. }
  463. /// <summary>
  464. /// Subtraction
  465. /// </summary>
  466. /// <param name="input"></param>
  467. /// <param name="operand"></param>
  468. /// <returns></returns>
  469. public static object Minus(object input, object operand)
  470. {
  471. return DoMathsOperation(input, operand, Expression.Subtract);
  472. }
  473. /// <summary>
  474. /// Multiplication
  475. /// </summary>
  476. /// <param name="input"></param>
  477. /// <param name="operand"></param>
  478. /// <returns></returns>
  479. public static object Times(object input, object operand)
  480. {
  481. return input is string && operand is int
  482. ? Enumerable.Repeat((string) input, (int) operand)
  483. : DoMathsOperation(input, operand, Expression.Multiply);
  484. }
  485. /// <summary>
  486. /// Division
  487. /// </summary>
  488. /// <param name="input"></param>
  489. /// <param name="operand"></param>
  490. /// <returns></returns>
  491. public static object DividedBy(object input, object operand)
  492. {
  493. return DoMathsOperation(input, operand, Expression.Divide);
  494. }
  495. private static object DoMathsOperation(object input, object operand, Func<Expression, Expression, BinaryExpression> operation)
  496. {
  497. return input == null || operand == null
  498. ? null
  499. : ExpressionUtility.CreateExpression(operation, input.GetType(), operand.GetType(), input.GetType(), true)
  500. .DynamicInvoke(input, operand);
  501. }
  502. }
  503. internal static class StringExtensions
  504. {
  505. public static bool IsNullOrWhiteSpace(this string s)
  506. {
  507. return string.IsNullOrEmpty(s) || s.Trim().Length == 0;
  508. }
  509. }
  510. }