Hemanth.HM

A Computer Polyglot, CLI + WEB ♥'r.

String.prototype.replace You Might Have Missed!

| Comments

If you ask for an example of String.prototype.replace in JavaScript, the most common response would be:

1
2
var str = 'foobar';
var replaced = str.replace('bar', 'baz');

or

1
2
var str = 'The quick brown fox had a great Xmas';
var replace = str.replace(/Xmas/i, 'Christmas!');

So it's mostly about seach and replace feature that most (P.S: By most of them I mean those I have come across on IRC.) of them wouldn talk about but would have not noticed that the signature of the replace method is like:

1
replace(regexp|substr, newSubStr|function[, flags])

From the signature, the focus of this post will be on the function in the params, this will be invoked to create the new substring and receives the below parameters:

  • match: The matched substring.

  • p1,p2..pn: The nth parenthesized submatch string.

  • offset: The offset of the matched substring.

  • string: The entire string which is being processed.

Let us see few example application of the same:

A simple example of increasing your protein and fat intake ;)

1
2
3
> function replacer(match) { return 2 * match }
> '10 gms of protein and 5gms of fat.'.replace(/[0-9]+/g, replacer)
> '20gms of protein and 10gms of fat.'

The below snippet replaces a Fahrenheit degree with its equivalent Celsius degree, for an input 212F, the function returns 100C, nothing big about this, but if you notice that the replace function's second agrument is a function convert which receives the parameters specified in the table above and returns a string.

1
2
3
4
5
6
7
8
9
10
// from mdn

function f2c(temprature) {
  function convert(match, p1, offset, string) {
    return ((p1 - 32) * 5/9) + 'C';
  }
  var s = String(temprature);
  var test = /(-?\d+(?:\.\d*)?)F\b/g;
  return s.replace(test, convert);
}

This feature would be more useful when you are doing a replace operation over a loop, using a replacer function like this one could totally avoid a loop.

Say, the input is an string that looks like:

1
let str = '___.___.___.__._...__';

Where __. is a high singal and __. is a low singal and rest of them are noise, you can filter them easily with an explicity loop using the replacer function like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let str = '___.___.___.__._...__';
let res = [];
str.replace(/(___.)|(__.)/g, function(match, p1, p2) {
  if (p1) { res.push({ high: true, length: p1.length }); }
  if (p2) { res.push({ high: false, length: 1 }); }
});

console.log(res);

/*
[ { high: true, length: 4 },
  { high: true, length: 4 },
  { high: true, length: 4 },
  { high: false, length: 1 } ]
*/

Well, it has been a decent amount of time since I wrote amount some fundamentals of JavaScript, hope this was useful for you, feel free to share few of your experince with replacer functions.

365 Days of Github

| Comments

Today my github streak looks like below, well this should have happened 210 days before if I were to have a good internet connection on my vacation in the Andamans.

I have open sourced about 474 projects so far (i.e is from 2008), some are tiny and some are decently large.

I have been part of larger of projects like yeoman koajs git-extars and other orgs as well.

I don't have the exact count of humans who have crossed the 365 days mark, but I have come across couple of dozens who have and each of them would have their own experiences, given the geo location and the projects they have worked on.

Let me start with related FAQs and few picks from my AMA and then will try to share my learning from it.

What is the graph all about?

A profile contributions graph is a record of contributions you've made to GitHub repositories.

That includes:

  • Issues and pull requests opened within the last year on a standalone repository.

  • All the commits made within the last year.

  • Contributions to Private repos are not visible to all. (Just a caution)

Can we cheat here?

Yes, a bot could help you to fake a streak but it's even more easier to find if it's faked or it's a genuine effort.

How do you get time to commit?

Well, to be very frank I am not very good at managing time, but it's more of a habit. Related AMA#21

How did it all start?

Well, I have been lurking around in Github from Jul 25, 2008, I was contributing to Ubuntu from 2005ish over launchpad, my first major contribution was for diaspora and later on yeoman

