Anthony Su

coding adventures

Understanding Pseudoclassical Inheritance in JavaScript

Introduction

In JavaScript: The Good Parts, Douglas Crockford disapproves of Pseudoclassical Inheritance in favor of Functional Inheritance. However, a quick survey of JavaScript resources such as Mozilla Developer Network(MDN) and JavaScript Tools/Libraries such as Google Closure, CoffeeScript, YUI3, and Jasmine indicate that Pseudoclassical pattern seems to be quite a popular inheritance pattern.

Drawbacks of Functional Inheritance

Michael Bolin who was a core contributor to Google Closure presents a strong case for Pseudoclassical Inheritance in his blog post Inheritance Patterns in JavaScript. In his post he discusses drawbacks for using Functional Inheritance and also addresses Douglas Crockford’s concerns for Pseudoclassical Inheritance.

Here is an example of Functional Inheritance from Douglas Crockford’s book:

Functional Inheritance Example
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
var mammal = function(spec) {

    var that = {};

    that.get_name = function() {

        return spec.name;

    };

    that.says = function() {
        return spec.saying || '';
    };

    return that;
}

var cat = function(spec) {

    spec.saying = spec.saying || 'meow';
    var that = mammal(spec);
    that.purr = function(n) {

        var i, s = '';

        for (i = 0; i < n; i++) {

            if (s) {
                s += '-';
            }
            s += 'r';
        }

        return s;
    };
    that.get_name = function() {
        return that.says() + ' ' + spec.name + ' ' + that.says();
    };
    return that;

}

var myMammal = mammal({name: 'Herb'});
var myCat = cat({name: 'Fiona'});
    myCat.get_name(); // "meow Fiona meow"
    myCat.purr(5); // "r-r-r-r-r"

and the same “classes” modeled using Pseudoclassical Inheritance:

Pseudoclassical Inheritance Example
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
var Mammal = function(name) {
    this.name = name;
};

Mammal.prototype.get_name = function() {
    return this.name;
};

Mammal.prototype.says = function() {
    return this.saying || '';
};

var Cat = function(name) {
    Mammal.call(this, name);
};

Cat.prototype = Object.create(Mammal.prototype);
Cat.prototype.constructor = Cat;

Cat.prototype.saying = 'meow';

Cat.prototype.purr = function(n) {

    var i, s = '';

    for (i = 0; i < n; i++) {

        if (s) {
            s += '-';
        }
        s += 'r';
    }

    return s;
};
Cat.prototype.get_name = function() {
    return this.says() + ' ' + this.name + ' ' + this.says();
};

var myMammal = new Mammal('Herb');
var myCat = new Cat('Fiona');
    myCat.get_name(); // "meow Fiona meow"
    myCat.purr(5); // "r-r-r-r-r"

Main Drawbacks

I would recommend reading Michael Bolins Inheritance Patterns in JavaScript for an in depth explanation of these drawbacks. Note that some of his points are made in respect to Google Closure.

  1. Instance of types take up more memory

    • Every time mammal() is called, two new functions are created (one per method of the type). Each time, the functions are basically the same, but they are bound to different values. These functions are expensive because each is a closure that maintains a reference for every named variable in the enclosing function in which the closure was defined. This may accidentally prevent objects from being garbage collected, causing a memory leak.
    • This is not a concern when Mammal is called because of how it takes advantage of prototype-based inheritance. Each method is defined once on Mammal.prototype and is therefore available to every instance of Mammal. This limits the number of function objects that are created and does not run the risk of leaking memory
  2. Types cannot be tested using instanceof

    • From MDN, the instanceof operator tests whether an object has in its prototype chain the prototype property of a constructor.

      object instanceof constructor

    • Since prototypes are not used for implementing inheritance for cat(), there is no appropriate constructor to use for instanceof
  3. Encourages adding properties to Function.prototype and Object.prototype
    • In his book, Crockford augment’s the prototype to assist in creating superclass methods
Prototype Augmentation from JavaScript: The Good Parts
1
2
3
4
5
6
7
8
9
10
11
12
13
// From Chapter 4.
Function.prototype.method = function(name, func) {
  this.prototype[name] = func;
  return this;
};

// From Chapter 5.
Object.method('superior', function(name) {
  var that = this, method = that[name];
  return function() {
    return method.apply(that, arguments);
  };
});
  • Adding methods to the prototype is dangerous, especially because the for in construct includes properties added to the prototype.

  • Makes it impossible to update all instances of a type

    • You need to individually update each instance.
    • In Pseudoclassical Inheritance, updating all instance of a type is as simple as updating properties or methods on the prototype.

Closure-related/Other Drawbacks

  1. Methods cannot be inlined
    • Methods in the functional pattern are often bound to variables that cannot be referenced externally, so there is no way for Closure Compiler to rewrite method calls in a manner that eliminates the method dispatch
  2. Superclass methods cannot be renamed(or will be renamed incorrectly)
    • Method renaming from JavaScript minifiers can use issues
  3. Results in an extra level of indentation
    • Coding preference
  4. Naming newly created objects is awkward

Naive Implementation of Pseudoclassical Inheritance

Here is an example of implementing Pseudoclassical Inheritance from JavaScript Garden. The main idea is to create a dummy instance of the parent Foo via new Foo and also call the parent constructor.

Naive Pseudoclassical Inheritance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Foo() {
    this.value = 42;
}
Foo.prototype = {
    method: function() {}
};

function Bar() {
    Foo.call(this); // call parent constructor
}

// Set Bar's prototype to a new instance of Foo
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';

// Make sure to list Bar as the actual constructor
Bar.prototype.constructor = Bar;

var test = new Bar(); // create a new bar instance

While this way of implementing Pseudoclassical Inheritance is not wrong per se, there is a little awkwardness to how the child’s prototype (Bar.prototype) is being set. Imagine the case, where the parent constructor takes in a couple parameters. It would be strange to invoke the new Parent() with dummy parameters because the instantiated object is a dummy instance. Additionally, the superclass’s constructor may have side effects (i.e. anything instance properties set in the superclass constructor get added to the prototype)or do something that is computationally intensive. Therefore, since the object that gets instantiated for the prototype is usually just a throwaway instance, you don’t want to create it unnecessarily.

General Implementation of Pseudoclassical Inheritance

To improve on the naive implementation of Pseudoclassical inheritance, we can create a dummy constructor, set it’s prototype to the prototype of the parent, and create a dummy instance that is used as the prototype of the child. Same as before, we also need to reset the prototype.constructor of the child to child(because the prototype needs to reference the appropraite constructor) and call the parent constructor in the child.

Use a dummy constructor when creating the object used for the prototype because superclass’s constructor may have side effects or do something that is computationally intensive

We can improve the the previous Foo Bar example like so:

PseudoClassical Inheritance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Foo() {
    this.value = 42;
}
Foo.prototype = {
    method: function() {}
};

function Bar() {
    Foo.call(this); // call parent constructor
}

// Set Bar's prototype to a new dummy instance that has use Foo.prototype for its prototype
Bar.prototype = Object.create(Foo.prototype); // new Foo(); 

// Make sure to list Bar as the actual constructor
Bar.prototype.constructor = Bar;

var test = new Bar(); // create a new bar instance

/* Test's prototype chain
  test -> Bar.prototype -> Foo.protoype -> Object -> null
*/

Pay close attention to the use of the native Object.create method which creates a new object with the specified prototype object and properties.

The Object.create() method creates a new object with the specified prototype object and properties.

Here is a simple Object.create polyfill from Crockford’s website.

Object.create
1
2
3
4
5
6
7
if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

And an optimized polyfill from MDN

Object.create polyfill
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (typeof Object.create != 'function') {
  Object.create = (function() {
    var Object = function() {};
    return function (prototype) {
      if (arguments.length > 1) {
        throw Error('Second argument not supported');
      }
      if (typeof prototype != 'object') {
        throw TypeError('Argument must be an object');
      }
      Object.prototype = prototype;
      var result = new Object();
      Object.prototype = null;
      return result;
    };
  })();
}

Pseudoclassical Inheritance in the wild

Based on our understanding of why and how to implement Pseudoclassical Inheritance, now we’ll take a look at how this pattern is being used for large JavaScript Libraries.

Google Closure

Closure is a set of individual JavaScript tools that are also designed to help developers build complex web applications, and is used by Gmail, Google Maps, and Google Docs. Inheritance in Google Closure is implementance via Pseudoclassical Inheritance. Google closure also adds a base method to the child constructor to expose a covenient way to invoke parent methods.

Inheritance via Google Closure
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
/**
 * Inherit the prototype methods from one constructor into another.
 *
 * Usage:
 * <pre>
 * function ParentClass(a, b) { }
 * ParentClass.prototype.foo = function(a) { };
 *
 * function ChildClass(a, b, c) {
 *   ChildClass.base(this, 'constructor', a, b);
 * }
 * goog.inherits(ChildClass, ParentClass);
 *
 * var child = new ChildClass('a', 'b', 'see');
 * child.foo(); // This works.
 * </pre>
 *
 * @param {Function} childCtor Child class.
 * @param {Function} parentCtor Parent class.
 */
goog.inherits = function(childCtor, parentCtor) {
  /** @constructor */
  function tempCtor() {};
  tempCtor.prototype = parentCtor.prototype;
  childCtor.superClass_ = parentCtor.prototype;
  childCtor.prototype = new tempCtor();
  /** @override */
  childCtor.prototype.constructor = childCtor;

  /**
   * Calls superclass constructor/method.
   *
   * This function is only available if you use goog.inherits to
   * express inheritance relationships between classes.
   *
   * NOTE: This is a replacement for goog.base and for superClass_
   * property defined in childCtor.
   *
   * @param {!Object} me Should always be "this".
   * @param {string} methodName The method name to call. Calling
   *     superclass constructor can be done with the special string
   *     'constructor'.
   * @param {...*} var_args The arguments to pass to superclass
   *     method/constructor.
   * @return {*} The return value of the superclass method/constructor.
   */
  childCtor.base = function(me, methodName, var_args) {
    var args = Array.prototype.slice.call(arguments, 2);
    return parentCtor.prototype[methodName].apply(me, args);
  };
};

CoffeeScript

In addition to using Pseudoclassical inheritance for the underlying implementation of CoffeeScript, Jeremy Askenas also discusses inconviences to libraries that try to provide a cleaner syntax for classical inheritance.

JavaScript’s prototypal inheritance has always been a bit of a brain-bender, with a whole family tree of libraries that provide a cleaner syntax for classical inheritance on top of JavaScript’s prototypes: Base2, Prototype.js, JS.Class, etc. The libraries provide syntactic sugar, but the built-in inheritance would be completely usable if it weren’t for a couple of small exceptions: it’s awkward to call super (the prototype object’s implementation of the current function), and it’s awkward to correctly set the prototype chain.

The crux of Jeremy’s implementation of Pseudoclassical inheritance is the __extends function. An interesting part of the implementation is the for loop which copies static methods from the parent onto the child.

1
2
3
 for (var key in parent) {
    if (__hasProp.call(parent, key)) child[key] = parent[key];
}
Inheritance implemented in compiled-down CoffeeScript
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
var Animal, Horse, Snake, sam, tom,
    __hasProp = {}.hasOwnProperty,
    __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;
    };

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

  Animal.prototype.move = function(meters) {
    return alert(this.name + (" moved " + meters + "m."));
  };

  return Animal;

})();

Snake = (function(_super) {
  __extends(Snake, _super);

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

  Snake.prototype.move = function() {
    alert("Slithering...");
    return Snake.__super__.move.call(this, 5);
  };

  return Snake;

})(Animal);

Jasmine

Jasmine is a behavior-driven development framework for testing JavaScript code. In Jasmine, inherit is attached to the utility object util.

1
2
3
4
5
6
  util.inherit = function(childClass, parentClass) {
    var Subclass = function() {
    };
    Subclass.prototype = parentClass.prototype;
    childClass.prototype = new Subclass();
  };

YUI3

YUI is a free, open source JavaScript and CSS library from Yahoo for building richly interactive web applications.

The method in YUI for inheritance is Y.extend used like so Y.extend(Programmer, Person); where a Programmer inherits from Person.

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
/**
 * Utility to set up the prototype, constructor and superclass properties to
 * support an inheritance strategy that can chain constructors and methods.
 * Static members will not be inherited.
 *
 * @method extend
 * @param {function} r   the object to modify.
 * @param {function} s the object to inherit.
 * @param {object} px prototype properties to add/override.
 * @param {object} sx static properties to add/override.
 * @return {object} the extended object.
 */
Y.extend = function(r, s, px, sx) {
    if (!s || !r) {
        Y.error('extend failed, verify dependencies');
    }

    var sp = s.prototype, rp = Y.Object(sp);
    r.prototype = rp;

    rp.constructor = r;
    r.superclass = sp;

    // assign constructor property
    if (s != Object && sp.constructor == OP.constructor) {
        sp.constructor = s;
    }

    // add prototype overrides
    if (px) {
        Y.mix(rp, px, true);
    }

    // add object overrides
    if (sx) {
        Y.mix(r, sx, true);
    }

    return r;
};

