ad-hoc, runtime, protocol/interface contract enforcement for javascript
JavaScript CSS
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src
.gitignore
README.md
pom.xml
require-2.1.1.min.js
todos.txt

README.md

protocop

A lightweight tool for ad-hoc, runtime, protocol/interface contract enforcement in javascript . See http://en.wikipedia.org/wiki/Protocol_(object-oriented_programming).

user stories

As an engineer who TDDs javascript code, I want an easy way to enforce contracts on shared components, so that I can trust the "green" when I refactor.

example

// Suppose you have 2 animals

var goodAnimal = {
    specialProperty:"foobar",
    name:"ralph",
	jump:function(){},
	respond:function(name){}
};

var badAnimal = {};


// Define your interface/protocol		
var types =  protocop.createTypeSystem();

var animalType = types.compile(
	"name:string",
	"jump:function",
    "respond:function(string)->string"
);

// We can do static checks against the interfaces
equal(animalType.check(goodAnimal).matches, true);
equal(animalType.check(badAnimal).matches, false);

// We can use assert() to do static checks too
try{
	animalType.assert(badAnimal);
	fail("shouldn't get here because assert will throw an exception");
}catch(e){
	equal(e, 'Found 3 interface violations:\n' +
		    '    1: expected a property named "name"\n' +
		    '    2: expected a property named "jump"\n' +
		    '    3: expected a property named "respond"');
}


// Now let's add dynamic protocol enforcement.
var animal = animalType.dynamic(goodAnimal);

try{
	animal.respond();
	fail("shouldn't get here because we passed an invalid number of arguments");
}catch(e){
	equal(e, "arity problem: expected 1 but was 0");
}

try{
	animal.respond("hi");
	fail("we didn't return anything ... contract violation!");
}catch(e){
	equal(e, "respond(): invalid return type: expected type string but was undefined");
}


// Meanwhile, in test land, let's mock-out the interesting parts of the contract ...
var mockAnimal = animalType.stub({
	respond:function(message){return 2323;}
});


// Oops, we violated our contract!
try{
	mockAnimal.respond(33);
	fail("shouldn't get here because we passed an invalid argument type");
}catch(e){
	equal(e, "respond(): invalid argument #1: expected type string but was number");
}

try{
	mockAnimal.respond("hi");
	fail("shouldn't get here because our mock returned the wrong result type");
}catch(e){
	equal(e, "respond(): invalid return type: expected type string but was number");
}

// Unimplemented stub methods throw a timely exception
try{
	mockAnimal.jump();
	fail("shouldn't get here because we haven't mocked out this method");
}catch(e){
	equal(e, "stub method not implemented: jump()");
}

// Now, for a little "unprotected" code execution... 
types.disable();
try{
	animal.respond();
	animal.respond("hi");
	mockAnimal.respond("hi");
}catch(err){
	fail("Shouldn't get there, since all checks were disabled (" + err + ")");
}

see also