I manage my side projects by collaborating with humans! (:

Related AMA#11 and AMA#4

What do you get from this?

Nothing, but the below feeling!

Learnings:

  • Don't over burn yourself!

  • Don't get anxious it's just a streak.

  • Start as many as projects/orgs you can, collaborate with humans and contribute more!

  • It took about 180 days for this to become a part of life.

  • Make new mistakes, make them in public out and loud, that is one of the finest ways to learn.

  • Accept negative criticism with a smile.

  • Accept and work on all the positive criticism.

  • Ask people about their thoughts on IRC, Social Media et.al

  • Pause and reflect at times.

  • Make a public list of TODO items, so that people will help you with it and you will be cautious about them.

  • Make sure your projects have good readme!

  • Make meta repos for ideating if needed.

  • Invite friends to collaborate, get people started with FOSS.

  • Names of the repos matter a lot! Specially if it's a node module, ruby gems or similar.

  • Don't wait for permission of others to send a PR or start an org.

  • Don't get addicted! (Trying not to ;) )

  • Thank people who helped you, out loud.

  • Sometimes whatever you do need not be a success story, it's not meant to be as well, do it for the fun of it!

  • Pickup new stuff now and then, experiment a lot!

  • Never stop! Getting burnt in this is very common, have seen great minds getting tired at this and have stopped contributing :(

Well, this is all I can think of for now, I am sure I would have missed many points here, will update as and when I get more learning from this habit.

Are You Async Yet?

| Comments

Previsouly I had written a post on intro to ES7/ES2016 async-await in this post I shall take a simple example which shall demonstarte ways to reach to a callbackless code.

Getting a random comic with xkcd-imgs module.

var xkcd = require('xkcd-imgs'); xkcd.img(function(err, res){ if(!err) { console.log(res); } });

Same code with async-await

var promisify = require('es6-promisify'); var xkcd = promisify(require('xkcd-imgs').img); console.log(await xkcd());

Let us consider more generic example of fetching some data from an URL. (Internals of xkcd-imgs module)

var request = require('request'); request('http://xkcd-imgs.herokuapp.com/', function (error, response, body) { if (!error && response.statusCode == 200) { console.log(body); } });
var result = JSON.parse(await require("request-promise")('http://xkcd-imgs.herokuapp.com/')); console.log(result);

Or you could use the fetch API

var fetch = require('node-fetch'); await (await fetch('http://xkcd-imgs.herokuapp.com/')).json();

Indeed there babeljs to take care of async-await compilation for you!

So dive in and enjoy async programming in JavaScript without callbacks ;)

Recursive Map, Reduce and Filter in Javascript

| Comments

Here is a more functional way of map, reduce and filter functions in javascript:

map:

1
2
let map = (fn,list) => !list.length ? []:
  [fn(list[0])].concat(map(fn,list.slice(1)));
1
map(x=>x+1,[1,2,3,4)) // => [2,3,4,5]

reduce:

1
2
let reduce = (fn, value, list) => (!list.length) ? value :
  reduce(fn, fn(value,list[0]),list.slice(1));
1
reduce((x,y)=>x+y,0,[1,2,3,4]); // => 10

filter:

1
2
3
let filter = (predicate,list) => !list.length ? []:
  (predicate(list[0]) ?
    [list[0]] : []).concat(filter(predicate,list.slice(1)));
1
filter(x=>x>2,[1,2,3,4,5]); // => [3,4,5]

Do let me know if you are aware of better way to do the same ;)

Authoring Node Modules

| Comments

So far I have authored/contributed around 200+ modules on npm and they get around 1.5M downloads per month, which is a decent figure; as a part of this I have learnt a few things and I would like to share the same in this post.

Todo before writing a module:

  • Search npm and look for an already existing module that solves your issue: you could do a npm search <module> or search from the site

  • If you find one such good module, do read its code and see if you can improve something, it might be performance, logic or test fixes.

  • If you find a module and it does not do exactly what you are looking for, then send a PR with the changes you wish.

Writing a neat package:

  • If you are one of those smart lazy devs, you might want to use generator-node. If that is too heavy for you then checkout generator-nm

  • If you do not want generators you can stick with npm init and create the required dir structure manually.

  • Make sure your package.json is valid, maybe you would need package-json-validator

  • If you are new to npm you can use validate-npm-package-name to check if your package name is a valid npm package name.

  • It would be good if you make sure that your package.json has a files attribute which in turn has a main attribute in it.

  • Make sure you have test cases in place and also integrate it with continuous build service, like travis.

  • Use badges like: nodei, david et.al

  • Make sure your README.md looks good, as it has info about how to install your module, what it does, API docs and a gif, logo is a plus.

  • Take care while releasing package, using tools like release-it

Getting to the top:

There are many ways to showcase your module so that people will find it and hopefully use it but here are a few good ways to create a useful package:

  • Dig into GitHub and find a few trending projects, read the source, find code that can be extracted into a module, make a module and send a PR with it, most of time it gets accepted as modularity always wins.

  • Dig into the most dependent modules of node and repeat the above steps.

  • If the above did not work in your favour, make your own light weight module that just does a small part of the larger module.

P.S: It's not just about getting to the top, rather it's about doing one thing and doing it the best way.

Further reading:

P.S: Thanks to @nihar108 for typo and grammar fixes.

ES7 Async Await

| Comments

async/await of ES7 is one my fav proposals, that would for sure change the way we handle asynchronous code in javascript!

Let see it's application with few examples:

Promise sample:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let p1 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => { resolve('Promises 1 '); }, 30);
  });
}

let p2 = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => { resolve('Promise 2'); }, 10);
  });
}

