implement hooks for Class constructors (AOP-style), close #1123
This commit is contained in:
parent
8350bb1e08
commit
782e8e7dcf
@ -1,10 +1,10 @@
|
||||
describe("Class", function() {
|
||||
|
||||
|
||||
describe("#extend", function() {
|
||||
var Klass,
|
||||
constructor,
|
||||
method;
|
||||
|
||||
|
||||
beforeEach(function() {
|
||||
constructor = jasmine.createSpy("Klass constructor");
|
||||
method = jasmine.createSpy("Klass#bar method");
|
||||
@ -12,78 +12,78 @@ describe("Class", function() {
|
||||
Klass = L.Class.extend({
|
||||
statics: {bla: 1},
|
||||
includes: {mixin: true},
|
||||
|
||||
|
||||
initialize: constructor,
|
||||
foo: 5,
|
||||
bar: method
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("should create a class with the given constructor & properties", function() {
|
||||
var a = new Klass();
|
||||
|
||||
|
||||
expect(constructor).toHaveBeenCalled();
|
||||
expect(a.foo).toEqual(5);
|
||||
|
||||
|
||||
a.bar();
|
||||
|
||||
|
||||
expect(method).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it("should inherit parent classes' constructor & properties", function() {
|
||||
var Klass2 = Klass.extend({baz: 2});
|
||||
|
||||
|
||||
var b = new Klass2();
|
||||
|
||||
|
||||
expect(b instanceof Klass).toBeTruthy();
|
||||
expect(b instanceof Klass2).toBeTruthy();
|
||||
|
||||
|
||||
expect(constructor).toHaveBeenCalled();
|
||||
expect(b.baz).toEqual(2);
|
||||
|
||||
|
||||
b.bar();
|
||||
|
||||
|
||||
expect(method).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
||||
it("should support static properties", function() {
|
||||
expect(Klass.bla).toEqual(1);
|
||||
});
|
||||
|
||||
|
||||
it("should inherit parent static properties", function() {
|
||||
var Klass2 = Klass.extend({});
|
||||
|
||||
|
||||
expect(Klass2.bla).toEqual(1);
|
||||
});
|
||||
|
||||
|
||||
it("should override parent static properties", function() {
|
||||
var Klass2 = Klass.extend({statics: {bla: 2}});
|
||||
|
||||
|
||||
expect(Klass2.bla).toEqual(2);
|
||||
});
|
||||
|
||||
|
||||
it("should include the given mixin", function() {
|
||||
var a = new Klass();
|
||||
expect(a.mixin).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
it("should be able to include multiple mixins", function() {
|
||||
var Klass2 = L.Class.extend({
|
||||
includes: [{mixin: true}, {mixin2: true}]
|
||||
});
|
||||
var a = new Klass2();
|
||||
|
||||
|
||||
expect(a.mixin).toBeTruthy();
|
||||
expect(a.mixin2).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
it("should grant the ability to include the given mixin", function() {
|
||||
Klass.include({mixin2: true});
|
||||
|
||||
|
||||
var a = new Klass();
|
||||
expect(a.mixin2).toBeTruthy();
|
||||
});
|
||||
|
||||
|
||||
it("should merge options instead of replacing them", function() {
|
||||
var KlassWithOptions1 = L.Class.extend({
|
||||
options: {
|
||||
@ -97,18 +97,50 @@ describe("Class", function() {
|
||||
foo3: 4
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var a = new KlassWithOptions2();
|
||||
|
||||
|
||||
expect(a.options).toEqual({
|
||||
foo1: 1,
|
||||
foo2: 3,
|
||||
foo3: 4
|
||||
});
|
||||
});
|
||||
|
||||
it("should add constructor hooks correctly", function () {
|
||||
var spy1 = jasmine.createSpy("init hook 1");
|
||||
|
||||
Klass.addInitHook(spy1);
|
||||
Klass.addInitHook('bar', 1, 2, 3);
|
||||
|
||||
var a = new Klass();
|
||||
|
||||
expect(spy1).toHaveBeenCalled();
|
||||
expect(method).toHaveBeenCalledWith(1, 2, 3);
|
||||
});
|
||||
|
||||
it("should inherit constructor hooks", function () {
|
||||
var spy1 = jasmine.createSpy("init hook 1"),
|
||||
spy2 = jasmine.createSpy("init hook 2");
|
||||
|
||||
Klass.addInitHook(spy1);
|
||||
|
||||
var Klass2 = Klass.extend({});
|
||||
Klass2.addInitHook(spy2);
|
||||
|
||||
var a = new Klass();
|
||||
|
||||
expect(spy1).toHaveBeenCalled();
|
||||
expect(spy2).not.toHaveBeenCalled();
|
||||
|
||||
var b = new Klass2();
|
||||
|
||||
expect(spy2).toHaveBeenCalled();
|
||||
expect(spy1.argsForCall.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO Class.include
|
||||
|
||||
// TODO Class.mergeOptions
|
||||
});
|
||||
});
|
||||
|
@ -8,9 +8,16 @@ L.Class.extend = function (/*Object*/ props) /*-> Class*/ {
|
||||
|
||||
// extended class with the new prototype
|
||||
var NewClass = function () {
|
||||
|
||||
// call the constructor
|
||||
if (this.initialize) {
|
||||
this.initialize.apply(this, arguments);
|
||||
}
|
||||
|
||||
// call all constructor hooks
|
||||
for (var i = 0, len = this._initHooks.length; i < len; i++) {
|
||||
this._initHooks[i].call(this);
|
||||
}
|
||||
};
|
||||
|
||||
// instantiate class without calling constructor
|
||||
@ -49,6 +56,9 @@ L.Class.extend = function (/*Object*/ props) /*-> Class*/ {
|
||||
// mix given properties into the prototype
|
||||
L.extend(proto, props);
|
||||
|
||||
// inherit constructor hooks
|
||||
proto._initHooks = this.prototype._initHooks ? this.prototype._initHooks.slice() : [];
|
||||
|
||||
return NewClass;
|
||||
};
|
||||
|
||||
@ -58,6 +68,18 @@ L.Class.include = function (props) {
|
||||
L.extend(this.prototype, props);
|
||||
};
|
||||
|
||||
// merge new default options to the Class
|
||||
L.Class.mergeOptions = function (options) {
|
||||
L.extend(this.prototype.options, options);
|
||||
};
|
||||
|
||||
// add a constructor hook
|
||||
L.Class.addInitHook = function (fn) { // (Function) || (String, args...)
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
var init = typeof fn === 'function' ? fn : function () {
|
||||
this[fn].apply(this, args);
|
||||
};
|
||||
|
||||
this.prototype._initHooks.push(init);
|
||||
};
|
||||
|
@ -25,7 +25,6 @@ L.Map = L.Class.extend({
|
||||
|
||||
this._initContainer(id);
|
||||
this._initLayout();
|
||||
this._initHooks();
|
||||
this._initEvents();
|
||||
|
||||
if (options.maxBounds) {
|
||||
@ -681,16 +680,6 @@ L.Map = L.Class.extend({
|
||||
}
|
||||
});
|
||||
|
||||
L.Map.addInitHook = function (fn) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
var init = typeof fn === 'function' ? fn : function () {
|
||||
this[fn].apply(this, args);
|
||||
};
|
||||
|
||||
this.prototype._initializers.push(init);
|
||||
};
|
||||
|
||||
L.map = function (id, options) {
|
||||
return new L.Map(id, options);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user