Y.Object used within Y.extend is essentially a wrapper for Object.create with a fallback. The fallback wraps the dummy constructor around an Immediately Invoked Function Expression(IIFE), so that the dummy constuctor can be reused.

Y.Object
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
/**
 * Returns a new object that uses _obj_ as its prototype. This method wraps the
 * native ES5 `Object.create()` method if available, but doesn't currently
 * pass through `Object.create()`'s second argument (properties) in order to
 * ensure compatibility with older browsers.
 *
 * @method ()
 * @param {Object} obj Prototype object.
 * @return {Object} New object using _obj_ as its prototype.
 * @static
 */
O = Y.Object = Lang._isNative(Object.create) ? function (obj) {
    // We currently wrap the native Object.create instead of simply aliasing it
    // to ensure consistency with our fallback shim, which currently doesn't
    // support Object.create()'s second argument (properties). Once we have a
    // safe fallback for the properties arg, we can stop wrapping
    // Object.create().
    return Object.create(obj);
} : (function () {
    // Reusable constructor function for the Object.create() shim.
    function F() {}

    // The actual shim.
    return function (obj) {
        F.prototype = obj;
        return new F();
    };
}()),

Conclusion

I hope this article sheds light on the advantages of using Pseudoclassical Inheritance over Functional Inheritance and clarifies how to implement Pseudoclassical Inheritance in an optimal manner.

Additional Things I Learned From jQuery Source

Introduction

Several months ago I decided to build a client side library called Guac. The library supports a similar and trimmed down API of that of jQuery. My library is by no means production ready, but building it was a good exercise for me to also explore the internals of jQuery.

This posts will discuss some of the internal workings of jQuery and explain how these ideas relate to the higher level API of jQuery. I will be walking you through parts of the jQuery codebase.

I would also recommend taking a look at Paul Irish’s related posts: 10 Things I learned From jQuery Source and 11 More Things I learned From jQuery source. Here is also a github gist that summarizes those videos. I try not to overlap with ideas he has already explained unless they are crucial to what I am discussing below.

At the time of this writing, the version of jQuery I am exploring is v2.1.1.

How the development modules are structured

From a development perspective jQuery is broken down into a bunch of modules.

These modules are defined using the Asynchronous Module Definition AMD specification.

The main file of jQuery is src/jquery.js and its relevant dependencies are listed as the array in the define function.

AMD Definition for jQuery
1
2
3
4
5
6
7
8
9
define([
    "./core", // refers to ./core.js
    "./selector", // refers to ./selector.js
    // .. more dependencies
], function( jQuery ) {

return jQuery;

});

This way of defining modules is crucial to how these modules are built. As we will discuss requirejs is used to resolve dependencies and load related modules/files.

Source:src/jquery.js

How jQuery is built

The README.md for jQuery describes at a high level how the jQuery source is built. In particular you will need the npm and grunt. Grunt is a task runner which allows you to automate repetitive tasks from the command line. Grunt also provides a development API, which jQuery uses. In the development directory there is a related Gruntfile that is read when grunt is ran on the command line. After you install npm and grunt you can build jQuery by running npm install && grunt. I’m going to focus on the lower levels on how jQuery is built.

jQuery uses requirejs to build out jQuery by running requirejs as a node module The files that are responsible for building jQuery are stored in the directory build/tasks. These are loaded by the Gruntfile:

Load Build Tasks
1
2
// Integrate jQuery specific tasks
grunt.loadTasks( "build/tasks" );

Source: build/tasks

The build task is executed when grunt is run on the command line. This is because grunt runs the default task, which includes building among another things like checking the JavaScript code quality, minifying the source for distribution, and comparing file size of the current git branch to that of master.

default grunt task
1
2
3
4
// Short list as a high frequency watch task
grunt.registerTask( "dev", [ "build:*:*", "lint" ] );

grunt.registerTask( "default", [ "jsonlint", "dev", "uglify", "dist:*", "compare_size" ] );

Source Code: register default grunt task

The relevant configuration for the tasks are also stored in the Gruntfile as a JavaScript object.

Grunt Configuration for build
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
build: {
    all: {
        dest: "dist/jquery.js",
        minimum: [
            "core",
            "selector"
        ],
        // Exclude specified modules if the module matching the key is removed
        removeWith: {
            ajax: [ "manipulation/_evalUrl", "event/ajax" ],
            callbacks: [ "deferred" ],
            css: [ "effects", "dimensions", "offset" ],
            sizzle: [ "css/hiddenVisibleSelectors", "effects/animatedSelector" ]
        }
    }
}

Source: grunt build configuration

build/tasks/build.js registers a multitask called build that iterates over all targets of build if none are specified when built is run on the command line: grunt build.

register multitask
1
2
3
4
5
6
7
grunt.registerMultiTask(
        "build",
        "Concatenate source, remove sub AMD definitions, " +
            "(include/exclude modules with +/- flags), embed date/version",
        function() {
            // ...
        });

Source Code: build/tasks register build tasks

The important line in build.js is requirejs.optimize(config, function( response ) { ... that uses requirejs’ optimize as function to build out the file.

The configuration config that is passed to require.js optimize is also important to take a look at. A more detailed definition of these options is available here.

configuration for requirejs.optimize build for jQuery
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
config = {
    baseUrl: "src", // all modules are located relative to this path
    name: "jquery",
    out: "dist/jquery.js",
    // We have multiple minify steps
    optimize: "none",
    // Include dependencies loaded with require
    findNestedDependencies: true,
    // Avoid breaking semicolons inserted by r.js
    skipSemiColonInsertion: true,
    // these files are used to prepend and append 
    // to optimized response
    wrap: {
        startFile: "src/intro.js",
        endFile: "src/outro.js"
    },
    // we map the "sizzle" module to its actual source
    paths: {
        sizzle: "../external/sizzle/dist/sizzle"
    },
    rawText: {},
    // A function that will be called for every write to an optimized bundle
    // of modules. This allows transforms of the content before serialization.
    // convert does the heavy lifting on massaging the files :  mainly stripping out the definitions generated by requirejs
    onBuildWrite: convert
};

An important property to note is the property onBuildWrite and the function convert which is a callback that is invoked with the library is built. In particular convert mainly strips out the definitions generated by requirejs.

The optimized contents are then passed to the config.out function which will handle writing the text to the relevant destination.

jQuery’s config.out
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    /**
    * Handle Final output from the optimizer
    * @param {String} compiled
    */
    config.out = function( compiled ) {
    compiled = compiled
        // Embed Version
        .replace( /@VERSION/g, version )
        // Embed Date
        // yyyy-mm-ddThh:mmZ
        .replace( /@DATE/g, ( new Date() ).toISOString().replace( /:\d+\.\d+Z$/, "Z" ) );

    // Write concatenated source to file
    grunt.file.write( name, compiled );
    };

Source Code:build/tasks/build.js config.out

Lastly there is another task called custom that handles the custom exclusion/inclusion of certain modules.

jQuery Alias

You’re probably familiar $ variable which is often used for selecting DOM Elements like so $("#awesomeID")

In fact, the $ is actual just an alias for jQuery, so you can also use jQuery("#awesomeID") instead of $("#awesomeID").

The related line within the codebase is

jQuery aliasing
1
window.jQuery = window.$ = jQuery;

Source Code: src/exports/global.js

Variables at the global scope are automatically attached to the window object. Similarly if you want to create a global from a variable from an inner scope, add it to the window object.

Since the jQuery codebase is encapsulated in an IIFE to avoid polluting the global namespace, jQuery and $ are attached to the window object to export it as a global.

Export jQuery and $ to Global Scope
1
2
3
4
5
(function() { // Immediately Invoked Function Expression (IIFE) to encapsulate code base
    // ...
    window.jQuery = window.$ = jQuery; // create alias and export global variables
    // ...
})();

Please also note that other libraries such as prototype do also use $ as a variable, so if you are using $ in jQuery and other libraries refer to jQuery’s documentation on avoiding conflicts with other libraries.

Prototype Alias

If you’ve ever tried creating your own jQuery plugin you’ll notice that you add the plugin to $.fn.

As an example for jQuery’s plugin tutorial, creating a plugin called greenify that makes retrieved text green would work like so:

jQuery example plugin: greenify
1
2
3
4
    $.fn.greenify = function() {
        this.css( "color", "green" );
    };
    $( "a" ).greenify(); // Makes all the links green.

In fact creating a plugin actually attaches greenify to jQuery’s prototype, because $.fn is an alias for prototype. Recall that an object inherit methods and properties from their prototype. Since, your plugin is attached to the prototype, you can invoke the plugin after creating your jQuery instance.

The related line that creates this aliasing is as follows:

jQuery.prototype aliasing
1
2
3
jQuery.fn = jQuery.prototype = {
    // ...
}

Source Code: src/core.js

Just to verify that jQuery.fn is indeed an alias for jQuery.prototype, we can check that their memory addresses are equal.

verify jQuery.fn is an alias for jQuery.prototype
1
jQuery.fn === jQuery.prototype // true

Using fn as an alias for prototype is a very convenient shorthand. I believe fn (function) also makes sense semantically because when you are creating a plugin, you are essentially adding another method to the jQuery Object.

Method Chaining

Many of jQuery’s methods return this (referring to the jQuery instance)

For example addClass

addClass returns this
1
2
3
4
    addClass: function( value ) {
        // ...
        return this;
    }

Source Code

Since this is a reference to the jQuery object, when a method returns this, you can immediately invoke another method like so:

Method Chaining Example
1
$(".box").addClass("red").css("opacity", 0.7);

jQuery Constructor

Every time you invoke jQuery or $, you are invoking a constructor. Often times you initialize an object by invoking the constructor with the new keyword. jQuery hides this by calling new jQuery.fn.init(selector, context) internally, when jQuery is invoked.

jQuery Constructor
1
2
3
4
5
6
// Define a local copy of jQuery
jQuery = function( selector, context ) {
    // The jQuery object is actually just the init constructor 'enhanced'
    // Need init if jQuery is called (just allow error to be thrown if not included)
    return new jQuery.fn.init( selector, context );
}

Source Code: src/core.js

Since jQuery.fn.init is the internal constructor that is used to initialize the jQuery object, the prototype of init is set to the prototype of jQuery.

Set fn.init.prototype to jQuery.fn
1
2
3
4
5
// Give the init function the jQuery prototype for later instantiation
init.prototype = jQuery.fn;

// verify that they are indeed equal
jQuery.fn.init.prototype === jQuery.fn && jQuery.fn === jQuery.prototype

Source Code: src/core/init.js

Function Overloading

Many programming languages support a feature known as function overloading
which allows for more than one function of the same name in the same scope as long as they differ by certain criteria. According to this function overloading table from Microsoft, the parts of a function declaration that are used to differentiate between functions within the same scope include number of arguments, type of arguments, presence or absence of ellipsis and const or volatile.

Although this feature is not explicitly supported in JavaScript, John Resig’s describe a method for simulating overloading by number of arguments.

jQuery also supports function overloading by checking the type of arguments and the jQuery() documentation discusses such usage in more detail.

Notice the // HANDLE comments within the source code that account for all the different cases.

jQuery.fn.init
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
init = jQuery.fn.init = function( selector, context ) {
        var match, elem;

        // HANDLE: $(""), $(null), $(undefined), $(false)
        if ( !selector ) {
            return this;
        }

        // Handle HTML strings
        if ( typeof selector === "string" ) {
            if ( selector[0] === "<" &&
                selector[ selector.length - 1 ] === ">" &&
                selector.length >= 3 ) {

                // Assume that strings that start and end with <> are HTML and skip the regex check
                match = [ null, selector, null ];

            } else {
                match = rquickExpr.exec( selector );
            }

            // Match html or make sure no context is specified for #id
            if ( match && (match[1] || !context) ) {

                // HANDLE: $(html) -> $(array)
                if ( match[1] ) {
                    context = context instanceof jQuery ? context[0] : context;

                    // Option to run scripts is true for back-compat
                    // Intentionally let the error be thrown if parseHTML is not present
                    jQuery.merge( this, jQuery.parseHTML(
                        match[1],
                        context && context.nodeType ? context.ownerDocument || context : document,
                        true
                    ) );

                    // HANDLE: $(html, props)
                    if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
                        for ( match in context ) {
                            // Properties of context are called as methods if possible
                            if ( jQuery.isFunction( this[ match ] ) ) {
                                this[ match ]( context[ match ] );

                            // ...and otherwise set as attributes
                            } else {
                                this.attr( match, context[ match ] );
                            }
                        }
                    }

                    return this;

                // HANDLE: $(#id)
                } else {
                    elem = document.getElementById( match[2] );

                    // Support: Blackberry 4.6
                    // gEBID returns nodes no longer in the document (#6963)
                    if ( elem && elem.parentNode ) {
                        // Inject the element directly into the jQuery object
                        this.length = 1;
                        this[0] = elem;
                    }

                    this.context = document;
                    this.selector = selector;
                    return this;
                }

            // HANDLE: $(expr, $(...))
            } else if ( !context || context.jquery ) {
                return ( context || rootjQuery ).find( selector );

            // HANDLE: $(expr, context)
            // (which is just equivalent to: $(context).find(expr)
            } else {
                return this.constructor( context ).find( selector );
            }

        // HANDLE: $(DOMElement)
        } else if ( selector.nodeType ) {
            this.context = this[0] = selector;
            this.length = 1;
            return this;

        // HANDLE: $(function)
        // Shortcut for document ready
        } else if ( jQuery.isFunction( selector ) ) {
            return rootjQuery.ready !== undefined ?
                rootjQuery.ready( selector ) :
                // Execute immediately if ready is not present
                selector( jQuery );
        }

        if ( selector.selector !== undefined ) {
            this.selector = selector.selector;
            this.context = selector.context;
        }

        return jQuery.makeArray( selector, this );
    };

Source Code: src/core/init.js

jQuery’s Array-like properties

An interesting feature of the jQuery is that instances have Array like properties as each instance has a length property and stores its elements in numeric indices for its elements.

Here is a sample of properties from a jQuery object:

Array-like properties from jQuery object
1
2
3
4
5
6
7
8
9
{
    0: div.box,
    1: div.box,
    2: div.box,
    3: div.box,
    4: div.box,
    length: 5
    // ...
}

jQuery’s Array-like behavior meshes well with method chaining, because for methods that return this or the instance, you now have the option to not only call another instance method but also to access selected elements.

Method Chaining and jQuery’s Array-like properties
1
2
3
4
5
6
7
8
9
10
11
12
13
// Assume we have html divs with a box class

// we can call a method after the constructor returns
$(".box").addClass("red");

// we can access an element
$(".box")[0] // get the first box

// we can chain methods to gether
$(".box").addClass("red").css("opacity", 0.7);

// add class to all boxes and get the first elemeent
$(".box").addClass("foo")[0];

jQuery also has an instance method called get that retrieves the elements matched from jQuery, using the array like properties we discussed above.

Note that this is different static jQuery.get that is used to load data from the server with a HTTP GET request.

jQuery.fn.get
1
2
3
4
5
6
7
8
9
10
11
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function( num ) {
    return num != null ?

        // Return just the one element from the set
        ( num < 0 ? this[ num + this.length ] : this[ num ] ) :

        // Return all the elements in a clean array
        slice.call( this );
},

Source Code: src/core.js

Constuctor Walkthroughs

Now we’ll discuss a few applications/internals of the jQuery constructor. For a more detailed view of the meat of the constructor refer to src/core/init.

First of all if nothing is passed to the constructor, the current instance is simply returned.

falsy values passed to jQuery constuctor
1
2
3
4
// HANDLE: $(""), $(null), $(undefined), $(false)
if ( !selector ) {
    return this;
}

Source Code: src/core/init.js

Next the constructor handles strings. At first the function checks if the string contains brackets and then uses a regex expression to check whether or not the string matches html or contains an id.

The regex expression is called rquickExpr.

rquickExpr
1
2
3
4
// A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
// Strict HTML recognition (#11290: must start with <)
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,

Source src/core/init

The example I will first be discussing is a simple selection for a class.

1. Select selector

Find selector
1
    $(".box") // find all elements with the box class

Since this selector will not match the regex described above, the search will the constructor will invoke jQuery.fn.find to locate the search the document for the relevant elements

invoke jQuery.fn.find
1
2
3
4
5
// HANDLE: $(expr, $(...))
    if (...) {
    } else if ( !context || context.jquery ) {
        return ( context || rootjQuery ).find( selector );
    }

This is the function definition for jQuery.fn.find.

jQuery.fn.find
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
jQuery.fn.extend({
    find: function( selector ) {
        var i,
            len = this.length,
            ret = [],
            self = this;

        if ( typeof selector !== "string" ) {
            return this.pushStack( jQuery( selector ).filter(function() {
                for ( i = 0; i < len; i++ ) {
                    if ( jQuery.contains( self[ i ], this ) ) {
                        return true;
                    }
                }
            }) );
        }

        for ( i = 0; i < len; i++ ) {
            jQuery.find( selector, self[ i ], ret ); // invoke sizzle
        }

        // Needed because $( selector, context ) becomes $( context ).find( selector )
        ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
        ret.selector = this.selector ? this.selector + " " + selector : selector;
        return ret;
    }
});

We pass a string to jQuery.fn.find and then the static method jQuery.find is invoked. jQuery.find is really just an alias for Sizzle, the selector engine.

The results of items found by Sizzle are stored as an array in the ret variable.

That array is then passed into to the function pushStack which merges a new instance of jQuery this.constructor with the current array of matched elements, elements.

As we discussed above, invoking the constructor with no values, will just immediately return the instance of jQuery.

jQuery.pushStack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    // Take an array of elements and push it onto the stack
    // (returning the new matched element set)
    pushStack: function( elems ) {

        // Build a new jQuery matched element set
        var ret = jQuery.merge( this.constructor(), elems );

        // Add the old object onto the stack (as a reference)
        ret.prevObject = this;
        ret.context = this.context;

        // Return the newly-formed element set
        return ret;
    },

Another important aspect of push stack is that it keeps reference to the previous object or parent of the search. This is helpful for methods like end which return the reference to the parent element.

Sample use of jQuery.end
1
2
3
4
5
$( "ul.first" )
    .find( ".foo" )
        .css( "background-color", "red" ) // update .foo elements
    .end() // return to ul.first
// refer to http://api.jquery.com/end/

Source: jQuery.end

jQuery.merge (used in pushStack) copies over the second array into the first array. In this case, the elements returned from jQuery’s sizzle are copied over to the instance (this).

Notice that this form of merging is consistent with jQuery’s Array-like properties discussed above.

jQuery.merge
1
2
3
4
5
6
7
8
9
10
11
12
13
merge: function( first, second ) {
        var len = +second.length,
            j = 0,
            i = first.length;

        for ( ; j < len; j++ ) {
            first[ i++ ] = second[ j ];
        }

        first.length = i;

        return first;
}

Source: src/core.js

2. Build HTML

If the content matches the HTML regex describe previously, an array of DOM nodes generated from the parsed html is merged into the current instance.

Sample for constructing elements with jQuery using html
1
    $("<div></div>") // build a div element
parse html in constructor
1
2
3
4
5
jQuery.merge( this, jQuery.parseHTML(
                    match[1],
                    context && context.nodeType ? context.ownerDocument || context : document,
                    true
));

3. document.ready

$(document).ready( handler ) is a construct that is used to invoke the handler when the DOM has been constructed.

Since document is a DOM element it will simply be stored as element 0 of the instance.

handle DOMElement
1
2
3
4
5
if ( selector.nodeType ) {
    this.context = this[0] = selector;
    this.length = 1;
    return this;
}

Source: src/core/init.js

Then jQuery.fn.ready is invoked with the callback. An interesting to note is that that invoking .ready does not require any elements although the api does not recommend using ready like this: $().ready( handler ) (this is not recommened).

There is another shorthand for $(document).ready where you pass the function to the constructor.

Shorthand document.ready
1
    $( handler )

Internally jQuery stores a reference to the document called rootjQuery. If a function is passed to the constructor, then ready is called on rootjQuery.

rootjQuery
1
2
3
4
5
6
7
8
9
// A central reference to the root jQuery(document)
var rootjQuery,

// ...

// ...

// Initialize central reference
rootjQuery = jQuery( document );

Source code: src/core/init.js

Handle: $(function)
1
2
3
4
5
6
7
8
9
10
// ...
} else if ( jQuery.isFunction( selector ) ) {
    return rootjQuery.ready !== undefined ?
        rootjQuery.ready( selector ) :
        // Execute immediately if ready is not present
        selector( jQuery );

}

