packages feed

stache 0.1.7 → 0.1.8

raw patch · 17 files changed

+1084/−1078 lines, 17 filesdep ~aesondep ~stachedep ~vector

Dependency ranges changed: aeson, stache, vector

Files

CHANGELOG.md view
@@ -1,3 +1,9 @@+## Stache 0.1.8++* Rename `specs` directory to `specification` as the previous name somehow+  caused conflicts when deploying an application on Heroku with Stache as a+  dependency.+ ## Stache 0.1.7  * Added `mustache` quasi-quoter.
README.md view
@@ -15,7 +15,7 @@ render them.  The implementation uses the Megaparsec parsing library to parse the-templates which is results in superior quality of error messages.+templates which results in superior quality of error messages.  For rendering you only need to create Aeson's `Value` where you put the data to interpolate. Since the library re-uses Aeson's instances and most data
Text/Mustache.hs view
@@ -15,7 +15,7 @@ -- text) and one to render them. -- -- The implementation uses the Megaparsec parsing library to parse the--- templates which is results in superior quality of error messages.+-- templates which results in superior quality of error messages. -- -- For rendering you only need to create Aeson's 'Data.Aeson.Value' where -- you put the data to interpolate. Since the library re-uses Aeson's
mustache-spec/Spec.hs view
@@ -58,12 +58,12 @@  spec :: Spec spec = do-  specData "Comments"      $(embedFile "specs/comments.yml")-  specData "Delimiters"    $(embedFile "specs/delimiters.yml")-  specData "Interpolation" $(embedFile "specs/interpolation.yml")-  specData "Inverted"      $(embedFile "specs/inverted.yml")-  specData "Partials"      $(embedFile "specs/partials.yml")-  specData "Sections"      $(embedFile "specs/sections.yml")+  specData "Comments"      $(embedFile "specification/comments.yml")+  specData "Delimiters"    $(embedFile "specification/delimiters.yml")+  specData "Interpolation" $(embedFile "specification/interpolation.yml")+  specData "Inverted"      $(embedFile "specification/inverted.yml")+  specData "Partials"      $(embedFile "specification/partials.yml")+  specData "Sections"      $(embedFile "specification/sections.yml")  specData :: String -> ByteString -> Spec specData aspect bytes = describe aspect $ do
+ specification/comments.yml view
@@ -0,0 +1,103 @@+overview: |+  Comment tags represent content that should never appear in the resulting+  output.++  The tag's content may contain any substring (including newlines) EXCEPT the+  closing delimiter.++  Comment tags SHOULD be treated as standalone when appropriate.+tests:+  - name: Inline+    desc: Comment blocks should be removed from the template.+    data: { }+    template: '12345{{! Comment Block! }}67890'+    expected: '1234567890'++  - name: Multiline+    desc: Multiline comments should be permitted.+    data: { }+    template: |+      12345{{!+        This is a+        multi-line comment...+      }}67890+    expected: |+      1234567890++  - name: Standalone+    desc: All standalone comment lines should be removed.+    data: { }+    template: |+      Begin.+      {{! Comment Block! }}+      End.+    expected: |+      Begin.+      End.++  - name: Indented Standalone+    desc: All standalone comment lines should be removed.+    data: { }+    template: |+      Begin.+        {{! Indented Comment Block! }}+      End.+    expected: |+      Begin.+      End.++  - name: Standalone Line Endings+    desc: '"\r\n" should be considered a newline for standalone tags.'+    data: { }+    template: "|\r\n{{! Standalone Comment }}\r\n|"+    expected: "|\r\n|"++  - name: Standalone Without Previous Line+    desc: Standalone tags should not require a newline to precede them.+    data: { }+    template: "  {{! I'm Still Standalone }}\n!"+    expected: "!"++  - name: Standalone Without Newline+    desc: Standalone tags should not require a newline to follow them.+    data: { }+    template: "!\n  {{! I'm Still Standalone }}"+    expected: "!\n"++  - name: Multiline Standalone+    desc: All standalone comment lines should be removed.+    data: { }+    template: |+      Begin.+      {{!+      Something's going on here...+      }}+      End.+    expected: |+      Begin.+      End.++  - name: Indented Multiline Standalone+    desc: All standalone comment lines should be removed.+    data: { }+    template: |+      Begin.+        {{!+          Something's going on here...+        }}+      End.+    expected: |+      Begin.+      End.++  - name: Indented Inline+    desc: Inline comments should not strip whitespace+    data: { }+    template: "  12 {{! 34 }}\n"+    expected: "  12 \n"++  - name: Surrounding Whitespace+    desc: Comment removal should preserve surrounding whitespace.+    data: { }+    template: '12345 {{! Comment Block! }} 67890'+    expected: '12345  67890'
+ specification/delimiters.yml view
@@ -0,0 +1,158 @@+overview: |+  Set Delimiter tags are used to change the tag delimiters for all content+  following the tag in the current compilation unit.++  The tag's content MUST be any two non-whitespace sequences (separated by+  whitespace) EXCEPT an equals sign ('=') followed by the current closing+  delimiter.++  Set Delimiter tags SHOULD be treated as standalone when appropriate.+tests:+  - name: Pair Behavior+    desc: The equals sign (used on both sides) should permit delimiter changes.+    data: { text: 'Hey!' }+    template: '{{=<% %>=}}(<%text%>)'+    expected: '(Hey!)'++  - name: Special Characters+    desc: Characters with special meaning regexen should be valid delimiters.+    data: { text: 'It worked!' }+    template: '({{=[ ]=}}[text])'+    expected: '(It worked!)'++  - name: Sections+    desc: Delimiters set outside sections should persist.+    data: { section: true, data: 'I got interpolated.' }+    template: |+      [+      {{#section}}+        {{data}}+        |data|+      {{/section}}++      {{= | | =}}+      |#section|+        {{data}}+        |data|+      |/section|+      ]+    expected: |+      [+        I got interpolated.+        |data|++        {{data}}+        I got interpolated.+      ]++  - name: Inverted Sections+    desc: Delimiters set outside inverted sections should persist.+    data: { section: false, data: 'I got interpolated.' }+    template: |+      [+      {{^section}}+        {{data}}+        |data|+      {{/section}}++      {{= | | =}}+      |^section|+        {{data}}+        |data|+      |/section|+      ]+    expected: |+      [+        I got interpolated.+        |data|++        {{data}}+        I got interpolated.+      ]++  - name: Partial Inheritence+    desc: Delimiters set in a parent template should not affect a partial.+    data: { value: 'yes' }+    partials:+      include: '.{{value}}.'+    template: |+      [ {{>include}} ]+      {{= | | =}}+      [ |>include| ]+    expected: |+      [ .yes. ]+      [ .yes. ]++  - name: Post-Partial Behavior+    desc: Delimiters set in a partial should not affect the parent template.+    data: { value: 'yes' }+    partials:+      include: '.{{value}}. {{= | | =}} .|value|.'+    template: |+      [ {{>include}} ]+      [ .{{value}}.  .|value|. ]+    expected: |+      [ .yes.  .yes. ]+      [ .yes.  .|value|. ]++  # Whitespace Sensitivity++  - name: Surrounding Whitespace+    desc: Surrounding whitespace should be left untouched.+    data: { }+    template: '| {{=@ @=}} |'+    expected: '|  |'++  - name: Outlying Whitespace (Inline)+    desc: Whitespace should be left untouched.+    data: { }+    template: " | {{=@ @=}}\n"+    expected: " | \n"++  - name: Standalone Tag+    desc: Standalone lines should be removed from the template.+    data: { }+    template: |+      Begin.+      {{=@ @=}}+      End.+    expected: |+      Begin.+      End.++  - name: Indented Standalone Tag+    desc: Indented standalone lines should be removed from the template.+    data: { }+    template: |+      Begin.+        {{=@ @=}}+      End.+    expected: |+      Begin.+      End.++  - name: Standalone Line Endings+    desc: '"\r\n" should be considered a newline for standalone tags.'+    data: { }+    template: "|\r\n{{= @ @ =}}\r\n|"+    expected: "|\r\n|"++  - name: Standalone Without Previous Line+    desc: Standalone tags should not require a newline to precede them.+    data: { }+    template: "  {{=@ @=}}\n="+    expected: "="++  - name: Standalone Without Newline+    desc: Standalone tags should not require a newline to follow them.+    data: { }+    template: "=\n  {{=@ @=}}"+    expected: "=\n"++  # Whitespace Insensitivity++  - name: Pair with Padding+    desc: Superfluous in-tag whitespace should be ignored.+    data: { }+    template: '|{{= @   @ =}}|'+    expected: '||'
+ specification/interpolation.yml view
@@ -0,0 +1,238 @@+overview: |+  Interpolation tags are used to integrate dynamic content into the template.++  The tag's content MUST be a non-whitespace character sequence NOT containing+  the current closing delimiter.++  This tag's content names the data to replace the tag.  A single period (`.`)+  indicates that the item currently sitting atop the context stack should be+  used; otherwise, name resolution is as follows:+    1) Split the name on periods; the first part is the name to resolve, any+    remaining parts should be retained.+    2) Walk the context stack from top to bottom, finding the first context+    that is a) a hash containing the name as a key OR b) an object responding+    to a method with the given name.+    3) If the context is a hash, the data is the value associated with the+    name.+    4) If the context is an object, the data is the value returned by the+    method with the given name.+    5) If any name parts were retained in step 1, each should be resolved+    against a context stack containing only the result from the former+    resolution.  If any part fails resolution, the result should be considered+    falsey, and should interpolate as the empty string.+  Data should be coerced into a string (and escaped, if appropriate) before+  interpolation.++  The Interpolation tags MUST NOT be treated as standalone.+tests:+  - name: No Interpolation+    desc: Mustache-free templates should render as-is.+    data: { }+    template: |+      Hello from {Mustache}!+    expected: |+      Hello from {Mustache}!++  - name: Basic Interpolation+    desc: Unadorned tags should interpolate content into the template.+    data: { subject: "world" }+    template: |+      Hello, {{subject}}!+    expected: |+      Hello, world!++  - name: HTML Escaping+    desc: Basic interpolation should be HTML escaped.+    data: { forbidden: '& " < >' }+    template: |+      These characters should be HTML escaped: {{forbidden}}+    expected: |+      These characters should be HTML escaped: &amp; &quot; &lt; &gt;++  - name: Triple Mustache+    desc: Triple mustaches should interpolate without HTML escaping.+    data: { forbidden: '& " < >' }+    template: |+      These characters should not be HTML escaped: {{{forbidden}}}+    expected: |+      These characters should not be HTML escaped: & " < >++  - name: Ampersand+    desc: Ampersand should interpolate without HTML escaping.+    data: { forbidden: '& " < >' }+    template: |+      These characters should not be HTML escaped: {{&forbidden}}+    expected: |+      These characters should not be HTML escaped: & " < >++  - name: Basic Integer Interpolation+    desc: Integers should interpolate seamlessly.+    data: { mph: 85 }+    template: '"{{mph}} miles an hour!"'+    expected: '"85 miles an hour!"'++  - name: Triple Mustache Integer Interpolation+    desc: Integers should interpolate seamlessly.+    data: { mph: 85 }+    template: '"{{{mph}}} miles an hour!"'+    expected: '"85 miles an hour!"'++  - name: Ampersand Integer Interpolation+    desc: Integers should interpolate seamlessly.+    data: { mph: 85 }+    template: '"{{&mph}} miles an hour!"'+    expected: '"85 miles an hour!"'++  - name: Basic Decimal Interpolation+    desc: Decimals should interpolate seamlessly with proper significance.+    data: { power: 1.210 }+    template: '"{{power}} jiggawatts!"'+    expected: '"1.21 jiggawatts!"'++  - name: Triple Mustache Decimal Interpolation+    desc: Decimals should interpolate seamlessly with proper significance.+    data: { power: 1.210 }+    template: '"{{{power}}} jiggawatts!"'+    expected: '"1.21 jiggawatts!"'++  - name: Ampersand Decimal Interpolation+    desc: Decimals should interpolate seamlessly with proper significance.+    data: { power: 1.210 }+    template: '"{{&power}} jiggawatts!"'+    expected: '"1.21 jiggawatts!"'++  # Context Misses++  - name: Basic Context Miss Interpolation+    desc: Failed context lookups should default to empty strings.+    data: { }+    template: "I ({{cannot}}) be seen!"+    expected: "I () be seen!"++  - name: Triple Mustache Context Miss Interpolation+    desc: Failed context lookups should default to empty strings.+    data: { }+    template: "I ({{{cannot}}}) be seen!"+    expected: "I () be seen!"++  - name: Ampersand Context Miss Interpolation+    desc: Failed context lookups should default to empty strings.+    data: { }+    template: "I ({{&cannot}}) be seen!"+    expected: "I () be seen!"++  # Dotted Names++  - name: Dotted Names - Basic Interpolation+    desc: Dotted names should be considered a form of shorthand for sections.+    data: { person: { name: 'Joe' } }+    template: '"{{person.name}}" == "{{#person}}{{name}}{{/person}}"'+    expected: '"Joe" == "Joe"'++  - name: Dotted Names - Triple Mustache Interpolation+    desc: Dotted names should be considered a form of shorthand for sections.+    data: { person: { name: 'Joe' } }+    template: '"{{{person.name}}}" == "{{#person}}{{{name}}}{{/person}}"'+    expected: '"Joe" == "Joe"'++  - name: Dotted Names - Ampersand Interpolation+    desc: Dotted names should be considered a form of shorthand for sections.+    data: { person: { name: 'Joe' } }+    template: '"{{&person.name}}" == "{{#person}}{{&name}}{{/person}}"'+    expected: '"Joe" == "Joe"'++  - name: Dotted Names - Arbitrary Depth+    desc: Dotted names should be functional to any level of nesting.+    data:+      a: { b: { c: { d: { e: { name: 'Phil' } } } } }+    template: '"{{a.b.c.d.e.name}}" == "Phil"'+    expected: '"Phil" == "Phil"'++  - name: Dotted Names - Broken Chains+    desc: Any falsey value prior to the last part of the name should yield ''.+    data:+      a: { }+    template: '"{{a.b.c}}" == ""'+    expected: '"" == ""'++  - name: Dotted Names - Broken Chain Resolution+    desc: Each part of a dotted name should resolve only against its parent.+    data:+      a: { b: { } }+      c: { name: 'Jim' }+    template: '"{{a.b.c.name}}" == ""'+    expected: '"" == ""'++  - name: Dotted Names - Initial Resolution+    desc: The first part of a dotted name should resolve as any other name.+    data:+      a: { b: { c: { d: { e: { name: 'Phil' } } } } }+      b: { c: { d: { e: { name: 'Wrong' } } } }+    template: '"{{#a}}{{b.c.d.e.name}}{{/a}}" == "Phil"'+    expected: '"Phil" == "Phil"'++  - name: Dotted Names - Context Precedence+    desc: Dotted names should be resolved against former resolutions.+    data:+      a: { b: { } }+      b: { c: 'ERROR' }+    template: '{{#a}}{{b.c}}{{/a}}'+    expected: ''++  # Whitespace Sensitivity++  - name: Interpolation - Surrounding Whitespace+    desc: Interpolation should not alter surrounding whitespace.+    data: { string: '---' }+    template: '| {{string}} |'+    expected: '| --- |'++  - name: Triple Mustache - Surrounding Whitespace+    desc: Interpolation should not alter surrounding whitespace.+    data: { string: '---' }+    template: '| {{{string}}} |'+    expected: '| --- |'++  - name: Ampersand - Surrounding Whitespace+    desc: Interpolation should not alter surrounding whitespace.+    data: { string: '---' }+    template: '| {{&string}} |'+    expected: '| --- |'++  - name: Interpolation - Standalone+    desc: Standalone interpolation should not alter surrounding whitespace.+    data: { string: '---' }+    template: "  {{string}}\n"+    expected: "  ---\n"++  - name: Triple Mustache - Standalone+    desc: Standalone interpolation should not alter surrounding whitespace.+    data: { string: '---' }+    template: "  {{{string}}}\n"+    expected: "  ---\n"++  - name: Ampersand - Standalone+    desc: Standalone interpolation should not alter surrounding whitespace.+    data: { string: '---' }+    template: "  {{&string}}\n"+    expected: "  ---\n"++  # Whitespace Insensitivity++  - name: Interpolation With Padding+    desc: Superfluous in-tag whitespace should be ignored.+    data: { string: "---" }+    template: '|{{ string }}|'+    expected: '|---|'++  - name: Triple Mustache With Padding+    desc: Superfluous in-tag whitespace should be ignored.+    data: { string: "---" }+    template: '|{{{ string }}}|'+    expected: '|---|'++  - name: Ampersand With Padding+    desc: Superfluous in-tag whitespace should be ignored.+    data: { string: "---" }+    template: '|{{& string }}|'+    expected: '|---|'
+ specification/inverted.yml view
@@ -0,0 +1,193 @@+overview: |+  Inverted Section tags and End Section tags are used in combination to wrap a+  section of the template.++  These tags' content MUST be a non-whitespace character sequence NOT+  containing the current closing delimiter; each Inverted Section tag MUST be+  followed by an End Section tag with the same content within the same+  section.++  This tag's content names the data to replace the tag.  Name resolution is as+  follows:+    1) Split the name on periods; the first part is the name to resolve, any+    remaining parts should be retained.+    2) Walk the context stack from top to bottom, finding the first context+    that is a) a hash containing the name as a key OR b) an object responding+    to a method with the given name.+    3) If the context is a hash, the data is the value associated with the+    name.+    4) If the context is an object and the method with the given name has an+    arity of 1, the method SHOULD be called with a String containing the+    unprocessed contents of the sections; the data is the value returned.+    5) Otherwise, the data is the value returned by calling the method with+    the given name.+    6) If any name parts were retained in step 1, each should be resolved+    against a context stack containing only the result from the former+    resolution.  If any part fails resolution, the result should be considered+    falsey, and should interpolate as the empty string.+  If the data is not of a list type, it is coerced into a list as follows: if+  the data is truthy (e.g. `!!data == true`), use a single-element list+  containing the data, otherwise use an empty list.++  This section MUST NOT be rendered unless the data list is empty.++  Inverted Section and End Section tags SHOULD be treated as standalone when+  appropriate.+tests:+  - name: Falsey+    desc: Falsey sections should have their contents rendered.+    data: { boolean: false }+    template: '"{{^boolean}}This should be rendered.{{/boolean}}"'+    expected: '"This should be rendered."'++  - name: Truthy+    desc: Truthy sections should have their contents omitted.+    data: { boolean: true }+    template: '"{{^boolean}}This should not be rendered.{{/boolean}}"'+    expected: '""'++  - name: Context+    desc: Objects and hashes should behave like truthy values.+    data: { context: { name: 'Joe' } }+    template: '"{{^context}}Hi {{name}}.{{/context}}"'+    expected: '""'++  - name: List+    desc: Lists should behave like truthy values.+    data: { list: [ { n: 1 }, { n: 2 }, { n: 3 } ] }+    template: '"{{^list}}{{n}}{{/list}}"'+    expected: '""'++  - name: Empty List+    desc: Empty lists should behave like falsey values.+    data: { list: [ ] }+    template: '"{{^list}}Yay lists!{{/list}}"'+    expected: '"Yay lists!"'++  - name: Doubled+    desc: Multiple inverted sections per template should be permitted.+    data: { bool: false, two: 'second' }+    template: |+      {{^bool}}+      * first+      {{/bool}}+      * {{two}}+      {{^bool}}+      * third+      {{/bool}}+    expected: |+      * first+      * second+      * third++  - name: Nested (Falsey)+    desc: Nested falsey sections should have their contents rendered.+    data: { bool: false }+    template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"+    expected: "| A B C D E |"++  - name: Nested (Truthy)+    desc: Nested truthy sections should be omitted.+    data: { bool: true }+    template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"+    expected: "| A  E |"++  - name: Context Misses+    desc: Failed context lookups should be considered falsey.+    data: { }+    template: "[{{^missing}}Cannot find key 'missing'!{{/missing}}]"+    expected: "[Cannot find key 'missing'!]"++  # Dotted Names++  - name: Dotted Names - Truthy+    desc: Dotted names should be valid for Inverted Section tags.+    data: { a: { b: { c: true } } }+    template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == ""'+    expected: '"" == ""'++  - name: Dotted Names - Falsey+    desc: Dotted names should be valid for Inverted Section tags.+    data: { a: { b: { c: false } } }+    template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == "Not Here"'+    expected: '"Not Here" == "Not Here"'++  - name: Dotted Names - Broken Chains+    desc: Dotted names that cannot be resolved should be considered falsey.+    data: { a: { } }+    template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == "Not Here"'+    expected: '"Not Here" == "Not Here"'++  # Whitespace Sensitivity++  - name: Surrounding Whitespace+    desc: Inverted sections should not alter surrounding whitespace.+    data: { boolean: false }+    template: " | {{^boolean}}\t|\t{{/boolean}} | \n"+    expected: " | \t|\t | \n"++  - name: Internal Whitespace+    desc: Inverted should not alter internal whitespace.+    data: { boolean: false }+    template: " | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n"+    expected: " |  \n  | \n"++  - name: Indented Inline Sections+    desc: Single-line sections should not alter surrounding whitespace.+    data: { boolean: false }+    template: " {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n"+    expected: " NO\n WAY\n"++  - name: Standalone Lines+    desc: Standalone lines should be removed from the template.+    data: { boolean: false }+    template: |+      | This Is+      {{^boolean}}+      |+      {{/boolean}}+      | A Line+    expected: |+      | This Is+      |+      | A Line++  - name: Standalone Indented Lines+    desc: Standalone indented lines should be removed from the template.+    data: { boolean: false }+    template: |+      | This Is+        {{^boolean}}+      |+        {{/boolean}}+      | A Line+    expected: |+      | This Is+      |+      | A Line++  - name: Standalone Line Endings+    desc: '"\r\n" should be considered a newline for standalone tags.'+    data: { boolean: false }+    template: "|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|"+    expected: "|\r\n|"++  - name: Standalone Without Previous Line+    desc: Standalone tags should not require a newline to precede them.+    data: { boolean: false }+    template: "  {{^boolean}}\n^{{/boolean}}\n/"+    expected: "^\n/"++  - name: Standalone Without Newline+    desc: Standalone tags should not require a newline to follow them.+    data: { boolean: false }+    template: "^{{^boolean}}\n/\n  {{/boolean}}"+    expected: "^\n/\n"++  # Whitespace Insensitivity++  - name: Padding+    desc: Superfluous in-tag whitespace should be ignored.+    data: { boolean: false }+    template: '|{{^ boolean }}={{/ boolean }}|'+    expected: '|=|'
+ specification/partials.yml view
@@ -0,0 +1,109 @@+overview: |+  Partial tags are used to expand an external template into the current+  template.++  The tag's content MUST be a non-whitespace character sequence NOT containing+  the current closing delimiter.++  This tag's content names the partial to inject.  Set Delimiter tags MUST NOT+  affect the parsing of a partial.  The partial MUST be rendered against the+  context stack local to the tag.  If the named partial cannot be found, the+  empty string SHOULD be used instead, as in interpolations.++  Partial tags SHOULD be treated as standalone when appropriate.  If this tag+  is used standalone, any whitespace preceding the tag should treated as+  indentation, and prepended to each line of the partial before rendering.+tests:+  - name: Basic Behavior+    desc: The greater-than operator should expand to the named partial.+    data: { }+    template: '"{{>text}}"'+    partials: { text: 'from partial' }+    expected: '"from partial"'++  - name: Failed Lookup+    desc: The empty string should be used when the named partial is not found.+    data: { }+    template: '"{{>text}}"'+    partials: { }+    expected: '""'++  - name: Context+    desc: The greater-than operator should operate within the current context.+    data: { text: 'content' }+    template: '"{{>partial}}"'+    partials: { partial: '*{{text}}*' }+    expected: '"*content*"'++  - name: Recursion+    desc: The greater-than operator should properly recurse.+    data: { content: "X", nodes: [ { content: "Y", nodes: [] } ] }+    template: '{{>node}}'+    partials: { node: '{{content}}<{{#nodes}}{{>node}}{{/nodes}}>' }+    expected: 'X<Y<>>'++  # Whitespace Sensitivity++  - name: Surrounding Whitespace+    desc: The greater-than operator should not alter surrounding whitespace.+    data: { }+    template: '| {{>partial}} |'+    partials: { partial: "\t|\t" }+    expected: "| \t|\t |"++  - name: Inline Indentation+    desc: Whitespace should be left untouched.+    data: { data: '|' }+    template: "  {{data}}  {{> partial}}\n"+    partials: { partial: ">\n>" }+    expected: "  |  >\n>\n"++  - name: Standalone Line Endings+    desc: '"\r\n" should be considered a newline for standalone tags.'+    data: { }+    template: "|\r\n{{>partial}}\r\n|"+    partials: { partial: ">" }+    expected: "|\r\n>|"++  - name: Standalone Without Previous Line+    desc: Standalone tags should not require a newline to precede them.+    data: { }+    template: "  {{>partial}}\n>"+    partials: { partial: ">\n>"}+    expected: "  >\n  >>"++  - name: Standalone Without Newline+    desc: Standalone tags should not require a newline to follow them.+    data: { }+    template: ">\n  {{>partial}}"+    partials: { partial: ">\n>" }+    expected: ">\n  >\n  >"++  - name: Standalone Indentation+    desc: Each line of the partial should be indented before rendering.+    data: { content: "<\n->" }+    template: |+      \+       {{>partial}}+      /+    partials:+      partial: |+        |+        {{{content}}}+        |+    expected: |+      \+       |+       <+      ->+       |+      /++  # Whitespace Insensitivity++  - name: Padding Whitespace+    desc: Superfluous in-tag whitespace should be ignored.+    data: { boolean: true }+    template: "|{{> partial }}|"+    partials: { partial: "[]" }+    expected: '|[]|'
+ specification/sections.yml view
@@ -0,0 +1,263 @@+overview: |+  Section tags and End Section tags are used in combination to wrap a section+  of the template for iteration++  These tags' content MUST be a non-whitespace character sequence NOT+  containing the current closing delimiter; each Section tag MUST be followed+  by an End Section tag with the same content within the same section.++  This tag's content names the data to replace the tag.  Name resolution is as+  follows:+    1) Split the name on periods; the first part is the name to resolve, any+    remaining parts should be retained.+    2) Walk the context stack from top to bottom, finding the first context+    that is a) a hash containing the name as a key OR b) an object responding+    to a method with the given name.+    3) If the context is a hash, the data is the value associated with the+    name.+    4) If the context is an object and the method with the given name has an+    arity of 1, the method SHOULD be called with a String containing the+    unprocessed contents of the sections; the data is the value returned.+    5) Otherwise, the data is the value returned by calling the method with+    the given name.+    6) If any name parts were retained in step 1, each should be resolved+    against a context stack containing only the result from the former+    resolution.  If any part fails resolution, the result should be considered+    falsey, and should interpolate as the empty string.+  If the data is not of a list type, it is coerced into a list as follows: if+  the data is truthy (e.g. `!!data == true`), use a single-element list+  containing the data, otherwise use an empty list.++  For each element in the data list, the element MUST be pushed onto the+  context stack, the section MUST be rendered, and the element MUST be popped+  off the context stack.++  Section and End Section tags SHOULD be treated as standalone when+  appropriate.+tests:+  - name: Truthy+    desc: Truthy sections should have their contents rendered.+    data: { boolean: true }+    template: '"{{#boolean}}This should be rendered.{{/boolean}}"'+    expected: '"This should be rendered."'++  - name: Falsey+    desc: Falsey sections should have their contents omitted.+    data: { boolean: false }+    template: '"{{#boolean}}This should not be rendered.{{/boolean}}"'+    expected: '""'++  - name: Context+    desc: Objects and hashes should be pushed onto the context stack.+    data: { context: { name: 'Joe' } }+    template: '"{{#context}}Hi {{name}}.{{/context}}"'+    expected: '"Hi Joe."'++  - name: Deeply Nested Contexts+    desc: All elements on the context stack should be accessible.+    data:+      a: { one: 1 }+      b: { two: 2 }+      c: { three: 3 }+      d: { four: 4 }+      e: { five: 5 }+    template: |+      {{#a}}+      {{one}}+      {{#b}}+      {{one}}{{two}}{{one}}+      {{#c}}+      {{one}}{{two}}{{three}}{{two}}{{one}}+      {{#d}}+      {{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}+      {{#e}}+      {{one}}{{two}}{{three}}{{four}}{{five}}{{four}}{{three}}{{two}}{{one}}+      {{/e}}+      {{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}+      {{/d}}+      {{one}}{{two}}{{three}}{{two}}{{one}}+      {{/c}}+      {{one}}{{two}}{{one}}+      {{/b}}+      {{one}}+      {{/a}}+    expected: |+      1+      121+      12321+      1234321+      123454321+      1234321+      12321+      121+      1++  - name: List+    desc: Lists should be iterated; list items should visit the context stack.+    data: { list: [ { item: 1 }, { item: 2 }, { item: 3 } ] }+    template: '"{{#list}}{{item}}{{/list}}"'+    expected: '"123"'++  - name: Empty List+    desc: Empty lists should behave like falsey values.+    data: { list: [ ] }+    template: '"{{#list}}Yay lists!{{/list}}"'+    expected: '""'++  - name: Doubled+    desc: Multiple sections per template should be permitted.+    data: { bool: true, two: 'second' }+    template: |+      {{#bool}}+      * first+      {{/bool}}+      * {{two}}+      {{#bool}}+      * third+      {{/bool}}+    expected: |+      * first+      * second+      * third++  - name: Nested (Truthy)+    desc: Nested truthy sections should have their contents rendered.+    data: { bool: true }+    template: "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |"+    expected: "| A B C D E |"++  - name: Nested (Falsey)+    desc: Nested falsey sections should be omitted.+    data: { bool: false }+    template: "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |"+    expected: "| A  E |"++  - name: Context Misses+    desc: Failed context lookups should be considered falsey.+    data: { }+    template: "[{{#missing}}Found key 'missing'!{{/missing}}]"+    expected: "[]"++  # Implicit Iterators++  - name: Implicit Iterator - String+    desc: Implicit iterators should directly interpolate strings.+    data:+      list: [ 'a', 'b', 'c', 'd', 'e' ]+    template: '"{{#list}}({{.}}){{/list}}"'+    expected: '"(a)(b)(c)(d)(e)"'++  - name: Implicit Iterator - Integer+    desc: Implicit iterators should cast integers to strings and interpolate.+    data:+      list: [ 1, 2, 3, 4, 5 ]+    template: '"{{#list}}({{.}}){{/list}}"'+    expected: '"(1)(2)(3)(4)(5)"'++  - name: Implicit Iterator - Decimal+    desc: Implicit iterators should cast decimals to strings and interpolate.+    data:+      list: [ 1.10, 2.20, 3.30, 4.40, 5.50 ]+    template: '"{{#list}}({{.}}){{/list}}"'+    expected: '"(1.1)(2.2)(3.3)(4.4)(5.5)"'++  - name: Implicit Iterator - Array+    desc: Implicit iterators should allow iterating over nested arrays.+    data:+      list: [ [1, 2, 3], ['a', 'b', 'c'] ]+    template: '"{{#list}}({{#.}}{{.}}{{/.}}){{/list}}"'+    expected: '"(123)(abc)"'++  # Dotted Names++  - name: Dotted Names - Truthy+    desc: Dotted names should be valid for Section tags.+    data: { a: { b: { c: true } } }+    template: '"{{#a.b.c}}Here{{/a.b.c}}" == "Here"'+    expected: '"Here" == "Here"'++  - name: Dotted Names - Falsey+    desc: Dotted names should be valid for Section tags.+    data: { a: { b: { c: false } } }+    template: '"{{#a.b.c}}Here{{/a.b.c}}" == ""'+    expected: '"" == ""'++  - name: Dotted Names - Broken Chains+    desc: Dotted names that cannot be resolved should be considered falsey.+    data: { a: { } }+    template: '"{{#a.b.c}}Here{{/a.b.c}}" == ""'+    expected: '"" == ""'++  # Whitespace Sensitivity++  - name: Surrounding Whitespace+    desc: Sections should not alter surrounding whitespace.+    data: { boolean: true }+    template: " | {{#boolean}}\t|\t{{/boolean}} | \n"+    expected: " | \t|\t | \n"++  - name: Internal Whitespace+    desc: Sections should not alter internal whitespace.+    data: { boolean: true }+    template: " | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n"+    expected: " |  \n  | \n"++  - name: Indented Inline Sections+    desc: Single-line sections should not alter surrounding whitespace.+    data: { boolean: true }+    template: " {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n"+    expected: " YES\n GOOD\n"++  - name: Standalone Lines+    desc: Standalone lines should be removed from the template.+    data: { boolean: true }+    template: |+      | This Is+      {{#boolean}}+      |+      {{/boolean}}+      | A Line+    expected: |+      | This Is+      |+      | A Line++  - name: Indented Standalone Lines+    desc: Indented standalone lines should be removed from the template.+    data: { boolean: true }+    template: |+      | This Is+        {{#boolean}}+      |+        {{/boolean}}+      | A Line+    expected: |+      | This Is+      |+      | A Line++  - name: Standalone Line Endings+    desc: '"\r\n" should be considered a newline for standalone tags.'+    data: { boolean: true }+    template: "|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|"+    expected: "|\r\n|"++  - name: Standalone Without Previous Line+    desc: Standalone tags should not require a newline to precede them.+    data: { boolean: true }+    template: "  {{#boolean}}\n#{{/boolean}}\n/"+    expected: "#\n/"++  - name: Standalone Without Newline+    desc: Standalone tags should not require a newline to follow them.+    data: { boolean: true }+    template: "#{{#boolean}}\n/\n  {{/boolean}}"+    expected: "#\n/\n"++  # Whitespace Insensitivity++  - name: Padding+    desc: Superfluous in-tag whitespace should be ignored.+    data: { boolean: true }+    template: '|{{# boolean }}={{/ boolean }}|'+    expected: '|=|'
− specs/comments.yml
@@ -1,103 +0,0 @@-overview: |-  Comment tags represent content that should never appear in the resulting-  output.--  The tag's content may contain any substring (including newlines) EXCEPT the-  closing delimiter.--  Comment tags SHOULD be treated as standalone when appropriate.-tests:-  - name: Inline-    desc: Comment blocks should be removed from the template.-    data: { }-    template: '12345{{! Comment Block! }}67890'-    expected: '1234567890'--  - name: Multiline-    desc: Multiline comments should be permitted.-    data: { }-    template: |-      12345{{!-        This is a-        multi-line comment...-      }}67890-    expected: |-      1234567890--  - name: Standalone-    desc: All standalone comment lines should be removed.-    data: { }-    template: |-      Begin.-      {{! Comment Block! }}-      End.-    expected: |-      Begin.-      End.--  - name: Indented Standalone-    desc: All standalone comment lines should be removed.-    data: { }-    template: |-      Begin.-        {{! Indented Comment Block! }}-      End.-    expected: |-      Begin.-      End.--  - name: Standalone Line Endings-    desc: '"\r\n" should be considered a newline for standalone tags.'-    data: { }-    template: "|\r\n{{! Standalone Comment }}\r\n|"-    expected: "|\r\n|"--  - name: Standalone Without Previous Line-    desc: Standalone tags should not require a newline to precede them.-    data: { }-    template: "  {{! I'm Still Standalone }}\n!"-    expected: "!"--  - name: Standalone Without Newline-    desc: Standalone tags should not require a newline to follow them.-    data: { }-    template: "!\n  {{! I'm Still Standalone }}"-    expected: "!\n"--  - name: Multiline Standalone-    desc: All standalone comment lines should be removed.-    data: { }-    template: |-      Begin.-      {{!-      Something's going on here...-      }}-      End.-    expected: |-      Begin.-      End.--  - name: Indented Multiline Standalone-    desc: All standalone comment lines should be removed.-    data: { }-    template: |-      Begin.-        {{!-          Something's going on here...-        }}-      End.-    expected: |-      Begin.-      End.--  - name: Indented Inline-    desc: Inline comments should not strip whitespace-    data: { }-    template: "  12 {{! 34 }}\n"-    expected: "  12 \n"--  - name: Surrounding Whitespace-    desc: Comment removal should preserve surrounding whitespace.-    data: { }-    template: '12345 {{! Comment Block! }} 67890'-    expected: '12345  67890'
− specs/delimiters.yml
@@ -1,158 +0,0 @@-overview: |-  Set Delimiter tags are used to change the tag delimiters for all content-  following the tag in the current compilation unit.--  The tag's content MUST be any two non-whitespace sequences (separated by-  whitespace) EXCEPT an equals sign ('=') followed by the current closing-  delimiter.--  Set Delimiter tags SHOULD be treated as standalone when appropriate.-tests:-  - name: Pair Behavior-    desc: The equals sign (used on both sides) should permit delimiter changes.-    data: { text: 'Hey!' }-    template: '{{=<% %>=}}(<%text%>)'-    expected: '(Hey!)'--  - name: Special Characters-    desc: Characters with special meaning regexen should be valid delimiters.-    data: { text: 'It worked!' }-    template: '({{=[ ]=}}[text])'-    expected: '(It worked!)'--  - name: Sections-    desc: Delimiters set outside sections should persist.-    data: { section: true, data: 'I got interpolated.' }-    template: |-      [-      {{#section}}-        {{data}}-        |data|-      {{/section}}--      {{= | | =}}-      |#section|-        {{data}}-        |data|-      |/section|-      ]-    expected: |-      [-        I got interpolated.-        |data|--        {{data}}-        I got interpolated.-      ]--  - name: Inverted Sections-    desc: Delimiters set outside inverted sections should persist.-    data: { section: false, data: 'I got interpolated.' }-    template: |-      [-      {{^section}}-        {{data}}-        |data|-      {{/section}}--      {{= | | =}}-      |^section|-        {{data}}-        |data|-      |/section|-      ]-    expected: |-      [-        I got interpolated.-        |data|--        {{data}}-        I got interpolated.-      ]--  - name: Partial Inheritence-    desc: Delimiters set in a parent template should not affect a partial.-    data: { value: 'yes' }-    partials:-      include: '.{{value}}.'-    template: |-      [ {{>include}} ]-      {{= | | =}}-      [ |>include| ]-    expected: |-      [ .yes. ]-      [ .yes. ]--  - name: Post-Partial Behavior-    desc: Delimiters set in a partial should not affect the parent template.-    data: { value: 'yes' }-    partials:-      include: '.{{value}}. {{= | | =}} .|value|.'-    template: |-      [ {{>include}} ]-      [ .{{value}}.  .|value|. ]-    expected: |-      [ .yes.  .yes. ]-      [ .yes.  .|value|. ]--  # Whitespace Sensitivity--  - name: Surrounding Whitespace-    desc: Surrounding whitespace should be left untouched.-    data: { }-    template: '| {{=@ @=}} |'-    expected: '|  |'--  - name: Outlying Whitespace (Inline)-    desc: Whitespace should be left untouched.-    data: { }-    template: " | {{=@ @=}}\n"-    expected: " | \n"--  - name: Standalone Tag-    desc: Standalone lines should be removed from the template.-    data: { }-    template: |-      Begin.-      {{=@ @=}}-      End.-    expected: |-      Begin.-      End.--  - name: Indented Standalone Tag-    desc: Indented standalone lines should be removed from the template.-    data: { }-    template: |-      Begin.-        {{=@ @=}}-      End.-    expected: |-      Begin.-      End.--  - name: Standalone Line Endings-    desc: '"\r\n" should be considered a newline for standalone tags.'-    data: { }-    template: "|\r\n{{= @ @ =}}\r\n|"-    expected: "|\r\n|"--  - name: Standalone Without Previous Line-    desc: Standalone tags should not require a newline to precede them.-    data: { }-    template: "  {{=@ @=}}\n="-    expected: "="--  - name: Standalone Without Newline-    desc: Standalone tags should not require a newline to follow them.-    data: { }-    template: "=\n  {{=@ @=}}"-    expected: "=\n"--  # Whitespace Insensitivity--  - name: Pair with Padding-    desc: Superfluous in-tag whitespace should be ignored.-    data: { }-    template: '|{{= @   @ =}}|'-    expected: '||'
− specs/interpolation.yml
@@ -1,238 +0,0 @@-overview: |-  Interpolation tags are used to integrate dynamic content into the template.--  The tag's content MUST be a non-whitespace character sequence NOT containing-  the current closing delimiter.--  This tag's content names the data to replace the tag.  A single period (`.`)-  indicates that the item currently sitting atop the context stack should be-  used; otherwise, name resolution is as follows:-    1) Split the name on periods; the first part is the name to resolve, any-    remaining parts should be retained.-    2) Walk the context stack from top to bottom, finding the first context-    that is a) a hash containing the name as a key OR b) an object responding-    to a method with the given name.-    3) If the context is a hash, the data is the value associated with the-    name.-    4) If the context is an object, the data is the value returned by the-    method with the given name.-    5) If any name parts were retained in step 1, each should be resolved-    against a context stack containing only the result from the former-    resolution.  If any part fails resolution, the result should be considered-    falsey, and should interpolate as the empty string.-  Data should be coerced into a string (and escaped, if appropriate) before-  interpolation.--  The Interpolation tags MUST NOT be treated as standalone.-tests:-  - name: No Interpolation-    desc: Mustache-free templates should render as-is.-    data: { }-    template: |-      Hello from {Mustache}!-    expected: |-      Hello from {Mustache}!--  - name: Basic Interpolation-    desc: Unadorned tags should interpolate content into the template.-    data: { subject: "world" }-    template: |-      Hello, {{subject}}!-    expected: |-      Hello, world!--  - name: HTML Escaping-    desc: Basic interpolation should be HTML escaped.-    data: { forbidden: '& " < >' }-    template: |-      These characters should be HTML escaped: {{forbidden}}-    expected: |-      These characters should be HTML escaped: &amp; &quot; &lt; &gt;--  - name: Triple Mustache-    desc: Triple mustaches should interpolate without HTML escaping.-    data: { forbidden: '& " < >' }-    template: |-      These characters should not be HTML escaped: {{{forbidden}}}-    expected: |-      These characters should not be HTML escaped: & " < >--  - name: Ampersand-    desc: Ampersand should interpolate without HTML escaping.-    data: { forbidden: '& " < >' }-    template: |-      These characters should not be HTML escaped: {{&forbidden}}-    expected: |-      These characters should not be HTML escaped: & " < >--  - name: Basic Integer Interpolation-    desc: Integers should interpolate seamlessly.-    data: { mph: 85 }-    template: '"{{mph}} miles an hour!"'-    expected: '"85 miles an hour!"'--  - name: Triple Mustache Integer Interpolation-    desc: Integers should interpolate seamlessly.-    data: { mph: 85 }-    template: '"{{{mph}}} miles an hour!"'-    expected: '"85 miles an hour!"'--  - name: Ampersand Integer Interpolation-    desc: Integers should interpolate seamlessly.-    data: { mph: 85 }-    template: '"{{&mph}} miles an hour!"'-    expected: '"85 miles an hour!"'--  - name: Basic Decimal Interpolation-    desc: Decimals should interpolate seamlessly with proper significance.-    data: { power: 1.210 }-    template: '"{{power}} jiggawatts!"'-    expected: '"1.21 jiggawatts!"'--  - name: Triple Mustache Decimal Interpolation-    desc: Decimals should interpolate seamlessly with proper significance.-    data: { power: 1.210 }-    template: '"{{{power}}} jiggawatts!"'-    expected: '"1.21 jiggawatts!"'--  - name: Ampersand Decimal Interpolation-    desc: Decimals should interpolate seamlessly with proper significance.-    data: { power: 1.210 }-    template: '"{{&power}} jiggawatts!"'-    expected: '"1.21 jiggawatts!"'--  # Context Misses--  - name: Basic Context Miss Interpolation-    desc: Failed context lookups should default to empty strings.-    data: { }-    template: "I ({{cannot}}) be seen!"-    expected: "I () be seen!"--  - name: Triple Mustache Context Miss Interpolation-    desc: Failed context lookups should default to empty strings.-    data: { }-    template: "I ({{{cannot}}}) be seen!"-    expected: "I () be seen!"--  - name: Ampersand Context Miss Interpolation-    desc: Failed context lookups should default to empty strings.-    data: { }-    template: "I ({{&cannot}}) be seen!"-    expected: "I () be seen!"--  # Dotted Names--  - name: Dotted Names - Basic Interpolation-    desc: Dotted names should be considered a form of shorthand for sections.-    data: { person: { name: 'Joe' } }-    template: '"{{person.name}}" == "{{#person}}{{name}}{{/person}}"'-    expected: '"Joe" == "Joe"'--  - name: Dotted Names - Triple Mustache Interpolation-    desc: Dotted names should be considered a form of shorthand for sections.-    data: { person: { name: 'Joe' } }-    template: '"{{{person.name}}}" == "{{#person}}{{{name}}}{{/person}}"'-    expected: '"Joe" == "Joe"'--  - name: Dotted Names - Ampersand Interpolation-    desc: Dotted names should be considered a form of shorthand for sections.-    data: { person: { name: 'Joe' } }-    template: '"{{&person.name}}" == "{{#person}}{{&name}}{{/person}}"'-    expected: '"Joe" == "Joe"'--  - name: Dotted Names - Arbitrary Depth-    desc: Dotted names should be functional to any level of nesting.-    data:-      a: { b: { c: { d: { e: { name: 'Phil' } } } } }-    template: '"{{a.b.c.d.e.name}}" == "Phil"'-    expected: '"Phil" == "Phil"'--  - name: Dotted Names - Broken Chains-    desc: Any falsey value prior to the last part of the name should yield ''.-    data:-      a: { }-    template: '"{{a.b.c}}" == ""'-    expected: '"" == ""'--  - name: Dotted Names - Broken Chain Resolution-    desc: Each part of a dotted name should resolve only against its parent.-    data:-      a: { b: { } }-      c: { name: 'Jim' }-    template: '"{{a.b.c.name}}" == ""'-    expected: '"" == ""'--  - name: Dotted Names - Initial Resolution-    desc: The first part of a dotted name should resolve as any other name.-    data:-      a: { b: { c: { d: { e: { name: 'Phil' } } } } }-      b: { c: { d: { e: { name: 'Wrong' } } } }-    template: '"{{#a}}{{b.c.d.e.name}}{{/a}}" == "Phil"'-    expected: '"Phil" == "Phil"'--  - name: Dotted Names - Context Precedence-    desc: Dotted names should be resolved against former resolutions.-    data:-      a: { b: { } }-      b: { c: 'ERROR' }-    template: '{{#a}}{{b.c}}{{/a}}'-    expected: ''--  # Whitespace Sensitivity--  - name: Interpolation - Surrounding Whitespace-    desc: Interpolation should not alter surrounding whitespace.-    data: { string: '---' }-    template: '| {{string}} |'-    expected: '| --- |'--  - name: Triple Mustache - Surrounding Whitespace-    desc: Interpolation should not alter surrounding whitespace.-    data: { string: '---' }-    template: '| {{{string}}} |'-    expected: '| --- |'--  - name: Ampersand - Surrounding Whitespace-    desc: Interpolation should not alter surrounding whitespace.-    data: { string: '---' }-    template: '| {{&string}} |'-    expected: '| --- |'--  - name: Interpolation - Standalone-    desc: Standalone interpolation should not alter surrounding whitespace.-    data: { string: '---' }-    template: "  {{string}}\n"-    expected: "  ---\n"--  - name: Triple Mustache - Standalone-    desc: Standalone interpolation should not alter surrounding whitespace.-    data: { string: '---' }-    template: "  {{{string}}}\n"-    expected: "  ---\n"--  - name: Ampersand - Standalone-    desc: Standalone interpolation should not alter surrounding whitespace.-    data: { string: '---' }-    template: "  {{&string}}\n"-    expected: "  ---\n"--  # Whitespace Insensitivity--  - name: Interpolation With Padding-    desc: Superfluous in-tag whitespace should be ignored.-    data: { string: "---" }-    template: '|{{ string }}|'-    expected: '|---|'--  - name: Triple Mustache With Padding-    desc: Superfluous in-tag whitespace should be ignored.-    data: { string: "---" }-    template: '|{{{ string }}}|'-    expected: '|---|'--  - name: Ampersand With Padding-    desc: Superfluous in-tag whitespace should be ignored.-    data: { string: "---" }-    template: '|{{& string }}|'-    expected: '|---|'
− specs/inverted.yml
@@ -1,193 +0,0 @@-overview: |-  Inverted Section tags and End Section tags are used in combination to wrap a-  section of the template.--  These tags' content MUST be a non-whitespace character sequence NOT-  containing the current closing delimiter; each Inverted Section tag MUST be-  followed by an End Section tag with the same content within the same-  section.--  This tag's content names the data to replace the tag.  Name resolution is as-  follows:-    1) Split the name on periods; the first part is the name to resolve, any-    remaining parts should be retained.-    2) Walk the context stack from top to bottom, finding the first context-    that is a) a hash containing the name as a key OR b) an object responding-    to a method with the given name.-    3) If the context is a hash, the data is the value associated with the-    name.-    4) If the context is an object and the method with the given name has an-    arity of 1, the method SHOULD be called with a String containing the-    unprocessed contents of the sections; the data is the value returned.-    5) Otherwise, the data is the value returned by calling the method with-    the given name.-    6) If any name parts were retained in step 1, each should be resolved-    against a context stack containing only the result from the former-    resolution.  If any part fails resolution, the result should be considered-    falsey, and should interpolate as the empty string.-  If the data is not of a list type, it is coerced into a list as follows: if-  the data is truthy (e.g. `!!data == true`), use a single-element list-  containing the data, otherwise use an empty list.--  This section MUST NOT be rendered unless the data list is empty.--  Inverted Section and End Section tags SHOULD be treated as standalone when-  appropriate.-tests:-  - name: Falsey-    desc: Falsey sections should have their contents rendered.-    data: { boolean: false }-    template: '"{{^boolean}}This should be rendered.{{/boolean}}"'-    expected: '"This should be rendered."'--  - name: Truthy-    desc: Truthy sections should have their contents omitted.-    data: { boolean: true }-    template: '"{{^boolean}}This should not be rendered.{{/boolean}}"'-    expected: '""'--  - name: Context-    desc: Objects and hashes should behave like truthy values.-    data: { context: { name: 'Joe' } }-    template: '"{{^context}}Hi {{name}}.{{/context}}"'-    expected: '""'--  - name: List-    desc: Lists should behave like truthy values.-    data: { list: [ { n: 1 }, { n: 2 }, { n: 3 } ] }-    template: '"{{^list}}{{n}}{{/list}}"'-    expected: '""'--  - name: Empty List-    desc: Empty lists should behave like falsey values.-    data: { list: [ ] }-    template: '"{{^list}}Yay lists!{{/list}}"'-    expected: '"Yay lists!"'--  - name: Doubled-    desc: Multiple inverted sections per template should be permitted.-    data: { bool: false, two: 'second' }-    template: |-      {{^bool}}-      * first-      {{/bool}}-      * {{two}}-      {{^bool}}-      * third-      {{/bool}}-    expected: |-      * first-      * second-      * third--  - name: Nested (Falsey)-    desc: Nested falsey sections should have their contents rendered.-    data: { bool: false }-    template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"-    expected: "| A B C D E |"--  - name: Nested (Truthy)-    desc: Nested truthy sections should be omitted.-    data: { bool: true }-    template: "| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"-    expected: "| A  E |"--  - name: Context Misses-    desc: Failed context lookups should be considered falsey.-    data: { }-    template: "[{{^missing}}Cannot find key 'missing'!{{/missing}}]"-    expected: "[Cannot find key 'missing'!]"--  # Dotted Names--  - name: Dotted Names - Truthy-    desc: Dotted names should be valid for Inverted Section tags.-    data: { a: { b: { c: true } } }-    template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == ""'-    expected: '"" == ""'--  - name: Dotted Names - Falsey-    desc: Dotted names should be valid for Inverted Section tags.-    data: { a: { b: { c: false } } }-    template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == "Not Here"'-    expected: '"Not Here" == "Not Here"'--  - name: Dotted Names - Broken Chains-    desc: Dotted names that cannot be resolved should be considered falsey.-    data: { a: { } }-    template: '"{{^a.b.c}}Not Here{{/a.b.c}}" == "Not Here"'-    expected: '"Not Here" == "Not Here"'--  # Whitespace Sensitivity--  - name: Surrounding Whitespace-    desc: Inverted sections should not alter surrounding whitespace.-    data: { boolean: false }-    template: " | {{^boolean}}\t|\t{{/boolean}} | \n"-    expected: " | \t|\t | \n"--  - name: Internal Whitespace-    desc: Inverted should not alter internal whitespace.-    data: { boolean: false }-    template: " | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n"-    expected: " |  \n  | \n"--  - name: Indented Inline Sections-    desc: Single-line sections should not alter surrounding whitespace.-    data: { boolean: false }-    template: " {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n"-    expected: " NO\n WAY\n"--  - name: Standalone Lines-    desc: Standalone lines should be removed from the template.-    data: { boolean: false }-    template: |-      | This Is-      {{^boolean}}-      |-      {{/boolean}}-      | A Line-    expected: |-      | This Is-      |-      | A Line--  - name: Standalone Indented Lines-    desc: Standalone indented lines should be removed from the template.-    data: { boolean: false }-    template: |-      | This Is-        {{^boolean}}-      |-        {{/boolean}}-      | A Line-    expected: |-      | This Is-      |-      | A Line--  - name: Standalone Line Endings-    desc: '"\r\n" should be considered a newline for standalone tags.'-    data: { boolean: false }-    template: "|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|"-    expected: "|\r\n|"--  - name: Standalone Without Previous Line-    desc: Standalone tags should not require a newline to precede them.-    data: { boolean: false }-    template: "  {{^boolean}}\n^{{/boolean}}\n/"-    expected: "^\n/"--  - name: Standalone Without Newline-    desc: Standalone tags should not require a newline to follow them.-    data: { boolean: false }-    template: "^{{^boolean}}\n/\n  {{/boolean}}"-    expected: "^\n/\n"--  # Whitespace Insensitivity--  - name: Padding-    desc: Superfluous in-tag whitespace should be ignored.-    data: { boolean: false }-    template: '|{{^ boolean }}={{/ boolean }}|'-    expected: '|=|'
− specs/partials.yml
@@ -1,109 +0,0 @@-overview: |-  Partial tags are used to expand an external template into the current-  template.--  The tag's content MUST be a non-whitespace character sequence NOT containing-  the current closing delimiter.--  This tag's content names the partial to inject.  Set Delimiter tags MUST NOT-  affect the parsing of a partial.  The partial MUST be rendered against the-  context stack local to the tag.  If the named partial cannot be found, the-  empty string SHOULD be used instead, as in interpolations.--  Partial tags SHOULD be treated as standalone when appropriate.  If this tag-  is used standalone, any whitespace preceding the tag should treated as-  indentation, and prepended to each line of the partial before rendering.-tests:-  - name: Basic Behavior-    desc: The greater-than operator should expand to the named partial.-    data: { }-    template: '"{{>text}}"'-    partials: { text: 'from partial' }-    expected: '"from partial"'--  - name: Failed Lookup-    desc: The empty string should be used when the named partial is not found.-    data: { }-    template: '"{{>text}}"'-    partials: { }-    expected: '""'--  - name: Context-    desc: The greater-than operator should operate within the current context.-    data: { text: 'content' }-    template: '"{{>partial}}"'-    partials: { partial: '*{{text}}*' }-    expected: '"*content*"'--  - name: Recursion-    desc: The greater-than operator should properly recurse.-    data: { content: "X", nodes: [ { content: "Y", nodes: [] } ] }-    template: '{{>node}}'-    partials: { node: '{{content}}<{{#nodes}}{{>node}}{{/nodes}}>' }-    expected: 'X<Y<>>'--  # Whitespace Sensitivity--  - name: Surrounding Whitespace-    desc: The greater-than operator should not alter surrounding whitespace.-    data: { }-    template: '| {{>partial}} |'-    partials: { partial: "\t|\t" }-    expected: "| \t|\t |"--  - name: Inline Indentation-    desc: Whitespace should be left untouched.-    data: { data: '|' }-    template: "  {{data}}  {{> partial}}\n"-    partials: { partial: ">\n>" }-    expected: "  |  >\n>\n"--  - name: Standalone Line Endings-    desc: '"\r\n" should be considered a newline for standalone tags.'-    data: { }-    template: "|\r\n{{>partial}}\r\n|"-    partials: { partial: ">" }-    expected: "|\r\n>|"--  - name: Standalone Without Previous Line-    desc: Standalone tags should not require a newline to precede them.-    data: { }-    template: "  {{>partial}}\n>"-    partials: { partial: ">\n>"}-    expected: "  >\n  >>"--  - name: Standalone Without Newline-    desc: Standalone tags should not require a newline to follow them.-    data: { }-    template: ">\n  {{>partial}}"-    partials: { partial: ">\n>" }-    expected: ">\n  >\n  >"--  - name: Standalone Indentation-    desc: Each line of the partial should be indented before rendering.-    data: { content: "<\n->" }-    template: |-      \-       {{>partial}}-      /-    partials:-      partial: |-        |-        {{{content}}}-        |-    expected: |-      \-       |-       <-      ->-       |-      /--  # Whitespace Insensitivity--  - name: Padding Whitespace-    desc: Superfluous in-tag whitespace should be ignored.-    data: { boolean: true }-    template: "|{{> partial }}|"-    partials: { partial: "[]" }-    expected: '|[]|'
− specs/sections.yml
@@ -1,263 +0,0 @@-overview: |-  Section tags and End Section tags are used in combination to wrap a section-  of the template for iteration--  These tags' content MUST be a non-whitespace character sequence NOT-  containing the current closing delimiter; each Section tag MUST be followed-  by an End Section tag with the same content within the same section.--  This tag's content names the data to replace the tag.  Name resolution is as-  follows:-    1) Split the name on periods; the first part is the name to resolve, any-    remaining parts should be retained.-    2) Walk the context stack from top to bottom, finding the first context-    that is a) a hash containing the name as a key OR b) an object responding-    to a method with the given name.-    3) If the context is a hash, the data is the value associated with the-    name.-    4) If the context is an object and the method with the given name has an-    arity of 1, the method SHOULD be called with a String containing the-    unprocessed contents of the sections; the data is the value returned.-    5) Otherwise, the data is the value returned by calling the method with-    the given name.-    6) If any name parts were retained in step 1, each should be resolved-    against a context stack containing only the result from the former-    resolution.  If any part fails resolution, the result should be considered-    falsey, and should interpolate as the empty string.-  If the data is not of a list type, it is coerced into a list as follows: if-  the data is truthy (e.g. `!!data == true`), use a single-element list-  containing the data, otherwise use an empty list.--  For each element in the data list, the element MUST be pushed onto the-  context stack, the section MUST be rendered, and the element MUST be popped-  off the context stack.--  Section and End Section tags SHOULD be treated as standalone when-  appropriate.-tests:-  - name: Truthy-    desc: Truthy sections should have their contents rendered.-    data: { boolean: true }-    template: '"{{#boolean}}This should be rendered.{{/boolean}}"'-    expected: '"This should be rendered."'--  - name: Falsey-    desc: Falsey sections should have their contents omitted.-    data: { boolean: false }-    template: '"{{#boolean}}This should not be rendered.{{/boolean}}"'-    expected: '""'--  - name: Context-    desc: Objects and hashes should be pushed onto the context stack.-    data: { context: { name: 'Joe' } }-    template: '"{{#context}}Hi {{name}}.{{/context}}"'-    expected: '"Hi Joe."'--  - name: Deeply Nested Contexts-    desc: All elements on the context stack should be accessible.-    data:-      a: { one: 1 }-      b: { two: 2 }-      c: { three: 3 }-      d: { four: 4 }-      e: { five: 5 }-    template: |-      {{#a}}-      {{one}}-      {{#b}}-      {{one}}{{two}}{{one}}-      {{#c}}-      {{one}}{{two}}{{three}}{{two}}{{one}}-      {{#d}}-      {{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}-      {{#e}}-      {{one}}{{two}}{{three}}{{four}}{{five}}{{four}}{{three}}{{two}}{{one}}-      {{/e}}-      {{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}-      {{/d}}-      {{one}}{{two}}{{three}}{{two}}{{one}}-      {{/c}}-      {{one}}{{two}}{{one}}-      {{/b}}-      {{one}}-      {{/a}}-    expected: |-      1-      121-      12321-      1234321-      123454321-      1234321-      12321-      121-      1--  - name: List-    desc: Lists should be iterated; list items should visit the context stack.-    data: { list: [ { item: 1 }, { item: 2 }, { item: 3 } ] }-    template: '"{{#list}}{{item}}{{/list}}"'-    expected: '"123"'--  - name: Empty List-    desc: Empty lists should behave like falsey values.-    data: { list: [ ] }-    template: '"{{#list}}Yay lists!{{/list}}"'-    expected: '""'--  - name: Doubled-    desc: Multiple sections per template should be permitted.-    data: { bool: true, two: 'second' }-    template: |-      {{#bool}}-      * first-      {{/bool}}-      * {{two}}-      {{#bool}}-      * third-      {{/bool}}-    expected: |-      * first-      * second-      * third--  - name: Nested (Truthy)-    desc: Nested truthy sections should have their contents rendered.-    data: { bool: true }-    template: "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |"-    expected: "| A B C D E |"--  - name: Nested (Falsey)-    desc: Nested falsey sections should be omitted.-    data: { bool: false }-    template: "| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |"-    expected: "| A  E |"--  - name: Context Misses-    desc: Failed context lookups should be considered falsey.-    data: { }-    template: "[{{#missing}}Found key 'missing'!{{/missing}}]"-    expected: "[]"--  # Implicit Iterators--  - name: Implicit Iterator - String-    desc: Implicit iterators should directly interpolate strings.-    data:-      list: [ 'a', 'b', 'c', 'd', 'e' ]-    template: '"{{#list}}({{.}}){{/list}}"'-    expected: '"(a)(b)(c)(d)(e)"'--  - name: Implicit Iterator - Integer-    desc: Implicit iterators should cast integers to strings and interpolate.-    data:-      list: [ 1, 2, 3, 4, 5 ]-    template: '"{{#list}}({{.}}){{/list}}"'-    expected: '"(1)(2)(3)(4)(5)"'--  - name: Implicit Iterator - Decimal-    desc: Implicit iterators should cast decimals to strings and interpolate.-    data:-      list: [ 1.10, 2.20, 3.30, 4.40, 5.50 ]-    template: '"{{#list}}({{.}}){{/list}}"'-    expected: '"(1.1)(2.2)(3.3)(4.4)(5.5)"'--  - name: Implicit Iterator - Array-    desc: Implicit iterators should allow iterating over nested arrays.-    data:-      list: [ [1, 2, 3], ['a', 'b', 'c'] ]-    template: '"{{#list}}({{#.}}{{.}}{{/.}}){{/list}}"'-    expected: '"(123)(abc)"'--  # Dotted Names--  - name: Dotted Names - Truthy-    desc: Dotted names should be valid for Section tags.-    data: { a: { b: { c: true } } }-    template: '"{{#a.b.c}}Here{{/a.b.c}}" == "Here"'-    expected: '"Here" == "Here"'--  - name: Dotted Names - Falsey-    desc: Dotted names should be valid for Section tags.-    data: { a: { b: { c: false } } }-    template: '"{{#a.b.c}}Here{{/a.b.c}}" == ""'-    expected: '"" == ""'--  - name: Dotted Names - Broken Chains-    desc: Dotted names that cannot be resolved should be considered falsey.-    data: { a: { } }-    template: '"{{#a.b.c}}Here{{/a.b.c}}" == ""'-    expected: '"" == ""'--  # Whitespace Sensitivity--  - name: Surrounding Whitespace-    desc: Sections should not alter surrounding whitespace.-    data: { boolean: true }-    template: " | {{#boolean}}\t|\t{{/boolean}} | \n"-    expected: " | \t|\t | \n"--  - name: Internal Whitespace-    desc: Sections should not alter internal whitespace.-    data: { boolean: true }-    template: " | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n"-    expected: " |  \n  | \n"--  - name: Indented Inline Sections-    desc: Single-line sections should not alter surrounding whitespace.-    data: { boolean: true }-    template: " {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n"-    expected: " YES\n GOOD\n"--  - name: Standalone Lines-    desc: Standalone lines should be removed from the template.-    data: { boolean: true }-    template: |-      | This Is-      {{#boolean}}-      |-      {{/boolean}}-      | A Line-    expected: |-      | This Is-      |-      | A Line--  - name: Indented Standalone Lines-    desc: Indented standalone lines should be removed from the template.-    data: { boolean: true }-    template: |-      | This Is-        {{#boolean}}-      |-        {{/boolean}}-      | A Line-    expected: |-      | This Is-      |-      | A Line--  - name: Standalone Line Endings-    desc: '"\r\n" should be considered a newline for standalone tags.'-    data: { boolean: true }-    template: "|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|"-    expected: "|\r\n|"--  - name: Standalone Without Previous Line-    desc: Standalone tags should not require a newline to precede them.-    data: { boolean: true }-    template: "  {{#boolean}}\n#{{/boolean}}\n/"-    expected: "#\n/"--  - name: Standalone Without Newline-    desc: Standalone tags should not require a newline to follow them.-    data: { boolean: true }-    template: "#{{#boolean}}\n/\n  {{/boolean}}"-    expected: "#\n/\n"--  # Whitespace Insensitivity--  - name: Padding-    desc: Superfluous in-tag whitespace should be ignored.-    data: { boolean: true }-    template: '|{{# boolean }}={{/ boolean }}|'-    expected: '|=|'
stache.cabal view
@@ -31,7 +31,7 @@ -- POSSIBILITY OF SUCH DAMAGE.  name:                 stache-version:              0.1.7+version:              0.1.8 cabal-version:        >= 1.10 license:              BSD3 license-file:         LICENSE.md@@ -46,7 +46,7 @@ extra-doc-files:      CHANGELOG.md                     , README.md data-files:           bench-data/*.mustache-                    , specs/*.yml+                    , specification/*.yml                     , templates/*.mustache  source-repository head@@ -97,7 +97,7 @@                     , hspec            >= 2.0  && < 3.0                     , hspec-megaparsec >= 0.2  && < 0.4                     , megaparsec       >= 5.0  && < 6.0-                    , stache           >= 0.1.7+                    , stache           >= 0.1.8                     , text             >= 1.2  && < 1.3   other-modules:      Text.Mustache.Compile.THSpec                     , Text.Mustache.ParserSpec@@ -122,7 +122,7 @@                     , file-embed                     , hspec            >= 2.0  && < 3.0                     , megaparsec       >= 5.0  && < 6.0-                    , stache           >= 0.1.7+                    , stache           >= 0.1.8                     , text             >= 1.2  && < 1.3                     , yaml             >= 0.8  && < 0.9   if flag(dev)@@ -140,10 +140,10 @@                     , criterion        >= 0.6.2.1 && < 1.2                     , deepseq          >= 1.4  && < 1.5                     , megaparsec       >= 5.0  && < 6.0-                    , stache           >= 0.1.7+                    , stache           >= 0.1.8                     , text             >= 1.2  && < 1.3   if flag(dev)-    ghc-options:      -Wall -Werror+    ghc-options:      -O2 -Wall -Werror   else     ghc-options:      -O2 -Wall   default-language:   Haskell2010