A clean way to test rejected promise

To test the the exception in a rejected promise could be a little bit painful.

And Mocha is Promise-friendly, which means it fails the test if exception is not caught.

So as a result, here is a simple code example to explain how it is being done:

1
2
3
4
5
6
7
8
9
it 'should throw session-expired exception'
new Session().generateId().bindUserFromRedis()
.then ->
null
.catch (ex) ->
ex
.then (ex) ->
expect(ex).to.be.instanceof(ResponseError)
.and.that.have.property('errorName', 'session-expired')

Update: A Chai Plugin can mitigate the pain

1
2
3
4
5
it('should throw session-expired exception', () => {
return expect(new Session().generateId().bindUserFromRedis())
.to.evetually.rejected
.and.that.have.property('errorName', 'session-expired')
})

Update 2: With async, it can be converted into normal test

1
2
3
4
5
it('should throw session-expired exception', () => {
return expect(async () => await new Session().generateId().bindUserFromRedis())
.to.throw
.and.that.have.property('errorName', 'session-expired')
})

JavaScript Prototype Chain Mutator

In JavaScript world, JSON serialization is widely used. When fetching data from server via Ajax, the data is usually represented in JSON; or loading configuration/data from file in Node.js application, the configuration/data is usually in JSON format.

JSON serialization is powerful and convenient, but there is limitation. For security and other reason, behavior and type information are forbidden in JSON. Functions members are removed when stringify a JavaScript object, also functions are not allowed in JSON.

Comparing Yaml to Ruby, this limitation isn’t that convenient when writing JavaScript application. For example, to consume the JSON data fetched via ajax from server, I really wish I can invoke some method on the deserialized model.

Here is simple example:

Ideal World
1
2
3
4
5
6
7
8
9
10
11
12
13
class Rect
constructor: (width, height) ->
@width = width if width?
@height = height if height?
area: ->
@width * @height
$.get '/rect/latest', (rectJSON) ->
rect = JSON.parse(rectJSON)
console.log rect.area() # This code doesn't work because there is rect is a plain object

The code doesn’t work, because rect in a plain object, which doesn’t contains any behavior. Someone called the rect DTO, Data Transfer Object, or POJO, Plain Old Java Object, a concept borrowed from Java world. Here we call it DTO.

To add behaviors to DTO, there are variant approaches. Such as create a behavior wrapper around the DTO, or create a new model with behavior and copy all the data from DTO to model. These practices are borrowed from Java world, or traditional Object Oriented world.

In fact, in JavaScript, there could be a better and smarter way to achieve that: Object Mutation, altering object prototype chain on the fly to convert a object into the instance of a specific type. The process is really similar to biologic genetic mutation, converting a species into another by altering the gene, so I borrow the term mutation.

With the idea, we can achieve this:

Mutate rect with Mutator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Rect
constructor: (width, height) ->
@width = width if width?
@height = height if height?
area: ->
@width * @height
$.get '/rect/latest', (rectJSON) ->
rect = JSON.parse(rectJSON)
mutate(rect, Rect)
console.log rect.area()

The key to implement mutate function is to simulate new operator behavior, alerting object.__proto__ and apply constructor to the instance! For more detail, check out the library mutator Bower version NPM version, which is available as both NPM package and bower package.

When implementing the mutator, in IE, again, in the evil IE, the idea doesn’t work. Before IE 11, JavaScript prototype chain for instance is not accessible. There is nothing equivalent to object.__proto__ in IE 10 and prior. The most similar workaround is doing a hard-copy of all the members, but it still fails in type check and some dynamical usage.

Background

object.__proto__ is a Mozilla “private” implementation until EcmaScript 6.
It is interesting that most JavaScript support it except IE.
Luckily, IE 11 introduced some features in EcmaScript 6, object.__proto__ is one of them.

Upgrading DSL From CoffeeScript to JSON: Part.2. Redefine DSL behavior

This is the second post in this series, previous one discussed the JSON schema migration mechanism.

After finish JSON DSL implementation, the No.1 problem I need to handle is how to upgrading the configuration in CoffeeScript to JSON format.

One of the solutions is to do it manually. Well, it is possible, but… JSON isn’t a language really designed for human, composing configuration for 50+ sites doesn’t sound like a pleasant work for me. Even when I finished it, how can I ensure all the configuration is properly upgraded? The sun is bright today, I don’t want to waste whole afternoon in front of the computer checking the JSON. In one word, I’m lazy…

Since most of the change of DSL is happened on representation instead of structure. So in most cases, there is 1-to-1 mapping between v1 DSL and v2 DSL. So maybe I can generate the most of v2 DSL by using V1 DSL! Then manually handle some exceptions.

Here is a snippet of V1 DSL