async function getVal() {
  var res1 = await p1();
  var res2 = await p2();
  return res1 + res2;
}

(async function() {
  var res = await getVal();
  console.log(res); // Promise 1 Promise 2
}());

FS stuff:

1
2
3
4
5
var lieFS = require('lie-fs'); // Promisifed FS.
(async function() {
  var list = await fs.readdir('~/');
  console.log(list);
}());

Chain animation [From the spec]:

1
2
3
4
5
6
7
8
9
async function chainAnimationsAsync(elem, animations) {
  var ret = null;
  try {
    for (let anim in animations) {
      ret = await anim(elem);
    }
  } catch(e) { /* ignore and keep going */ }
  return ret;
}

async await fetch!

1
let data = await (await fetch(url)).json()

Do let me know if you have your own set, until then happy async/await!

Create a Nodeschool Workshop

| Comments

Today happens to be the international nodeschool day and hence this post!

There are many ways of creating a nodeschool workshop, in this post I shall walk you through the steps of creating a workshop using a module /me authored named adventure-runner

First up install the module: npm install --save adventure-runner

All you need in your workshop root:

  • runner.js: The brain of the workshop.

  • problems dir: Where all your problems are located.

  • package.json: Like any other module.

runner.js would be like:

1
2
3
var runner = require('adventure-runner');

runner('example-adventure',[ 'dinosaurs', 'robots', 'wowsers' ]);

or

1
2
3
var runner = require('adventure-runner');

runner('example-adventure','./problems');

P.S: Use the first variant if the order of the problems are important.

The problems dir will have sub dirs of problem in it, in our example the diansaurs dir must have a index.js in that, which would:

  • Exports problem statement with exports.problem

  • Exports verify function exports.verify = function(args, cb) where args would be the args passed from the CLI to verify and cb would decide if the solution to the problem was proper or not.

Let's create a simple nodeschool adventure, called adventure-math:

Basic dir setup:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Create a dir named adventure-math and cd into it.
mkdir adventure-math && cd $_

# Create a empty package.json and install the deps.
echo {} > package.json
npm install adventure-runner

# Create a `runner.js`
touch runner.js

# Create a problems dir and cd into it
(
  mkdir problems && cd $_

  # Create a addition problem dir with index.js in it.
  mkdir addition
  touch addition/index.js
)

Write some code:

Fill the runner.js with the style you intent to use.

1
2
3
var runner = require('adventure-runner');

runner('math-adventure','./problems');

Fill the problems/index.js with the problem.

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
var pwd = require('process').cwd();

// Problem def, quick tip use ES6 template strings.
exports.problem = 'Write a program that adds two given numbers: \n\n' +

  '* Create a file `add.js` which returns the sum of two numbers\n\n' +

  '* Don\'t forget to export you function. module.exports = function() {}`);\n\n' +

  'Finally to verify do a `math-adventure verify add.js`\n\n';

// Verifier
exports.verify = function(args,cb) {

  // Propose solution
  var proposed = require(pwd + '/' + args[0]);

  // Check if the solution is correct.

  if ( proposed(3,4) == 7 ) {
    console.log("You have solved it!");
    return cb(true);
  } else {
    console.log("Sorry, your solution is wrong :(");
  }
};

Mention the bin property in your package.json along with other fields, so that it looks something like below [Even better if you had used npm init ;)] :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
  "name": "adventure-math",
  "version": "0.0.0",
  "description": "Learn your math!",
  "bin": {
    "adventure-math": "runner.js"
  },
  "author": "Hemanth.HM <[email protected]>",
  "license": "MIT",
  "keywords": [
    "nodeschool",
    "adventure",
    "education",
    "math",
    "fun"
  ],
  "dependencies": {
    "adventure-runner": "^2.0.0"
  }
}

Final steps:

npm link to link the binary and now you must see something like below on executing adventure-math on your CLI.

nodeschool-sample.png

The user is expected to write the solution and verify it for themselves ;)

Hope you liked the post, feel free to modify the flow as per your need.

For the lazy ones here are few links:

That's it for now, happy node-schooling! :)

Currying in ES6

| Comments

As a ritual, let us start with an image of hot curry! :

Indiandishes by kspoddar

Breaking down a function that receives multiple arguments into a series of functions that receives part of the arguments is termed as currying a function.

Moses Schönfinkel introduced it and later was implemented by Haskell Curry, hence it's famous as curry.

Say we have a function : f::(x, y) -> z when curried we get curry(f) :: x -> y -> z.

In ES6 with the help of arrow functions and spread operators we can implement curry like:

1
let curry1 = f => (a) => f(a);
1
let curry2 = f => (...a) => (...b) => f(...a, ...b);
1
let curry3 = f => (...a) => (...b) => (...c) => f(...a, ...b, ...c);
1
let curry4 = f => (...a) => (...b) => (...c) => (...d) => f(...a, ...b, ...c, ...d);

