Bang: text snippets on the command line with Node.js

There's a great Ruby gem called Boom by Zach Holman for managing text snippets via the command line. I've used it since it was released and have even contributed to it a few times. But after using it for a long time, I realize that I don't really need the "lists" feature – the ability to store snippets with keys two levels deep. Because of Boom's syntax, I often accidentally create lists because I can't quite remember the name of the key I'm looking for.

I decided this was a good prompt for a new program, so I created Bang. Bang is a module for Node that gives you a very simple key value store with one level of depth. I use it to store all sorts of things: articles I refer to often, simple code snippets, Imgur links to animated GIFs, and strings with Unicode characters that are a pain to type.

For those, like me, who are experimenting with Node, CoffeeScript, testing using Jasmine, and annotated source using Docco, you will want to check out the source on GitHub to see some examples of all of these.

Install Bang

Install Node and npm.

$ npm install -g bang

Set a key

$ bang apples oranges

Get a key

$ bang apples
oranges

"oranges" is now copied to your clipboard.

Delete a key

$ bang -d apples

List keys

$ bang
  foo: bar
 blah: bleh
jimmy: cuadra
 bang: is rad

Feedback

I hope you enjoy Bang and find it useful. If you have a problem or suggestion, feel free to open an issue or send a pull request.

TL;DR

CoffeeScript classes: under the hood

CoffeeScript has a very elegant mechanism for creating classes. If you're new to JavaScript, you may not be aware that there are no native classes, and that CoffeeScript classes are actually syntactic sugar for JavaScript's constructor functions and object prototypes. Most people are more familiar with the syntax offered by CoffeeScript, but it's a good idea to know what's happening behind the scenes.

The prototypal model

In JavaScript, there are no classes, in the classical sense. Objects are created and inherit directly from other objects. Functions are a type of object, and when invoked with the new operator, create a new object which use the function as a constructor. This new object has a hidden link to the prototype property of the constructor function that establishes its inheritance. If you attempt to access a property on the new object that doesn't exist, JavaScript will follow the inheritance chain to the constructor's prototype and use the value it finds there.

When you create a class in CoffeeScript, you're really creating a constructor function. Each instance method in the class is actually a property of the constructor's prototype.

A simple class

Let's take a look at an example class, Bear. A bear is very simple. It has one property, name, and one method, attack. A class delcared with the class keyword creates an empty constructor function. The class definition is followed by an object defining the properties of the constructor's prototype. Each key in the object becomes a property on the prototype. The special key constructor becomes the body of the constructor function itself.

class Bear
  constructor: (@name) ->

  attack: ->
    "#{@name} the bear attacks with his bare paws!"

oswalt = new Bear "Oswalt"
console.log oswalt.attack()
# Oswalt the bear attacks with his bare paws!

