Company

About Guide API Docs Git Repo

Company Guide

Key Concepts

Units

In a Company-based application, each component (or module, as they’re referred to in the Modules and Callbacks article) is represented by objects called units, which inherit from the Unit type.

Implicit Mediation

Company uses a special object called the dispatcher as a mediator. The main difference with Company’s dispatcher and simple mediators like the window object is that it is an implicit mediator: units can communicate through Company’s dispatcher without calling it directly. Instead, units use special methods that abstract the dispatcher, which decouples the units themselves.

Publish-Subscribe

Units converse with each other using a simple pubsub-inspired API. Each unit inherits a subscribe method that’s used to hook a callback to other units, as well as a publish method that can be used to broadcast messages to other units.

Company Basics

Creating Units

Units can be created using the Unit constructor, which takes a single optional argument called the descriptor. This snippet creates a new unit object with a greet method:

var unit = new Unit({

	greet: function(name){
		console.log('Hello, ' + name);
	}

});

In order to keep stuff reusable, you can use mixins to add additional functionality to your unit. You can declare mixins using a Uses property in your descriptor:

// Mixins
var ObjectMixin = {
	objMethod: function(){}
};

var ClassMixin = new Class({
	classMethod: function(){}
});

var TypeMixin = new Type('T', function(){}).implement({
	typeMethod: function(){}
});

var UnitMixin = new Unit({
	unitMethod: function(){}
});

// Unit

var unit = new Unit({
	
	Uses: [ObjectMixin, ClassMixin, TypeMixin, UnitMixin]

});

console.log(typeof unit.objMethod); // function;
console.log(typeof unit.classMethod); // function;
console.log(typeof unit.typeMethod); // function;
console.log(typeof unit.unitMethod); // function;

Subscribe and Publish

To make the most out of Company, though, you’ll need to create two or more unit objects. These objects can then talk to each other via the pubsub system through the subscribe and publish methods.

var unitA = new Unit({

	initSetup: function(){
		this.subscribe('greet', this.greet);
	},

	greet: function(name){
		console.log('Hello, ' + name);
	}

});

var unitB = new Unit({

	initSetup: function(){
		this.publish('greet', 'Bobby');
	}

});

The snippet above creates two unit objects. The first unit object, unitA, uses the subscribe method to listen to messages of the type greet. The second unit object unitB, on the other hand, uses publish to broadcast messages to other units.

Units can stop subscribing to messages by calling on the unsubscribe method:

var unitA = new Unit({

	initSetup: function(){
		this.subscribe('greet', this.greet);
	},

	greet: function(name){
		console.log('Hello, ' + name);
		this.unsubscribe('greet', this.greet);
	}

});

var unitB = new Unit({

	initSetup: function(){
		this.publish('greet', 'Bobby');
	}

});

Special Setups

You might have noticed the method above named initSetup. This method is a special setup method that’s understood by the Unit constructor. This method is invoked automatically upon creation of the unit object, and can be used to setup various properties of the current module.

Aside from initSetup, units can also have two other setups methods: readySetup and loadSetup, which are called on domready and on load respectively. This setup methods can be useful for attaching event handlers to your unit’s element assets, which might only be available during the domready or load events.

var unit = new Unit({

	initSetup: function(){
		console.log('This is echoed immediately.');
	},

	readySetup: function(){
		console.log('This is echoed on domready.');
	},

	loadSetup: function(){
		console.log('This is echoed on load.');
	},

});

Variables? Optional!

Because units are self-contained and are meant to talk to one another using the pubsub system, variable referencing is optional.

new Unit({

	initSetup: function(){
		this.subscribe('greet', this.greet);
	},

	greet: function(name){
		console.log('Hello, ' + name);
	}

});

new Unit({

	initSetup: function(){
		this.publish('greet', 'Bobby');
	}

});

In fact, the use of implicit-mediation means that you can make units completely oblivious to one another. Here we have two “private” units:

(function(){
	new Unit({

		initSetup: function(){
			this.subscribe('greet', this.greet);
		},

		greet: function(name){
			console.log('Hello, ' + name);
		}

	});
})();

(function(){
	new Unit({

		initSetup: function(){
			this.publish('greet', 'Bobby');
		}

	});
})();