Well, now you might be thinking of curryN or nCurry which would be like:

1
2
3
4
5
6
7
8
9
10
11
12
let nCurry = n =>
  (f, ...args) =>  {
        return function(...nargs) {
            let combinedArgs = args.concat(nargs);
            if (combinedArgs.length < n) {
              combinedArgs.unshift(f);
              return _curry.apply(null, largs);
            } else {
              return f.apply(null, largs);
            }
        };
  };

And can be used like:

1
2
3
4
5
6
7
8
nCurry(n)(f);

/*
Example:

nucrry(6)(fn); // Would give the curried version of `fn` that takes 6 args.

*/

Simpler example:

1
2
3
4
5
6
7
function listify(a,b,c,d) {
  return [a,b,c,d];
}

var listifyCurry = ncurry(4)(listify);

console.log(listifyCurry(1)(2)(3)(4)); [1,2,3,4]

Hope you enjoyed your curry! ;)

ES7 Features

| Comments

ECMAScript 7 is the next evolution of the ECMA-262 standard, this is at a very early stage, you may want to checkout paws-on-es6 as well.

Exponentiation Operator

Performs exponential calculation on operands. Same algorithm as js Math.pow(x, y)

1
2
3
let cubed = x => x ** 3;

cubed(2) // 8;

Array comprehensions

Declarative form for creating computed arrays with a literal syntax that reads naturally.

1
2
3
4
5
6
7
8
9
10
let numbers = [ 1, 4, 9 ];

[for (num of numbers) Math.sqrt(num)];
// => [ 1, 2, 3 ]

[for (x of [ 1, 2, 3]) for (y of [ 3, 2, 1 ]) x*y];
// => [ 3, 2, 1, 6, 4, 2, 9, 6, 3 ]

[for (x of [ 1, 2, 3, 4, 5, 6 ]) if (x%2 === 0) x];
// => [ 2, 4, 6 ]

Generator comprehensions

Create a generator function based on an existing iterable object.

1
2
(for (i of [ 2, 4, 6 ]) i*i );
// generator function which yields 4, 16, and 36

Async functions

Deferred Functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function wait(t){
  return new Promise((r) => setTimeout(r, t));
}

async function asyncMania(){
  console.log("1");
  await wait(1000);
  console.log("2");
}

asyncMania()
.then(() => alert("3"));

// logs: 1 2 3

Async generators

Deferred generators.

1
2
3
4
5
6
7
8
9
10
11
12
13
// provider
async function* nums() {
  yield 1;
  yield 2;
  yield 3;
}

// consumer
async function printData() {
  for(var x on nums()) {
    console.log(x);
  }
}

Object Observe

Asynchronously observing the changes to an object.

1
2
3
4
5
6
7
var obj = {};

Object.observe( obj,function(changes) {console.log(changes);} );

obj.name = "hemanth";

// Would log -> [ { type: 'new', object: { name: 'hemanth' }, name: 'name' } ]

Object.getOwnPropertyDescriptors

Returns a property descriptor for an own property.

1
2
3
let life = { answer: 42 };
Object.getOwnPropertyDescriptor(life, 'answer');
//^ { configurable: true, enumerable: true, value: 42, writable: true }

Array.prototype.includes

Determines whether an array includes a certain element or not.

1
2
3
[1, 2, 3].includes(3, 0, 7); // true
[1, 2, NaN].includes(NaN); // true
[0,+1,-1].includes(42); // false

Typed Objects

Portable, memory-safe, efficient, and structured access to contiguously allocated data.

1
2
3
4
5
6
7
8
9
var Point = new StructType({
  x: int32,
  y: int32
});

var point = new Point({
  x: 42,
  y: 420
});

P.S: The same is maintained as a git repo.

SMS Service With Firefox OS

| Comments

Assume a senario, a course booking service which need an SMS feature with the below work flow:

  • A customer sent a message of the format: <name> <course_name> <course_time> <number_of_tickets>

  • We need to reply to the sender with a thank you message of the format: Thank you <name>! Your booking (<number_of_tickets tickets) for <course_name> at <course_time> is confirmed.

This can be easily achived with the below code in fxos:

1
2
3
4
5
6
7
navigator.mozMobileMessage.onreceived = (sms) => {
   let cust = sms.message.sender,
   [name,courseName,courseTime, tcktCnt] = sms.message.body.split(' '),
   msg = `Thank you ${name}! Your booking (${tcktCnt} tickets) for ${courseName} at ${courseTime} is confrimed.`

   navigator.mozMobileMessage.send(cust, msg);
 }

Well, this is just a snippet, you would have to do a bit more to make it a service, for a quick hacky way, you could run the offical SMS app in debug mode and execute this snippet in the browser console.

There might be more better ways to do it, but this was one of easiest ways for me at a hackathon.