summaryrefslogtreecommitdiff
path: root/specs/~lambdas.json
blob: 7b6d59c95ec6c919435ecc1ef22b192202c119a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
{
  "__ATTN__": "Do not edit this file; changes belong in the appropriate YAML file.",
  "overview": "Lambdas are a special-cased data type for use in interpolations and\nsections.\n\nWhen used as the data value for an Interpolation tag, the lambda MUST be\ntreatable as an arity 0 function, and invoked as such.  The returned value\nMUST be rendered against the default delimiters, then interpolated in place\nof the lambda.\n\nWhen used as the data value for a Section tag, the lambda MUST be treatable\nas an arity 1 function, and invoked as such (passing a String containing the\nunprocessed section contents).  The returned value MUST be rendered against\nthe current delimiters, then interpolated in place of the section.\n",
  "tests": [
    {
      "name": "Interpolation",
      "desc": "A lambda's return value should be interpolated.",
      "data": {
        "lambda": {
          "__tag__": "code",
          "ruby": "proc { \"world\" }",
          "raku": "sub { \"world\" }",
          "perl": "sub { \"world\" }",
          "js": "function() { return \"world\" }",
          "php": "return \"world\";",
          "python": "lambda: \"world\"",
          "clojure": "(fn [] \"world\")",
          "lisp": "(lambda () \"world\")"
        }
      },
      "template": "Hello, {{lambda}}!",
      "expected": "Hello, world!"
    },
    {
      "name": "Interpolation - Expansion",
      "desc": "A lambda's return value should be parsed.",
      "data": {
        "planet": "world",
        "lambda": {
          "__tag__": "code",
          "ruby": "proc { \"{{planet}}\" }",
          "raku": "sub { q+{{planet}}+ }",
          "perl": "sub { \"{{planet}}\" }",
          "js": "function() { return \"{{planet}}\" }",
          "php": "return \"{{planet}}\";",
          "python": "lambda: \"{{planet}}\"",
          "clojure": "(fn [] \"{{planet}}\")",
          "lisp": "(lambda () \"{{planet}}\")"
        }
      },
      "template": "Hello, {{lambda}}!",
      "expected": "Hello, world!"
    },
    {
      "name": "Interpolation - Alternate Delimiters",
      "desc": "A lambda's return value should parse with the default delimiters.",
      "data": {
        "planet": "world",
        "lambda": {
          "__tag__": "code",
          "ruby": "proc { \"|planet| => {{planet}}\" }",
          "raku": "sub { q+|planet| => {{planet}}+ }",
          "perl": "sub { \"|planet| => {{planet}}\" }",
          "js": "function() { return \"|planet| => {{planet}}\" }",
          "php": "return \"|planet| => {{planet}}\";",
          "python": "lambda: \"|planet| => {{planet}}\"",
          "clojure": "(fn [] \"|planet| => {{planet}}\")",
          "lisp": "(lambda () \"|planet| => {{planet}}\")"
        }
      },
      "template": "{{= | | =}}\nHello, (|&lambda|)!",
      "expected": "Hello, (|planet| => world)!"
    },
    {
      "name": "Interpolation - Multiple Calls",
      "desc": "Interpolated lambdas should not be cached.",
      "data": {
        "lambda": {
          "__tag__": "code",
          "ruby": "proc { $calls ||= 0; $calls += 1 }",
          "raku": "sub { state $calls += 1 }",
          "perl": "sub { no strict; $calls += 1 }",
          "js": "function() { return (g=(function(){return this})()).calls=(g.calls||0)+1 }",
          "php": "global $calls; return ++$calls;",
          "python": "lambda: globals().update(calls=globals().get(\"calls\",0)+1) or calls",
          "clojure": "(def g (atom 0)) (fn [] (swap! g inc))",
          "lisp": "(let ((g 0)) (lambda () (incf g)))"
        }
      },
      "template": "{{lambda}} == {{{lambda}}} == {{lambda}}",
      "expected": "1 == 2 == 3"
    },
    {
      "name": "Escaping",
      "desc": "Lambda results should be appropriately escaped.",
      "data": {
        "lambda": {
          "__tag__": "code",
          "ruby": "proc { \">\" }",
          "raku": "sub { \">\" }",
          "perl": "sub { \">\" }",
          "js": "function() { return \">\" }",
          "php": "return \">\";",
          "python": "lambda: \">\"",
          "clojure": "(fn [] \">\")",
          "lisp": "(lambda () \">\")"
        }
      },
      "template": "<{{lambda}}{{{lambda}}}",
      "expected": "<&gt;>"
    },
    {
      "name": "Section",
      "desc": "Lambdas used for sections should receive the raw section string.",
      "data": {
        "x": "Error!",
        "lambda": {
          "__tag__": "code",
          "ruby": "proc { |text| text == \"{{x}}\" ? \"yes\" : \"no\" }",
          "raku": "sub { $^section eq q+{{x}}+ ?? \"yes\" !! \"no\" }",
          "perl": "sub { $_[0] eq \"{{x}}\" ? \"yes\" : \"no\" }",
          "js": "function(txt) { return (txt == \"{{x}}\" ? \"yes\" : \"no\") }",
          "php": "return ($text == \"{{x}}\") ? \"yes\" : \"no\";",
          "python": "lambda text: text == \"{{x}}\" and \"yes\" or \"no\"",
          "clojure": "(fn [text] (if (= text \"{{x}}\") \"yes\" \"no\"))",
          "lisp": "(lambda (text) (if (string= text \"{{x}}\") \"yes\" \"no\"))"
        }
      },
      "template": "<{{#lambda}}{{x}}{{/lambda}}>",
      "expected": "<yes>"
    },
    {
      "name": "Section - Expansion",
      "desc": "Lambdas used for sections should have their results parsed.",
      "data": {
        "planet": "Earth",
        "lambda": {
          "__tag__": "code",
          "ruby": "proc { |text| \"#{text}{{planet}}#{text}\" }",
          "raku": "sub { $^section ~ q+{{planet}}+ ~ $^section }",
          "perl": "sub { $_[0] . \"{{planet}}\" . $_[0] }",
          "js": "function(txt) { return txt + \"{{planet}}\" + txt }",
          "php": "return $text . \"{{planet}}\" . $text;",
          "python": "lambda text: \"%s{{planet}}%s\" % (text, text)",
          "clojure": "(fn [text] (str text \"{{planet}}\" text))",
          "lisp": "(lambda (text) (format nil \"~a{{planet}}~a\" text text))"
        }
      },
      "template": "<{{#lambda}}-{{/lambda}}>",
      "expected": "<-Earth->"
    },
    {
      "name": "Section - Alternate Delimiters",
      "desc": "Lambdas used for sections should parse with the current delimiters.",
      "data": {
        "planet": "Earth",
        "lambda": {
          "__tag__": "code",
          "ruby": "proc { |text| \"#{text}{{planet}} => |planet|#{text}\" }",
          "raku": "sub { $^section ~ q+{{planet}} => |planet|+ ~ $^section }",
          "perl": "sub { $_[0] . \"{{planet}} => |planet|\" . $_[0] }",
          "js": "function(txt) { return txt + \"{{planet}} => |planet|\" + txt }",
          "php": "return $text . \"{{planet}} => |planet|\" . $text;",
          "python": "lambda text: \"%s{{planet}} => |planet|%s\" % (text, text)",
          "clojure": "(fn [text] (str text \"{{planet}} => |planet|\" text))",
          "lisp": "(lambda (text) (format nil \"~a{{planet}} => |planet|~a\" text text))"
        }
      },
      "template": "{{= | | =}}<|#lambda|-|/lambda|>",
      "expected": "<-{{planet}} => Earth->"
    },
    {
      "name": "Section - Multiple Calls",
      "desc": "Lambdas used for sections should not be cached.",
      "data": {
        "lambda": {
          "__tag__": "code",
          "ruby": "proc { |text| \"__#{text}__\" }",
          "raku": "sub { \"__\" ~ $^section ~ \"__\" }",
          "perl": "sub { \"__\" . $_[0] . \"__\" }",
          "js": "function(txt) { return \"__\" + txt + \"__\" }",
          "php": "return \"__\" . $text . \"__\";",
          "python": "lambda text: \"__%s__\" % (text)",
          "clojure": "(fn [text] (str \"__\" text \"__\"))",
          "lisp": "(lambda (text) (format nil \"__~a__\" text))"
        }
      },
      "template": "{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}",
      "expected": "__FILE__ != __LINE__"
    },
    {
      "name": "Inverted Section",
      "desc": "Lambdas used for inverted sections should be considered truthy.",
      "data": {
        "static": "static",
        "lambda": {
          "__tag__": "code",
          "ruby": "proc { |text| false }",
          "raku": "sub { 0 }",
          "perl": "sub { 0 }",
          "js": "function(txt) { return false }",
          "php": "return false;",
          "python": "lambda text: 0",
          "clojure": "(fn [text] false)",
          "lisp": "(lambda (text) (declare (ignore text)) nil)"
        }
      },
      "template": "<{{^lambda}}{{static}}{{/lambda}}>",
      "expected": "<>"
    }
  ]
}