Skip to content

Commit

Permalink
Merge pull request #1285 from ickata/master
Browse files Browse the repository at this point in the history
Class.Singleton
  • Loading branch information
SergioCrisostomo committed Sep 29, 2014
2 parents 9ad3cf6 + 01846ad commit 1105475
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 0 deletions.
18 changes: 18 additions & 0 deletions Docs/Class/Class.Singleton.md
@@ -0,0 +1,18 @@
Class: Class.Singleton {#Class-Singleton}
=================================

Extends [Class][];. Creates a class that always returns the same instance.

### Simple Example

var MyClass = new Class.Singleton({

foo : function () {
alert('bar');
}

});

new MyClass() === new MyClass(); // returns true

[Class]: /core/Class/Class
51 changes: 51 additions & 0 deletions Source/Class/Class.Singleton.js
@@ -0,0 +1,51 @@
/*
---
script: Class.Singleton.js
name: Class.Singleton
description: Always provides a single instance of a class
license: MIT-style license.
authors:
- Hristo Chakarov
requires:
- Core/Class
provides: [Class.Singleton]
...
*/

Class.Singleton = new Class({

initialize : function(descriptor){
// here we keep reference of the single instance
var singleton;
// create a regular Class
var constructor = new Class(descriptor);
// We return another constructor, because we need to make sure that we
// always return the same one and only instance.
return function(){
if (singleton){
return singleton;
}
// Obviously we instantiate that class for the first time.
// Create brand new object & extend it with the prototype of the
// original `constructor`.
singleton = Object.append({}, constructor.prototype);
singleton.constructor = constructor;
// We also need to call the constructor as a function, passing the
// arguments object.
var return_value = constructor.apply(singleton, arguments);
// In case the `constructor` returns something other than `this` -
// return that value; otherwise return the `singleton`.
singleton = typeof return_value == 'object' ? return_value : singleton;
return singleton;
};
}

});
77 changes: 77 additions & 0 deletions Specs/Class/Class.Singleton.js
@@ -0,0 +1,77 @@
/*
---
name: Class.Singleton Tests
requires: [More/Class.Singleton]
provides: [Class.Singleton.Tests]
...
*/
describe('Class.Singleton', function(){
var ClassA = new Class.Singleton({

Extends: Events,
Implements: [Options],

options: {foo: 'bar'},

initialize: function(name, options){
this.name = name;
this.setOptions(options);
},

getOption: function(name){
return this.options[name];
},

fireEvent: function(){
this.setOptions({fireEventCalled : true});
return this.parent.apply(this, arguments);
}

});

var ClassB = new Class.Singleton({

initialize: function(){
return new Element('div');
}

});

var instanceA = new ClassA('Test', {integer: 5});

instanceA.addEvent('test', function(){
this.setOptions({eventHandlerCalled: true});
});

instanceA.fireEvent('test');

it('should always return single instance', function(){
expect(instanceA == new ClassA()).toBeTruthy();
expect(new ClassB() == new ClassB()).toBeTruthy();
});

it('should not return the same instance across different classes', function(){
expect(instanceA == new ClassB()).toBeFalsy();
});

it('should properly implement methods from the prototype', function(){
expect(typeof instanceA.getOption == 'function').toBeTruthy();
expect(typeof instanceA.setOptions == 'function').toBeTruthy();
expect(typeof instanceA.fireEvent == 'function').toBeTruthy();
expect(typeof instanceA.addEvent == 'function').toBeTruthy();
});

it('should take into considerations constructor parameters', function(){
expect(instanceA.getOption('integer') === 5).toBeTruthy();
});

it('should be able to call parent method', function(){
expect(instanceA.getOption('fireEventCalled')).toBeTruthy();
expect(instanceA.getOption('eventHandlerCalled')).toBeTruthy();
});

it('should be able to return other object than `this`', function(){
expect(typeOf(new ClassB()) == 'element').toBeTruthy();
});

});

0 comments on commit 1105475

Please sign in to comment.