summaryrefslogtreecommitdiff
path: root/specs/~lambdas.yml
blob: e4eea420bcbd57b8a1fdeef8726795633bf6e125 (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
overview: |
  Lambdas are a special-cased data type for use in interpolations and
  sections.

  When used as the data value for an Interpolation tag, the lambda MUST be
  treatable as an arity 0 function, and invoked as such.  The returned value
  MUST be rendered against the default delimiters, then interpolated in place
  of the lambda.

  When used as the data value for a Section tag, the lambda MUST be treatable
  as an arity 1 function, and invoked as such (passing a String containing the
  unprocessed section contents).  The returned value MUST be rendered against
  the current delimiters, then interpolated in place of the section.
tests:
  - name: Interpolation
    desc: A lambda's return value should be interpolated.
    data:
      lambda: !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: !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: !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: !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: !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: !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: !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: !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: !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: !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: "<>"