Repository: mozilla/nunjucks
Pull request #826 (2016-08-31 15:56:25)

Add elseif case ("alias" of elif) to parseIf
This commit adds an `elseif` case that falls through to `elif`. Having `elseif` provides consistency between nunjucks and twig so the same templates can be used with either one.

carljm: Can you add a test for this?
kswedberg: Sure, I'd be happy to do that. Any suggestions for what exactly to test? I was thinking I'd replicate an `elif` test, bit the only test I see for `elif` in /tests/parser.js is this one:

```js
expect(function() {
    parser.parse('hello {% if sdf %} data');
}).to.throwException(/expected elif, else, or endif/);
```
carljm: Heh, looks like the existing testing of `elif` leaves something to be desired. I'd just add a compiler test (these are in practice our end-to-end functional tests) showing that if/elseif/endif works as expected. And if you're up for adding one for `elif` while you're at it, that'd be great :-)
carljm: (by "works as expected" I just mean something simple like `{% if foo == 1 %}one{% elseif foo == 2 %}two{% endif %}` and pass in a few different values for `foo` in the context, assert the template output.
carljm: Tests look great, thanks! And sorry I forgot to mention this in the first round, but would you also be willing to add a changelog entry (in the 2.x section), following the pattern of the existing entries? Thanks!
kswedberg: Sure thing. 

Also, not sure if you want docs updated or not, but I could change:

> You can specify alternate conditions with `elif` and `else`

to: 

> You can specify alternate conditions with `elif` (or `elseif`, which is simply an alias of `elif`) and `else`
carljm: Sure, please do update the docs as well.
kswedberg: Ok, I think I have everything in there, and I hope I didn't make too much of a mess out of the merge I just did. I thanked myself in the changelog, which was weird, but it fit the pattern, so what the heck.
carljm: Looks great, thank you!

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c2c0e68..7fe6cfb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -30,6 +30,9 @@ Changelog
 2.x (unreleased)
 ----------------
 
+* Add `elseif` as an alias of `elif` for parity with Twig. Thanks kswedberg.
+  Merge of [#826](https://github.com/mozilla/nunjucks/pull/826).
+
 * Add nunjucks env to express app settings as `nunjucksEnv`.
   Merge of [#829](https://github.com/mozilla/nunjucks/pull/829).
 
diff --git a/docs/fr/templating.md b/docs/fr/templating.md
index 4a1761c..12b8a0a 100644
--- a/docs/fr/templating.md
+++ b/docs/fr/templating.md
@@ -17,7 +17,7 @@ Ceci est un aperçu des caractéristiques des templates disponibles dans Nunjuck
 ## File Extensions
 
 Bien que vous soyez libre d'utiliser n'importe quelle extension de fichier pour vos
-fichiers de template Nunjucks, la communauté de Nunjucks a adopté `.njk`.  
+fichiers de template Nunjucks, la communauté de Nunjucks a adopté `.njk`.
 
 Si vous développez des outils ou des aides de syntaxe pour éditeur pour Nunjucks,
 veuillez inclure la reconnaissance de l'extension `.njk`.
@@ -170,7 +170,7 @@ exactement comme le `if` de javascript.
 Si `variable` est défini et évalué à `true`, "C'est vrai"
 s'affichera, sinon rien n'apparaitra.
 
-Vous pouvez spécifier des conditions alternatives avec `elif` et `else` :
+Vous pouvez spécifier des conditions alternatives avec `elif` (ou `elsif`) et `else` :
 
 ```jinja
 {% if faim %}
diff --git a/docs/templating.md b/docs/templating.md
index 9704e19..0cc86c3 100644
--- a/docs/templating.md
+++ b/docs/templating.md
@@ -179,7 +179,8 @@ exactly as javascript's `if` behaves.
 If variable is defined and evaluates to true, "It is true" will be
 displayed. Otherwise, nothing will be.
 
-You can specify alternate conditions with `elif` and `else`:
+You can specify alternate conditions with `elif` (or `elseif`, which is simply an alias of `elif`)
+and `else`:
 
 ```jinja
 {% if hungry %}
diff --git a/src/parser.js b/src/parser.js
index 7a1e7d7..3daec50 100644
--- a/src/parser.js
+++ b/src/parser.js
@@ -448,14 +448,14 @@ var Parser = Object.extend({
         var tag = this.peekToken();
         var node;
 
-        if(this.skipSymbol('if') || this.skipSymbol('elif')) {
+        if(this.skipSymbol('if') || this.skipSymbol('elif') || this.skipSymbol('elseif')) {
             node = new nodes.If(tag.lineno, tag.colno);
         }
         else if(this.skipSymbol('ifAsync')) {
             node = new nodes.IfAsync(tag.lineno, tag.colno);
         }
         else {
-            this.fail('parseIf: expected if or elif',
+            this.fail('parseIf: expected if, elif, or elseif',
                       tag.lineno,
                       tag.colno);
         }
@@ -463,10 +463,11 @@ var Parser = Object.extend({
         node.cond = this.parseExpression();
         this.advanceAfterBlockEnd(tag.value);
 
-        node.body = this.parseUntilBlocks('elif', 'else', 'endif');
+        node.body = this.parseUntilBlocks('elif', 'elseif', 'else', 'endif');
         var tok = this.peekToken();
 
         switch(tok && tok.value) {
+        case 'elseif':
         case 'elif':
             node.else_ = this.parseIf();
             break;


Test patch:
diff --git a/tests/compiler.js b/tests/compiler.js
index 3999580..100e9a5 100644
--- a/tests/compiler.js
+++ b/tests/compiler.js
@@ -131,6 +131,27 @@
                   { food: {'pizza': true }},
                   'yum');
 
+            equal('{% if pizza %}yum{% elif anchovies %}yuck{% endif %}',
+                  {pizza: true },
+                  'yum');
+
+            equal('{% if pizza %}yum{% elseif anchovies %}yuck{% endif %}',
+                  {pizza: true },
+                  'yum');
+
+            equal('{% if pizza %}yum{% elif anchovies %}yuck{% endif %}',
+                  {anchovies: true },
+                  'yuck');
+
+            equal('{% if pizza %}yum{% elseif anchovies %}yuck{% endif %}',
+                  {anchovies: true },
+                  'yuck');
+
+            equal('{% if topping == "pepperoni" %}yum{% elseif topping == "anchovies" %}' +
+                  'yuck{% else %}hmmm{% endif %}',
+                  {topping: 'sausage' },
+                  'hmmm');
+
             finish(done);
         });