Modules in Ringo
Ringo实现了CommonJS Modules1.1规范,在Javascript世界中,存在多个可用Module patterns,但是在Ringo的世界里,我们只用这个:
剖析Module
In Ringo,每一个javascript文件都被当做是一个module,Ringo提供导入、导出的实现。
一个简单的例子会让事情变得更明白。下面我们实现一个foobar.js模块(module),我们希望这个模块提供add方法,而不是其内部私有方法adder:
// foobar.js
varadder = function(a, b) {
return a + b;
};
exports.add = function(a, b) {
return adder(a, b );
};
这样,我们就完成了一个module的实现,我们现在可以在ringo环境中,通过require引入这个模块,然后调用这个模块对外开放的add方法(以下在Ringo命令行中执行, >>是Ringo命令行提示符):
>> varfoobar = require(‘foobar’);
>> foobar.add(3, 4);
7
而模块(module)中的私有(没有export)的方法,我们不能调用:
>> foobar.adder(2, 2);
TypeError: Cannot find function adder in object [object Object].
Ringo为每一个模块(module)对象提供了一个module对象,这个module对象包含如下属性:
模块在私有区域执行,在模块中,除了显式定义为exported的对象属性,其他都是私有不被外部环境或者其他模块可见的——这个解决了JavaScript编程中常见的统一Namespace中,属性混乱、冲突的问题。
Module IDs: module文件名称,去除.js扩展名,相对ID,绝对ID——类似于相对路径、绝对路径的概念。
Module Path: 一些列的路径位置(多个!),Ringo会在其中寻在module,可以通过如下途径设置:
从Ringo 0.8版本开始,默认的module路劲(module path)包含安装目录下的modules和packages文件夹。Ringo 0.8也可以不用配置的从Java Classpath中装载modules。——0.8之前的版本?不提了。
Packages
Package是组合几个相关的模块(module)以及相关资源的单位。
Package是包含package.json(Package描述文件)的文件夹。下面的package.json能够被Ringo的模块装载机制(Module Loader)识别:
{
“main”: “/lib/main.js”
}
如 果我们在使用require(或者其他通过module id引入模块的机制)引入模块时,module id指向自定义的包目录,并且package.json文件中定义了main属性,Ringo将尝试装载制定资源。main的属性中的文件路劲必须是 针对package root的相对路径。
如上mypkg是一个存在package.json的包目录。
如果module id指向一个目录,目录中不存在package.json(不是Package),或者存在package.json但是其中没有定义main属性,Ring将尝试装载该目录下的index.js文件。
如果module id的一部分为package目录(存在package.json以及main属性。),Ringo将剩余的module id部分在Package 目录的lib目录中解析、寻找(就是说引用路径可以省略实例目录lib。这种方式可能是方便package内部模块引用而出现的。);在package.json文件中可以定义directories.lib属性,覆盖默认的lib文件夹:
{
“directories”: {
“lib”: “lib”
}
}
Ringo也可以通过ringo-admin工具,进行简单的package管理工作。
Caching & Reloading
每一个模块(module)在第一次装载后会被缓存(caching),Ringo根据module id决定一个模块是第一次装载,还是可以直接从缓存中装载;避免模块被装载超过一次,——但是在一些特定环境下,模块仍然可能被重复装载。
默 认情况下,Ringo 模块装载机制会在模块被required(这事嘛意思? require调用,还是require之后,每一次针对模块导出方法的调用??——经不严格测试,应该是做require调用时)时,自动检查此模块以 及其依赖的模块是否被修改,被修改了的模块会被重新装载。
以产品模式运行ringo可以避免模块的修改检查。 -p –production 或者在servlet环境中配置。
Ringo 模块扩展
CommonJS 模块管理规范设计的比较简洁,Ringo在此基础上,做了一些精巧、细微的扩展——这些扩展主要是针对export、import功能。对于“标准、规 范”的随意扩展,会导致将来代码不能迁移,还好Ringo提供了工具,可以将这些代码转换为pure CommonJS规范代码。
include就是Ringo提供的一个扩展,其用户类似于require。但是include相当于把模块代码直接copy到本地,而不是仅仅引入模块中export的属性。
在Ringo中,我们可以结合Javascript 1.8的destructuring assignment新特性,进一步增强原有的require功能:
var{foo, bar} = require(“some/module”);
在模块中,使用:
export(“foo”, “bar”, “baz”);
Destructuring Assignment是个挺有意思的新功能,后续在Ringo环境中,我们会尝试去学习使用它。(wfeng007:比较高级的javascript语言版本才提供这个特性。)