0

Im writing a series of coffeescript files for doing math operations and I need to write some tests. I figure that mocha and chai are the way to go. At the moment, Im using the namespace method to group all my separate functions together in order to keep things tidy:

namespace = (target, name, block) ->
  [target, name, block] = [(if typeof exports isnt 'undefined' then exports else window), arguments...] if arguments.length < 3
  top    = target
  target = target[item] or= {} for item in name.split '.'
  block target, top

exports? exports.namespace = namespace

The thing I'd like to test at the moment is my matrix class, which looks a little like this:

namespace "CoffeeMath", (exports) ->

  class exports.Matrix4
    for name in ['add', 'subtract', 'multiply', 'divide', 'addScalar', 'subtractScalar', 'multiplyScalar', 'divideScalar', 'translate']
        do (name) ->
          Matrix4[name] = (a,b) ->
          a.copy()[name](b)

    Matrix4.DIM = 4

    # Take a list in column major format
    constructor: (@a=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]) ->
      # etc etc ...

Now compiling all this up with the lovely coffeescript compiler is all well. I have a test like this:

chai = require 'chai'
chai.should()

{namespace} = require '../src/aname'
{Matrix4} = require '../src/math'

describe 'Matrix4 tests', ->
  m = null
  it 'should be the identity matrix', ->
    m  = new exports.Matrix4()
    m.a.should.equal '[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]'

The problem is, I get the following error:

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
ReferenceError: namespace is not defined
    at Object.<anonymous> (/Users/oni/Projects/Saito.js/src/math.coffee:3:3)
    at Object.<anonymous> (/Users/oni/Projects/Saito.js/src/math.coffee:631:4)
    at Module._compile (module.js:441:26)

aname should be included I believe and that exports the namespace function so I cant see why namespace is not defined. Any thoughts?

Oni
  • 652
  • 2
  • 9
  • 22

1 Answers1

1

From the fine manual:

To export an object, add to the special exports object.

And then, exports is returned by require:

module.exports is the object that's actually returned as the result of a require call.

So, when you say this:

namespace = require '../src/aname'

you have namespace.namespace available inside your test.

CoffeeScript wraps each file in a function wrapper to avoid polluting the global namespace:

all CoffeeScript output is wrapped in an anonymous function: (function(){ ... })(); This safety wrapper, combined with the automatic generation of the var keyword, make it exceedingly difficult to pollute the global namespace by accident.

This means that you have something like this in the compiled JavaScript:

(function() {
    exports.namespace = ...
})();
(function() {
    # Matrix4 definition which uses the 'namespace' function
})();
(function() {
    var namespace = ...
})();

The result is that namespace is not visible where you define Matrix4 since the test and Matrix4 exist in separate functions and thus separate scopes.

If you want to use namespace inside your math file, then you'll have to require it there rather in the code that requires your math file.

Community
  • 1
  • 1
mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • Thanks for that! Its a big help. Still attempting to merge a web based coffeescript application with a node based testing environment. this is one step closer. Cheers – Oni May 14 '12 at 12:58