// ...

Source code: src/core/init.js

4. $({})

Finally if the item passed into the constuctor does not match any of these cases (and others not discussed here) the constructor simply makes an array out of the element passed in.

Example that reaches default case
1
2
    $({});
    // returns [{}]
default constructor case
1
return jQuery.makeArray( selector, this );

Source code: src/core/init. More on makeArray.

Why would use a construct like $({})? Wrapping an object around jQuery allows you to apply jQuery’s methods onto the object.

Ben Alman wrote a tiny pub-sub system using such a construct.

Tiny Pub-Sub by Ben Alman
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* jQuery Tiny Pub/Sub - v0.7 - 10/27/2011
 * http://benalman.com/
 * Copyright (c) 2011 "Cowboy" Ben Alman; Licensed MIT, GPL */

(function($) {

  var o = $({});

  $.subscribe = function() {
    o.on.apply(o, arguments);
  };

  $.unsubscribe = function() {
    o.off.apply(o, arguments);
  };

  $.publish = function() {
    o.trigger.apply(o, arguments);
  };

}(jQuery));

Source Code jquery-tiny-pubsub

Static Methods

jQuery has static methods which do not require an instance of jQuery to operate. Many of these methods are utility methods such as isArray or each.

Static Method Example: $.each
1
2
3
4
5
6
$.each([1,2,3], function(i, el){
   console.log(el);
});
// 1
// 2
// 3

An interesting thing to note is that there are static methods and instance methods in the codebase that have the same name.

Many of these instance methods also invoke the static methods within their definition.

jQuery.fn.each instance method
1
2
3
4
5
// ...
each: function( callback, args ) {
    return jQuery.each( this, callback, args ); // use static each
},
// ...

Source: jQuery.fn.each jQuery.each

jQuery.fn.find instance method
1
2
3
4
5
6
7
8
9
10
11
12
13
find: function( selector ) {
    var i,
        len = this.length,
        ret = [],
        self = this;

    // ...
    for ( i = 0; i < len; i++ ) {
        jQuery.find( selector, self[ i ], ret ); // use static jQuery.find
    }

    // ...
}

Source: jQuery.find jQuery.fn.find

Implicit Iteration

Under the hood, many of jQuery’s methods such as addClass iterate over all the elements that were selected, which makes the API very to use especially for first time coders.

Sample Use Case Implicit Iteration
1
$(".box").addClass("red"); // add red class to all elements that contain the box class

Given our understanding of static methods and jQuery’s Array-like Properties, implementing implicit iteration (automatic iteration hidden from the API level) involves iterating over the this object reference that contains all the elements.

Simple Iteration addClass
1
2
3
4
for ( ; i < len; i++ ) {
    elem = this[ i ]; // recall that each element is stored in the this object
    // ... do some class manipulation for the element
}

Source Code: src/attributes/classes.js

If you are passing a function to addClass, jQuery uses the this.fn.each to iterate over the object. This is because this.fn.each uses jQuery.each which invokes the function on each element. So in the inner line of the callback this actually refers to the individual element.

this.each iteration addClass
1
2
3
4
5
6
if ( jQuery.isFunction( value ) ) {
    return this.each(function( j ) {
        // 'this' here refers to the individual element.
        jQuery( this ).addClass( value.call( this, j, this.className ) ); // invoke function and individual method
    });
}

Source Code: src/attributes/classes.js

More details on jQuery.each

I hope this article gives you a good overview of how jQuery is built and certain aspects of the codebase. Applying these principles I hope you will be at more ease should you choose to further explore jQuery’s codebase or write more JavaScript.

Understanding the Intuition of Easing

Introduction

Recently I’ve been studying motion and I wanted to write a post regarding what I’ve learned primarily regarding easing.

I stumbled upon Rachel Smith’s beginner post on easing, a couple weeks ago which was really eye-opening. Starting out, these tips were really helpful and spurred more research on the mechanics and principles of easing.

Some additional resources I would recommend reading are

Some of the key points to take away from these posts regarding motion in general include

  1. Physical objects have mass and move only when forces are applied to them. Consequently, objects can’t start or stop instantaneously. Animation with abrupt starts and stops or rapid changes in direction appears unnatural and can be an unexpected and unpleasant disruption for the user.
  2. Motion with swift acceleration and gentle deceleration feels natural and delightful.
  3. Enter and exit frame at peak velocity. This behavior emulates natural movement: a person entering the frame of vision does not begin walking at the edge of the frame but well before it. Easing in when entering and slowing down when exiting draw the user’s attention to that motion, which, in most cases, isn’t the effect you want. Likewise
    • Use ease-out to move something onto the stage
    • Use ease-in to move something off stage
    • Use ease-in-out to move something across the stage (from one point to another)
  4. Account for mass. Lighter/smaller objects may accelerate or decelerate faster, because they have less mass and require less force to do so. Larger/heavier objects may need more time to reach peak speed and come to rest.

There are already lots of posts around the web teaching you how to implement CSS transitions and use jQuery Easings as well as tools to select and create your own easings.

The purpose of this post is to develop an intuition of easing by:

  1. develop an understanding of what easings are and the relationship between different easings
  2. learn how to select/apply easings
  3. examine real world application of easings such as on Flickr’s website and Google Glass’ website.

Motion and Tweening

In filmaking, movies or motion pictures can be thought of as a series of still images or frames that compose a complete moving picture.

Likewise in traditional animation, animators would either draw out every single frame of an animation from start to end with the straight ahead technique or draw keyframes (important frames of a sequence) and then generate intermediate frames between the keyframes known as inbetweens. The process of generating intermediate frames between keyframes is also known as tweening or interpolating and the resulting sequence of frames is known as a tween.

