本章讨论辅助开发扩展的工具。
扩展开发者的工具
Venkman, JavaScript 调试器
Venkman是一个成熟的运行于firefox中的javascript调试器。它像典型的调试器一样工作,既可以用于开发扩展有可以用于一般的网络开发。
由于其与扩展和firefox本身的javascript一起工作。这个调试器还开业作为一种学习设计方法的好方式。
安装
Venkman与mozilla suite和当前版本的seamonkey捆绑在一起的,但是在firefox中需要作为扩展进行安装。参考:https://addons.mozilla.org/firefox/216/
在firefox中直接打开上面的URL安装这个扩展,然后重启firefox即可。
开始
从工具菜单选择“JavaScript Debugger”
用于调试的目标javascript
当venkman第一次运行的时候,只能调试当前你的网页浏览器打开的文件。这是因为打开太多的javascript文件来调试会使浏览器变慢,但在开发扩展的过程中你需要超越这个限制。取消在debug菜单下的“Exclude Browser Files”选项。
运行QuickNote
为了说明这一功能,我们要为我们的调试器使用QuickNote中的文件存储机制。从下面的URL中安装QuickNote并重启firefox。https://addons.mozilla.org/firefox/46/
在重启firefox之后,激活QuickNote。然后选择Tools:QuickNote:Float使其在独立的窗口中显示。
使用Venkman
阅读源代码
激活venkman,然后在屏幕左上角选择Open Windows:quicknote.xul:Files。双击quicknote.js以源代码视图打开文件。
插入断点
现在你可能需要设置断点。试着使用QuickNote_saveNote函数来插入。
开始调试
在QuickNote中输入一些文本,然后从菜单中选择Save Current Tab。调试的时候会在你插入断点的地方停止程序。
在单步执行的过程中Local Variables窗口始终会显示变量和对象。对于有很多变量的函数,这读取起来会很困难,因此你可以指出特定的你想要监视的变量。
监视的变量出现在watches标签页,在每次改变的时候都会进行更新。
然后就可以继续单步执行以观察程序中的变化和变量的变化。
一旦监察完成,你可以继续并使停止了的程序正常执行。
开发扩展过程中,作者几乎不需要实现任何工作,就可以用这个来监视扩展的处理过程。在QuickNote的例子中,我们首先设置一个断点,然后进行单步执行。
使用Step Over可以跳过一个函数,使用Step Into可以步入一个函数;一旦你对某个函数的观察目的达到,则可以使用Step Out跳出该程序,然后Step Into可以进入下一个函数。
在你不确定会发生什么的地方设置断点,在下一次你运行程序的时候,使用Continue以转至那个位置并重新开始观察。
MozUnit
MozUnit是一个javascript工具可以用于辅助进行单元测试。它提供一个与相似的UI。对java程序员来说很容易就能上手。
安装
MozUnit是Mozlab的一个特例,从下面的URL安装Mozlab并重启Firefox
http://hyperstruct.net/projects/mozunit
重启之后,打开你用来写测试的编辑器。打开about:config并编辑extensions.mozlab.mozunit.editor属性参数如表1所示。例如,如果你想要使用Terapad,将下面的东西加进去:
C:\app\tpad090\Terapad.exe /jl=%l %f
表1:MozUnit使用的参数
Parameter |
Description |
%f |
Filename |
%l |
Line number |
%c |
Column number |
作者使用的Meadow用gnuserv打开:C:\app\Meadow\bin\gnuclientw.exe +%l:%c %f
注意:至少在这些测试中,你不可能在编辑器中编辑程序文件。而且可能的话最好不要在文件名中包含空格。
用法
一个RPN计算器
我们用JavaScript来实现一个简单的RPN(逆波兰系数)运算来看看如何使用MozUnit。
在编程区域,我们创建一个叫做RpnCalc的类。首先,我们为这个类构造一个简单的接口(清单1)。将其保存为calc.js。
清单1:calc.js(第一步)
function RpnCalc() {
}
RpnCalc.prototype = {
init: function() {
},
push: function(val) {
},
plus: function() {
},
pop: function() {
}
}
实现加法
创建测试实例
在开始创建这个测试实例之前。首先,选择菜单项Tools:Mozlab:Open MozUnit Runner以运行MozUnit窗口。选择菜单项File:New并将其保存在相同目录下,命名为test_calc.js。因为这个文件是测试的目标。接着,点击Edit按钮运行“2 1+”测试实例(清单2)。注意,在这个文件中,方法名称作为测试名称。
在JUnit以及相似的包中,包含测试实例的方法中以testhoge开头的被认为是测试实例。MozUnit使用相同的表示法,但是你也可以让字符串作为方法名,使测试实例自文档化。
清单2:test_calc.js文件内容(第一个测试实例)
var TestCase = mozlab.mozunit.TestCase;
var assert = mozlab.mozunit.assertions;
var tc = new TestCase('Rpn Calc Testcase');
var module = new ModuleManager();
var rpncalc = module.require('package', 'calc');
tc.tests = {
'2 1 +': function() {
var calc = new rpncalc.RpnCalc();
calc.init();
calc.push(2);
calc.push(1);
calc.plus();
assert.equals(calc.pop(), 3);
}
}
清单3:为calc.js增加的内容:
function RpnCalc() {
this.stack = new Array();
}
RpnCalc.prototype = {
init: function() {
this.stack = new Array();
},
push: function(val) {
this.stack.push(Number(val));
},
_letfunc: function(func) {
a = this.pop();
b = this.pop();
this.push(func(a, b));
},
plus: function() {
return this._letfunc(this._plus);
},
_plus: function(a, b) {
return a + b;
},
pop: function() {
return this.stack.pop();
}
}
错误检查
现在你准备好了你的第一个测试实例。当你运行的时候应该会看到一个红条,表示运行失败了。
在calc.js中执行
我们需要充实calc.js文件,用清单3中的内容更新该文件。
运行测试
再次运行这个测试。你应该会看到一个绿条表示测试成功。
实现减法
现在我们来添加减法。
创建测试实例
首先,添加用于减法测试的方法。打开test_calc.js并用清单4中的方法更新。
calc.js中的实现
然后我们需要添加执行的代码。这与加法很相似。用清单5中的方法更新calc.js文件。
运行测试
如果我们在这里运行这个测试,我们会得到红条。什么问题呢?屏幕上会出现“Expected -1, got 1”。原因是使用pop()获取的参数混淆了。因此,需要用清单6中的函数来更新_letfunc。
如果我们再次运行测试,应该会看到一个绿条表示可以正确运行。
测试的好处
这里所描述的实现测试表明方法可以正确的运行,并增加了实现的信心。
乘法和除法的实现都是一样的,但是如果无效的字符串传递来了之后你会怎样处理?如果你试图在堆栈中布运行任何东西,你会返回什么结果呢?当你做处理这些的时候试着将现实世界记在脑中。
清单4:test_calc.js(添加测试实例)
'2 1 -': function() {
var calc = new rpncalc.RpnCalc();
calc.init();
calc.push(2);
calc.push(1);
calc.minus();
assert.equals(calc.pop(), 1);
},
清单5:calc.js (实现减法运算)
minus: function() {
this._letfunc(this._minus);
},
_minus: function(a, b) {
return a - b;
},
清单6:calc.js(修正实现减法的错误)
_letfunc: function(func) {
// correct pop order
b = this.pop();
a = this.pop();
this.push(func(a, b));
},
理解源代码
在开源社区,通过学习源代码你可以学习到很多软件是如何工作的知识;对于大量代码的工程,如Firefox,通常人们会使用特殊的源代码浏览工具来理解它。
Mozilla Cross-Reference
Mozilla Cross-Reference是一个由mozilla.org提供的全文可搜索的源代码清单。我们要使用MXR(http://mxr.mozilla.org/),一个Linux下的源代码浏览器。
开始
访问这个URL: http://mxr.mozilla.org/.在左手边你可以看到一个用于搜索的起始以及一个搜索表格。
用法
我在寻找什么?
如果你只是随机的浏览一下这些源代码,你可能会没有什么收获。因此,我们来看看该从何处开始入手。
假如我们已经在源代码中找到了清单7中的内容。我们可以从通过其名称猜测其功能是处理文件,但是我们仍然还有下面这些问题:
1. nsILocalFile.initWithPath是干什么的?它需要哪些参数?
2. nsILocalFile.initWithPath实际上是如何处理的?
我们来检查一下这些问题。
这是干什么的?它有什么样的参数?
首先,搜索一下这个组件的定义。输入接口nsILocalFile(带一个结尾的空格)到搜索区内,然后开始搜索。
几乎所有继承自nsISupports的组件,在搜索的时候加上一个结尾空格作为定界符会很容易的指定你在寻找的东西。
这是nsILocalFile.idl文件的原因。每一个方法都带有注释。
在initWithPath中,nsILocalFile对象进行初始化。并且,其内任何已经存在的信息都会重置。还考虑到了当使用的路径指向的不是文件的潜在问题。
这个函数需要一个完整的路径作为参数,相对路径会抛出错误。
这会帮助你理解initWithPath的规范。
var file = Components.classes['@mozilla.org/file/local;1']
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(hoge);
这实际是如何实现的?
如果我们想要明白某些事情是如何实现的,我们需要如何进行搜索呢?去掉nsILocalFile中的I加上两个冒号,然后将函数名的第一个字母大写,结果是nsLocalFile::InitWithPath。这是这个函数的C++实现的名称。使用它作为你的搜索字符串。
那会产生一个nsLocalFileWin.cpp文件以及其他操作系统特定的文件。看一下nsLocalFileWin.cpp文件内部——例如,我们会看到它在检查驱动器名称中是否存在一个“:”。
我们还可以看到在WinCE中网络路径的处理是如何的不同。只需要看看InitWithPath,我们可以看到路径有效性检查是如何工作的。
结论
在本章中,我们介绍性的看了一些工具。如果你在阅读本文时有任何的恍然大悟的时刻,我希望你会采取接下来的步奏并实际上将他们用于工作中。我希望你会发现本章帮助你成为了一个更加有效率的扩展开发者。
gonzui
gunzui是一个来自Satoru Takabayashi的全文本源代码搜索引擎。Satoru Takabayashi是一个人们所熟知的Namazu搜索引擎软件开发者。
安装
Windows用户可以利用一个由Soutaro Matsumoto创建的叫做“gonzui for win32”的独立版本。http://soutaro.com/gonzui-win32/
按下面的步骤运行:下载gonzui-win32-1.2.2.zip并将其解压到合适的目录下。
1. 下载Firefox的源代码,并将其放在gonzui相同的目录下(只是因为在相同目录下会更容易的去指定文件)。
2. 打开命令行运行窗口,转到包含有gonzui的目录下。
3. 下一个命令会导入源代码:gonzui-import.exe Mozilla
4. 一旦导入过程结束,输入下面的命令来运行gonzui服务器: gonzui-server.exe
5. 现在你可以通过在你的网页浏览器地址栏中http://localhost:46984输入来访问gonzui了。
这让你浏览所有的包,点击链接可以遍历它们,并且可以用内部链接位置作为起始位置。
译文PDF下载