Ver 1 DSL snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
AdKiller.run ->
@host 'imagetwist.com', ->
@clean('#myad', '#popupOverlay')
@revealImg('.pic')
@host 'yankoimages.net', ->
@clean('#firopage')
@revealImg('img')
@host 'imageback.info', 'imagepong.info', 'imgking.us', 'imgabc.us', ->
@revealA('.text_align_center a')
@host 'imgserve.net',
'imgcloud.co',
'hosterbin.com',
'myhotimage.org',
'img-zone.com',
'imgtube.net',
'pixup.us',
'imgcandy.net',
'croftimage.com',
'www.imagefolks.com',
'imgcloud.co',
'imgmoney.com',
'imagepicsa.com',
'imagecorn.com',
'imgcorn.com',
"imgboo.me",
'imgrim.com',
'imgdig.com',
'imgnext.com',
'hosturimage.com',
'image-gallery.us',
'imgmaster.net',
'img.spicyzilla.com',
'bulkimg.info',
'pic.apollon-fervor.com',
'08lkk.com',
'damimage.com',
->
@click('#continuetoimage input')
@clean('#logo')
@safeRevealImg('#container img[class]')

In version 1 implementation, @host defines the sites. And in the block of @host method, @click, @clean, @revealImg methods define the actions for the sites. The @host method instantiate new instance of Cleaner. The code block is invoked when cleaner is triggered, which does the actually cleaning.

Now I want to keep this file, since it shares the configuration between version 1 and version 2. And I redefine the behaviors of the cleaning method, such as @clean, @click, etc., I generate the JSON data when it is invoked instead of really altering the DOM. So I got this:

seed_data_generator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env coffee
fs = require('fs')
AdKiller =
run: (block) ->
@scripts = {}
@hosts = {}
block.call(this)
fs.writeFileSync 'seed_data.json', JSON.stringify({version: 1, @hosts, @scripts})
host: (hosts..., block) ->
@currentScript = []
scriptId = hosts[0]
@scripts[scriptId] = @currentScript
for host in hosts
@hosts[host] = scriptId
block.call(this)
remove: (selectors...) ->
selectors.unshift 'remove'
@currentScript.push selectors
clean: (selectors...) -> # Backward compatibility
selectors.unshift 'remove'
@currentScript.push selectors
hide: (selectors...) ->
selectors.unshift 'clean'
@currentScript.push selectors
click: (selector) ->
@currentScript.push ['click', selector]
revealA: (selector) ->
@currentScript.push ['revealA', selector]
revealImg: (selector) ->
@currentScript.push ['revealImg', selector]
safeRevealA: (selector) ->
@currentScript.push ['safeRevealA', selector]
safeRevealImg: (selector) ->
@currentScript.push ['safeRevealImg', selector]
AdKiller.run ->
@host 'imagetwist.com', ->
@clean('#myad', '#popupOverlay')
@revealImg('.pic')
# ...

So now I can easily invoking this piece of code, to convert verion 1 DSL to JSON format.

DSL behavior redefinition is a super powerful trick, we used it on JSON parsing, validation, and generation before on PlayUp project. Which saved us tons of time from writing boring code.

Upgrading DSL from CoffeeScript to JSON: Part.1. Migrator

I’m working on the Harvester-AdKiller version 2 recently. Version 2 dropped the idea “Code as Configuration”, because the nature of Chrome Extension. Recompiling and reloading the extension every time when configuration changed is the pain in the ass for me as an user.

For security reason, Chrome Extension disabled all the Javascript runtime evaluation features, such as eval or new Function('code'). So that it become almost impossible to edit code as data, and later applied it on the fly.

Thanks to the version 1, the feature and DSL has almost fully settled, little updates needed in the near future. So I can use a less flexible language as the DSL instead of CoffeeScript.

Finally I decided to replace CoffeeScript to JSON, which can be easily edited and applied on the fly.

After introducing JSON DSL, to enable DSL upgrading in the future, an migration system become important and urgent. (Actually, this prediction is so solid. I have changed the JSON schema once today.) So I come up a new migration system:

Upgrader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Upgrader
constructor: ->
@execute()
execute: =>
console.log "[Upgrader] Current Version: #{Configuration.version}"
migrationName = "#{Configuration.version}"
migration = this[migrationName]
unless migration?
console.log '[Upgrader] Latest version, no migration needed.'
return
console.log "[Upgrader] Migration needed..."
migration.call(this, @execute)
'undefined': (done) ->
console.log "[Upgrader] Load data from seed..."
Configuration.resetDataFromSeed(done)
'1.0': (done) ->
console.log "[Upgrader] Migrating configuration schema from 1.0 to 1.1..."
# Do the migration logic here
done()

The Upgrader will be instantiate when extension started, after Configuration is initialized, which holds the DSL data for runtime usage.