It is suggested that you use “handler-less” units like these as much as possible to prevent the temptation of calling units directly.

Shared Dispatcher and Prefixes

Each window context has a single, internal dispatcher object used by all units. This means that any unit published message, regardless of the origin, will be broadcasted to all units in the current window context.

// first
(function(){
	new Unit({

		initSetup: function(){
			this.subscribe('greet', this.greet);
		},

		greet: function(name){
			console.log('Hello, ' + name);
		}

	});
})();

// second
(function(){
	new Unit({

		initSetup: function(){
			this.publish('greet', 'Bobby');
		}

	});
})();

// third
(function(){
	new Unit({

		initSetup: function(){
			this.publish('greet', 'Robert');
		}

	});
})();

In this example we have 3 units. Both units two and three publish the same “greet” message, which means that both messages will dispatch the callback from the unit one.

Sometimes though, you might want to differentiate among the messages of each unit. The easiest way to do it would be to use prefixes:

// first
(function(){
	new Unit({

		initSetup: function(){
			this.subscribe('second.greet', this.greet);
		},

		greet: function(name){
			console.log('Hello, ' + name);
		}

	});
})();

// second
(function(){
	new Unit({

		initSetup: function(){
			this.publish('second.greet', 'Bobby');
		}

	});
})();

// third
(function(){
	new Unit({

		initSetup: function(){
			this.publish('third.greet', 'Robert');
		}

	});
})();

Here we prefixed the message types with a descriptor of the unit. We then changed our subscribe code in the first unit to only respond to messages of the second.greet type.

To save typing though, you can declare a string Prefix property in your unit descriptor. The publish method will then automatically prepend this string to the message type:

// first
(function(){
	new Unit({

		initSetup: function(){
			this.subscribe('second.greet', this.greet);
		},

		greet: function(name){
			console.log('Hello, ' + name);
		}

	});
})();

// second
(function(){
	new Unit({

		Prefix: 'second',

		initSetup: function(){
			this.publish('greet', 'Bobby');
		}

	});
})();

// third
(function(){
	new Unit({

		Prefix: 'third',

		initSetup: function(){
			this.publish('greet', 'Robert');
		}

	});
})();

You can get a unit’s prefix using the getPrefix method, and set it via the setPrefix method:

new Unit({

	Prefix: 'unit',

	initSetup: function(){
		console.log(this.getPrefix()); // 'unit'
		this.setPrefix('notunit');
		console.log(this.getPrefix()); // 'notunit'
	}

});

If you want to publish a message from a prefixed unit without the prefix, you can prepend the message type with an exclamation point. This will signal publish to leave the type string alone:

// first
(function(){
	new Unit({

		initSetup: function(){
			this.subscribe('second.greet', this.greet);
		},

		greet: function(name){
			console.log('Hello, ' + name);
		}

	});
})();

// second
(function(){
	new Unit({

		Prefix: 'second',

		initSetup: function(){
			this.publish('greet', 'Bobby');
		}

	});
})();

// third
(function(){
	new Unit({

		Prefix: 'third',

		initSetup: function(){
			this.publish('!second.greet', 'Robert');
		}

	});
})();

Finalized Messages

The publish method allows you to finalize a message by passing true as a third argument to the method:

new Unit({

	Prefix: 'first',

	initSetup: function(){
		this.publish('done', null, true);
	}

});

When you publish a finalized message, the message will be broadcasted to all current subscribers as well as any future subscribers. This is useful for one-off messages that are needed for any current or future subscribers.

Replayed Messages

Finalized messages are controlled by the publishing unit: a message can only be final if the unit declares it as final. Sometimes though, you’ll want to be able to access the last broadcasted message of a type during subscription. This is needed especially for systems where the units will be lazy loaded, and therefore need to catch up on the last broadcasted message.

A simple answer to this is to use message replays during subscription. To do this, you’ll have to prefix the message type argument to the subscribe call with an exclamation point:

// first
(function(){
	new Unit({

		Prefix: 'first',

		initSetup: function(){
			this.publish('greet', 'Bobby');
		}

	});
})();

