如何为使用CoffeeScript编写的类创建命名空间?
例如,我有树类 Aa , Bb 和 Cc 。我希望它们插入到globaly assesible命名空间 - MyClasses ,允许交叉它们并在jasmine-node中使用它们。
class MyClasses.Aa
@someProp: true
class MyClasses.Bb
@someProp2: false
class MyClasses.Cc
@doSomeStuff: -> MyClasses.Aa.someProp = false
我知道,我可以将它们注入一个文件并进行编译,但我希望有一个类=一个文件。
我该怎么办呢? 谢谢!
编辑:我试过这种方式,但我觉得它不好,但它适用于浏览器和jasmine-noderoot = exports ? this
root.MyClasses = root.MyClasses ? {}
root.MyClasses.Aa =
class Aa
答案 0 :(得分:2)
使用RequireJS。
在一个名为“my-classes.coffee”的文件中,定义命名空间。
define [], ->
# You need this if you want it to work in multiple environments.
# Otherwise just use `window` to work in the browser.
root = exports ? this
root.MyClasses = {}
您可以在另一个名为“aa.coffee”的文件中定义您的课程。
define ['my-classes'], (MyClasses) ->
class MyClasses.Aa
@someProp: true
另一个档案:
define ['my-classes'], (MyClasses) ->
class MyClasses.Bb
@someProp2: false
现在,当您需要时,它应导出MyClasses
,其中包含MyClasses.Aa
。
require ['my-classes', 'aa'], (MyClasses, _) ->
console.log MyClasses.Aa.someProp
这样做的一个问题是你不能只依赖require
语句中的“my-classes”。如果您这样做,MyClasses.Aa
将是未定义的。但是你也不能只依赖“aa”,因为“aa”除了通过添加到MyClasses之外不会导出任何东西。在上面的代码段中,MyClasses.Bb
未定义,因为我没有明确依赖它。这就是为什么许多人要么使用一个巨大的文件,要么复制重新导出命名空间的样板。
如果有人知道如何解决这个问题,请告诉我。
我个人认为RequireJS使用起来很复杂,并且有许多不同的方法来设置它。我使用jasmine的一种方法是使用cake任务将我的CoffeeScript预编译为JavaScript,然后使用这样的spec文件。
requirejs = require('requirejs')
# Set the baseURL to your compiled JS dir.
requirejs.config { baseUrl: __dirname + '/../lib' }
requirejs ['my-classes', 'aa'], (MyClasses, _) ->
describe "someProp", ->
it "should be true", ->
expect(MyClasses.Aa.someProp).toEqual true
这可能不是最好的方法,但我能够使用它在浏览器,节点服务器和jasmine-node测试中运行模块。我也看到有些人使用custom runners来避免spec文件中的样板文件。
如果您不想使用RequireJS,可能会发现this question有帮助。它的工作原理是使用CoffeeScript FAQs上定义的namespace
函数。
答案 1 :(得分:1)
Coffeescript wiki中有一个建议的解决方案:
来自https://github.com/jashkenas/coffee-script/wiki/FAQ:
# Code:
#
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
# Usage:
#
namespace 'Hello.World', (exports) ->
# `exports` is where you attach namespace members
exports.hi = -> console.log 'Hi World!'
namespace 'Say.Hello', (exports, top) ->
# `top` is a reference to the main namespace
exports.fn = -> top.Hello.World.hi()
Say.Hello.fn() # prints 'Hi World!'
答案 2 :(得分:0)
您可以使用-b
标记编译CoffeeScript文件,从而删除安全包装。或者用你已经拥有的东西将你的类暴露到全局范围
root = exports ? window
MyClasses = root.MyClasses = root.MyClasses ? {}
class MyClasses.Aa
@someProp: true
# same header as a.coffee
class MyClasses.Bb
@someProp2: false
# same header as a.coffee
class MyClasses.Cc
@doSomeStuffWith: (someClass)->
# pass a class to the method instead of just
# modifying another class within the same scope
someClass.someProp = false
重复其他课程。在第一行中,我发现window
比this
更明确,第二行也允许您在没有长命名空间序列的情况下将类附加到MyClasses
。
在浏览器中,您的类将位于全局对象MyClasses
在node.js中你会像这样使用它们(这是一个有点冗长的恕我直言):
var Aa = require("./a").MyClasses.Aa,
Bb = require("./b").MyClasses.Bb,
Cc = require("./c").MyClasses.Cc;
console.log(Aa.someProp) // true
console.log(Bb.someProp2) // false
Cc.doSomeStuffWith(Aa)
console.log(Aa.someProp) // false
pd:我没有用node-jasmine检查它。