Straight Ahead Pose to Pose

The top illustrates a straight-ahead technique, while the bottom represents the keyframes that will be used from pose-to-pose animation

Source: Smashing Magazine

From a programmatic perspective, motion is simply the numerical change of position with time.

What is easing

Easing comes into play because it used to model how position changes with time. Robert Penner created a set of easing functions to model these positional changes. Easings are applied to tweens to specify the speed at which the animation progresses at different points within the tween.

Note on position

As Robert Penner notes, position doesn’t have be a physical position but can be any one dimensional value such as opacity. Of course you can animate two- and three-dimensional motion such as area and volume, but these animation are broken down into several one-dimensional values.

How to interpret easing graphs

There is quite a selection of easing functions to choose from, so how do you choose which one works best for you? Luckily, these easing functions have been visualized as position vs. time graphs, so understanding how to interpret these graphs is crucial for selecting the right easing. You can also “listen” to these easings.Position is the y axis (vertical) and time is the x axis (horizontal). For the most part, each axis is bound between 0 and 1 (representing 0 to 100% of position or time), but as we’ll see position of easings such as easeOutBack can exceed 1 and easeInBack can go below 0. You can also think of the bounds of the y and x axes representing start/end position and start/end time respectively.

As a physics refresher, change in position = displacement = (position2 - position1)and average velocity = displacement / time. Looking at a position vs. time graph, we can interpret a line or curve as a set of points. Each point represents a position. If you take the slope between the two points (position2 - position1) / (time2 - time1) then you get the velocity within that time frame. It also important to remember that velocity is a vector quantity meaning that it represents both a value and direction (how fast and in which direction), whereas speed is a scalar quantity only representing a value (how fast). So negative velocity represents the same speed of an equivalent positive velocity but in the opposite direction.

Finally, if you take the slope of the velocity graph, (velocity2 - velocity1) / (time2 - time1) then you get the acceleration. In other words, acceleration tells you whether or not the object speeds up or slows down with time and in which direction. An acceleration of 0, means that velocity was constant.

The follow graph from here as displayed below visualizes these concepts well.

Velocity and Acceleration

Source: Hyperphysics

There are 4 basic easing functions :
1. linear
2. ease-in
3. ease-out
4. ease-in-out

Below we’ll look at how to interpret these graphs. I would also recommend playing with this easing visualization created by Gilmore Davidson which is where the following images are adapted from.

Linear

Linear Easing

Source: SydJS Easing Presentation

The slope of this graph is a constant value, because the line is straight. A constant velocity means that there is no acceleration.

Ease-In

Ease In

Source: SydJS Easing Presentation

The slope of this graph gets steeper over time meaning that the velocity increases over time. In other words, the object starts out slow and accelerates over time.

Ease-Out

Ease Out

Source: SydJS Easing Presentation

This graph behaves in the opposite manner of an ease-in graph. The slope of this graph gets flatter over time meaning that the velocity decreases over time. In other words, the object starts out fast and decelerates over time.

Ease-In-Out

Ease In-Out

Source: SydJS Easing Presentation

This graph is a combination of an ease-in and ease-out graph. Looking at the slope, we see that initially the object starts out slow and accelerates over time before hitting a peak velocity, followed by a gradual deceleration before stopping.

Different Degrees of Easing

These “standard” easing classes model position as a power function of time t raised to some power: Linear - 1, Quad(ratic) - 2, Cubic - 3, Quart(ic) - 4, Quint(ic) - 5.

We’ll look at these different degrees of easing by examining the easeIn curve. Recall that the bounds for time are between 0 and 1 and that decimal values yield smaller values when raised to increased powers.

Degrees of Easing

Source: Penner

Let t = 0.8
    t^2 = 0.64
    t^3 = 0.512
    t^4 = 0.4096
    t^5 = 0.32768

Since decimal values yield smaller results decrease with increased power, this means that increasing powers exaggerates the easing effect. In particular for easeIn easings, the object remains slower for a longer time and accelerates faster when it finally speeds up.

Linear

Power of 1. Uses Constant Velocity.

Quad

Power of 2. Interesting tidbit to distinguish Quad from Quart: Although the prefix quad means four, quad originally referred to the four sides of a square. Therefore a squared variable is a quadratic.

Cubic

Power of 3.

Quart

Power of 4.

Quint

Power of 5.

Other Easings

Sinusoidal Easing

sinEasing

Source: Penner

The position is a function of a sin: p(t) = sin(t * π/2). Sinusoidal easing is quite gentle, even more so than quadratic easing. Its path doesn’t have a lot of curvature. Much of the curve resembles a straight line angled at 45 degrees, with just a bit of a curve to it.

Exponential Easing

Recall that for an exponential function such as exponential growth, time t is an exponent 2t, whereas in power functions time is a value raised to a constant value for example t2. Generally exponential functions grow faster than power functions and are therefore more exaggerated.

exponentialEasing

Source: Penner

History of Exponential Easing

The Exponential Easing is based off what Robert Penner calls the standard exponential slide, that was used often used in ActionScript, a dialect of ECMAScript used for Flash.

// a standard exponential slide
this.onEnterFrame = function () {
var distance = this.destinationX - this._x;
    this._x += distance / 2;
};

The idea is simply that you move a fraction of the distance—say one-half—to your destination in each unit of time. For instance, if you need to move a total of 10 feet, you could move 5 feet, then 2.5 feet, then 1.25, then .625, and so on.

Notice that this is a Geometric Series, which is a sum of a sequence of terms where there is a constant ratio between successive terms. The sum of a Geometric series is c / (1 - r), where c is constant multiplied to each term and r is the ratio between each term We can verify the above example: 10 = 5 / (1 - 1/2) where c = 5 and r = 1 / 2.

Circular Easing

Circ Easing

Source: Penner

The position is a based of the equation for a half circle: p(t) = 1 - sqrt(1 - t^2). This equation is derived from the equation of a unit circle x^2 + y^2 = 1 Solving for y, we get that the upper half of the circle is y = sqrt(1 - x^2). Likewise the lower half of the circle is y = -sqrt(1 - x^2), because negating the equation flips the graph vertically (over the y axis). Finally we add 1 to the equation so that the unit circle is shifted up to top y = (-sqrt(1 - x^2)) + 1, Since the bounds of time > 0 our graph is a quarter circle residing in the top right quadrant. This can be rewritten as y(x) = 1 - sqrt(1 - x^2).

Similar to quintic and exponential easing, the accleration for circular easing is dramatic, but it also happens more suddenly. Since the circle exhibits more curvature, we see a greater range of velocity as well as sharper changes towards the beginning of easeInCirc and at the end of easeOutCirc.

The following diagram displays all easings mentioned so far in juxtaposition, ordered by roughly increasing curvature/acceleration.

Standard Easings

Source: SydJS Easing Presentation

Special Effect Easings

More complex curves have been modeled to create special effects.

Back

This easing exceeds the start or end position for easeIn and easeOut respectively, before springing back into place. The easing displayed below is easeOutBack.

easeOutBack

Source: SydJS Easing Presentation

See the Pen easeOutBack by Anthony Su (@radialglo) on CodePen.

Elastic

This easing oscillates around the start or end position for easeIn and easeOut respectively.

easeOutElastic

Source: SydJS Easing Presentation

See the Pen easeOutElastic by Anthony Su (@radialglo) on CodePen.

Bounce

The start and end position form boundaries for easeIn and easeOut respectively, whereupon the object bounces.

easeOutBounce

Source: SydJS Easing Presentation

See the Pen easeOutBounce by Anthony Su (@radialglo) on CodePen.

CSS Easing

Although Robert Penner’s equations were written originally as functions, many of these functions can also be used in CSS3 using the cubic-bezier transition timing function. These functions have been approximated as cubic bezier curves by Matthew Lein. For more on bezier curves read this article. Here is a bezier curve simulation from Jason Davies and another one by Tim Holman.

A limitation of using cubic bezier curves is that cubic bezier curves contain at most one peak and one valley. So if you want to use an easing that has more than one peak/trough, such as easeInElastic or easeInOutBounce then you must use a JavaScript or some other programmatic implementation of easing.

How to apply easings

Generally speaking, linear motion is often mechanical rather than natural. You want to conform to the natural laws of motion so that your animation is believable.

However this does not mean you should completely ignore linear easings even if your not animating mechanical objects. Easings don’t neccesarily need to model physical position, but can really used to model any kind of one dimensional value such as opacity. Similarly some applications of linear easing can be used for creating camera effects like zooming or panning when creating a timelapse or the Ken Burns Effect for creating videos with still imagery.

Naturally, your eye will be able to discern something moving at a slower speed than something moving at a higher speed. It’s no coincidence that slow motion scenes in action movies also tend to be the most interesting. As such, enter and exit the stage at peak velocity. Entering and exiting the stage are less important in comparison to when the object finally halts on stage or begins to leave the stage, respectively.

Timing

If your just starting out some suggested duration of easings are

Ease-outs: around 200ms - 500ms. This gives the eye chance to see the animation, but doesn’t feel obstructive.

Ease-ins: around 200ms - 500ms. Bear in mind that it will jolt at the end (from the acceleration) and no amount of timing changes will soften that feel.

Bounce or elastic effects: around 800ms - 1200ms. You need to allow time for the elastic or bounce effect to ‘settle’. Without this extra time the elastic bouncing part of the animation will be really aggressive and unpleasant to the eye.

Car example

We’ll be animating a car to understand how to apply easing.

EaseInOut

Initially your car starts out parked. When you start your car, you need to push on the pedal to accelerate to a comfortable cruising speed and finally when you are stopping at stop light you gently decelerate so that the ride is comfortable for your passengers.

If you were to witness the full start and stop action of the car you would see an easeInOut easing. Use easeInOut to move something across the stage (from one point to another).

See the Pen Car driving across stage by Anthony Su (@radialglo) on CodePen.

EaseOut

Let’s say you were to see a friend arrive at your house for an evening party. By the time your friend reaches your house he/she will already be traveling at peak velocity and will gently decelerate before parking in front of your house. Use easeOut to move something onto the stage

See the Pen Car driving onto stage by Anthony Su (@radialglo) on CodePen.

EaseIn

After the party, you say goodbye to your friend and watch as his/her car leaves your neighborhood. Your friend needs to start the parked car and accelerate to reach a comfortable crusing speed. By the time the car leaves your field of vision it will be traveling at peak velocity. Use easeIn to move something off stage

See the Pen Car backing off stage by Anthony Su (@radialglo) on CodePen.

Now that you know how to apply easeIn, easeOut, and easeInOut you can change the power of your easing (Quad, Cubic, Quart …) to minimize or exaggerate the effect.

Easings in the Wild

Next let’s examine how easing is being used across the web.

Flickr

Flickr is built using YUI, Yahoo User Interface Library, Yahoo’s JavaScript framework. The site currently uses scroll-jacking, which is the process of overriding default user scrolling with a custom interaction design paradigm.

The user interface also has arrow buttons, bullet lists, and accepts keyboard input such as space bar / page down, j/k, arrow keys for navigation.

From the source code we can see the handling of keypresses and clicks. All of these input methods are used to animate the scroll position.

Keydown Source

Y.one(document).on('keydown', function(e) {

    var down, up, beginning, end;
    var ignoreMultiple;

    // space bar / page down, j/k, arrow keys
    if (e.keyCode) {
        down = (e.keyCode === 32 || e.keyCode === 34 || e.keyCode === 74 || e.keyCode === 40);
        up = (e.keyCode === 33 || e.keyCode === 75 || e.keyCode === 38);
        beginning = (e.keyCode === 36);
        end = (e.keyCode === 35);
    }

    // ignore if in an input, select/option etc.
    if (!document.activeElement || !document.activeElement.nodeName.match(/(input|select|option)/i)) {

        // block multiple events only for up/down arrow keys.
        if (!down && !up) {
            ignoreMultiple = true;
        }

        // do the nav thing
        if (down) {
            animateTo('#section-' + getNextSection(), ignoreMultiple);
        } else if (up) {
            animateTo('#section-' + getPreviousSection(), ignoreMultiple);
        } else if (beginning) {
            animateTo('#section-1');
        } else if (end) {
            animateTo('#section-' + maxSections);
        }

        // override default actions
        if (up || down || beginning || end) {
            e.preventDefault();
            return false;
        }

    }

});

Click Source

