You can play with the result of this tutorial in JSBin
1) Our input data
We will parse the list of everyone who completed this tutorial. This list is available as git repo and you can add yourself to the list afterwards ;-)
It is structured as following:
alias:country
The alias can be a unique alphanumerical string, whereas the country code is a string consisting of exactly two chars as defined by ISO 3166-2. Therefore it could look like this:
greenify:DE
daviddao:HK
mhelvens:NL
timruffles:UK
iriscshih:TW
2) Bootstrapping the project
We have selected these options:
? Module name? (required) biojs-io-graduates
? Description? A parser for the BioJS tutorial graduate list
? Module version? 0.1.0
? Author name? greenify
? Author email? [email protected]
? Github username? greenify
? Keywords for npm (separate with comma) graduate, parser
? A visualization lib? No
? Unit tests: Yes
? Configure a build system? (Gulp) No
? Linting (Check code style with JSHint) No
? Choose your license type: MIT
? Is this correct? Yes
slush
already prefills some files and creates a dummy test. When we later create
files you will need to replace them.
3) Export your component
Now it is time to export your component in order to provide your functionality with the other BioJS components or in your module (e.g your first test case).
We use the CommonJS Syntax to export modules in BioJS.
So let us start with the ground work for the parser - we use read_static
to make this tutorial super easy for you ;-)
In the next tutorial we will show you how to read the entire list.
We can export the parser in the following way:
(lib/index.js
)
var graduates = {};
graduates.read_static = function() {
var data = "greenify:DE\ndaviddao:HK\nmhelvens:NL\ntimruffles:UK\niriscshih:TW\n\n";
return graduates.parse(data);
};
graduates.parse = function(data) {
// you need to fill this
return {};
};
module.exports = graduates;
(replace the entire file with the code above)
4) How to run node code?
We can require
our exported package from any file - so let us create a temporary
test file to show this:
(lib/tests.js
)
var graduates = require('./index');
var result = graduates.parse("greenify:DE\ndaviddao:HK");
console.log(result);
You can run your application directly with Node:
node tests.js
As we haven’t done any work, our package currently outputs {}
,
but of course it should return {"DE": 1, "HK: 1}
.
Other BioJS components are also able to include your component by using:
var graduates = require('biojs-io-graduates');
graduates.parse("greenify:DE\ndaviddao:HK");
// should return {"DE": 1, "HK": 1}
We don’t need the file tests.js
for our further development as we will use
real unit tests.
If the path is relative like a ./lib/index.js
, you require
local files.
There is an excellent guide on how the require
command works under the hood.
5) The first testcase
Please add this very simple test to your component.
test/simple.js
var assert = require("chai").assert;
var tutorial = require("../");
describe('Graduates', function(){
describe('parse', function(){
it('should return match with default object', function(){
var dummyObj = {DE: 1, HK: 1, NL: 1, UK: 1, TW: 1};
assert.deepEqual(tutorial.read_static(), dummyObj);
});
});
});
Please remove the prefilled test file test/test_graduates.js
or replace it with
our test file.
You can execute your first test with:
npm test
It is really ok if you see errors - you will fix them later ;-) So as long as you see something similar to following output, you can safely continue.
Graduates
parse
1) should return match with default object
0 passing (9ms)
1 failing
1) Graduates parse should return match with default object:
AssertionError: expected {} to deeply equal { DE: 1, HK: 1, NL: 1, UK: 1, TW: 1 }
+ expected - actual
+{
+ "DE": 1
+ "HK": 1
+ "NL": 1
+ "TW": 1
+ "UK": 1
+}
-{}
at Function.assert.deepEqual (/home/greenify/biojs/packages/biojs-io-graduates/node_modules/chai/lib/chai/interface/assert.js:205:32)
at Context.<anonymous> (/home/greenify/biojs/packages/biojs-io-graduates/test/test_graduates.js:14:14)
at callFn (/home/greenify/biojs/packages/biojs-io-graduates/node_modules/mocha/lib/runnable.js:250:21)
at Test.Runnable.run (/home/greenify/biojs/packages/biojs-io-graduates/node_modules/mocha/lib/runnable.js:243:7)
at Runner.runTest (/home/greenify/biojs/packages/biojs-io-graduates/node_modules/mocha/lib/runner.js:373:10)
at /home/greenify/biojs/packages/biojs-io-graduates/node_modules/mocha/lib/runner.js:451:12
at next (/home/greenify/biojs/packages/biojs-io-graduates/node_modules/mocha/lib/runner.js:298:14)
at /home/greenify/biojs/packages/biojs-io-graduates/node_modules/mocha/lib/runner.js:308:7
at next (/home/greenify/biojs/packages/biojs-io-graduates/node_modules/mocha/lib/runner.js:246:23)
at Immediate._onImmediate (/home/greenify/biojs/packages/biojs-io-graduates/node_modules/mocha/lib/runner.js:275:5)
at processImmediate [as _immediateCallback] (timers.js:358:17)
npm ERR! Test failed. See above for more details.
In this tutorial we use Mocha as JavaScript test framework.
However you can use your favorite - you only need to change the test
command in the scripts
section of your package.json
.
If you are super lazy, you can install mocha
globally with npm install -g mocha
and then run mocha
as a single command.
There is even mocha --watch
that automatically reruns all tests on a file change.
6) Your first, big task
If you are new JavaScript or have not coded for a while, you might want to have a look at this cheatsheet.
Please fill in the missing code inside the graduate.parse()
function.
Every alias has a country and we are interested in the distribution, so aliases per country.
If you look closer at the unit test, you see that the valid solution for our static example is:
{DE: 1, HK: 1, NL: 1, UK: 1, TW: 1};
You can either rerun the tests with npm test
or use mocha --watch
if you installed mocha.
7) Verify your solution
No please do NOT have a look at our solution, if your unit test is green - your solution is correct! Please only continue if your solution is working.
Solution:
graduates.parse = function(data) {
// count countries
var parsed = {};
for (var i = 0; i < data.length; i++) {
// skip empty rows
if (data[i].trim().length === 0) {
continue;
}
var row = data[i].split(":");
// init if new
if (typeof parsed[row[1]] === "undefined") {
parsed[row[1]] = 0;
}
parsed[row[1]] ++;
}
return parsed;
};
And of course this is also possible as short “one-liner”.
var _ = require("lodash"); // you need to install lodash (npm install lodash --save)
graduates.parse = function(data) {
return _(data).map(function(e){return e.split(":")[1]}).countBy().value();
}
Congratulations! You wrote your very first Biojs 2 Component.
8) Extend the generic parser
We provide a small generic parser, that provides some common functionality like downloading files. First we need to install the generic component:
npm install biojs-io-parser --save
Then we can require it at the head of the lib/index.js
.
var parser = require("biojs-io-parser");
And finally we inherit the methods from the generic parser. Therefor add this call anywhere, but after the parser variables is defined.
parser.mixin(graduates);
Yes that it that easy to use existing code :)
But we are pretty sure that you want to test this too!
As our the online list might change we use nock
to mock a webserver.
npm install --save-dev nock
Then we mock our dummy file:
var nock = require('nock')
var testURL = 'http://an.url'
scope = nock(testURL)
.persist()
.get('/list')
.replyWithFile(200, __dirname + '/dummy.list');
and add a new test (be careful to add it inside the describe
method):
it('should work with live data', function(done){
tutorial.read(testURL + "/list", function(err, parsed){
// the dummy file contains exactly this obj
var dummyObj = {DE: 1, HK: 1, NL: 1, UK: 1, TW: 1};
assert.deepEqual(parsed, dummyObj);
done(); // you need to call the done callback to resume mocha
});
});
If you everything worked, running npm test
should still work and now you have
added the functionality of the generic biojs parser.
9) Add yourself to the graduate list
You worked hard - now it is time to acknowledgment. Please pick a fancy alias, lookup your country alpha-2 code and add yourself to the graduate list
If you are unfamiliar with git, check out the Git guide or 15 minutes interactive lesson by Codeschool.
If you can’t think of a fancy alias, pick either your github username or let software help you ;-)