KENSHO
var add = function (a, b) {
return a + b;
};
4 entities: a, b, add and a function
Each entity can interact with other 3
Kensho Node
var add = function (a, b) {
return a + b;
};
for N entities: N * (N - 1) interactions
Kensho Node
Kensho Node
Replace the boilerplate with equivalent short and readable code
Kensho Node
var path = require('path');
var first = path.join(__dirname, '../foo');
...
var second = path.join(__dirname, '../bar');
Kensho Node
var join = require('path').join;
var first = join(__dirname, '../foo');
...
var second = join(__dirname, '../bar');
Kensho Node
var relativePath = require('path')
.join.bind(null, __dirname);
var first = relativePath('../foo');
...
var second = relativePath('../bar');
Kensho Node
var first = path.join(__dirname, '../foo');
// vs
var second = relativePath('../bar');
Kensho Node
var relativePath = path.join.bind(null, __dirname);
relativePath('foo.js');
Kensho Node
function fn(a, b, c) { ... }
var newFn = fn.bind(null, valueA, valueB);
newFn(valueC);
Kensho Node
Place on the left arguments that are likely to be known first
function fn(a, b, c) { ... }
var newFn = fn.bind(null, valueA, valueB);
newFn(valueC);
Kensho Node
function updateUserInfo(userId, newInfo){ ... }
// vs
function updateUserInfo(newInfo, userId){ ... }
Kensho Node
// user-service.js
function updateUserInfo(userId, newInfo) { ... }
// user-controller.js
function onLogin(id) {
var updateUser = updateUserInfo.bind(null, id);
$('form').on('submit', function onSubmitted(form) {
updateUser(form);
});
}
Kensho Node
// user-service.js
function updateUserInfo(userId, newInfo) { ... }
// user-controller.js
function onLogin(id) {
var updateUser = updateUserInfo.bind(null, id);
$('form').on('submit', function onSubmitted(form) {
updateUser(form);
});
}
Kensho Node
// user-service.js
function updateUserInfo(userId, newInfo) { ... }
// user-controller.js
function onLogin(id) {
var updateUser = updateUserInfo.bind(null, id);
$('form').on('submit', updateUser);
}
Kensho Node
Kensho Node
function fn(a, b, c) { ... }
var newFn = fn.bind(null, valueA, valueB);
Kensho Node
// or
var _ = require('lodash');
var newFn = _.partial(fn, valueA, valueB);
// or
var R = require('ramda');
var newFn = R.partial(fn, valueA, valueB);
['1', '2', '3'].map(parseInt); // [1, NaN, NaN]
// function parseInt(x, radix)
// but Array.map sends (value, index, array)
['1', '2', '3'].map(function (x) {
return parseInt(x, 10);
});
['1', '2', '3'].map(_.partialRight(parseInt, 10));
// [1, 2, 3]
// radix is bound,
// index and array arguments are ignored
Kensho Node
// function parseInt(x, radix)
['1', '2', '3'].map(_.partial(parseInt, _, 10));
// [1, 2, 3]
// or
var S = require('spots');
['1', '2', '3'].map(S(parseInt, S, 10));
// [1, 2, 3]
Kensho Node
// Express
// same callbacks to check if the user is logged in and authorized
app.get('/repos',
passport.isAuthenticated, passport.isAuthorized, ctrl.getRepos);
app.get('/repos/:user/:name',
passport.isAuthenticated, passport.isAuthorized, ctrl.getRepo);
app.get('/repos/view/:user/:name',
passport.isAuthenticated, passport.isAuthorized, ctrl.viewFile);
app.get(<url>, passport.isAuthenticated, passport.isAuthorized, ...);
Kensho Node
// prefill 2 middle arguments using spots
var S = require('spots');
var authGet = S(app.get, S,
passport.isAuthenticated, passport.isAuthorized)
.bind(app);
// authGet(<url>, <controller>)
Kensho Node
authGet('/repos', ctrl.getRepos);
authGet('/repos/:user/:name', ctrl.getRepo);
authGet('/repos/view/:user/:name', ctrl.viewFile);
// divide by 10
function divide(a, b) { return a / b; }
var selective = require('heroin');
var by10 = selective(divide, { b: 10 });
console.log(by10(10)); // 1 (a = 10, b = 10)
console.log(by10(2)); // 0.2 (a = 2, b = 10)
Kensho Node
function fn(options) { ... }
var obind = require('obind');
var withBar = obind(fn, { bar: 'bar' });
withBar({ baz: 'baz' });
/*
equivalent to
foo({
bar: 'bar',
baz: 'baz'
})
*/
Kensho Node
var numbers = [3, 1, 7];
var constant = 2;
var k = 0;
for(k = 0; k < numbers.length; k += 1) {
console.log(numbers[k] * constant);
}
// 6 2 14
Kensho Node
function mul(a, b) {
return a * b;
}
function print(n) {
console.log(n);
}
numbers.map(function (n) {
return mul(n, constant);
}).forEach(print);
// 6 2 14
Kensho Node
function mul(a, b) {
return a * b;
}
var byK = mul.bind(null, constant);
var print = console.log.bind(console);
numbers
.map(byK)
.forEach(print);
Kensho Node
var numbers = [3, 1, 7];
var constant = 2;
function mul(a, b) {
return a * b;
}
var _ = require('lodash');
var byK = _.partial(mul, constant);
var print = _.bind(console.log, console);
_.forEach(_.map(numbers, byK), print);
Kensho Node
var mul = _.curry(function (a, b) {
return a * b;
});
var byK = mul(constant);
function mul(a, b) {
return a * b;
}
var byK = _.partial(mul, constant);
Curried functions have partial application built in.
Kensho Node
function cb(item, index, array) { ... }
// ES5 method
Array.prototype.map(cb);
// Lodash method
_.map(array, cb);
Place on the left arguments that are likely to be known first
Kensho Node
var R = require('ramda');
// callback is first argument
R.map(cb, array);
// all functions are curried
var by5 = R.multiply(5);
by5(10); // 50
Kensho Node
var numbers = [3, 1, 7];
var constant = 2;
var R = require('ramda');
var print = R.bind(console.log, console);
var multiplyAll = R.map(R.multiply(constant));
var printAll = R.forEach(print);
printAll(multiplyAll(numbers));
Kensho Node
var multiplyAll = R.map(R.multiply(constant));
var printAll = R.forEach(print);
printAll(multiplyAll(numbers));
Kensho Node
var multiplyAll = R.map(R.multiply(constant));
var printAll = R.forEach(print);
var computation = R.compose(printAll, multiplyAll);
computation (numbers);
Static logic
Dynamic data
Kensho Node
var mulPrint = R.pipe(
R.map(R.multiply(constant)),
R.tap(debugLog),
R.forEach(R.bind(console.log, console))
);
mulPrint (numbers);
R.pipe for readability
R.tap for debugging
Kensho Node
var glob = require('glob');
function getJavaScriptFiles(cb) {
glob('*.js', function (err, files) {
if (err) {
return cb(err);
}
cb(null, files);
});
}
getJavaScriptFiles(function (err, files) {
if (err) {
return console.error(err);
}
console.log(files);
});
Kensho Node
var getJavaScriptFiles = require('q')
.denodeify(require('glob'))
.bind(null, '*.js');
getJavaScriptFiles()
.then(console.log)
.catch(console.error)
.done();
Kensho Node
var Q = require('q');
function asyncF() {
var defer = Q.defer();
process.nextTick(function () {
defer.resolve('f');
});
return defer.promise;
}
function asyncAddOo(value) {
var defer = Q.defer();
process.nextTick(function () {
defer.resolve(value + 'oo');
});
return defer.promise;
}
function print(x) {
console.log('value =', x);
return x;
}
function verify(x) {
console.assert(x === 'foo');
}
asyncF()
.then(asyncAddOo)
.then(print)
.then(verify)
.done();
// "foo"
var Q = require('q');
function asyncAddOo(value) {
var defer = Q.defer();
process.nextTick(function () {
defer.resolve(value + 'oo');
});
return defer.promise;
}
function print(x) {
console.log('value =', x);
return x;
}
function verify(x) {
console.assert(x === 'foo');
}
Q('f')
.then(asyncAddOo)
.then(print)
.then(verify)
.done();
Kensho Node
var Q = require('q');
function addOo(value) {
return value + 'oo';
}
function print(x) {
console.log('value =', x);
return x;
}
function verify(x) {
console.assert(x === 'foo');
}
Q('f')
.then(addOo)
.then(print)
.then(verify)
.done();
Kensho Node
var Q = require('q');
var R = require('ramda');
function print(x) {
console.log('value =', x);
return x;
}
function verify(x) {
console.assert(x === 'foo');
}
Q('f')
// apply second arg
.then(R.add(R.__, 'oo'))
.then(print)
.then(verify)
.done();
Kensho Node
var Q = require('q');
var R = require('ramda');
function print(x) {
console.log('value =', x);
}
function verify(x) {
console.assert(x === 'foo');
}
Q('f')
// apply second arg
.then(R.add(R.__, 'oo'))
.then(R.tap(print))
.then(verify)
.done();
Kensho Node
var Q = require('q');
var R = require('ramda');
function print(x) {
console.log('value =', x);
}
function verify(x) {
console.assert(x === 'foo');
}
var printThenVerify = R.pipeP(
R.add(R.__, 'oo'),
R.tap(print),
verify
);
Q('f')
.then(printThenVerify);
Remove boilerplate while the code is still readable to you
Kensho Node
fs.readdirAsync('.')
.map(processFile, { concurrency: 3 })
.then(fileResults);
Kensho Node
QUnit.test('a test', function(assert) {
var done = assert.async();
asyncOperation()
.then(function () {
// assert something
done();
});
});
Kensho Node
// Mocha
it('works', function (done) {
asyncOperation()
.then(function () {
// assert something
done();
});
});
Kensho Node
// Mocha
it('works', function () {
return asyncOperation()
.then(function () {
// assert something
});
});
Kensho Node
// typical AngularJS unit test
describe('typical test', function () {
var $rootScope, foo;
beforeEach(function () {
angular.mock.module('A');
// other modules
});
beforeEach(inject(function (_$rootScope_, _foo_) {
$rootScope = _$rootScope_;
foo = _foo_;
}));
it('finally a test', function () {
$rootScope.$apply(); // for example
expect(foo).toEqual('bar');
});
});
Kensho Node
ngDescribe({
modules: 'A',
inject: ['$rootScope', 'foo'],
tests: function (deps) {
it('finally a test', function () {
deps.$rootScope.$apply();
expect(deps.foo).toEqual('bar');
});
});
});
Kensho Node
it('does something', function () {
...
expect(foo).toEqual('bar');
});
test "does something" failed
Error:
What has actually failed and why?
Kensho Node
it('does something', function () {
...
expect(foo).toEqual('bar',
'expected foo to equal "bar"');
});
test "does something" failed
Error: expected foo to equal "bar"
Why did it fail?
Kensho Node
it('does something', function () {
...
expect(foo).toEqual('bar',
'expected foo ' + foo + ' to equal "bar"');
});
test "does something" failed
Error: expected foo something to equal "bar"
Message repeats the predicate!
Kensho Node
it('does something', function () {
...
expect(foo).toEqual('bar',
'expected foo ' + JSON.stringify(foo) +
' to equal "bar"');
});
Kensho Node
// require('lazy-ass');
it('does something', function () {
la(foo === 'bar',
'expected foo', foo, 'to equal "bar"');
});
Kensho Node
var helpfulDescribe = require('lazy-ass-helpful');
helpfulDescribe(function tests() {
it('does something', function () {
la(foo === 'bar');
});
});
Kensho Node
var helpfulDescribe = require('lazy-ass-helpful');
helpfulDescribe(function tests() {
it('does something', function () {
la(foo === 'bar',
'condition [foo === "bar"], foo is', foo);
});
});
Executed code
Kensho Node
// need all arguments after "y"
function f(x, y) {
var a = Array.prototype.slice.call(arguments, 2);
...
};
// using lodash
function f(x, y) {
// need all arguments after "y"
var a = _.toArray(arguments).slice(2);
...
};
// using ES6 rest parameter
function f(x, y, ...a) {
// a is an array of arguments after "y"
...
};
Kensho Node
function f (x, y, z) {
if (y === undefined)
y = 7;
if (z === undefined)
z = 42;
return x + y + z;
};
// es6
function f (x, y = 7, z = 42) {
return x + y + z
}
Kensho Node
var foo = '...';
var o = {};
o[foo] = 42;
// es6
var foo = '...';
var o = {
[foo]: 42
}
Kensho Node
numbers.map(function (v) { return v + 1; });
// es6
numbers.map(v => v + 1);
// I prefer
var R = require('ramda');
var add1 = R.add(1);
numbers.map(add1);
Kensho Node
Kensho Node