chainlang.create(lang)

requires exactly one argument (representing the new chain language)
expect(callCreateWithNoArgs).to.throwException();
expect(callCreateWithTwoArgs).to.throwException();
returns a chain function for the new language, used to start chained expressions
var newLang = chainlang.create({});
expect(newLang).to.be.a('function');

chainlang.append(obj, path, node)

Adds descendant nodes and all required ancestors to an object (like mkdirp)
var manualCreation = {};
manualCreation.has = {};
manualCreation.has.a = {};
manualCreation.has.a.greatGrandchild = 1;

var convenientCreation = {};
chainlang.append(convenientCreation, 'has.a.greatGrandchild', 1);

expect(manualCreation).to.eql(convenientCreation);

A chain function returned from chainlang.create

Accepts an optional argument, and throws if more than one argument is provided
var chain = chainlang.create({});

expect(
    function(){chain();}
).not.to.throwException();
expect(
    function(){chain({});}
).not.to.throwException();
expect(
    function(){chain({}, {});}
).to.throwException();
Starts a chain of methods bound to a chain object with proxied version of all the language spec fields
var stubLang = {
    topLevelFn: function(){},
    topLevelProp: "someValue",
    secondLevel: {
        fn: function(){},
        prop: "someValue",
        thirdLevel: {
            fn: function(){},
            prop: "someValue"
        }
    }
}

var chainConstructor = chainlang.create(stubLang);

expect(allFieldsOfFirstAppearInSecond(stubLang, chainConstructor())).to.be(true);

A chain object

Implicitly returns itself from all decendant methods
var chain = chainlang.create({
    returnsNothing: function(){
        return;
    },
    levelTwo: {
        returnsNothing: function(){
            return;
        }
    }
});

expect(
    chain().returnsNothing()
).to.eql(
    chain()
);

expect(
    chain().levelTwo.returnsNothing()
).to.eql(
    chain()
);
Will return any explicit return value instead of returning itself implicitly
var chain = chainlang.create({
    returnsSomething: function(){
        return 'something';
    }
});

expect(
    chain().returnsSomething()
).to.eql("something")
contains a "_data" property which can be used to pass data through the chain and is initially empty
var link = chainlang.create({})();
expect(link).to.have.key('_data');

var hasOwnKey = false;
for(var key in link._data){
    if(link._data.hasOwnProperty(key)){
        hasOwnKey = true;
    }
}
expect(hasOwnKey).to.be(false);
contains a "_subject" property, which references the optional parameter to the chain function
var chain = chainlang.create({
    getSubject: function(){
        return this._subject;
    }
});

var actualSubject = {iAm: "theSubject"};

expect(
    chain(actualSubject).getSubject()
).to.be.eql(actualSubject);
allows chaining of methods arbitrarily nested within properties of the language
var chain = chainlang.create(
    {
        addOne : function(){
            this._subject = this._subject + 1;
        },
        secondLevel : {
            addOne : function (){
                this._subject = this._subject + 1;
            },
            thirdLevel : {
                addOne : function(){
                    this._subject = this._subject + 1;
                }
            }                    
        }
    });

expect(
    chain(1).addOne()._subject
).to.be(2);

expect(
    chain(1).addOne().secondLevel.addOne()._subject
).to.be(3);

expect(
    chain(1).addOne().secondLevel.thirdLevel.addOne()._subject
).to.be(3);

expect(
    chain(1).addOne().secondLevel.addOne().secondLevel.thirdLevel.addOne()._subject
).to.be(4);
is bound to "this" for every method call in the chain, even for methods of child objects
var spy = sinon.spy();

var chain = chainlang.create({
    topLevelFn: spy,
    secondLevel: {
        secondLevelFn: spy
    }
});

var theChain = chain();

// Running some methods to spy on their `this` value
chain().topLevelFn().secondLevel.secondLevelFn();

expect(spy.thisValues[0]).to.be.eql(theChain);
expect(spy.thisValues[1]).to.be.eql(theChain);

The _data property of a chain

is initally an empty object
var chain = chainlang.create({});
expect(chain()._data).to.be.eql({});
persists for the life of the chain, and so can be used to share data between non-adjacent links in the chain
var chain = chainlang.create({
    setsData : function(){
        this._data.field = 1;
    },
    doesNothing : function(){
        return;
    },
    readsAndReturnsData: function(){
        return this._data.field;
    }
});

expect(
    chain().setsData().doesNothing().readsAndReturnsData()
).to.be(1);

Any node in the chain object graph

may include child nodes, even if it is a method
var spy = sinon.spy();

var chainSpec = {};
chainSpec.prop = spy; /* spy is a function, so prop is a method */
chainSpec.prop.methodsStillAvailable = function(){
    return true;
}

var chain = chainlang.create(chainSpec);

chain().prop();

expect(spy.called).to.be(true);
expect(chain().prop.methodsStillAvailable()).to.be(true);