View all posts

CoffeeScript comprhension

Just some days ago, while working on CoffeeScript test files, I noticed that generated Javascript was not honestly the one I was expecting

describe 'Assertion tests', ->
  describe 'Template tests', ->
    for uri in fixtures.testUris
      describe "Testing #{uri.uriTemplate}", ->
        res = validations.validateUriTemplate uri.uriTemplate
        it "Result validation should be #{uri.expectedResult}", ->
          console.log "if #{uri.expectedResult} is true"
          if uri.expectedResult is true
            assert.isTrue res
          else
            assert.typeOf res, 'string'

And this is the generated Javascript, that you can also verify by yourself on CoffeeScript website

describe('Assertion tests', function() {
  return describe('Template tests', function() {
    var uri, _i, _len, _ref, _results;
    _ref = fixtures.testUris;
    _results = [];
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      uri = _ref[_i];
      _results.push(describe("Testing " + uri.uriTemplate, function() {
        var res;
        res = validations.validateUriTemplate(uri.uriTemplate);
        return it("Result validation should be " + uri.expectedResult, function() {
          console.log("if " + uri.expectedResult + " is true");
          if (uri.expectedResult === true) {
            return assert.isTrue(res);
          } else {
            return assert.typeOf(res, 'string');
          }
        });
      }));
    }
    return _results;
  });
});

The cumbersome thing, actually, is the _result array being populated and then returned after the for loop. As we know, CoffeScript consider the last function istruction as a return one, and since in my case it is a for block, it considers to return the entire result.

Obiously this is not the intended behavior: I am just looping through an array and nothing else. This is a code taken from test (so honestly I could also don’t care about memory waste), but in production code it could be worth to avoid this.

The solution is pretty simple:

describe 'Assertion tests', ->
  describe 'Template tests', ->
    for uri in fixtures.testUris
      describe "Testing #{uri.uriTemplate}", ->
        res = validations.validateUriTemplate uri.uriTemplate
        it "Result validation should be #{uri.expectedResult}", ->
          console.log "if #{uri.expectedResult} is true"
          if uri.expectedResult is true
            assert.isTrue res
          else
            assert.typeOf res, 'string'
      undefined

Explicitly specifing the return, array creation and population is completely avoided.

I definitely disagree with the “last istruction is a return one” facility, actually.