joii-unit
Version:
UnitTest Framework for JOII-based applications
371 lines (342 loc) • 11.5 kB
JavaScript
/*
JavaScript Unit Testing Framework _ _ _
- Powered by JOII (_)___ (_|_) .__ __
/ / __ \/ / / __ __ ____ |__|/ |_
(c)2014, <harold@iedema.me> / / /_/ / / / | | \/ \| \ __\
Released under the MIT license. __/ /\____/_/_/ | | / | \ || |
--------------------------------- /___/ ------------ |____/|___| /__||__| ---
*/
(function(g, namespace, Class, undefined) {
var ns = namespace('DependencyInjection');
/**
* Dependency Injection Definition
*
* @author Harold Iedema <harold@iedema.me>
*/
ns.Definition = Class({
'private object name' : null,
'private object fn' : null,
'private object instance' : null,
'private object api' : null,
'private object is_public' : true,
'private object args' : [],
'private object calls' : [],
'private object tags' : {},
/**
* @param string name The name of this definition.
* @param mixed fn Function or string referencing the function.
*/
'private __construct': function(fn)
{
if (typeof(fn) !== 'function') {
this.fn = this.findFunctionFromString(fn);
} else {
this.fn = fn;
}
},
/**
* Adds an argument to pass to the service constructor.
*
* @param mixed value
* @return DependencyInjection.Definition
*/
'public function addArgument': function(argument)
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
this.args.push(argument);
return this;
},
/**
* Sets the arguments to pass to the service constructor.
*
* @param mixed value
* @return DependencyInjection.Definition
*/
'public function setArguments': function(args)
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
this.args = args;
return this;
},
/**
* Gets the arguments to pass to the service constructor.
*
* @return array
*/
'public function getArguments': function()
{
return this.args;
},
/**
* Sets the methods to call after service initialization.
*
* @param array calls
* @return DependencyInjection.Definition
*/
'public function setMethodCalls': function(calls)
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
this.calls = [];
for (var i in calls) {
if (calls.hasOwnProperty(i)) {
this.calls[i] = calls[i];
}
}
return this;
},
/**
* Adds a method to call after service initialization.
*
* @param string method
* @param array args
* @return DependencyInjection.Definition
*/
'public function addMethodCall': function(method, args)
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
args = args || [];
this.calls.push([method, args]);
return this;
},
/**
* Removes a method call from this definition by the given name.
*
* @param string method
* @return DependencyInjection.Definition
*/
'public function removeMethodCall': function(method)
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
for (var i in this.calls) {
if (this.calls[i][0] === method) {
delete this.calls[i];
}
}
return this;
},
/**
* Check if the current definition has a given method to call after
* service initialization.
*
* @return bool
*/
'public function hasMethodCall': function(method)
{
for (var i in this.calls) {
if (this.calls[i][0] === method) {
return true;
}
}
return false;
},
/**
* Gets the methods to call after service initialization.
*
* @return array
*/
'public function getMethodCalls': function()
{
return this.calls;
},
/**
* Sets tags for this definition.
*
* @param array tags
* @return DependencyInjection.Definition
*/
'public function setTags': function(tags)
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
this.tags = tags;
return this;
},
/**
* Returns all tags.
*
* @return array
*/
'public function getTags': function()
{
return this.tags;
},
/**
* Gets a tag by name.
*
* @param string name The tag name
* @return array An array of attributes
*/
'public function getTag': function(name)
{
return typeof(this.tags[name]) !== 'undefined'
? this.tags[name] : [];
},
/**
* Add a tag for this definition.
*
* @param string name
* @param array attributes
* @return DependencyInjection.Definition
*/
'public function addTag': function(name, attributes)
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
if (typeof(this.tags[name]) === 'undefined') {
this.tags[name] = [];
}
this.tags[name].push(attributes);
return this;
},
/**
* Returns true if this definition has a tag with the given name.
*
* @return bool
*/
'public function hasTag': function(name)
{
return typeof(this.tags[name]) !== 'undefined';
},
/**
* Clears tags with the given name.
*
* @return DependencyInjection.Definition
*/
'public function clearTag': function(name)
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
if (typeof(this.tags[name]) !== 'undefined') {
delete this.tags[name];
}
return this;
},
/**
* @return DependencyInjection.Definition
*/
'public function clearTags': function()
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
this.tags = {};
return this;
},
/**
* Sets the visibility of this service.
*
* @return DependencyInjection.Definition
*/
'public function setPublic': function(flag)
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
this.is_public = flag;
return this;
},
/**
* Returns true if this definition is public.
*
* Being public means it's retrievable from the container. A private
* service is only usable as a dependency on other services.
*
* @return bool
*/
'public function isPublic': function()
{
return this.is_public;
},
/**
* Returns true if this definition has an instance of the function
* associated with it.
*
* @return bool
*/
'public function hasInstance': function()
{
return !!this.instance;
},
/**
* Returns the associated instance.
*
* @return Object
*/
'public function getInstance': function()
{
if (typeof(this.instance) !== 'undefined') {
return this.instance;
}
throw new Error('Definition is not initialized.');
},
/**
* Sets the instance for this definition.
*
* @param object instance
* @return DependencyInjection.Definition
*/
'public function setInstance': function(instance)
{
if (this.hasInstance()) {
throw new Error('Unable to update a definition that is already initialized.');
}
this.instance = instance;
return this;
},
/**
* Returns the function associated with this Definition.
*
* @return Function
*/
'public function getFunction': function()
{
return this.fn;
},
/**
* Finds the given function by string reference.
*
* @access private
* @return function
*/
'private function findFunctionFromString': function(str)
{
if (str.indexOf('.') === -1) {
// There are no namespace separators, just return it.
if (typeof(g[str]) === 'function') {
return g[str];
}
throw new Error(str + ' is undefined or not a function.');
}
var chunks = str.split('.'),
result = g,
str_rep = '',
current;
while ((current = chunks.shift())) {
str_rep += current;
if (typeof(result[current]) === 'undefined' || (
typeof(result[current]) !== 'object' &&
typeof(result[current]) !== 'function')) {
throw new Error(str_rep + ' is undefined or not iterable.');
}
result = result[current];
str_rep += '.';
}
return result;
}
});
} ((typeof window !== 'undefined' ? window : global),
(typeof window !== 'undefined' ? window : global).JOII.Unit.Namespace,
(typeof window !== 'undefined' ? window : global).JOII.ClassBuilder));