mirror of
https://github.com/kbparagua/paloma
synced 2023-03-27 23:21:17 -04:00
Merge pull request #92 from kbparagua/controller-factory-rework
Controller factory rework
This commit is contained in:
commit
9221b07d38
7 changed files with 250 additions and 158 deletions
|
@ -1,104 +1,49 @@
|
||||||
describe('Paloma.ControllerBuilder', function(){
|
describe('Paloma.ControllerBuilder', function(){
|
||||||
|
|
||||||
var _builder = null;
|
var TestController = Paloma.controller('Test');
|
||||||
function builder(){ return _builder; }
|
|
||||||
|
|
||||||
function newBuilder(){
|
|
||||||
_builder = new Paloma.ControllerBuilder();
|
|
||||||
return _builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
describe('#build(options)', function(){
|
||||||
|
|
||||||
describe('#build(controllerAndParent, prototype)', function(){
|
describe('when options.controller has no match', function(){
|
||||||
describe('when controller is not yet existing', function(){
|
var factory = {get: function(controller){ return null; }},
|
||||||
it('creates a new controller', function(){
|
builder = new Paloma.ControllerBuilder(factory);
|
||||||
var controller = newBuilder().build('MyController'),
|
|
||||||
instance = new controller();
|
|
||||||
|
|
||||||
expect(instance instanceof Paloma.BaseController).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when prototype is present', function(){
|
|
||||||
it('adds the prototype to the controller', function(){
|
|
||||||
var controller = newBuilder().build('MyController', {a: 100});
|
|
||||||
|
|
||||||
expect(controller.prototype.a).toEqual(100);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when parent is present', function(){
|
|
||||||
it('creates a subclass of that parent', function(){
|
|
||||||
var parent = newBuilder().build('Parent'),
|
|
||||||
child = builder().build('Child < Parent');
|
|
||||||
|
|
||||||
var controller = new child();
|
|
||||||
expect(controller instanceof parent).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when controller is already existing', function(){
|
|
||||||
it('returns the existing controller', function(){
|
|
||||||
var controller = newBuilder().build('test2');
|
|
||||||
expect( builder().build('test2') ).toEqual(controller);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when prototype is present', function(){
|
|
||||||
var controller = newBuilder().build('Test', {number: 9});
|
|
||||||
builder().build('Test', {number: 10});
|
|
||||||
|
|
||||||
it('updates the current prototype', function(){
|
|
||||||
expect(controller.prototype.number).toEqual(10);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when parent is present', function(){
|
|
||||||
var oldParent = newBuilder().build('OldParent'),
|
|
||||||
newParent = builder().build('NewParent');
|
|
||||||
|
|
||||||
describe('when no previous parent', function(){
|
|
||||||
var child = builder().build('ChildA');
|
|
||||||
builder().build('ChildA < NewParent');
|
|
||||||
|
|
||||||
var instance = new child();
|
|
||||||
|
|
||||||
it('assigns the new parent', function(){
|
|
||||||
expect(instance instanceof newParent).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('when has previous parent', function(){
|
|
||||||
var child = builder().build('ChildB < OldParent');
|
|
||||||
builder().build('ChildB < NewParent');
|
|
||||||
|
|
||||||
var instance = new child();
|
|
||||||
|
|
||||||
it('updates removes the oldParent', function(){
|
|
||||||
expect(instance instanceof oldParent).toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('assigns the new parent', function(){
|
|
||||||
expect(instance instanceof newParent).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('#get(name)', function(){
|
|
||||||
describe('when name has no match', function(){
|
|
||||||
it('returns null', function(){
|
it('returns null', function(){
|
||||||
expect( newBuilder().get('unknown') ).toBeNull();
|
var options = {controller: 'Test', action: 'show'};
|
||||||
|
expect( builder.build(options) ).toBeNull();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when name has match', function(){
|
describe('when options.controller has a match', function(){
|
||||||
it('returns the matched controller', function(){
|
var factory = {get: function(controller){ return TestController; }},
|
||||||
var controller = newBuilder().build('myController');
|
builder = new Paloma.ControllerBuilder(factory);
|
||||||
expect( builder().get('myController') ).toEqual(controller);
|
|
||||||
|
var options = {
|
||||||
|
controller: 'Test',
|
||||||
|
action: 'show',
|
||||||
|
params: {a: 1, b: 2}
|
||||||
|
};
|
||||||
|
|
||||||
|
var controller = builder.build(options);
|
||||||
|
|
||||||
|
it('returns a new instance of the controller class', function(){
|
||||||
|
expect(controller instanceof TestController).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("initializes controller instance's params", function(){
|
||||||
|
var expectedParams = {_controller: 'Test', _action: 'show', a: 1, b: 2};
|
||||||
|
var correct = true;
|
||||||
|
|
||||||
|
for (var k in expectedParams){
|
||||||
|
if (controller.params[k] != expectedParams[k])
|
||||||
|
correct = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(correct).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
104
test_app/spec/javascripts/controller_class_factory_spec.js
Normal file
104
test_app/spec/javascripts/controller_class_factory_spec.js
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
describe('Paloma.ControllerClassFactory', function(){
|
||||||
|
|
||||||
|
var _factory = null;
|
||||||
|
function factory(){ return _factory; }
|
||||||
|
|
||||||
|
function newFactory(){
|
||||||
|
_factory = new Paloma.ControllerClassFactory();
|
||||||
|
return _factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
describe('#make(controllerAndParent, prototype)', function(){
|
||||||
|
describe('when controller is not yet existing', function(){
|
||||||
|
it('creates a new controller', function(){
|
||||||
|
var controller = newFactory().make('MyController'),
|
||||||
|
instance = new controller();
|
||||||
|
|
||||||
|
expect(instance instanceof Paloma.BaseController).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when prototype is present', function(){
|
||||||
|
it('adds the prototype to the controller', function(){
|
||||||
|
var controller = newFactory().make('MyController', {a: 100});
|
||||||
|
|
||||||
|
expect(controller.prototype.a).toEqual(100);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when parent is present', function(){
|
||||||
|
it('creates a subclass of that parent', function(){
|
||||||
|
var parent = newFactory().make('Parent'),
|
||||||
|
child = factory().make('Child < Parent');
|
||||||
|
|
||||||
|
var controller = new child();
|
||||||
|
expect(controller instanceof parent).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when controller is already existing', function(){
|
||||||
|
it('returns the existing controller', function(){
|
||||||
|
var controller = newFactory().make('test2');
|
||||||
|
expect( factory().make('test2') ).toEqual(controller);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when prototype is present', function(){
|
||||||
|
var controller = newFactory().make('Test', {number: 9});
|
||||||
|
factory().make('Test', {number: 10});
|
||||||
|
|
||||||
|
it('updates the current prototype', function(){
|
||||||
|
expect(controller.prototype.number).toEqual(10);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when parent is present', function(){
|
||||||
|
var oldParent = newFactory().make('OldParent'),
|
||||||
|
newParent = factory().make('NewParent');
|
||||||
|
|
||||||
|
describe('when no previous parent', function(){
|
||||||
|
var child = factory().make('ChildA');
|
||||||
|
factory().make('ChildA < NewParent');
|
||||||
|
|
||||||
|
var instance = new child();
|
||||||
|
|
||||||
|
it('assigns the new parent', function(){
|
||||||
|
expect(instance instanceof newParent).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when has previous parent', function(){
|
||||||
|
var child = factory().make('ChildB < OldParent');
|
||||||
|
factory().make('ChildB < NewParent');
|
||||||
|
|
||||||
|
var instance = new child();
|
||||||
|
|
||||||
|
it('updates removes the oldParent', function(){
|
||||||
|
expect(instance instanceof oldParent).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('assigns the new parent', function(){
|
||||||
|
expect(instance instanceof newParent).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#get(name)', function(){
|
||||||
|
describe('when name has no match', function(){
|
||||||
|
it('returns null', function(){
|
||||||
|
expect( newFactory().get('unknown') ).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when name has match', function(){
|
||||||
|
it('returns the matched controller', function(){
|
||||||
|
var controller = newFactory().make('myController');
|
||||||
|
expect( factory().get('myController') ).toEqual(controller);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -1,61 +1,34 @@
|
||||||
Paloma.ControllerBuilder = function(){
|
Paloma.ControllerBuilder = function(classFactory){
|
||||||
this._controllers = {};
|
this.classFactory = classFactory;
|
||||||
this._inheritanceSymbol = '<';
|
this.options = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
Paloma.ControllerBuilder.prototype = {
|
Paloma.ControllerBuilder.prototype = {
|
||||||
|
|
||||||
build: function(controllerAndParent, prototype){
|
build: function(options){
|
||||||
var parts = this._extractParts(controllerAndParent),
|
this.options = options;
|
||||||
controller = this._getOrCreate( parts.controller );
|
|
||||||
|
|
||||||
this._updatePrototype(controller, prototype);
|
var ControllerClass = this._controllerClass();
|
||||||
this._updateParent(controller, parts.parent);
|
if ( !ControllerClass ) return null;
|
||||||
|
|
||||||
return controller;
|
return new ControllerClass( this._buildParams() );
|
||||||
},
|
},
|
||||||
|
|
||||||
get: function(name){
|
_controllerClass: function(){
|
||||||
return this._controllers[name] || null;
|
return this.classFactory.get( this.options.controller );
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateParent: function(controller, parent){
|
_buildParams: function(){
|
||||||
if (!parent) return;
|
var params = {
|
||||||
|
_controller: this.options.controller,
|
||||||
var parentClass = this.get(parent);
|
_action: this.options.action
|
||||||
if (parentClass) controller.prototype.__proto__ = parentClass.prototype;
|
|
||||||
},
|
|
||||||
|
|
||||||
_updatePrototype: function(controller, newPrototype){
|
|
||||||
for (var k in newPrototype)
|
|
||||||
if (newPrototype.hasOwnProperty(k))
|
|
||||||
controller.prototype[k] = newPrototype[k];
|
|
||||||
},
|
|
||||||
|
|
||||||
_getOrCreate: function(name){
|
|
||||||
return this.get(name) || this._create(name);
|
|
||||||
},
|
|
||||||
|
|
||||||
_create: function(name){
|
|
||||||
var controller = function(params){
|
|
||||||
Paloma.BaseController.call(this, params);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
controller.prototype.__proto__ = Paloma.BaseController.prototype;
|
for (var k in this.options.params)
|
||||||
|
if (this.options.params.hasOwnProperty(k))
|
||||||
|
params[k] = this.options.params[k];
|
||||||
|
|
||||||
this._controllers[name] = controller;
|
return params;
|
||||||
return controller;
|
|
||||||
},
|
|
||||||
|
|
||||||
_extractParts: function(controllerAndParent){
|
|
||||||
var parts = controllerAndParent.split( this._inheritanceSymbol );
|
|
||||||
|
|
||||||
var controller = parts[0].trim(),
|
|
||||||
parent = parts[1];
|
|
||||||
|
|
||||||
if (parent) parent = parent.trim();
|
|
||||||
|
|
||||||
return {controller: controller, parent: parent};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
61
vendor/assets/javascripts/paloma/controller_class_factory.js
vendored
Normal file
61
vendor/assets/javascripts/paloma/controller_class_factory.js
vendored
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
Paloma.ControllerClassFactory = function(){
|
||||||
|
this._controllers = {};
|
||||||
|
this._inheritanceSymbol = '<';
|
||||||
|
};
|
||||||
|
|
||||||
|
Paloma.ControllerClassFactory.prototype = {
|
||||||
|
|
||||||
|
make: function(controllerAndParent, prototype){
|
||||||
|
var parts = this._extractParts(controllerAndParent),
|
||||||
|
controller = this._getOrCreate( parts.controller );
|
||||||
|
|
||||||
|
this._updatePrototype(controller, prototype);
|
||||||
|
this._updateParent(controller, parts.parent);
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
},
|
||||||
|
|
||||||
|
get: function(name){
|
||||||
|
return this._controllers[name] || null;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateParent: function(controller, parent){
|
||||||
|
if (!parent) return;
|
||||||
|
|
||||||
|
var parentClass = this.get(parent);
|
||||||
|
if (parentClass) controller.prototype.__proto__ = parentClass.prototype;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updatePrototype: function(controller, newPrototype){
|
||||||
|
for (var k in newPrototype)
|
||||||
|
if (newPrototype.hasOwnProperty(k))
|
||||||
|
controller.prototype[k] = newPrototype[k];
|
||||||
|
},
|
||||||
|
|
||||||
|
_getOrCreate: function(name){
|
||||||
|
return this.get(name) || this._create(name);
|
||||||
|
},
|
||||||
|
|
||||||
|
_create: function(name){
|
||||||
|
var controller = function(params){
|
||||||
|
Paloma.BaseController.call(this, params);
|
||||||
|
};
|
||||||
|
|
||||||
|
controller.prototype.__proto__ = Paloma.BaseController.prototype;
|
||||||
|
|
||||||
|
this._controllers[name] = controller;
|
||||||
|
return controller;
|
||||||
|
},
|
||||||
|
|
||||||
|
_extractParts: function(controllerAndParent){
|
||||||
|
var parts = controllerAndParent.split( this._inheritanceSymbol );
|
||||||
|
|
||||||
|
var controller = parts[0].trim(),
|
||||||
|
parent = parts[1];
|
||||||
|
|
||||||
|
if (parent) parent = parent.trim();
|
||||||
|
|
||||||
|
return {controller: controller, parent: parent};
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
37
vendor/assets/javascripts/paloma/engine.js
vendored
37
vendor/assets/javascripts/paloma/engine.js
vendored
|
@ -1,5 +1,5 @@
|
||||||
Paloma.Engine = function(config){
|
Paloma.Engine = function(controllerBuilder){
|
||||||
this.builder = config.builder;
|
this.controllerBuilder = controllerBuilder;
|
||||||
this._clearRequest();
|
this._clearRequest();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,27 +29,29 @@ Paloma.Engine.prototype = {
|
||||||
this._logRequest();
|
this._logRequest();
|
||||||
this._lastRequest = this._request;
|
this._lastRequest = this._request;
|
||||||
|
|
||||||
var controllerClass = this.builder.get( this._request.controller );
|
this._executeControllerAction();
|
||||||
|
|
||||||
if (controllerClass){
|
|
||||||
var controller = new controllerClass( this._request.params );
|
|
||||||
this._executeActionOf(controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._clearRequest();
|
this._clearRequest();
|
||||||
},
|
},
|
||||||
|
|
||||||
_executeActionOf: function(controller){
|
_executeControllerAction: function(){
|
||||||
var action = controller[ this._request.action ];
|
var controller = this._buildController();
|
||||||
|
if (!controller) return;
|
||||||
|
|
||||||
if (action){
|
var callbackPerformer = new Paloma.BeforeCallbackPerformer(controller);
|
||||||
var callbackPerformer = new Paloma.BeforeCallbackPerformer(controller);
|
callbackPerformer.perform( this._request.action );
|
||||||
callbackPerformer.perform( this._request.action );
|
|
||||||
|
|
||||||
action.call(controller);
|
var method = controller[ this._request.action ];
|
||||||
|
if (method) method.call(controller);
|
||||||
|
|
||||||
this._lastRequest.executed = true;
|
this._lastRequest.executed = true;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
_buildController: function(){
|
||||||
|
return this.controllerBuilder.build({
|
||||||
|
controller: this._request.controller,
|
||||||
|
action: this._request.action,
|
||||||
|
params: this._request.params
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_shouldStop: function(){
|
_shouldStop: function(){
|
||||||
|
@ -71,4 +73,5 @@ Paloma.Engine.prototype = {
|
||||||
_clearRequest: function(){
|
_clearRequest: function(){
|
||||||
this._request = null;
|
this._request = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
3
vendor/assets/javascripts/paloma/index.js
vendored
3
vendor/assets/javascripts/paloma/index.js
vendored
|
@ -1,6 +1,7 @@
|
||||||
//= require ./init.js
|
//= require ./init.js
|
||||||
//= require ./base_controller.js
|
//= require ./base_controller.js
|
||||||
//= require ./controller_builder.js
|
//= require ./controller_class_factory.js
|
||||||
//= require ./before_callback_performer.js
|
//= require ./before_callback_performer.js
|
||||||
|
//= require ./controller_builder.js
|
||||||
//= require ./engine.js
|
//= require ./engine.js
|
||||||
//= require ./paloma.js
|
//= require ./paloma.js
|
||||||
|
|
17
vendor/assets/javascripts/paloma/paloma.js
vendored
17
vendor/assets/javascripts/paloma/paloma.js
vendored
|
@ -1,10 +1,15 @@
|
||||||
(function(Paloma){
|
(function(Paloma){
|
||||||
|
|
||||||
Paloma._controllerBuilder = new Paloma.ControllerBuilder();
|
var classFactory = new Paloma.ControllerClassFactory(),
|
||||||
Paloma.engine = new Paloma.Engine({builder: Paloma._controllerBuilder});
|
controllerBuilder = new Paloma.ControllerBuilder(classFactory),
|
||||||
|
engine = new Paloma.Engine(controllerBuilder)
|
||||||
|
|
||||||
|
Paloma._controllerClassFactory = classFactory;
|
||||||
|
Paloma._controllerBuilder = controllerBuilder
|
||||||
|
Paloma.engine = engine;
|
||||||
|
|
||||||
Paloma.controller = function(name, prototype){
|
Paloma.controller = function(name, prototype){
|
||||||
return Paloma._controllerBuilder.build(name, prototype);
|
return classFactory.make(name, prototype);
|
||||||
};
|
};
|
||||||
|
|
||||||
Paloma._executeHook = function(){
|
Paloma._executeHook = function(){
|
||||||
|
@ -13,12 +18,12 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
Paloma.start = function(){
|
Paloma.start = function(){
|
||||||
if ( !this.engine.hasRequest() ) this._executeHook();
|
if ( !engine.hasRequest() ) this._executeHook();
|
||||||
if ( this.engine.hasRequest() ) this.engine.start();
|
if ( engine.hasRequest() ) engine.start();
|
||||||
};
|
};
|
||||||
|
|
||||||
Paloma.isExecuted = function(){
|
Paloma.isExecuted = function(){
|
||||||
return this.engine.lastRequest().executed;
|
return engine.lastRequest().executed;
|
||||||
};
|
};
|
||||||
|
|
||||||
})(window.Paloma);
|
})(window.Paloma);
|
||||||
|
|
Loading…
Reference in a new issue