When the execute method is invoked, it check the current version, and check is there a upgrading method match to this version. If yes, it triggers the migration; otherwise it succeed the migration. Each time a migration process is completed, it re-trigger execute method for another round of check.

Adding migration for a specific version of schema is quite simple. Just as method 1.0 does, declaring a method with the version number in the Upgrader.

'undefined' method is a special migration method, which is invoked there is no previous configuration found. So I initialize the configuration from seed data json file, which is generated from the version 1 DSL.

The seed data generation is also an interesting topic. Please refer to next post(Redfine DSL behavior) of this series for details.

Some tricky ways to calculate integer in javascript

Javascript is famous for its lack of preciseness, so it always surprises and make joke with the developers by breaking the common sense or instinct.

Javascript doesn’t provide integer type, but in daily life, integer sometimes is necessary, then how can we convert a trim a float number into integer in Javascript?
Some very common answers might be Math.floor, Math.round or even parseInt. But besides calling Math functions, is there any other answer?

The answer is bitwise operations. Amazing? Yes. Because bitwise operations are usually only applied to integers, so Javascript will try to convert the number into "integer" internally when a bitwise operation is applied, even it is still represented in type of number

Suppose value = 3.1415926, and we want integer is the trimmed value of value, then we can have:

Trim Float Number
1
2
3
4
5
6
7
8
9
10
11
12
var value = 3.1415926;
var integer = Math.floor(value);
integer = Math.round(value);
integer = parseInt(value);
integer = ~~value; // Bitwise NOT
integer = value | 0; // Bitwise OR
integer = value << 0; // Left Shift
integer = value >> 0; // Sign-propagating Right Shift
integer = value >>> 0; // Zero-fill Right Shift

For more detail information about bitwise operation in javascript, please check out the MDN document

All approaches listed before are working, but with different performance. And according to the result from JsPerf, I sort the algorithms by performance from good to bad:

  1. integer = ~~value;
  2. integer = value >>> 0; and integer = value << 0;
  3. integer = Math.floor(value);
  4. integer = value >> 0;
  5. integer = value | 0;
  6. integer = Math.round(value);
  7. integer = parseInt(value);

NOTE: The test cases are running in Chrome 24.0.1312.57 on Mac OS X 10.8.2

Negative Index in Coffee-Script

Coffee Script borrowed quite a lot syntax patterns from both Ruby and Python, especially from Ruby.
So people, like me, usually tends to write coffee-script in ruby way.

In ruby, we can retrieve the element in an array in reversed order by using a negative index, which means array[-1] returns the last element in the array. This grammar sugar is really convenient and powerful, so we can omit the code like this array[array.length - 1].

But for some reason, coffee-script doesn’t inherit this syntax. To me, it is weird. But after analyze this problem in detail, I found the reason.
Coffee script announce it has a golden rule: “coffee-script is just javascript”. So all the coffee script must be able to compiled into javascript.

Let’s try to analyze how the coffee script is compiled into javascript:

Coffee Script
1
2
3
array = [1..10]
second = array[1]
last = array[-1] // Psudocode

Obviously, the previous code should be compiled as following:

JavaScript
1
2
3
4
var array, last, second;
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
second = array[1];
last = array[array.length - 1];

The negative index should be processed specially, so we should check the index is negative or not while compiling. This translation seems easy but actually not, since we can and usually use variable as the index.

Variable as index
1
2
3
4
5
array = [1..10]
index = 1
second = array[index]
index = -index
last = array[index]

In the previous code, because we use the variable as index, which cannot be verified in compile-time, which means we need to compile the array reference code as following:

Compile Result
1
2
3
4
5
6
var array, index, last, second;
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
index = 1;
second = index >=0 ? array[index] : array[array.length + index];
index = -index;
last = index >=0 ? array[index] : array[array.length + index];

So every time we reference the array, we need to check whether the index is negative or not. This approach absolutely hurts the performance a lot, which in basically unacceptable.
So that’s why coffee-script doesn’t support the negative index.

Space Pitfall in coffee-script

Coffee Script had fixed quite a lot of pitfalls in Javascript. But on another hand it also introduced some other pitfalls, the most common one is the space.

Space in function declaration

Read the following code:

Show Message:Coffee
1
2
3
4
show = message ->
console.log message
show "space pitfall"

This is a quite simple script, but it failed to run. And if you might also feel confused about the error message: “message is not defined”

What happened to the code? We indeed had declared the message as argument of function show. To reveal the answer, we should analyze the compiled javascript.
Here is the compiled code:

Show Message:JS
1
2
3
4
5
6
7
8
// Generated by CoffeeScript 1.3.1
var show;
show = message(function() {
return console.log(message);
});
showe("space pitfall");

Look the fun declaration, you will see it is not a function declaration as we want but a function call.
The reason is that we omitted the parentheses around the argument and we add a new space between message and ->. So the coffee-script compiler interpret message as a function call with a function as parameter.

