Skip to content

Instantly share code, notes, and snippets.

@volkovasystems
Last active August 29, 2015 14:12
Show Gist options
  • Save volkovasystems/df3a95386b2e44796f06 to your computer and use it in GitHub Desktop.
Save volkovasystems/df3a95386b2e44796f06 to your computer and use it in GitHub Desktop.
Angular module for manipulating properties of entities.
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