Y.one('body').on('click', function(e) {

        var target = e.target;
        var href = target.get('href');
        var hash, hashOffset;
        var url;
        var anim;

        if (href) {

            // a #section-x link was clicked.

            if (href.match(/section/i)) {

                hashOffset = href.indexOf('#');

                if (hashOffset !== -1) {
                    hash = href.substr(hashOffset);
                    animateTo(hash);
                    e.preventDefault();
                    return false;
                }

            } else {

                // up/down navigation links.

                if (href.match(/\#down/i)) {

                    animateTo('#section-' + getNextSection());

                    e.preventDefault();
                    return false;

                } else if (href.match(/\#up/i)) {

                    animateTo('#section-' + getPreviousSection());

                    e.preventDefault();
                    return false;

                }

            }

        }

    });

Reading through the source you’ll notice the primary function that we see being used for navigation is animateTo.

The primary part of that function is to note initialization of the YUI Animation Class

scrollAnimation = new Y.Anim({
    node: scrollElement,
    to: {
        scrollTop: parseInt(targetY, 10)
    },
    // if existing animation was interrupted, move really fast to indicate responsiveness.
    easing: (interrupted ? 'easeOutStrong' : (scrollAction ? 'easeBoth' : 'easeBothStrong')),
    duration: duration
});

The JavaScript is animating the scrollTop of the document. Also pay attention to the line where the initialization of the easing property occurs. Notice how there are actually three forms of easings for navigation: easeBoth (equivalent to easeInOutQuad), easeBothStrong (equivalent to easeInOutQuartic), and easeOutStrong (equivalent to easeOutQuartic). For additional eases available in YUI, refer to the Easing Class.

These easing are being used as follows:

Flickr: Scroll Navigation

easeBoth

Flickr Scroll

  • If the user scrolls, use a easeInOutQuad easing to move to the next section – start out slow before swift acceleration followed by gradual deceleration.

  • The easing makes sense because there is one section moving off stage (easeIn) followed by another section moving into view (easeOut). Hence the use of easeBoth.

  • One interesting to note is that the transition is a response to the user’s scrolling. Because the transition starts out slow, the user may percieve this as a slow responsive website. The general rule of thumb is to respond to a user interaction quickly. Thus, potentially slow percieved performance is tradeoff when using an easeInOutQuad transition to respond to the user.

Flickr: Click Navigation

easeBothStrong

Flickr Click

  • For all other forms of input such as button click or valid keypresses use a more dramatic easeInOut function: easeInOutStrong (easeInOutQuartic).
  • It’s pretty interesting this easing is more exaggerated than that of scrolling. I think the rational is that because buttons are more custom than native scrolling, there is more flexibility to define a more dramatic transition.
  • From my view, I think the easing for scrolling and clicks should be consistent. At the same I would imagine that users probably stay with one method of navigation when browsing the site, so the difference could be negligible.

Flickr: Click vs Scroll Comparison

Flickr Click Scroll

To really compare click navigation(easeInOutQuartic) vs. scroll navigation(easeInOutQuad), notice the difference between the click and scroll when they are performed one after another. Since the click(Quartic) has a higher easing degree than scroll(Quad) the acceleration for the click is more dramatic. Note that the click occurs first followed by the scroll.

Flickr: Interrupt Navigation

easeOutStrong

Flickr Interrupt Click

  • If the user tries navigating while an animation is in progress (an interrupt) perform an easeOutQuartic easing to the next section. (Note from the dots on the right, that we are navigating from slide 1 to 3)
  • The interaction is defined such that when an interrupt occurs navigate to the newly desired slide.
  • As such, using easeOutStrong makes sense here. Since the currently slide is already moving it should continue moving at a high velocity before coming to rest.

Flickr: Far Click

easeBothStrong

Flickr Far Click

This is the same easing as the click navigation discussed above. In this example, the user jumps over sections navigating to slide 5 from slide 1 by clicking dot 5. The difference here is that because the scroll animation occurs over a longer distance within the same time, the velocity here is greater.

Google Glass

Next we’ll look at another implementation of a scroll-jacked website: Google Glass’ start page.

Google Glass: Click Navigation

easeInOutQuart

Glass Click

This site is implemented using CSS3. The easing that is being used is a cubic-bezier(.77,0,.175,1), which is easeInOutQuart, and the site makes use of CSS3 transforms to translate to the next slide. Recall that Flickr does use easeInOutQuart for some of its easing although the transition here appears to be more pronounced because a larger object(the background image) is being moved. This site less ways to navigate and does not allow for interrupts.

The gist of creating this effect is to define a state in which the slide is hidden and a state in which a slide is active and defining how to transition between each state.

/*
    translate 100% of the slide's body to move it offscreen
*/
.slide { 
    transform: translate3d(0,100%,0)
    transition: transform 1s;
    transition-timing-function: cubic-bezier(.77,0,.175,1);
}
/*
    don't translate
    toggling the .active class on a slide will bring the slide into view
*/
.slide.active {
    transform: translate3d(0,0,0)
}

Google Glass: Far Click

The way this site handles skipping over sections is to fade out the old image and fade in the new image. It fades out the image using the default transition: ease and then fading back in using the easeOutQuart cubic-bezier curve.

This interaction differs from Flickr which increases the velocity to make the jump between slides.

Glass Far Click

Paul Stamatiou

Paul Stamatiou is a designer at Twitter. This is a pretty interesting interaction he used for his site’s navigation.

Stamatiou Nav

This interaction uses a custom bezier-curve cubic-bezier(0.325, 0, 0.000, 1.650) which is a combination of a very short easeIn followed by an exaggerated easeOutBack. This gives the navigation playfulness.

crazy Ease Out Back

Source: Ceaser

Google Design Example: Radial Action

This example is from Google’s Material Design section on Responsive Interaction. In this example we see that the epicenter of action occurs at left and ripples out to the right.

Radial React

Tools

Some tools I would recommend to further explore easing are:

Conclusion

Motion is becoming more prevalent on the web and on mobile. I hoped through this post you have developed an understanding of what easings are the relationship betwen different easings and learned how to choose and apply easings. Lastly I’ve linked some videos for inspiration.

The illusion of life from cento lodigiani on Vimeo.

Elements of Design from matt greenwood on Vimeo.

Further Reading

  1. 12 Principles of Animation
  2. Robert Penner Easing Resources
  3. Google Design Guidelines
  4. Google Web Fundametals on Easing
  5. Motion and Animation, A new mobile UX Design Material

What I Learned From Launching Version 2 of My Portfolio

radialglo version 2

Introduction

I recently relaunched my portfolio! My site is currently runs on Amazon EC2 which is a service that Amazon provides that allows users to rent virtual computers to run their own applications. The backend of my application runs on express, a web application framework for node. My client side code is written using Guac, a framework I wrote modeled after jQuery after studying its source code. This framework is still under active development.

In this post I will talk about my NodeJS production environment on Amazon EC2.

How EC2 fits into Scalable Web Architecture

Usually when building scalable web architecture, you will have multiple instances of your application behind load balancers. Below the web server/application layer is the persistence layer that runs a database management system. Finally, since roughly 80-90% of the end-user response time is spent downloading static components in the page (Performance Golden Rule.), a Content Delivery Network is used to distribute static content. A CDN manages servers in multiple geographically distributed locations, stores copies of the videos (and other types of Web content, including documents, images, and audio) in its servers, and attempts to direct each user request to a CDN location that will provide the best user experience.

Read here for more on Scaling Internet Applications.

Web Application Hosting Architecture

Amazon’s getting started with AWS highlights a sample web application designed in the manner described above. From their website:

In this diagram, Amazon EC2 instances run the application and web server and belong to an Amazon EC2 Security Group.
The Amazon EC2 Security Group acts as an exterior firewall for the Amazon EC2 instances.
An Auto Scaling group is used to maintain a fleet of Amazon EC2 instances that can handle the presented load.
This Auto Scaling group spans over multiple Availability Zones to protect against potential failures if an Availabilty Zone becomes unavailable.
To ensure that traffic is distributed evenly among the Amazon EC2 instances, an Elastic Load Balancer is associated with the Auto Scaling group.
If the Auto Scaling group launches or terminates instances based on load, then the Elastic Load Balancer will automatically adjust accordingly.
The database tier consists of Amazon RDS database instances, including master and local slave, located in multiple Availability Zones for failover protection.
Amazon RDS provides automated backups to Amazon S3. Amazon S3 stores backups and static content.
Since the consumers of this application may be globally distributed or a large number may visit the site at one time, high volume static content is edge cached using Amazon CloudFront for better performance.
Amazon Route 53 can be used to provide secure and reliable routing to your infrastructure that uses Amazon Web Services.

Source

My personal website, radialglo, operates at a small scale and simply use Amazon EC2 to run my web and application server. Since my site recieves relatively low traffic, I currently don’t use load balancers, and to minimize costs I currently don’t use a CDN.

Create AWS account

If you haven’t already create an Amazon Web Services account. Please note that there is a free usage tier for the first 12 months after you sign up for AWS.

Setting up an Amazon EC2 instance

EC2 Management Console

After setting up your AWS account, you will need to choose the type of AMI you want to run.

Choose an AMI

An AMI (Amazon Machine Image) is a template that contains the software configuration (operating system, application server, and applications) required to launch your instance. You can select an AMI provided by AWS, our user community, or the AWS Marketplace; or you can select one of your own AMIs.

Essentially you choose the type of operating system you want to run, and create an instance of that operating system. A similar analogy would be purchasing a MacBook Air which is an instance of the Mac OS X operating system. At the time of the writing I selected Ubuntu 13.10 (Saucy Salamander) Server. as my AMI.

Difference Between Desktop and Server Images

The server image is a stripped down version of the desktop image with additional server software such as Apache 2. Ths additional software allows other computers/machines to communicate with your server. The server also does not contain a GUI(graphical user interface) for security and performance reasons.

More from the ubuntu documentation.

1. The first difference is in the CD contents. The “Server” CD avoids including what Ubuntu considers desktop packages (packages like X, Gnome or KDE), but does include server related packages (Apache2, Bind9 and so on). Using a Desktop CD with a minimal installation and installing, for example, apache2 from the network, one can obtain the exact same result that can be obtained by inserting the Server CD and installing apache2 from the CD-ROM.

2. The Ubuntu Server Edition installation process is slightly different from the Desktop Edition. Since by default Ubuntu Server doesn’t have a GUI, the process is menu driven, very similar to the Alternate CD installation process.

3. Before 12.04, Ubuntu server installs a server-optimized kernel by default. Since 12.04, there is no difference in kernel between Ubuntu Desktop and Ubuntu Server since linux-image-server is merged into linux-image-generic.

4. For Ubuntu LTS releases before 12.04, the Ubuntu Desktop Edition only receives 3 years of support. This was increased to 5 years in Ubuntu LTS 12.04 In contrast, all Ubuntu LTS Server Edition releases are supported for 5 years.

Choose an Instance Type

After selecting your AMI, choose an instance type.

Instance types have varying CPU, memory, storage, and networking capacity which gives you the flexibility to choose the appropriate mix of resources for your applications Since I’m running low traffic website, I used the t1.micro instance which is part of the free eligibility tier.

Choose an Instance Type

For steps 3 and 4 in the dashboard, I used the default instance and storage configurations. I also skipped step 5 for tagging instances, because I am currently running on instance.

Security Groups

A security group defines firewall rules for your instances. These rules specify which incoming network traffic should be delivered to your instance (e.g., accept web traffic on port 80). All other traffic is ignored. You can modify rules for a group at any time. The new rules are automatically enforced for all running instances. For more information about security groups, go to Using Security Groups in the Amazon Elastic Compute Cloud (Amazon EC2). Security Groups Instance Page

Logging into Your EC2 Instance

You must use key-based authentication to login to your Amazon EC2 Instance. This allows you to securely access your instance without a password.

You can also import your own key pairs to your Amazon instance. For more refer to EC2 Key Pair Documentation

On a Linux/Unix instance, the public key content is placed in an entry within ~/.ssh/authorized_keys. After you have created/downloaded your private key pair you can ssh into your server using that private key ssh -i ~/.ssh/your_private_key remote_user@remote_host

I added my EC2 instance to my user ssh configuration file in my local development environment located at ~/.ssh/config.

1
2
3
4
Host awshost
    HostName 11.111.111.111
    User bob
    IdentityFile /Users/bob/.ssh/id_rsa

Now I can simply ssh into my EC2 instance with the command ssh awshost.

You can also add a bash alias ~/.bash_aliases for issuing this command. For example:

1
alias ssh_server="ssh awshost"

Port Forwarding

Before proceeding make sure you that the security group for your instance has been configured to accept HTTP traffic on port 80.

Why port forward

Running with superuser privileges (in order to bind the port) may be a security risk to the host, therefore port forwarding is used to redirect a low-numbered port to another high-numbered port, so that application software may execute as a common operating system user with reduced privileges. Standard practices say no non-root process gets to talk to the Internet on a port less than 1024.

Use case for port forwarding

Express (the web application framework for node) is capable of performing everything that is expected of a modern web server, such as logging requests, HTTPS, serving files and so on.

If you are running a small application it may make sense to have your node application double up as a web and application server. This is where port forwarding comes in. Because I ran my application as both web and application server, giving root access is not ideal because my application server should not need root permissions.

However, if you are building a large scalable, application you should put a reverse proxy in front of the application server. More regarding reverse proxies will be discussed below.

Enable port forwarding

The /etc/sysctl.conf file allows you to configure various Linux networking and system settings.

No settings where enabled for my EC2 Instance by default. Running cat /proc/sys/net/ipv4/ip_forward will print 1 if forwarding is enabled.

Now we want to edit /etc/syctl.conf to enabled port forwarding.

sudo vim /etc/sysctl.conf

In this file, uncomment this line:

net.ipv4.ip_forward

This will enable ip forwarding. Then, to enable the changes made in sysctl.conf:

sudo sysctl -p /etc/sysctl.conf loads the values from the file we just edited. Now, let’s check that ip forwarding is enabled:

cat /proc/sys/net/ipv4/ip_forward This should print 1.

How to port forward

Kent Brewster at Pinterest wrote a useful gist for getting node to talk to port 80. Here are the steps I went through.

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
// First list out configuration for IP table
sudo iptables -t nat -L -n -v

// -t nat => we are modifying the nat(Network Address Translation) table
// -n => use numeric output
// -v => use verbose to output exact rules

// Output showing no routing options
Chain PREROUTING (policy ACCEPT 21 packets, 1296 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain INPUT (policy ACCEPT 21 packets, 1296 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 43 packets, 3815 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 43 packets, 3815 bytes)
pkts bytes target     prot opt in     out     source               destination

// Redirect TCP port 80 to port 3000

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j  REDIRECT --to-ports 3000

// Output table again to verify that configuration worked
sudo iptables -t nat -L -n -v

Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target     prot opt in     out     source               destination
6   384 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:80 redir ports 3000

Chain INPUT (policy ACCEPT 6 packets, 384 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 2 packets, 178 bytes)
pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 2 packets, 178 bytes)
pkts bytes target     prot opt in     out     source               destination

Reverse Proxy - an alternative to port forwarding

A reverse proxy manages inbound request from the internet and manages connections within your servers, where as forward proxies filters outbound connections from clients.

More specifically from the Apache mod_proxy documentation:

An ordinary forward proxy is an intermediate server that sits between the client and the origin server. In order to get content from the origin server, the client sends a request to the proxy naming the origin server as the target and the proxy then requests the content from the origin server and returns it to the client. The client must be specially configured to use the forward proxy to access other sites.

A typical usage of a forward proxy is to provide Internet access to internal clients that are otherwise restricted by a firewall.

As standard practice in the industry, you should put reverse proxies in front of the application server to load balance and scale the app.

A reverse proxy (or gateway), by contrast, appears to the client just like an ordinary web server. No special configuration on the client is necessary. The client makes ordinary requests for content in the name-space of the reverse proxy. The reverse proxy then decides where to send those requests, and returns the content as if it was itself the origin.

According to this article written by Citrix, reverse proxies are also particularly good for application delivery including:

  • Load Balancing (TCP Multiplexing)
  • SSL Offload/Acceleration (SSL Multiplexing)
  • Caching
  • Compression
  • Content Switching/Redirection
  • Application Firewall
  • Server Obfuscation
  • Authentication
  • Single Sign On

reverse proxy

Source

I currently have not set up a reverse proxy, but am looking into setting one up in the next iteration.

Setting Up Git for Deployment

If you need a refresher on Git I would recommend talking a look at Atlassian’s Git Tutorials and the Git book.

My code deployment is adapted from Getting Git on a Server from the the Git book and http://toroid.org//ams/git-website-howto.

The gists of my setup is to create a create a bare repository for shared users to check in their code and a separate working directory( a single checkout of one version of the project ) that is populated with code from the bare repository via a post-recieve hook.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// On the server, create a new repository to mimic the local one
git init --bare radialglo.git

// initialize a detached workign directory
mkdir app

// Create a post-recieve hook, that updates the code in the app, and restarts the app server
// vim radialglo.git/hooks/post-recieve

#!/bin/bash
APP_DIR="app"
// note that our working tree is not in the same directory as our bare repostiory
git --work-tree=$APP_DIR checkout -f
cd $APP_DIR
forever stopall
// install production dependencies and restart server
npm i --production && forever start app.js

Setting up NodeJS

For more information regarding installing node via package manager refer to documentation here.

I installed node on Ubuntu 13.10.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
sudo apt-get install nodejs

// verify nodejs works
nodejs -v // => v0.10.15

// symlink node to nodejs, /usr/bin/node to /usr/bin/nodejs
sudo ln -s /usr/bin/nodejs /usr/bin/node

// verify symlink works
node -v // => v0.10.15

// install node package manager
sudo apt-get install npm
// verify npm works
npm -v // 1.4.7

Linkedin wrote a great article for performance tips for NodeJS.

Setting up Express

First let’s install express.

1
npm i --save express

--save saves meta data regarding your dependencies (name and version number) into a dependency management file called package.json. Using the flag --save-dev saves the dependencies as development dependencies. The package.json file is really convenient because you don’t need to save your

A middleware is a JavaScript function to handle HTTP requests to an Express app. It can manipulate the request and the response objects or perform an isolated action, or terminate the request flow by sending a response to the client, or pass on the control to the next middleware (from Express Web Application Development ).

I am currently using Express 4 which is quite bare bones in comparison to Express 3 because it no longer comes with bundled middleware.

My package.json for development looks like this:

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
{
  "name": "Radialglo",
  "version": "0.1.0",
  "author": "asu",
  "private": true,
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-watch": "*",
    "grunt-contrib-jshint": "~0.6.3",
    "grunt-contrib-uglify": "*",
    "grunt-contrib-cssmin": "*",
    "grunt-contrib-sass": "*",
    "grunt-cssc": "*",
    "grunt-htmlhint": "*",
    "load-grunt-tasks": "~0.2.0",
    "grunt-contrib-concat": "~0.4.0",
    "grunt-shell": "~0.6.4"
  },
  "dependencies": {
    "normalize.css": "~3.0.1",
    "express": "~4.0.0",
    "compression": "~1.0.1",
    "forever": "~0.11.0",
    "marked": "~0.3.2",
    "path": "~0.4.9",
    "jade": "~1.3.1",
    "body-parser": "~1.0.2"
  }
}

Some useful packages include compression and body-parser.

As previously mentioned, Node can also serve as a web server. For example, Node serves static content. compress is used to gzip static content before it is returned to the user:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

var express = require('express'),
    app = express(),
    compress = require('compression')(),
    ...;

// set the maxAge for one day specified in seconds for cache-control
// From rfc 2616
// When the max-age cache-control directive is present in a cached response, 
// the response is stale if its current age is greater than the age value given (in seconds) 
// at the time of a new request for that resource. The max-age directive on a response implies that
// the response is cacheable (i.e., "public") unless some other, more restrictive cache directive is also present.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

app.use(compress);

// expose the static directory
app.use(express.static(__dirname + '/public', { maxAge: 86400 }));
Templating

To decouple the output representation, I used Jade, a templating language to handle the view.

npm --save express to install express.

1
2
3
4
5
// set templating engine for express
app.set('view engine', 'jade');

// set view directory
app.set('views', './views');
AWS SDK for JavaScript

Amazon also provides an AWS Software Development Kit for NodeJS. This provides opportunities to build more complex applications.

I learned a lot from developing version 2 of radiaglo.com, and for next iteration look to experimenting more with other services provided by AWS such as S3 as well as configuring servers (nginx in particular).

Attribute Nodes of HTML Elements

Context

The following question was asked recently on Piazza

Do JavaScript event attributes (in addition to other HTML attributes, like “id”, “style”, etc), onclick for example, create non-child attribute nodes of the associated html element?

For example:

Diagram of Question
1
2
3
4
5
6
7
8
9
10
<body id="test" onclick="doSomething();">
    This is <b>a</b> test.
</body>
 
Would this create 7 nodes?
              (onclick)  <--  (body) --> (id)
                             /   |   \
                   ("this is")  (b)  ("test")
                                 |
                               ("a")

Response

Short answer:

Yes

Long Answer:

Yes, but be aware… There are different ways to add event handlers to an element, and not all methods introduce an attribute node. The two ways of adding event handlers by creating an attribute node are

  1. directly in HTML (what you did)
  2. using JavaScript such as the method setAttribute .

However there are still different ways to add event handlers that don’t introduce attribute nodes.

As as side note, there are 5 versions of the the DOM specification (DOM Level 0 -3) and the current version DOM4 also known as the DOM Living Standard (http://dom.spec.whatwg.org/) An interesting to note is that the DOM Level 2 introduced the Events specification http://www.w3.org/TR/DOM-Level-2-Events/events.html

In particular under the section 1.3.2. Interaction with HTML 4.0 event listeners,

“In HTML 4.0, event listeners were specified as attributes of an element. As such, registration of a second event listener of the same type would replace the first listener.The DOM Event Model allows registration of multiple event listeners on a single EventTarget. To achieve this, event listeners are no longer stored as attribute values.

In order to achieve compatibility with HTML 4.0, implementors may view the setting of attributes which represent event handlers as the creation and registration of an EventListener on the EventTarget. The value of useCapture defaults to false. This EventListener behaves in the same manner as any other EventListeners which may be registered on the EventTarget. If the attribute representing the event listener is changed, this may be viewed as the removal of the previously registered EventListener and the registration of a new one. No technique is provided to allow HTML 4.0 event listeners access to the context information defined for each event.

We didn’t really talk about (in class) adding event listeners and the difference between doing it in HTML versus JavaScript, but it’s generally bad practice to introduce event handlers in the HTML, because we want to separate the concerns of our structure(HTML) and our behavior(JavaScript). Otherwise there is too much coupling .(This is also why CSS stylesheets are often used instead of inline CSS). There are also other reasons. This concept is known as unobtrusive JavaScript, and you can read more about this here:http://www.w3.org/wiki/The_principles_of_unobtrusive_JavaScript. Finally let’s illustrate this through some HTML and JavaScript! Copy paste the code below into an .html file, and then open it in a browser. Click on the body and view console to see what exactly happens.

DOM versus DOM Tree
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<!DOCTYPE html>

<html>

<head>

  <script type="text/javascript">



    // dom levels https://developer.mozilla.org/en-US/docs/DOM_Levels

    // DOM Living Standard: http://dom.spec.whatwg.org/

    // http://www.w3.org/wiki/The_principles_of_unobtrusive_JavaScript



    var list = null;

    function log(txt) {

      console.log(list);

      var li = document.createElement("li");

      li.appendChild(document.createTextNode(txt));

      list.appendChild(li);

    }


    window.onload = function() {

      var doc = document,
          body = doc.body;

      // get the list node, when the page loads
      list = doc.getElementById("list");

      body.click();

      console.log(body.attributes["onclick"]); // it exists 
      console.log(body.getAttribute("onclick")); // it exists 


      // remove inline onclick attribute node
      body.removeAttribute("onclick");


      /*

        .attributes is a collection of all attribute nodes registered to the specified node.

        getAttribute is used to get the corresponding attribute node

      */




      // sets onclick attribute but doesn't introduce an attribute node
      body.onclick = function() {

        log("I am not an attribute node. Event added via .onclick");

      }
      body.click();


      console.log(body.getAttribute("onclick")); // null


      // now we can add another event via DOM Level 2 Specification
      // http://www.quirksmode.org/js/events_advanced.html

      body.addEventListener("click",function() {

        log("I am not an attribute node. Event added via addEventListener.");

      });


      body.click();
      console.log(body.getAttribute("onclick")); // null

    }

  </script>

</head>

<body onclick="log('I am an attribute node');">

  <ol id="list">

  </ol>

</body>

</html>

DOM Versus DOM Tree

Context

A fellow classmate asked the following question recently on Piazza

Is the value of a attribute in a element become a node in HTML DOM?
e.g. <a href="good"></a> is “good” a text node or something else?

Unfortunately, I was stumped on the question and decided it was time to finally begin reading the DOM specifications also known as DOM TR(Technical Reports) to get a deeper technical understanding of the DOM.

The current specification is DOM4. The most up to date version of this spec is available as the DOM Living Standard

One of the things I noticed is that many developers use the term DOM in place of where DOM Structure Model or DOM tree should actually be used. This distinction between these two terms is crucial in answering the question.

Response

It’s important to distinguish between the DOM and the DOM tree.

The DOM is a programming API for documents.

According to the spec, The Document Object Model (DOM) is an application programming interface (API) for valid HTML and well-formed XML documents.http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/introduction.html

The DOM tree refers to the structure model of the document(not the DOM).

According to the spec, In this specification, we use the term structure model to describe the tree-like representation of a document. We also use the term “tree” when referring to the arrangement of those information items which can be reached by using “tree-walking” methods; (this does not include attributes). http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/introduction.html

In other words, attribute is considered a node in the DOM(API for documents), but not a node in the DOM tree(structure of documents).

More specifically from the spec, Attr objects inherit the Node interface, but since they are not actually child nodes of the element they describe, the DOM does not consider them part of the document tree. Thus, the Node attributes parentNode, previousSibling, and nextSibling have a null value for Attr objects. http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-637646024

I did a search for HTML DOM, and none of the technical specifications refer to the any specification as HTML DOM, except for W3Schools.Be cautious with the wording of W3Schools http://www.w3schools.com/js/js_htmldom.asp. W3Schools is not affiliated with W3C and can occasionally be incorrect with some of these nuances. There is a site created by some of the industries leading front end engineers discussing this: http://www.w3fools.com/

To answer the question is a text node created for an attribute?, the answer is yes. From the spec, On setting(the node value), this creates a Text node with the unparsed contents of the string. I.e. any characters that an XML processor would recognize as markup are instead treated as literal text. See also the method setAttribute on the Element interface. http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-637646024

Finally some JavaScript to illustrate this!

DOM versus DOM Tree
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
57
58
59
<!DOCTYPE html>
<html>
<body>

<div id="top_bar">
    <div class="top_bar_left clearFix">
      <div class="top_bar_logo"></div>
     </div>
</div>

<script type="text/javascript">

  // https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType
  var NODE_TYPE = {
    ELEMENT: 1,
    ATTR: 2,
    TEXT: 3
    // ...
  };

  console.log ("INSPECTING DOM TREE ...");
      // top navigation bar in piazza
  var top_bar = document.getElementById("top_bar"),
      // get it's children
      // convert array-like NodeList to Array
      children = Array.prototype.slice.call(top_bar.childNodes),
      attr_children_count = 0;

    // iterate all the children of top_bar
    children.forEach(function(child) {
      if (child.nodeType === NODE_TYPE.ATTR) {
        attr_children_count += 1;
      }
      console.log(child);
    });

  // no attribute nodes in DOM tree
  if (attr_children_count === 0) {
    console.log("Attributes are not considered children in the DOM tree");
  }


  console.log ("INSPECTING ATTR NODE ...");
  // now let's inspect the attribute node id
  var id_node = top_bar.getAttributeNode("id"),
      // get it's children
      // convert array-like NodeList to Array
      id_node_children = Array.prototype.slice.call(id_node.childNodes);

  id_node_children.forEach(function(child) {
      // confirm that id node has child text node
      console.log(child.nodeValue); // "top_bar"
      console.log(child.nodeType); // 3 => indicates text node
  });

</script>

</body>
</html>

Note on DOM4

In DOM4, an Attribute object, no longer extends a node object so it is not considered a node in the DOM(API for documents) for the DOM4 Spec. You may also notice that the nodeType ATTRIBUTE_NODE is considered deprecated. https://developer.mozilla.org/en-US/docs/Web/API/Node.nodeType

Ruby Jumpstart

This posts is an introduction to Ruby and aggregates information I have learned from Codeacademy and Programming the World Wide Web and Agile Developement with Rails

Please visit here for a full list of documentation and sources on the ruby language. Another interesting resource is the Ruby’s User Guide, originally written by Yukhiro Matsumoto.


Table of Contents

1 - Origins and Uses of Ruby
2 - Naming Conventions
3 - Scalars
4 - Input and Output
5 - Control Statements
6 - Code Blocks and Iterators
7 - Procs and Lambdas 8 - Control Statements
9 - Fundamentals of Arrays
10 - Hashes
11 - Methods
12 - Sorting
13 - Pattern Matching
14 - Classes
15 - Modules

Origins and Uses of Ruby

Ruby was created in Japan by Yuki “matz” Matsumoto and was publicly released in 1995. Ruby blended parts of his favorite languages (Perl, Smalltalk, Eiffel, Ada, and Lisp) to form a new language that balanced functional programming with imperative programming.[1] Ruby has achieved mass acceptance especially with the quick growth of Rails, the web application framework created by 37signals

One interesting aspect about Ruby is that everything in Ruby is an object meaning that there are instance variables with methods. Recall that in other languages such as C, primitive data types (like integers and characters) are not objects.

1.http://www.ruby-lang.org/en/about/

Everything in Ruby is an object.

Naming Conventions

Local variables, method parameters, and method names should all start with a lower case letter or underscore: box, water_bottle, g6. Instance variables should begin with an “at”@ sign, such as @id, @telephone_number The convention is to use underscores to separate words in a multiword method or variable name water_bottle as opposed to waterBottle.

Class names, module names, and constants muststart with an uppercase letter. By convention they use capitalization, rather than underscores, to distinguish the start of words within the name. Class names look like Object, PurcharseOrder, and LineItem. This naming convention is also known as upper camel case, since the shape of the lettering looks like the humps of camel.

Rails uses symbols to identify things. In particular, symbols are used when naming method parameters and lookingthings up in hashes Symbols are prefixed with colons : like :action or :id

Naming Examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#local variables method parameters
watch
ti89
xbox360
@zip\_code

#Class Names, module names, constants
Shape
MusicInstrument

#symbols
:id
#symbol Example
redirect\_to :action => "edit", :id => params[:id]

# Replace \_ with underscore. Need \ to escape underscore in markdown.

By convention class names, modules names and constants use capitalization to distinguish the start of words within the name. This is known as upper camelcase
because of its shape.

Scalars

Ruby has three categories of datatypes - scalars,arrays and hashes. There are two categories of scalar types numerics and character strings. Recall that everything in Ruby is an object.

Numeric Literals

All numeric data types in Ruby are descendants of the Numeric class. The immediate child classes of Numeric are Float and Integer. The Integer class has two child classes Fixnum and Bignum.
An integer literal that fits into the range of a machine word, which is often 32 bits, is a Fixnum object (minus 1 bit). If the integer exceeds the size of the the Fixnum object then it is coereced into a Bignum object. There is no length limitation(other than the computer’s memory size) on integer literals.

Underscore characters can appear embedded in integer literals, which helps readability.

Underscores in numeric literals
1
2
3
4
5
  1\_000 * 3
   #=> 3000 

  # Replace \_ with underscore. Need \ to escape underscore in markdown.

A numeric literal that has either an embedded decimal point or a following exponent is a Float object and uses the machines double precision floating point architecture. A decimal point must be both preceded and followed by at least one digit so .35 is not valid.You must use 0.35.

A decimal point must be both preceded and followed by at least one digit.

String Literals

All string literals are String. There are two categories of string literals, single quoted and double quoted. Single quoted literals cannot include characters(other than single quote characters) specified with escape characters. You can specify a single quote delimiter by preceding the delimiter with a %q. If the new delimiter is a parantheses, brace, bracket, or a point bracket, the corresponding closing element must be used.

Single quoted strings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


  'It\'s good'
  #=> It\'s good

  'Roses are red, \n violets are blue'
  #=> Roses are red, \n violets are blue

  %q$I don't know$
  #=> 'I don't know'

  %q{You don't know?}
  #=> 'You don't know?'


Double quoted strings differ from single quoted strings in two ways: 1. They can include special characters in escape sequences 2. The values of variables names can be interpolated into a string. With string interpolation a block of code between #{ } is evaluated and then converted into a string.

With string interpolation a block of code between #{ } is evaluated and then converted into a string.

Finally a different delimiter can be used by preceding the delimiter with a %Q.

Double quoted strings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 "That's cool"
 #=> That's cool

 %Q@That's cool@
 #=> That's cool

 "That's \t cool" #escape sequence for tab
 #=> That's     cool

 puts "3 + 3 = #{3 + 3}"
 #=> 3 + 3 = 6

 six = 6
 puts "3 + 3 = #{six}"
 #=> 3 + 3 = 6


Numeric Operators

Most of the operatoirs in Ruby are similar to those in other common languages like + for addition, - for subtraction, * for multiplication, / for division.

Note however that Ruby does not support increment(++) and decrement(–) operators. Note that ** is the exponentiation operator.

Exponentation in Ruby
1
2
3
4
 2 ** 3

 #=> 8

Operators can also serves as methods. * can be used for repetition and + can be used for string concatenation.

String Repetition in Ruby
1
2
3
4
5
 "Hello " * 3

 #=> Hello Hello Hello


Ruby does not support increment and decrement operators.

String Methods

The + symbol and << symbol are used to concatenate strings.

String Concatenation
1
2
3
4
 "Hello" + "World"
 #=> "HelloWorld" 
 "Hello" << "World"
 #=> "HelloWorld"

There are many String methods in Ruby.

Ruby method names can end with an exclamation mark(a bang or mutator method) or a question mark(a predicate method). A bang method changes the object in place. A predicate method indicates that a method is boolean: returns true or false.

A bang method is a method name ending with a ! and changes the the object in place.

Bang Method
1
2
3
4
5
6
7
8
9
10
11
  str = "String"
  #=> "String" 
  str.upcase
  #=> "STRING" 
  str # str is not modified
  => "String"
  str.upcase!
  #=> "STRING" 
  str # str has been modified in place
  #=> "STRING

A few String methods are summarized below.

capitalize Convert first letter to uppercase and the rest to lowercase
chop Removes the last character
chomp removes a new line fro mthe right end, if there is one
upcase converts all of the letters in the object to uppercase
downcase converts all of the letters
strip Removes the spaces on both ends
lstrip Removes the spaces on the left end
rstrip Removes the spaces on the right end
reverse Reverse the characters of the string
swapcase Converts all uppercase letters to lowercase and all lowercase letters to uppercase

Strings can also be accessed by an index where 0 is the first position. If a negative index is used, the index starts at the back where the last character is -1. Strings can also be index like [index,length].

String Indexing Examples
1
2
3
4
5
6
7
8
9
10
 "12345"[0]
 #=> 1

 "12345"[-5]
 #=> 1

 "12345"[-5,3]
 #=> "123" 


Input and Output

Sometimes you may want to work with Ruby on the command line. One way is to run irb on the command line to start the Interactive Ruby Shell and then experimenting with Ruby in the console. You can execute a script by running ruby scriptname The -c flag can be used to check syntax. For a full set of flags run man ruby You can also execute a script by putting #!/usr/bin/env ruby at the top of your script and running your script like so ./scriptname If you use this method make sure that your script is executable by running chmod +x. Generally ruby scripts end with the extension .rb

Output

print is used to output a string. puts behaves like print but adds a newline to the end of output.

Output Exaple
1
2
3
4
5
 print "Hello"
 #Hello => nil 
 puts "Hello"
 #Hello
 #=> nil 

puts behaves like print but adds a newline to the end of output

Input

gets is used to retrieve a line of input from the keyboard. The parsed input is a string, and you can use string methods to filter the string. Use methods such as to_i or to_f to convert the input into an integer or float respectively.

Input Example
1
2
3
4
num = gets.chomp.to\_i
#removes newline character from input and converts input to an integer
#=> 9123 
# Replace \_ with underscore. Need \ to escape underscore in markdown.

Control Statements

Control Statements are used to control execution flow of a program.

Control Expressions

Control Expressions are logical expressions used to for control statments. A relational operator has two operands and an operator Relational Operator

== equals
!= not equals
< less than
> greater than
<= less than or equal to
>= greater than or equal to
<=> Comparator: for a <=> b returns 1 if a > b , -1 if a < b, and 0 if a == b This operator is also very help for sorting.
eql? returns true if parameter and reciever object have same type and value.
equal? returns true if parameter is the same as the reciever object. Effectly checks for same references.

Relational Operators
1
2
3
4
5
6
7
8
9
10
11
12
13
"thunderstorm".eql?("thunderstorm")
 #=> true 

 "thunderstorm".equal?("thunderstorm")
 #=> false 
 # both thunderstorms refer to different objects

 str = "thunderstorm"
 #=> "thunderstorm" 
 str2 = str
 #=> "thunderstorm" 
 str.equal?(str)
 #=>true
Operator Precedence and associativity

Operator precendence specifies the order in which operations should be carried out. The following operators are listed in precedence from greatest to least (in descending order). Operators on the same line have the same precedence. Associativity tells you how to evaluate operations if two or more operators have the same precendence either start evaluating from the left or right. If operators are nonassociative that means that these operators cannot associative with themselves.

Associativity Example
1
2
3
4
  3 + 7 - 4
 #=> 6
 #Left Associativity
 #(3 + 7) -4
Nonassociative Example
1
2
3
 1 < 2 < 3
 # < is a nonassociative operator
 #NoMethodError: undefined method `<' for true:TrueClass

** Right

Operator Precedence
1
2
3
4
 2 ** 2 ** 3

 #=> 256
 # 2 ** ( 2 ** 3) => 2 ** 8

!, unary + and - Right
Here is a pretty interesting article on how to define your own unary operator

Unary Operators
1
2
3
4
--------+-+ 3
#=> -3
-+3
#=> -3

*, /, % Left
+, - Left
& Left
> , <, >= , <= Nonassociative
==, !=, <=> Nonassociative
&& Left
|| Left
=, +=, -=, *=, **=, /=, %=, &=, &&=, ||= Right
not Right
or, and Left

and and or are control-flow modifiers like if and unless

More about using and vs &&

Selection statements

Selection statements are used for conditional branching of execution.

Selection Statements
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    if num == 1
      puts "one"
    elsif num == 2
      puts "two"
    elsif num == 3
      puts "three"
    else
      puts "I don't recognize this number"
    end

    case num
    when 1 then puts "one"
    when  2
      puts "two"
    when 3
      puts "three"
    else
       puts "I don't recognize this number"
    end

The case construct is the equivalent of a switch statement in other programming languages.

The then keyword following the when clauses can be replaced with a newline.

Loop Statements

Loop of statements repeatedly executed until a terminiting condition.

Loops in Ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 i = 10
 loop do
   i -= 1
   next if i % 2 == 1 #continue to next iteration if odd
   print "#{i}" #string interpolation
    break if i <= 0 #terminating condition that breaks out of loop
  end

  #=> 86420

  for num in 1...10 #up to but not including (exclusive)
      print num
  end

  #=> 123456789

  for num in 1..10 #up to including (inclusive)
      print num
  end

  #=> 12345678910

… and .. are range operators for exclusive and inclusive ranges.

next is the equivalent of a continue statement in other programming languages. The program continues to the next iteration of the loop.

Although if statements are fairly common in Ruby Applications, looping constructs are rarely used. Block and iterators often take their place.

In Ruby, looping constructs are rarely used. Instead, block and iterators take their place.

Code Blocks and Iterators

Code Blocks are groups of code between do … end or curly braces {}. By convention do…end is used for multiline blocks where as {} is used for single line blocks. do/end vs curly braces

Iterators are methods used to invoke blocks repeatedly. Note that blocks can accept parameters that are delimited like so |parameter|

times Iterator
1
2
3
4
5
6
7
8
9
10
11
12
10.times{|x| puts x}

# 0
# 1 
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9
each Iterator
1
2
3
4
5
6
7
8
9
10
11
12
fruits = ["apple","rasberry","lemon","cranberry"]

# each element is fruit is passed as an argument to the block
# fruit is variable name of  the parameter in the block
fruits.each {|fruit| puts "#{fruit} pie"}
# apple pie
# rasberry pie
# lemon pie
# cranberry pie

# returns the fruits array
# => ["apple", "rasberry", "lemon", "cranberry"] 
Iterating over Hashes
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
ratings = {
  memento: 3,
  primer: 3.5,
  matrix: 3,
  skyfall: 4,
  uhf: 1,
}

good = ratings.select {|k,ratings| ratings > 3}
#=> {:primer=>3.5, :skyfall=>4} 
#=> is equivalent to { primer: 3.5, skyfall: 4}

ratings = {
  memento: 3,
  primer: 3.5,
  skyfall: 4,
  uhf: 1,
}


ratings.each{|key,value| puts "#{key.capitalize} Ratings: #{value}"}

# Memento Ratings: 3
# Primer Ratings: 3.5
# Skyfall Ratings: 4
# Uhf Ratings: 1

collect is an iterator that applies the block on each element of the array. It creates a new array containing the values returned by the block. If you used the bang method it modifies the array in place.

collect Iterator
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    fruits = ["apple","rasberry","lemon","cranberry"]
#=> ["apple", "rasberry", "lemon", "cranberry"] 
   fruits.collect {|fruit| "#{fruit} pie"}
#=> ["apple pie", "rasberry pie", "lemon pie", "cranberry pie"] 
#note that a new array was created and fruits has stayed the same
   fruits
#=> ["apple", "rasberry", "lemon", "cranberry"] 
   fruits.collect! {|fruit| "#{fruit} pie"}
#=> ["apple pie", "rasberry pie", "lemon pie", "cranberry pie"] 
#note that because we used the bang method fruits has now changed
    fruits
#=> ["apple pie", "rasberry pie", "lemon pie", "cranberry pie"] 
    fruits.collect {|fruit| "#{fruit} pie"}
#=> ["apple pie pie", "rasberry pie pie", "lemon pie pie", "cranberry pie pie"] 

Methods can transfer control to a block and back again. This is can be done using the yield method, which invokes the block with an optional parameter.

Yield
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def yield_num(num)
  puts "inside of method yield_num"
  puts "Yield!"

  yield num
  #passing your own number directly to the block
  yield 20
end

yield_num(5) { |num| puts "Your lucky number is #{num}"}

#=> inside of method yield_num
#=> Yield!
#=> Your lucky number is 5
#=> Your lucky number is 20

Methods can transfer control to a block and back again. This is known as the yield method, which invokes the block with an optional parameter.

Procs and Lambdas

TODO

Proc

Procs are full-fledged objects, so they have all the powers and abilities of objects. (Blocks do not.)

Unlike blocks, procs can be called over and over without rewriting them. This prevents you from having to retype the contents of your block every time you need to execute a particular bit of code.

http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/ http://stackoverflow.com/questions/1435743/why-does-explicit-return-make-a-difference-in-a-proc http://ablogaboutcode.com/2012/01/04/the-ampersand-operator-in-ruby/

lambda

First, a lambda checks the number of arguments passed to it, while a proc does not. This means that a lambda will throw an error if you pass it the wrong number of arguments, whereas a proc will ignore unexpected arguments and assign nil to any that are missing.

Second, when a lambda returns, it passes control back to the calling method; when a proc returns, it does so immediately, without going back to the calling method.

Fundamentals of Arrays

An array is a series of elements. If you have arrays of arrays this is known as a multi-dimensional array. Array elements are indexed by integers with the first element being 0.

Ruby arrays differs from more traditional langauges such as C,C++, and Java because the lenght of an array is dynamic. They can shrinkand grown during program execution. If you’ve worked with C++, this is the same behaviior as a vector.

Generally arrays must store homogenous elements (elements of the same type). However Ruby arrays store heterogenous elements or a mix of elements.

Arrays
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Array.new(5)
#=>[nil, nil, nil, nil, nil] 

Arr.new(5,"fivetimes")
#=> ["fivetimes", "fivetimes", "fivetimes", "fivetimes", "fivetimes"] 

[1,2]
#=> [1, 2] 

[1,2][0] # get the first element from array
#=> 1 


Array.new(5,[1,2])
# => [[1, 2], [1, 2], [1, 2], [1, 2], [1, 2]] 

for-in

One method to loop over an array is to use the for-in statement.

for-in
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
arr = ["one","two","three","four"]

for x in arr
  puts x
end

#=>one
#=>two
#=>three
#=>four

multi = Array.new(5,[1,2])
# => [[1, 2], [1, 2], [1, 2], [1, 2], [1, 2]] 
for arr in multi # get nested array
  print "[ "
  for val in arr # get values from nested array
    print "#{val} "
  end
  puts "]"
end

#=> [ 1 2 ]
#=> [ 1 2 ]
#=> [ 1 2 ]
#=> [ 1 2 ]
#=> [ 1 2 ]

Arrays have an assortment of methods. Some common methods are demoed below.

Array methods
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
[1,2,3,4] + [13] # concatenate the arrays
#=> [1, 2, 3, 4, 13] 

[1,2,3,4] << [13] # append [13] to array
#=> [1, 2, 3, 4, [13]] 

[1,2,3,4] << 13   # append 13 to array
#=> [1, 2, 3, 4, 13] 

arr = [1,2,3,4]
arr.push(13) # adds 13 to right side of array
#=> [1, 2, 3, 4, 13] 

arr.pop # removes first element from right side
#=> 13

arr
#=> [1,2,3,4] 
# 13 is gone!

arr.unshift(13) # adds 13 to left side of array
#=> [13, 1, 2, 3, 4]

arr.shift #remove first element from left side
#=> 13 
arr
#=> [1, 2, 3, 4] 

arr.shift(2) #remove 2 more elements from left side
#=> [1, 2] 
arr
#=> [3, 4]

arr = [1,2,3,4]
arr.reverse
#=> [4, 3, 2, 1] 
arr
#=> [1, 2, 3, 4] #note that the original array has not changed 
arr.reverse!
#=> [4, 3, 2, 1] 
 arr
#=> [4, 3, 2, 1] #note that the original array changed because we called a ! method 

Arrays can also be treated as sets The & operator is used for set intersection, -, for set difference, and |, for set union

Sets
1
2
3
4
5
6
7
8
[1,2,3,4] & [2,45,6,7,8,9] # set intersect
#=> [2] 

[1,2,3,4] - [2,45,6,7,8,9] # set difference
#=> [1, 3, 4] 

[1,2,3,4] | [2,45,6,7,8,9] # set union
#=> [1, 2, 3, 4, 45, 6, 7, 8, 9] 

Hashes

Arrays are indexed by integers. There is another key, value collection called a hash where an object is reference by another object known as a symbol. If you’re coming from a background in JavaScript, PHP, you maybe used to acessing hashes using strings.

Hashes
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
# this is the old syntax for a ruby symbols
# symbols are declared as :symbol
oldnumhash = {
    :four => 4,
    :five =>  5,
    :six => 6
}

oldnumhash.each{|k,v| puts "#{k} maps to #{v}"}
#=> four maps to 4
#=> five maps to 5
#=> six maps to 6

# Ruby 1.9 introduced an even simpler syntax
# Notice that this the colon (:) comes right after the key
numhash = {
    one: 1,
    two: 2,
    three: 3
}

puts numhash[:one]
#=> 1
puts numhash[:two]
#=> 2
puts numhash[:three]
#=> 3

Here is a good description of why symbols are used as hash keys in Ruby

“Using symbols not only saves time when doing comparisons, but also saves memory, because they are only stored once.

Symbols in Ruby are basically “immutable strings” . That means that they can not be changed, and it implies that the same symbol when referenced many times throughout your source code, is always stored as the same entity, e.g. has the same object id.

Strings on the other hand are mutable, they can be changed anytime. This implies that Ruby needs to store each string you mention throughout your source code in it’s separate entity, e.g. if you have a string “name” multiple times mentioned in your source code, Ruby needs to store these all in separate String objects, because they might change later on (that’s the nature of a Ruby string).

If you use a string as a Hash key, Ruby needs to evaluate the string and look at it’s contents (and compute a hash function on that) and compare the result against the (hashed) values of the keys which are already stored in the Hash.

If you use a symbol as a Hash key, it’s implicit that it’s immutable, so Ruby can basically just do a comparison of the (hash function of the) object-id against the (hashed) object-ids of keys which are already stored in the Hash. (much faster)

Notes:

If you do string comparisons, Ruby can compare symbols just by their object ids, without having to evaluate them. That’s much faster than comparing strings, which need to be evaluated.

If you access a hash, Ruby always applies a hash-function to compute a “hash-key” from whatever key you use. You can imagine something like an MD5-hash. And then Ruby compares those “hashed keys” against each other.”

Source: tilo’s answer from http://stackoverflow.com/questions/8189416/why-use-symbols-as-hash-keys-in-ruby

Each object is identified by an integer which can be retrieved using the method .object_id. As mentioned previously only one copy of a symbol exists at a given time, meaning that there exists only one object id for that symbol.

Object id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# note that these string objects are different instances 
  puts "string".object_id
  puts "string".object_id

# these ids are different
#=>79341770
#=>79341710


# note that only one copy of the symbol :symbol exists at a time
puts :symbol.object_id
puts :symbol.object_id

# these ids are the same
#=>192008
#=>192008

Methods

TODO

Sorting

TODO

Pattern Matching

TODO

Classes

TODO

Modules

TODO

Ahoy! Octopress

Ay mate! I recently decided to start blogging about code with octopress as my blogging engine. This blog will focus on documenting my coding ventures. I’ve encountered other file based cms(content management systems) such as kirby and stacey (which run on PHP as opposed to Ruby), but ultimately decided to work with octopress because this framework is designed for Jekyll, the blog aware static site generator that powers Github Pages (so this site can be hosted on github). As an added bonus working with octopress provides beginners a good opportunity to tinker around in a Ruby environment.

Installing octopress on my local machine Ubuntu 11.10 (Oneiric Ocelot) was met with some setbacks which I resolved as describe below:

At the time of installing octopress,a prerequistie for installation was Ruby 1.9.3. I used rvm(Ruby Version Manager) as a utility to download the ruby binary. Unfortunately my installiation failed when running rvm install 1.9.3, so I re-ran the installation command in debug mode to print out additional output to locate the source of this issue.

Ruby Installation in Debug mode
1
rvm install 1.9.3 --debug
Installation Response Snippet
1
2
3
4
5
6
7
8
1.9.3 - install
Searching for binary rubies, this might take some time.
Remote file does not exist https://rvm.io/binaries/ubuntu/11.10/i386/ruby-1.9.3-p392.tar.bz2
Remote file does not exist http://jruby.org.s3.amazonaws.com/downloads/ruby-1.9.3-p392.tar.bz2
Remote file does not exist http://binaries.rubini.us/ubuntu/11.10/i386/ruby-1.9.3-p392.tar.bz2
...
No remote file name found
No binary rubies available for: ubuntu/11.10/i386/ruby-1.9.3-p392.

It turned out the public release 392(p392) binary file for 32-bit Ubuntu 11.10 could not be located from the various urls referenced by rvm and I couldn’t locate the binaries via a Google search either.

After browsing around I also tried a solution that uses ruby-rvm, but also discovered that Ubuntu warps ruby-rvm.

I ended install the head of ruby-1.9.3 and also ruby-2.0.0. So far I have been running octopress on ruby-2.0.0 and have not encountered any issues.

Ruby-head Installation
1
2
rvm install ruby-1.9.3-head --autolibs=3 --debug
#--autolibs=3 automatically installs packages/dependicies needed or that require updates

After downloading the 1.9.3-head and 2.0.0 binaries, I had issues running bundle install (which installs dependencies specified in my Gemfile). The error reported the bundler itself not being installed even though I installed it in the previous command. It turned out that my bundler was installed to a specific gemset and once I installed the bundler to the global gemset, bundle install could be executed.

Installing bundler to global gemset
1
2
3
4
5
bundle install
ERROR: Gem bundler is not installed, run `gem install bundler` first.

rvm gemset use global && gem install bundler
http://stackoverflow.com/questions/12326705/error-gem-bundler-is-not-installed-run-gem-install-bundler-first