// second
(function(){
	new Unit({

		initSetup: function(){
			this.subscribe('!first.greet', this.greet);
		},

		greet: function(name){
			console.log('Hello, ' + name);
		}

	});
})();

Here the first module publishes a non-finalized message called first.greet upon initialization. The second module, on the other hand, uses message replay by prefixing the message type with an exclamation point. This not only makes the second module listen to subsequent broadcasts but also immediately executes the callback with the arguments from the last executed broadcast.

Detaching and Attaching

You can temporarily pause units by calling on the detachUnit method:

new Unit({

	initSetup: function(){
		this.detachUnit();
		this.subscribe('second.greet', this.greet);
	},

	greet: function(name){
		console.log('Hello, ' + name);
	}

});

When a unit is detached, it is disconnected from the dispatcher. This means that it can call on its subscribe and publish methods, but it won’t be able to receive nor broadcast messages from and to other units.

You can use the isAttached method to check if a unit is currently connected to the dispatcher:

new Unit({

	initSetup: function(){
		this.detachUnit();
		console.log(this.isAttached()); // false
		this.subscribe('second.greet', this.greet);
	},

	greet: function(name){
		console.log('Hello, ' + name);
	}

});

When you’re ready to reconnect your mediator, you can use the attachUnit method:

new Unit({

	initSetup: function(){
		this.detachUnit();
		console.log(this.isAttached()); // false
		this.subscribe('second.greet', this.greet);

		var self = this;
		setTimeout(function(){
			self.attachUnit();
			console.log(self.isAttached()); // true
		}, 5000);
	},

	greet: function(name){
		console.log('Hello, ' + name);
	}

});

Company For All

Decorating Objects

While units are the primary building blocks of Company-based applications, there are times when you can’t create real unit objects. An example is when you need to use class instances in your application.

Company allows you to transform any kind of object as a unit through decoration, using the Unit.decorate generic. This generic function takes any object as an argument and returns a “unit-like” object:

// a regular unit
var unit = new Unit({
	
	initSetup: function(){
		this.subscribe('request.success', this.onData);
	},

	onData: function(xml, text){
		console.log(text);
	}

});
// a class instance
var request = new Request({
	url: 'somepage.php'
});

// decorate the instance
Unit.decorate(request).setPrefix('request');

request.send();

Unit-like objects have all the functionality of regular unit objects–they can subscribe to other unit’s messages and they can broadcast messages to all other units.

The reverse function for Unit.decorate is Unit.undecorate, and it removes any unit-related functionality from an object.

fireEvent Wrapping and Unwrapping

An object decorated by Unit.decorate will automatically get its fireEvent methods wrapped to also call publish. This is done so that any events fired by the object will also be broadcasted through the dispatcher.

If you don’t want the fireEvent method to be wrapped automatically, you can pass true as a second argument to Unit.decorate. This bypasses the wrapping:

// a regular unit
var unit = new Unit({
	
	initSetup: function(){
		this.subscribe('request.success', this.onData);
	},

	onData: function(xml, text){
		console.log(text);
	}

});
// a class instance
var request = new Request({
	url: 'somepage.php'
});

// decorate the instance
Unit.decorate(request, true).setPrefix('request');

request.send(); // this will not be broadcasted

You can explicitly wrap or unwrap an object’s fireEvent method using the Unit.wrapEvents and Unit.unwrapEvents functions respectively.

Unit With Classes

Company exports the Unit constructor as a type and not as a class. In normal MooTools usage, classes cannot subclass types or use them as mixins. Unit, however, is an exception because it’s implemented with a class-like constructor, which means that you can use Unit in custom classes.

// Subclassing
var UnitSub = new Class({

	Extends: Unit,

	Prefix: 'unitsub'

	initialize: function(){
		this.setupUnit();
		this.publish('hello', 'Bobby');
	}

});

// Mixin
var UnitMix = new Class({

	Implements: Unit,

	Prefix: 'unitmix'

	initialize: function(){
		this.setupUnit();
		this.publish('hello', 'Bobby');
	}

});

Take note how the setupUnit method is invoked in the initialize method of both classes. Because Unit is a type and not a class, you need to set it up explicitly using this method in order for it to work.

Keeping Company

You can learn more about the various methods and functions available from Company by checking out the API Docs