UNPKG

abstract-type

Version:

The abstract-type library includes the abstract `Type` class and `Value` class for streamable type info and validating value.

384 lines (334 loc) 16 kB
## abstract-type [![npm][npm-svg]][npm] [![Build Status][travis-svg]][travis] [![Code Climate][codeclimate-svg]][codeclimate] [![Test Coverage][codeclimate-test-svg]][codeclimate-test] [![downloads][npm-download-svg]][npm] [![license][npm-license-svg]][npm] [npm]: https://npmjs.org/package/abstract-type [npm-svg]: https://img.shields.io/npm/v/abstract-type.svg [npm-download-svg]: https://img.shields.io/npm/dm/abstract-type.svg [npm-license-svg]: https://img.shields.io/npm/l/abstract-type.svg [travis-svg]: https://img.shields.io/travis/snowyu/abstract-type.js/master.svg [travis]: http://travis-ci.org/snowyu/abstract-type.js [codeclimate-svg]: https://codeclimate.com/github/snowyu/abstract-type.js/badges/gpa.svg [codeclimate]: https://codeclimate.com/github/snowyu/abstract-type.js [codeclimate-test-svg]: https://codeclimate.com/github/snowyu/abstract-type.js/badges/coverage.svg [codeclimate-test]: https://codeclimate.com/github/snowyu/abstract-type.js/coverage The abstract-type library includes the abstract `Type` class and `Value` class for streamable type info and validating value. ## Concepts * Primitive Types * All registered types are primitive types. * It's the singleton type object on the global type factory. * Virtual Types * It's an object of a primitive type. * It can not be registered to the global type factory. * It could be unlimited number of virtual types. * It could use the LRU-cache factory to cache these virtual types(see usage). * Type Attributes: the attributes of the type. It's used to constrain the Type. All types have the `name` and `required` attributes. * `name` *(string)*: the type name. * required = true: the type name must be required. * enumerable = false: the type name can not be enumerable. * `required` *(boolean)*: the attribute whether is required(must be exists, not optional). default to false. * Value: the value with corresponding to the type information. ## Usage ### Create the number type The type has a name and can verify whether a value belongs to that type. We can draw the two concepts related to the type, from here: * Attributes: the attributes(meta data) of this type. * Value: the value of this type. * The Type Class * Properties: * $attributes *(object)*: the attributes of this type. * Methods(should be overridden): * `_initialize(aOptions)`: initialize the type object. * `_assign(options)`: assign an options of type to itself. * `_validate(aValue, aOptions)`: validate a value whether is valid. * `valueToString(aValue)`: (optional) convert the value to string, it's used to convert to json. * `toValue(aString)`: (optional) convert the string to the value, it's used to convert from json and assign from value. * `ValueType` property: (optional) defaults to `Value` Class. unless implement your own Value class. * The Value Class * Properties: * `value`: store the value here. * `$type` *(Type)*: point to the type of this value. * Static/Class Methods: * `tryGetTypeName(Value)`: try to guess the type name of the value. * `constructor(value[, type[, options]])`: create a value instance. * `value`: the assigned value. it will guess the type of the value if no type provided. * `type` *(Type)*: the type of the value * `options` *(object)*: the optional type of value options. it will create a new type if exists. * Methods: * `clone()`: clone this value object. * `assign(value, options)`: assign the value. * `aOptions` *(object)*: * `checkValidity` *(boolean)*: defaults to true. * `fromJson(json)`: assign a value from json string. * `createFromJson(json)`: create a new value object from json string. * `isValid()`: whether the value is valid. * `toObject(aOptions)`: return a parametric object of the value. it wont include type info. unless set the `withType` is true. * aOptions *(object)*: * `withType` *(boolean)*: whether includes the type info. default to false * These methods could be overridden: * `_toObject(aOptions)`: return the parametric object of this value. * `valueOf()`: return the value. * `_assign(value)`: assign the value to itself. * The Attributes class: describe the attributes of a type. an attribute could include these properties: * `name` *(string)*: the attribute name. you can specify a non-english name. * the english name(the attributes' key) is used in the internal of the type. * the `name` only used on export(`toObject`) or import(`assign`). * `type` *(string)*: the attribute type. * `enumerable` *(boolean)*: the attribute whether is a hidden attribute, defaults to true. * the hidden attribute can not export to the parametric object(serialized). * note: It's a hidden attribute too if attribute name begins with '$' char. * `required` *(boolean)*: the attribute whether it's required(MUST HAVE). * `value`: the default value of the attribute. * `assign(value, dest, src, key)` *(function)*: optional special function to assign the attribute's `value` from src[`key`] to dest[`key`]. * src, dest: the type object or the parametric type object. ```coffee TypeAttributes = require 'abstract-type/lib/attributes' Type = require 'abstract-type' register = Type.register aliases = Type.aliases class NumberType register NumberType aliases NumberType, 'number' $attributes: TypeAttributes min: name: 'min' type: 'Number' max: name: 'max' type: 'Number' #valueToString: (aValue)-> # aValue = String(aValue) stringToValue: (aString)-> if isInt aString aString = parseInt(aString) else if isFloat aString aString = parseFloat(aString) else aString = undefined aString _validate: (aValue, aOptions)-> aValue = @stringToValue(aValue) if isString aValue result = isNumber aValue if result if aOptions vMin = aOptions.min vMax = aOptions.max if vMin? result = aValue >= vMin if not result @error "should be equal or greater than minimum value: " + vMin if result and vMax? result = aValue <= vMax if not result @error "should be equal or less than maximum value: " + vMax result ``` ### Use the number type * Type(aTypeName, aOptions) * get the type info object from glabal cache if aOptions is null or the same as the original/default attributes value. * else create a new virtual type info object. * type.createType(aObject) (Type::createType) * create a new type info object instance always. * the aObject.name should be exists as the type name. ```js var cacheable = require('cache-factory') var Type = cacheable(require('abstract-type')) // apply the cache-able ability to Type require('number-type') //register the number type to Type. var number = Type('Number') // get the number type object. assert.equal(number, Type('Number')) var num = Type('Number', {min:1, max:6}) // create non-name a virutal type object. assert.notEqual(number, num) var NumberType = Type.registeredClass('Number') // get Number Type Class // create a virtual type object var TPositiveNumber = Type('Number', {min:0, cached: 'PositiveNumber'}) assert.notOk(TPositiveNumber.isValid(-1)) assert.ok(TPositiveNumber.isValid(1)) // validate a value var n = TPositiveNumber.create(123) // create the value n = TPositiveNumber.createValue(123) assert.ok(n.isValid()) assert.equal(Number(n) + 3, 126) //get the virtual type from cache: var N = Type('/type/AbstractNumber/Number/PositiveNumber') //N = NumberType('PositiveNumber') assert.equals(N, TPositiveNumber); ``` ## API ### Type = require('abstract-type') It's the abstract type info class and the type info manager. * `constructor([typeName, ]options)`: get a the default type info instance object from global cache or create a new virutal type object. * __arguments__ * `typeName` *(string)*: the type name. * `options` *(object)*: optional type options to apply. different types have different options. * `name` *(string)*: the type name. * `validate` *(function)*: assign the custom validate function. * `function(value)` the first argument is the value to validate. * return the validation result. * stored into the `customValidate` property internal. * `...`: the type's specified options to create a new virtual type object. * __return__ * *(object)*: the type object instance. * eg: ```js // get the default type object var TNumber = Type('number') // other way to get the default type object TNumber = Type({name: 'number'}) // another way to get the default type object TNumber = NumberType() // create a new virtual type object. var TPositiveNumber = Type('number', {min:0}) assert.notEqual(TPositiveNumber, TNumber) // create a new virtual type object. TPositiveNumber = Type('number', {validate: function(v){return v>=0}}) assert.notEqual(TPositiveNumber, TNumber) ``` * `Type.create(typeName, options)`:This class method is used to create a new Type instance object. * __arguments__ * `typeName` *(string)*: the type name. * `options` *(object)*: optional type options. different types have different options. * __return__ * *(object)*: the created type object instance. * `Type.createFrom(aObject)`: the class method to create a type object or value object from a parametric type object. * __arguments__ * `aObject` *(object)*: the encoding string should be decoded to an object. * `name` *(string)*: the type name required. * `value` : the optional value. return value object if exists. * __return__ * *(object)*: * the created type object instance with the type info if no value in it. * the created value object instance if value in it. * `Type.createFromJson(json)`:the class method to create a type object or value object from a json string. * __arguments__ * `json` *(string)*: the json string with type info. * `name` *(string)*: the type name required. * `value` : the optional value. return value object if exists. * __return__ * *(object)*: * the created type object instance with the type info if no value in it. * the created value object instance if value in it. * `Type.registerValidator(aValidator)`:This class method is used to register a custom validator. * __arguments__ * `aValidator` *(object)*: the validator. * `name` *(string)*: the validator option name. * `validate` *(function)*: the validator function: `function(value, options)` * __return__ * *(boolean)*: whether successful. * `Type.registerValidator(name, validate)`:This class method is used to register a custom validator. * __arguments__ * `name` *(string)*: the validator option name. * `validate` *(function)*: the validator function: `function(value, options)` * __return__ * *(boolean)*: whether successful. * `Type.unregisterValidator(name)`:This class method is used to unregister a custom validator. * __arguments__ * `name` *(string)*: the validator name to unregister. * __return__ * *(boolean)*: whether successful. * `cloneType()`:the instance method to clone the type object itself. * alias: clone * __return__ * *(object)*: the created type object instance with same type info. * eg: ```js var num = Type('Number', min:1) var num1 = num.cloneType() assert.ok(num.isSame(num1)) ``` * `createType(options)`: create a new the type object of this type with the type options. * __arguments__ * `options` *(object)*: optional type options. different types have different options. * it is the same as `cloneType()` if no options * __return__ * *(object)*: the created type object instance with the type info options. * `createValue(value, options)`:create a value from the type. * alias: create * __arguments__ * `value` *(Type)*: the value of this type to create * `options` *(object)*: optional type options * the new virtual type of the value will be created if exists * __return__ * *(object)*: the created value object instance. * `toObject(aObject, aNameRequired = true)`:convert the type info into aObject(an parametric type object). It could be streamable your type. * __arguments__ * `options` *(object)*: optional options * `value` *(Type)*: optional value, when value exists, the following options used: * `typeOnly` *(boolean)*: just type info if true. defaults to false. * `aNameRequired` *(boolean)*: write the name to aObject. defaults to true. * __return__ * *(object)*: the created object with type info. * `toJson(options)`:convert the type info to a json string. It could be streamable your type. It is almost equivalent to JSON.stringify(theTypeObject). * __arguments__ * `options` *(object)*: optional options * `value` *(Type)*: optional value, when value exists, the following options used: * `typeOnly` *(boolean)*: just type info if true. defaults to false. * __return__ * *(string)*: the json string with type info. * `validate(value, raiseError, options)`:validate a specified value whether is valid. * __arguments__ * `value` *(Type)*: the value to validate * `raiseError` *(boolean)*: whether throw error if validate failed. defaults to true. * `options` *(object)*: optional type options to override. defaults to this type options. * __return__ * *(boolean)*: whether is valid if no raise error. ### Value = require('abstract-type').Value the value class. You should implement the `valueToString(aValue)` and `stringToValue(aString)` method in your derived type class to make the value streamable. * `constructor(value[[, type], options])`: create a value object. * __arguments__ * `value` *(Type)*: the value to be created. * it will guess the type if no type object. * `type` *(Object)*: the optional type object. * `options` *(object)*: optional type options. * checkValidity *(boolean)*: whether check the value is valid. defaults to true. * __return__ * *(object)*: the created value object instance. * property `$type`: point to a type object. It can not be enumerable. * `clone()`: clone the value object. * __return__ * *(object)*: the created new value object instance with same as original info. * `create(value, options)`:create a new the value object. * __arguments__ * `value` *(Type)*: the value to be created. MUST BE the same type. * `options` *(object)*: optional type options. * checkValidity *(boolean)*: whether check the value is valid. defaults to true. * __return__ * *(object)*: the created value object instance. * `assign(value, options)`:assign a value to itself. * __arguments__ * `value` *(Type)*: the value to be assigned. MUST BE the same type. * `options` *(object)*: optional type options. * checkValidity *(boolean)*: whether check the value is valid. defaults to true. * __return__ * *(object)*: `this` object. * `isValid()`: validate the value whether is valid. * __return__ * *(boolean)*: whether the value is valid. * `toObject(options)`:convert the value to an object. It wont include type info via defaults. It could be streamable your value. * __arguments__ * `options` *(object)*: optional options * `withType` *(Boolean)*: whether with type info, defaults to false. * __return__ * *(object)*: the value and type info(if `withType`). * eg: ```js var Type = require('abstract-type') var Value = Type.Value var val = Value(1, Type 'Number') assert.equal val.toObject(), 1 ``` ## TODO + compare(value1, value2) and equals(value1, value2) to compare value. ## License MIT