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")' pwsh: '"world"' go: 'func() string { return "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}}")' pwsh: '"{{planet}}"' go: 'func() string { return "{{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}}")' pwsh: '"|planet| => {{planet}}"' go: 'func() string { return "|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)))' pwsh: 'if (($null -eq $script:calls) -or ($script:calls -ge 3)){$script:calls=0}; ++$script:calls; $script:calls' go: 'func() func() int { g := 0; return func() int { g++; return 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 () ">")' pwsh: '">"' go: 'func() string { return ">" }' template: "<{{lambda}}{{{lambda}}}" expected: "<>>" - 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"))' pwsh: 'if ($args[0] -eq "{{x}}") {"yes"} else {"no"}' go: 'func(text string) string { if text == "{{x}}" { return "yes" } else { return "no" } }' template: "<{{#lambda}}{{x}}{{/lambda}}>" expected: "" - 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))' pwsh: '"$($args[0]){{planet}}$($args[0])"' go: 'func(text string) string { return text + "{{planet}}" + 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))' pwsh: '"$($args[0]){{planet}} => |planet|$($args[0])"' go: 'func(text string) string { return text + "{{planet}} => |planet|" + 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))' pwsh: '"__$($args[0])__"' go: 'func(text string) string { return "__" + 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)' pwsh: '$false' go: 'func(text string) bool { return false }' template: "<{{^lambda}}{{static}}{{/lambda}}>" expected: "<>"