Soltuion
To fix this problem, we can remove the space between message and -> to enforce coffee-script compiler interpret them as a whole.

Show Message:Fix
1
2
3
4
show = message->
console.log message
show "space pitfall"

Best Practise
To avoid this pitfall, my suggestion is never omit the parentheses around the arguments, even there is only one argument.
And also including the function call, even coffee-script allow to omit the parentheses. Since you won’t able to chain the method call if you omit the parentheses.
So never omit parentheses, unless you are very certain that there is no any ambiguity and you won’t use method chain.

The space in array index

Since coffee script doesn’t support the negative index. So we should use following code as negative index:

Last Hero:Coffee
1
2
3
heros = ["Egeal Eye", "XMen", "American Captain", "IronMan"]
lastHero = heros[heros -1]
console.log lastHero

This piece of code is also failed to run, and the error message is “property of object is not a function”.
Quite wield right?
Let’s see what is behind the scene, here is the compiled code:

Last Hero:JS
1
2
3
4
5
6
7
8
// Generated by CoffeeScript 1.3.1
var heros, lastHero;
heros = ["Egeal Eyr", "XMen", "American Captain", "IronMan"];
lastHero = heros[heros.length(-1)];
console.log(lastHero);

Same problem, heros.length -1 is interpreted as heros.length(-1) instead of heros.length -1.
To fix this problem, we should write the code in following way:

Last Hero:Fix1
1
2
3
heros = ["Egeal Eye", "XMen", "American Captain", "IronMan"]
lastHero = heros[heros - 1]
console.log lastHero

Or

Last Hero:Fix2
1
2
3
heros = ["Egeal Eye", "XMen", "American Captain", "IronMan"]
lastHero = heros[heros-1]
console.log lastHero

Both solution is try to enforce the compiler divid the component in correct way.

And unfortunately, there is no way to avoid this problem, the only thing you can do is always be aware the spaces in expression.

Enhanced typeof() operator in JavaScript

Javascript is weakly typed, and its type system always behaves different than your expectation.
Javascript provide typeof operator to test the type of a variable. it works fine generally. e.g.

typeof default behaviors
1
2
3
4
5
6
typeof(1) === 'number'
typeof('hello') === 'string'
typeof({}) === 'object'
typeof(function(){}) === 'function'

But it is not enough, it behaves stupid when you dealing with objects created by constructors. e.g.
if you expected

Expected typeof behavior against object
1
typeof(new Date('2012-12-12')) === 'date' // Returns false

Then you must be disappointed, since actually
Actual typeof behavior against object
1
typeof(new Date('2012-12-12')) === 'object' // Returns true

Yes, when you apply typeof() operator on any objects, it just yield the general type “object” rather than the more meaningful type “date”.

How can we make the typeof() operator works in the way as we expected?
As we know when we create a object, the special property of the object constructor will be set to the function that create the object. which means:

Get constructor property of object
1
(new Date('2012-1-1')).constructor // Returns [Function Date]

So ideally we can retrieve the name of the function as the type of the variable. And to be compatible with javascript’s native operator, we need to convert the name to lower case. So we got this expression:

Simulate typeof operator behavior with constructor property
1
2
3
4
5
function typeOf(obj) { // Use capital O to differentiate this function from typeof operator
return obj ? obj.constructor.name.toLowerCase() : typeof(obj);
}
typeOf(new Date('2012-1-1')) === 'date' // Returns true

And luckily, we can also apply this to other primitive types, e.g:

Apply typeOf to primitive types
1
2
3
typeOf(123) === 'number'; // Returns true
typeOf('hello') === 'string'; // Returns true
typeOf(function(){}) === 'function'; // Returns true

or even

Apply typeOf to anonymous object
1
typeOf({}) === 'object'; // Returns true

So in general, we use this expression as new implementation of the typeof() operator! EXCEPT One case!

If someone declare the object constructor in this way, our new typeof() implementation will work improperly!

Closure encapsulated anonymous constructor
1
2
3
4
5
var SomeClass = (function() {
return function() {
this.someProperty='some value';
}
})();

or even define the constructor like this

Anonymous Closure
1
2
3
var SomeClass = function() {
this.someProperty = 'some value';
}

And we will find that

Apply typeOf to object instantiated by anonymous constructor
1
typeOf(new SomeClass) === ''; // Returns true

the reason behind this is because the real constructor of the SomeClass is actually an anonymous function, whose name is not set.

To solve this problem, we need to declare the name of the constructor:

Closure encapsulated named constructor
1
2
3
4
5
var SomeClass = (function() {
return function SomeClass() {
this.someProperty='some value';
}
})();

or even define the constructor like this

Named constructor
1
2
3
var SomeClass = function SomeClass() {
this.someProperty = 'some value';
}