Bear defines a simple constructor which takes one argument, the bear's name, and assigns it to the name property of the instance. The attack method simply returns a string saying the bear is attacking. We instantiate a new Bear named "Oswalt" and log the results of his attack method. This outputs "Oswalt the bear attacks with his bare paws!" to the console. Let's take a look at how CoffeeScript translates this into JavaScript. (I've left out some closures and added whitespace for clarity.)

var Bear, oswalt;

function Bear(name) {
  this.name = name;
}

Bear.prototype.attack = function() {
  return "" + this.name + " the bear attacks with his bare paws!";
};

oswalt = new Bear("Oswalt");
console.log(oswalt.attack());

As we can see, the Bear class is really just a function named Bear. It takes one argument and assigns it to the new instance's name property. The attack method is just a function assigned to the attack property of Bear's prototype. We instantiate an object by calling new Bear and passing it the bear's name. When we attempt to access the attack property of the new object, JavaScript sees there there is no such property, and travels up the hidden link to the class's prototype, where it finds the method we want and executes it.

Inheritance

CoffeeScript's class syntax is a bit cleaner than the compiled JavaScript, but ultimately not that different. Where CoffeeScript classes really shine is in abstracting away the clunky steps required to produce classical inhertiance via the prototypal model. Let's extend Bear to see how it works.

class BearWithChainsawPaws extends Bear
  attack: ->
    super + " BY THE WAY, HIS PAWS ARE CHAINSAWS."

rodrigo = new BearWithChainsawHands "Rodrigo"
console.log rodrigo.attack()
# Rodrigo the bear attacks with his bare paws! BY THE WAY, HIS PAWS ARE CHAINSAWS.

This new BearWithChainsawPaws class is a child class of Bear. It overrides the attack method but does not change the constructor. Note that the new attack method uses super to call Bear's version of attack. This is very useful, because there isn't a direct equivalent of super in JavaScript, as you can see in the compiled code (again modified for clarity):

var Bear, BearWithChainsawHands, rodrigo;

var __hasProp = Object.prototype.hasOwnProperty;

var __extends = function(child, parent) {
  for (var key in parent) {
    if (__hasProp.call(parent, key)) {
      child[key] = parent[key];
    }
  }

  function ctor() { this.constructor = child; }

  ctor.prototype = parent.prototype;
  child.prototype = new ctor;
  child.__super__ = parent.prototype;

  return child;
};

function Bear(name) {
  this.name = name;
}

Bear.prototype.attack = function() {
  return "" + this.name + " the bear attacks with his bare paws!";
};

__extends(BearWithChainsawHands, Bear);

function BearWithChainsawHands() {
  BearWithChainsawHands.__super__.constructor.apply(this, arguments);
}

BearWithChainsawHands.prototype.attack = function() {
  return BearWithChainsawHands.__super__.attack.apply(this, arguments) + " BY THE WAY, HIS PAWS ARE CHAINSAWS.";
};

rodrigo = new BearWithChainsawHands("Rodrigo");
console.log(rodrigo.attack());

There's a lot happening here, so let's take it a bit at a time.

The first thing to notice here is that CoffeeScript has generated some boilerplate above the classes themselves that wasn't there in the first example. __hasProp is just a shortcut for Object.prototype.hasOwnProperty. Since it's used in a loop in the following function, this is a bit more performant. It's not particularly important in understanding how inheritance works, however. The real meat is the next function.

__extends is a helper function that sets up one class to inherit from another. The for...in loop copies all the class-level methods from the parent to the child. In this particular case, our classes have only instance methods, but if we were to have defined a class property, say Bear.awesome = true, then the loop would copy true into BearWithChainsawPaws.awesome.

The second half of __extends sets up the prototype link (which contains the instance properties and methods) from the child to the parent. At its simplest, prototypal inheritance is achieved by assigning an instance of the parent to the child's prototype. __extends uses a bit of indirection to both establish this link, and to correctly assign the constructor property for all instances of the child. This property points back at the constructor function itself, and is necessary for the instanceof operator to give the desired result. The intermediate ctor method is used to for this purpose.

Lastly, a __super__ property is added to the child class, which establishes a reference to the parent's prototype. Without this, achieving super would require manually calling the parent class by name, which is error prone and not particularly maintainable. Inside BearWithChainsawHands's methods, we can see this reference to __super__ being used to call Bear's methods through the magic of apply – a method which invokes one object's method within the context of another object.

The point

While I do think CoffeeScript is pretty rad, the point of this post is to aid in understanding of what CoffeeScript is doing behind the scenes to provide its niceties. It uses good, clean JavaScript to abstract away what, to many, is an awkward approach, and in doing so, teaches a great deal about how JavaScript works.

Further reading

This post covers a lot of ground in a short span, and many parts of it could be explained in more depth. Here are some links to the MDC docs with more detail that should be helpful:

ECMAScript 5: Array methods

This is the third and final part of my series on ECMAScript 5. In part one, we looked at new methods for object creation and property definition. Part two focused on tamper proofing objects. I'll now provide a quick overview of the new high level array methods.

Unlike the new methods discussed in the first two parts, the methods here are all reproducible using JavaScript itself. Native implementations are simply faster and more convenient. Having a uniform API for these operations also promotes their usage, making code clearer when shared between developers.

Search methods

Array.prototype.indexOf

indexOf provides an easy way to determine whether or not an object is in an array. It returns the first index at which the item was found, or -1 if it was not found at all. Strict equality is used to determine that an item is present in the array. An optional second argument can start the search at an index other than 0.

var arr = ["apple", "banana", "carrot", "apple"];

arr.indexOf("apple"); // 0
arr.indexOf("daikon"); // -1

Array.prototype.lastIndexOf

Identical to indexOf, but returns the last index at which an item is found, if at all.

var arr = ["apple", "banana", "carrot", "apple"];

arr.lastIndexOf("apple"); // 3

Iteration methods

Array.prototype.forEach

Ever seen this before?

for (var i = 0, l = arr.length; i < l; i++) {
  doSomething(arr[i], i, arr);
}

There is now a clean, high level way to do this with forEach. The method accepts a callback which will be executed once for each item in the array. The callback receives three arguments: the value of the current iteration, the index of the current iteration, and the array itself. The following is equivalent to the above:

arr.forEach(doSomething);

An optional second argument specifies the value of this within the callback.

Array.prototype.every

every checks every element in an array against a condition, by means of a passed in function. If any of the items in the array cause the function to return a falsy value, every returns false. If they all return truthy values, every returns true. Like forEach, an optional second argument supplies a value for the callback's this, and the callback itself will receive the same three arguments.

var arr = ["apple", "banana", "carrot", "apple"];

arr.every(function (value, index, array) { return value.length > 1; }); // true
arr.every(function (value, index, array) { return value.length < 6; }); // false

Array.prototype.some

some is similar to every, but the passing condition is that at least one callback returns true, rather than all of them.

var arr = ["apple", "banana", "carrot", "apple"];

arr.some(function (value, index, array) { return value.length < 6; }); // true

Transformation methods

Array.prototype.map

Mapping is the most common transformation. It loops through an array, running a function and creating a new array built from the return values of each iteration. map takes the same optional second argument and receives the same callback arguments as the iteration methods.

var names = ["Abigail", "Bongo", "Carlitos"];

names.map(function (value, index, array) {
  return value + " Jones";
});
// ["Abigal Jones", "Bongo Jones", "Carlitos Jones"]

Array.prototype.filter

Filtering is like mapping, but creates a new array containing only the items of the original array that return a truthy value from the callback. filter takes the familiar optional argument and its callback receives the usual suspects.

var names = ["Abigail", "Bongo", "Carlitos"];

names.filter(function (value, index, array) {
  return value.length > 5
});
// ["Abigail", "Carlitos"]

Array.prototype.reduce

reduce is used to melt the items in an array down to a single value by the operations performed in its callback function. The callback takes the usual three iteration arguments, but is prepended with an extra argument, the value of the previous iteration's result. By default, the first iteration is effectively a no-op, so the calculation begins with the array's first value as the accumulated result and the array's second value as the current iteration. This is probably best illustrated with an example:

[10, 20, 30, 40, 50].reduce(function (accum, value, index, array) {
  return accum + value;
});
// 150

On the first iteration, accum is 10 and value is 20. The return value of accum + value becomes accum on the next iteration of the loop.

reduce can also take an initial value for accum as a second argument. When invoked this way, the first value in the callback is the first item in the array:

[10, 20, 30, 40, 50].reduce(function (accum, value, index, array) {
  return accum + value;
}, 50);
// 200

Array.prototype.reduceRight

reduce's sibling, which performs the same behavior and accepts the same arguments, except it iterates beginning with the rightmost item in the array and moves left. If not specified with a argument, the initial value of accum is the last value in the array, and the initial iteration value is the second to last.

[10, 20, 30, 40, 50].reduceRight(function (accum, value, index, array) {
  return accum - value;
});
// -50

ECMAScript 5 is full of goodness

ECMAScript 5 packs lots of new, useful features into JavaScript which speed up both development and performance of code. The new APIs are implented in the most recent versions of Chrome, Firefox, Safari, and (gasp!) Internet Explorer, so I encourage you to start using these new APIs today!

Page 6