Adding a 'context' property to the Checkit constructor options

This change introduces a `context` property on the options passed to the `Checkit` instance. The `context` property is supplied to any custom function-based validations as the third parameter (after the `params` parameter). The use-case this addresses in particular is Checkit-based model validation in BookshelfJS, where we may find ourselves needing more information than is available within the scope of the Checkit validation. 

The issue I was running into was that transactions were causing my application/mocha tests to hang. The culprit was executing another query while a transaction was in progress. To get around this, the validation can pass the current transaction to its validation query - but I needed to be able to pass in more information to the validation to do this. 

As a concrete, standalone example, see the following snippet:

```js
var Bookshelf = require('bookshelf'),
  InMemoryDB = Bookshelf.initialize({
    client: 'sqlite3',
    connection: {
      filename: ':memory:'
    }
  }),
  Promise = require('bluebird'),
  Checkit = require('checkit');

var Model = InMemoryDB.Model.extend({
  initialize: function(){
    this.on('creating', this.validateCreate, this);
    this.on('updating', this.validateUpdate, this);
  },

  creationValidations: { },

  updateValidations: { },

  validateCreate: function(model, attrs, options){
    return Checkit(this.creationValidations, {context: options})
      .run(this.toJSON());
  },
  
  validateUpdate: function(model, attrs, options){
    return Checkit(this.updateValidations, {context: options})
      .run(this.toJSON());
  }
});

var User = Model.extend({
  tableName: 'users',
  creationValidations : {
    email: [{
      rule: function(val, params, context){
        var query = InMemoryDB.knex('users');
        if (context && context.transacting){
          query.transacting(context.transacting);
        }
        
        return query.where('email', '=', val)
          .andWhere('id', '<>', this.target.id)
          .then(function(resp){
            if (resp.length > 0){
              throw new Error('The email address is already in use.');
            }
          });
      }
    }]
  }
});

var UserRelation = Model.extend({
  tableName: 'user_relations'
});

var buildSchema = function(done){
  InMemoryDB.knex.schema.createTable('users', function(table){
    table.integer('id');
    table.string('email');
  })
  .then(function(){
    return InMemoryDB.knex.schema.createTable('user_relations', function(table){
      table.integer('id');
      table.integer('child_id');
      table.integer('parent_id');
    });
  })
  .then(function(){
    done();
  });
};

var destroySchema = function(done){
  InMemoryDB.knex.schema.dropTable('users').then(function(res){
    return InMemoryDB.knex.schema.dropTable('user_relations');
  })
  .then(function(result){
    done();
  });
};

  
beforeEach(buildSchema);
  
afterEach(destroySchema);

describe('transactions', function(){
  
  it('should save everything together when saving in parallel', function(){
    return InMemoryDB.transaction(function(t){
      return Promise.all([
        new User().save({id: 1, email: 'user1@gmail.com'}, {method: 'insert', transacting: t}),
        new User().save({id: 2, email: 'user2@gmail.com'}, {method: 'insert', transacting: t}),
        new UserRelation().save({child_id: 1, parent_id: 2}, {method: 'insert', transacting: t})
      ])
      .then(function(){
        console.log("committing...");
        t.commit();
      })
      .caught(function(err){
        console.log("error saving", err);
        t.rollback();
      })
    });
  });
  
  it('should save everything together when saving in serial', function(){
    return InMemoryDB.transaction(function(t){
      return new User().save({id: 1, email: 'user1@gmail.com'}, {method: 'insert', transacting: t}).then(function(user1){
        console.log("saved user 1");
        return new User().save({id: 2, email: 'user2@gmail.com'}, {method: 'insert', transacting: t});
      })
      .then(function(user2){
        console.log("saved user 2");
        return new UserRelation().save({child_id: 1, parent_id: 2}, {method: 'insert', transacting: t});
      })
      .then(function(relation){
        console.log("saved the relation");
        t.commit();
      })
      .caught(function(err){
        console.log("an error occurred", err);
        t.rollback();
      })
    });
  });
  
  it('should still work fine without a transaction', function(){
    return new User().save({id: 1, email: 'user1@gmail.com'}, {method: 'insert'}).then(function(user1){
      console.log("saved user 1");
      return new User().save({id: 2, email: 'user2@gmail.com'}, {method: 'insert'});
    })
    .then(function(user2){
      console.log("saved user 2");
      return new UserRelation().save({child_id: 1, parent_id: 2}, {method: 'insert'});
    });
  });
  
});
```

In this example, the tests try to insert some users within a transaction block. When the users are saved, their validation functions fire off a query (to check for duplicate emails). Without being able to pass the transaction object, these tests hang. 


I've updated the documentation and included some tests. I also noticed the test-suite was missing test-coverage around function-based validation, so I've included a few of those tests as well. 

Thanks for your consideration.

Alex