inverted.yml 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. overview: |
  2. Inverted Section tags and End Section tags are used in combination to wrap a
  3. section of the template.
  4. These tags' content MUST be a non-whitespace character sequence NOT
  5. containing the current closing delimiter; each Inverted Section tag MUST be
  6. followed by an End Section tag with the same content within the same
  7. section.
  8. This tag's content names the data to replace the tag. Name resolution is as
  9. follows:
  10. 1) Split the name on periods; the first part is the name to resolve, any
  11. remaining parts should be retained.
  12. 2) Walk the context stack from top to bottom, finding the first context
  13. that is a) a hash containing the name as a key OR b) an object responding
  14. to a method with the given name.
  15. 3) If the context is a hash, the data is the value associated with the
  16. name.
  17. 4) If the context is an object and the method with the given name has an
  18. arity of 1, the method SHOULD be called with a String containing the
  19. unprocessed contents of the sections; the data is the value returned.
  20. 5) Otherwise, the data is the value returned by calling the method with
  21. the given name.
  22. 6) If any name parts were retained in step 1, each should be resolved
  23. against a context stack containing only the result from the former
  24. resolution. If any part fails resolution, the result should be considered
  25. falsey, and should interpolate as the empty string.
  26. If the data is not of a list type, it is coerced into a list as follows: if
  27. the data is truthy (e.g. `!!data == true`), use a single-element list
  28. containing the data, otherwise use an empty list.
  29. This section MUST NOT be rendered unless the data list is empty.
  30. Inverted Section and End Section tags SHOULD be treated as standalone when
  31. appropriate.
  32. tests:
  33. - name: Falsey
  34. desc: Falsey sections should have their contents rendered.
  35. data: { boolean: false }
  36. template: '"{{^boolean}}This should be rendered.{{/boolean}}"'
  37. expected: '"This should be rendered."'
  38. - name: Truthy
  39. desc: Truthy sections should have their contents omitted.
  40. data: { boolean: true }
  41. template: '"{{^boolean}}This should not be rendered.{{/boolean}}"'
  42. expected: '""'
  43. - name: Context
  44. desc: Objects and hashes should behave like truthy values.
  45. data: { context: { name: 'Joe' } }
  46. template: '"{{^context}}Hi {{name}}.{{/context}}"'
  47. expected: '""'
  48. - name: List
  49. desc: Lists should behave like truthy values.
  50. data: { list: [ { n: 1 }, { n: 2 }, { n: 3 } ] }
  51. template: '"{{^list}}{{n}}{{/list}}"'
  52. expected: '""'
  53. - name: Empty List
  54. desc: Empty lists should behave like falsey values.
  55. data: { list: [ ] }
  56. template: '"{{^list}}Yay lists!{{/list}}"'
  57. expected: '"Yay lists!"'
  58. - name: Doubled
  59. desc: Multiple inverted sections per template should be permitted.
  60. data: { bool: false, two: 'second' }
  61. template: |
  62. {{^bool}}
  63. * first
  64. {{/bool}}
  65. * {{two}}
  66. {{^bool}}
  67. * third
  68. {{/bool}}
  69. expected: |
  70. * first
  71. * second
  72. * third
  73. - name: Nested (Falsey)
  74. desc: Nested falsey sections should have their contents rendered.
  75. data: { bool: false }
  76. template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"
  77. expected: "| A B C D E |"
  78. - name: Nested (Truthy)
  79. desc: Nested truthy sections should be omitted.
  80. data: { bool: true }
  81. template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"
  82. expected: "| A E |"
  83. - name: Context Misses
  84. desc: Failed context lookups should be considered falsey.
  85. data: { }
  86. template: "[{{^missing}}Cannot find key 'missing'!{{/missing}}]"
  87. expected: "[Cannot find key 'missing'!]"
  88. # Dotted Names
  89. - name: Dotted Names - Truthy
  90. desc: Dotted names should be valid for Inverted Section tags.
  91. data: { a: { b: { c: true } } }
  92. template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == ""'
  93. expected: '"" == ""'
  94. - name: Dotted Names - Falsey
  95. desc: Dotted names should be valid for Inverted Section tags.
  96. data: { a: { b: { c: false } } }
  97. template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == "Not Here"'
  98. expected: '"Not Here" == "Not Here"'
  99. - name: Dotted Names - Broken Chains
  100. desc: Dotted names that cannot be resolved should be considered falsey.
  101. data: { a: { } }
  102. template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == "Not Here"'
  103. expected: '"Not Here" == "Not Here"'
  104. # Whitespace Sensitivity
  105. - name: Surrounding Whitespace
  106. desc: Inverted sections should not alter surrounding whitespace.
  107. data: { boolean: false }
  108. template: " | {{^boolean}}\t|\t{{/boolean}} | \n"
  109. expected: " | \t|\t | \n"
  110. - name: Internal Whitespace
  111. desc: Inverted should not alter internal whitespace.
  112. data: { boolean: false }
  113. template: " | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n"
  114. expected: " | \n | \n"
  115. - name: Indented Inline Sections
  116. desc: Single-line sections should not alter surrounding whitespace.
  117. data: { boolean: false }
  118. template: " {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n"
  119. expected: " NO\n WAY\n"
  120. - name: Standalone Lines
  121. desc: Standalone lines should be removed from the template.
  122. data: { boolean: false }
  123. template: |
  124. | This Is
  125. {{^boolean}}
  126. |
  127. {{/boolean}}
  128. | A Line
  129. expected: |
  130. | This Is
  131. |
  132. | A Line
  133. - name: Standalone Indented Lines
  134. desc: Standalone indented lines should be removed from the template.
  135. data: { boolean: false }
  136. template: |
  137. | This Is
  138. {{^boolean}}
  139. |
  140. {{/boolean}}
  141. | A Line
  142. expected: |
  143. | This Is
  144. |
  145. | A Line
  146. - name: Standalone Line Endings
  147. desc: '"\r\n" should be considered a newline for standalone tags.'
  148. data: { boolean: false }
  149. template: "|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|"
  150. expected: "|\r\n|"
  151. - name: Standalone Without Previous Line
  152. desc: Standalone tags should not require a newline to precede them.
  153. data: { boolean: false }
  154. template: " {{^boolean}}\n^{{/boolean}}\n/"
  155. expected: "^\n/"
  156. - name: Standalone Without Newline
  157. desc: Standalone tags should not require a newline to follow them.
  158. data: { boolean: false }
  159. template: "^{{^boolean}}\n/\n {{/boolean}}"
  160. expected: "^\n/\n"
  161. # Whitespace Insensitivity
  162. - name: Padding
  163. desc: Superfluous in-tag whitespace should be ignored.
  164. data: { boolean: false }
  165. template: '|{{^ boolean }}={{/ boolean }}|'
  166. expected: '|=|'