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
Markdown
## 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