Last active
August 29, 2015 14:12
-
-
Save volkovasystems/df3a95386b2e44796f06 to your computer and use it in GitHub Desktop.
Angular module for manipulating properties of entities.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular | |
.module( "Property", [ "Meta" ] ) | |
.factory( "Property", [ | |
"Meta", | |
function factory( Meta ){ | |
var Property = function Property( propertyName ){ | |
this.propertyName = propertyName; | |
Object.defineProperty( this, "-descriptorSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": { } | |
} ); | |
}; | |
/*: | |
The name of the property you want to handle. | |
*/ | |
Object.defineProperty( Property.prototype, "propertyName", { | |
"configurable": false, | |
"enumerable": false, | |
"get": function getPropertyName( ){ | |
return this[ "-propertyName" ]; | |
}, | |
"set": function setPropertyName( propertyName ){ | |
Object.defineProperty( this, "-propertyName", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": propertyName | |
} ); | |
Object.defineProperty( this, "-propertyNameHasBeenSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": true | |
} ); | |
} | |
} ); | |
/*: | |
Definition is a set of descriptors. | |
This is the exposed immutable property for handling descriptors. | |
You can either define all descriptors or set it individually. | |
*/ | |
Object.defineProperty( Property.prototype, "definitionSet", { | |
"configurable": false, | |
"enumerable": false, | |
"get": function getDefinitionSet( ){ | |
return this[ "-definitionSet" ]; | |
}, | |
"set": function setDefinitionSet( definitionSet ){ | |
definitionSet = Object.freeze( definitionSet ); | |
Object.defineProperty( this, "-definitionSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": definitionSet | |
} ); | |
Object.defineProperty( this, "-definitionHasBeenSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": true | |
} ); | |
} | |
} ); | |
/*: | |
Exposed immutable property for handling the attachment of the property name. | |
*/ | |
Object.defineProperty( Property.prototype, "entity", { | |
"configurable": false, | |
"enumerable": false, | |
"get": function getEntity( ){ | |
return this[ "-entity" ]; | |
}, | |
"set": function setEntity( entity ){ | |
Object.defineProperty( this, "-entity", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": entity | |
} ); | |
Object.defineProperty( this, "-entityHasBeenSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": true | |
} ); | |
} | |
} ); | |
/*: | |
Sets definition to the property, this is the complete descriptor configuration. | |
*/ | |
Object.defineProperty( Property.prototype, "define", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function define( definitionSet ){ | |
if( typeof definitionSet == "object" && | |
definitionSet && | |
Object.keys( definitionSet ).length == 0 ) | |
{ | |
throw new Error( "definition set is empty" ); | |
} | |
if( typeof definitionSet != "object" ){ | |
} | |
this.definitionSet = definitionSet; | |
return this; | |
} | |
} ); | |
/*: | |
The is method will be used to add descriptor to the property. | |
Example usage: | |
property( "data" ) | |
.is( "configurable" ) | |
.is( "writable" ) | |
*/ | |
Object.defineProperty( Property.prototype, "is", { | |
"configurable": false, | |
"enumerable": false, | |
"get": function getIs( ){ | |
if( this.definitionHasBeenSet( ) ){ | |
throw new Error( "definition has been set" ); | |
} | |
var is = Object.bind( function is( descriptorName ){ | |
this[ "-descriptorSet" ][ descriptorName ] = true; | |
return this; | |
}, this ); | |
//: Manage the chaining of the methods. | |
is.is = this.is; | |
is.not = this.not; | |
return is; | |
}, | |
"set": function setIs( ){ | |
//: Do nothing. | |
} | |
} ); | |
/*: | |
The not method will be used to falsify a descriptor of the property. | |
Example usage: | |
property( "data" ) | |
.not( "configurable" ) | |
.is.not( "writable" ) | |
*/ | |
Object.defineProperty( Property.prototype, "not", { | |
"configurable": false, | |
"enumerable": false, | |
"get": function getNot( ){ | |
if( this.definitionHasBeenSet( ) ){ | |
throw new Error( "definition has been set" ); | |
} | |
var not = Object.bind( function not( descriptorName ){ | |
this[ "-descriptorSet" ][ descriptorName ] = false; | |
return this; | |
}, this ); | |
not.not = this.not; | |
not.is = this.is; | |
return not; | |
}, | |
"set": function setIs( ){ | |
//: Do nothing. | |
} | |
} ); | |
/*: | |
Sets the entity and configure the definition of the property. | |
Example usage: | |
property( "data" ) | |
.define( { | |
"enumerable": true | |
} ) | |
.to( myObject ); | |
*/ | |
Object.defineProperty( Property.prototype, "to", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function to( entity ){ | |
if( this.entityHasBeenSet( ) ){ | |
throw new Error( "entity value is immutable" ); | |
} | |
this.of( entity ).configure( ); | |
return this; | |
} | |
} ); | |
/*: | |
Apply the definition set or the descriptor set to the property of the entity. | |
*/ | |
Object.defineProperty( Property.prototype, "configure", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function configure( ){ | |
if( this.entityHasNotBeenSet( ) ){ | |
throw new Error( "entity has not been set" ); | |
} | |
if( this.propertyHasBeenConfigured( ) ){ | |
throw new Error( "property has been configured" ); | |
} | |
if( this.doesExists( ) ){ | |
throw new Error( "property already exists" ); | |
} | |
if( this.definitionHasNotBeenSet( ) && | |
this.descriptorSetIsEmpty( ) ) | |
{ | |
throw new Error( "incomplete property definition" ); | |
} | |
if( this.definitionHasNotBeenSet( ) && | |
this.hasDescriptorSet( ) ) | |
{ | |
Object.defineProperty( this.entity, this.propertyName, this[ "-descriptorSet" ] ); | |
Object.defineProperty( this, "-propertyHasBeenConfigured", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": true | |
} ); | |
} | |
if( this.definitionHasBeenSet( ) && | |
this.descriptorSetIsEmpty( ) ) | |
{ | |
Object.defineProperty( this.entity, this.propertyName, this.definitionSet ); | |
Object.defineProperty( this, "-propertyHasBeenConfigured", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": true | |
} ); | |
} | |
return this; | |
} | |
} ); | |
/*: | |
Like the to method but it just initialize the entity of the property. | |
*/ | |
Object.defineProperty( Property.prototype, "of", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function of( entity ){ | |
if( this.entityHasBeenSet( ) ){ | |
throw new Error( "entity value is immutable" ); | |
} | |
this.entity = entity; | |
return this; | |
} | |
} ); | |
/*: | |
Sets value to the property of the entity. | |
*/ | |
Object.defineProperty( Property.prototype, "set", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function set( value ){ | |
if( this.entityHasNotBeenSet ){ | |
throw new Error( "entity has not been set" ); | |
} | |
this.entity[ this.propertyName ] = value; | |
return this; | |
} | |
} ); | |
/*: | |
Checks whether the property name has been set properly. | |
*/ | |
Object.defineProperty( Property.prototype, "propertyNameHasBeenSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function propertyNameHasBeenSet( ){ | |
return ( | |
typeof this[ "-propertyNameHasBeenSet" ] != "undefined" && | |
this[ "-propertyNameHasBeenSet" ] | |
); | |
} | |
} ); | |
/*: | |
Inverse of propertyNameHasNotBeenSet | |
*/ | |
Object.defineProperty( Property.prototype, "propertyNameHasNotBeenSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function propertyNameHasNotBeenSet( ){ | |
return !this.propertyNameHasBeenSet( ); | |
} | |
} ); | |
/*: | |
Checks whether the property has been configured already. | |
*/ | |
Object.defineProperty( Property.prototype, "propertyHasBeenConfigured", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function propertyHasBeenConfigured( ){ | |
return ( | |
typeof this[ "-propertyHasBeenConfigured" ] != "undefined" && | |
this[ "-propertyHasBeenConfigured" ] | |
); | |
} | |
} ); | |
/*: | |
Inverse of propertyHasBeenConfigured | |
*/ | |
Object.defineProperty( Property.prototype, "propertyHasNotBeenConfigured", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function propertyHasNotBeenConfigured( ){ | |
return !this.propertyHasBeenConfigured( ); | |
} | |
} ); | |
/*: | |
Checks if definition for this property exists. | |
*/ | |
Object.defineProperty( Property.prototype, "definitionHasBeenSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function definitionHasBeenSet( ){ | |
return ( | |
typeof this[ "-definitionHasBeenSet" ] != "undefined" && | |
this[ "-definitionHasBeenSet" ] | |
); | |
} | |
} ); | |
/*: | |
Inverse of definitionHasBeenSet | |
*/ | |
Object.defineProperty( Property.prototype, "definitionHasNotBeenSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function definitionHasNotBeenSet( ){ | |
return !this.definitionHasBeenSet( ); | |
} | |
} ); | |
/*: | |
Checks if the descriptor set contains configuration. | |
*/ | |
Object.defineProperty( Property.prototype, "hasDescriptorSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function hasDescriptorSet( ){ | |
return Object.keys( this[ "-descriptorSet" ] ).length > 0; | |
} | |
} ); | |
/*: | |
Inverse of hasDescriptorSet | |
*/ | |
Object.defineProperty( Property.prototype, "descriptorSetIsEmpty", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function descriptorSetIsEmpty( ){ | |
return !this.hasDescriptorSet( ); | |
} | |
} ); | |
/*: | |
Checks if entity exists. | |
*/ | |
Object.defineProperty( Property.prototype, "entityHasBeenSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function entityHasBeenSet( ){ | |
return ( | |
typeof this[ "-entityHasBeenSet" ] != "undefined" && | |
this[ "-entityHasBeenSet" ] | |
); | |
} | |
} ); | |
/*: | |
Inverse of entityHasBeenSet | |
*/ | |
Object.defineProperty( Property.prototype, "entityHasNotBeenSet", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function entityHasNotBeenSet( ){ | |
return !this.entityHasNotBeenSet( ); | |
} | |
} ); | |
/*: | |
Checks if the property has a value. | |
*/ | |
Object.defineProperty( Property.prototype, "hasValue", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function hasValue( ){ | |
if( this.entityHasNotBeenSet( ) ){ | |
throw new Error( "entity has not been set" ); | |
} | |
return typeof this.entity[ this.propertyName ] != "undefined"; | |
} | |
} ); | |
/*: | |
Checks if the property has no value. | |
*/ | |
Object.defineProperty( Property.prototype, "isEmpty", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function hasValue( ){ | |
if( this.entityHasNotBeenSet( ) ){ | |
throw new Error( "entity has not been set" ); | |
} | |
return !this.hasValue( ); | |
} | |
} ); | |
/*: | |
Checks whether the property is attached to an entity. | |
Regardless of whatever value it contains. | |
*/ | |
Object.defineProperty( Property.prototype, "doesExists", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function doesExists( ){ | |
if( this.entityHasNotBeenSet( ) ){ | |
throw new Error( "entity has not been set" ); | |
} | |
return this.propertyName in this.entity; | |
} | |
} ); | |
/*: | |
Dropping value sets the property to undefined to trigger GC if possible. | |
*/ | |
Object.defineProperty( Property.prototype, "dropValue", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function dropValue( ){ | |
if( this.entityHasNotBeenSet( ) ){ | |
throw new Error( "cannot drop value without entity" ); | |
} | |
if( this.hasValue( ) ){ | |
this.entity[ this.propertyName ] = undefined; | |
return this; | |
} | |
if( this.isEmpty( ) ){ | |
console.warn( "trying to drop non-existing value" ); | |
return this; | |
} | |
} | |
} ); | |
/*: | |
Dropping the entity removes the property from the entity and returns a new Property instance. | |
Because entity is immutable we have no way to remove this. | |
*/ | |
Object.defineProperty( Property.prototype, "dropEntity", { | |
"configurable": false, | |
"enumerable": false, | |
"writable": false, | |
"value": function dropEntity( ){ | |
if( this.entityHasBeenSet( ) ){ | |
this.dropValue( ); | |
delete this.entity[ this.propertyName ]; | |
return new Property( this.propertyName ); | |
} | |
if( this.entityHasNotBeenSet( ) ){ | |
console.warn( "trying to drop non-existing entity" ); | |
return this; | |
} | |
} | |
} ); | |
return Property; | |
} | |
] ) | |
.factory( "property", [ | |
"Property", | |
function factory( Property ){ | |
var property = function property( propertyName ){ | |
return new Property( propertyName ); | |
}; | |
return property; | |
} | |
] ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment