class-config-base

1.1.0 • Public • Published

class-config-base NPM MIT License Build Status Build Status Coverage Status

The base class of a configuration class which configures a interfacial class.

Install

npm install class-config-base

Load this module

For Node.js

const ClassConfig = require('class-config-base')

For Web browser (only supporting es6)

<script src="class-config-base.min.js"></script>

Usage

  1. Define default config object. This object determines the property default values, the property structure and the property data types of the class config class.

    const defaultConfig = { top: 0, left: 0, right: 100, bottom: 50 }
  2. Define the class config class.

    • defineMorePrivates method is optional and provides a timing to define more private data than private data defined by defaultConfig.
    • defineAccessors method is optional and creates descriptors to override property accessors.
    • defineInterfaces method creates descriptors to define properties and methods of the target interfacial class.
    class RectangleConfig extends ClassConfig {
      constructor (initConfig, opts) {
        super(initConfig, defaultConfig, opts)
      }
     
      defineMorePrivates ($private) {
        $private.zoom = 1
        $private.zoomRange = { min: 0.2, max: 5 }
      }
     
      defineAccessors ($private, config) {
        return {
          zoom: { /* writable property */
            enumerable: true,
            get () { return $private.zoom },
            set (v) {
              v = Math.max(v, config.zoomRange.min)
              v = Math.min(v, config.zoomRange.max)
              $private.zoom = v
            },
          },
        }
      }
      
      get width () { return this.right - this.left }
      get height () { return this.bottom - this.top }
     
      defineInterfaces (config, instance) {
        return {
          width: { /* writable property */
            enumerable: true,
            get () { return config.width * config.zoom },
            set (v) { config.right = config.left + v / config.zoom },
          },
          height: { /* writable property */
            enumerable: true,
            get () { return config.height * config.zoom },
            set (v) { config.bottom = config.top + v / config.zoom },
          },
          area: { /* replaceable property */
            enumerable: true,
            configurable: true,
            set (value) { Object.defineProperty(instance, 'area', {
              enumerable: true,
              configuable: true,
              writable: true,
              value,
            }) },
            get () {
              return config.width * config.zoom * config.height * config.zoom
            },
          },
          inflate: { /* method property */
            enumerable: true,
            configurable: true,
            writable: true,
            value: (dw, dh) => {
              config.right += dw
              config.bottom += dh
            },
          },
        }
      }
    }

    This module provides some useful functions to define accessors/interfaces simply. By using these functions, the above example can be rewritten as follows:

    const { readonly, writable, replaceable, method } = ClassConfig
     
    class RectangleConfig extends ClassConfig {
     
      constructor (initConfig, opts) {
        super(initConfig, defaultConfig, opts)
      }
     
      defineMorePrivates ($private) {
        $private.zoom = 1
        $private.zoomRange = { min: 0.2, max: 5 }
      }
     
      defineAccessors ($private, config) {
        return {
          zoom: writable({
            get () { return $private.zoom },
            set (v) {
              v = Math.max(v, config.zoomRange.min)
              v = Math.min(v, config.zoomRange.max)
              $private.zoom = v
            },
          }),
        }
      }
      
      get width () { return this.right - this.left }
      get height () { return this.bottom - this.top }
     
      defineInterfaces (config, instance) {
        return {
          width: writable({
            get () { return config.width * config.zoom },
            set (v) { config.right = config.left + v / config.zoom },
          }),
          height: writable({
            get () { return config.height * config.zoom },
            set (v) { config.bottom = config.top + v / config.zoom },
          }),
          area: replaceable({
            get () {
              return config.width * config.zoom * config.height * config.zoom
            },
          }),
          inflate: method((dw, dh) => {
            config.right += dw
            config.bottom += dh
          }),
        }
      }
    }
  3. Define the interfacial class with the class config.

    class Rectangle {
      constructor (config) {
        config.configure(this)
      }
    }

    The interfaces of interfacial class can be also defined by following way:

    class RectangleConfig extends ClassConfig {
      constructor (initConfig, opts) { ... }
      defineMorePrivates ($private) { ... }
      defineAccessors ($private, config) { ... }
    }
     
    class Rectangle {
      constructor (config) {
        config.configure(this, {
          width: writable({
            get () { return config.width * config.zoom },
            set (v) { config.right = config.left + v / config.zoom },
          }),
          height: writable({
            get () { return config.height * config.zoom },
            set (v) { config.bottom = config.top + v / config.zoom },
          }),
          area: replaceable({
            get () {
              return config.width * config.zoom * config.height * config.zoom
            },
          }),
          inflate: method((dw, dh) => {
            config.right += dw
            config.bottom += dh
          }),
        })
      }
    }
  4. Instantiate and use the interfacial class.

    const rectConfig = new RectangleConfig()
    const rect = new Rectangle(rectConfig)
     
    console.log(rect.toString()) // => [object Rectangle]
    console.log(Object.prototype.toString.call(rect)) // => [object Rectangle]
    console.log(rectConfig.toString())
    // => RectangleConfig { top: 0, left: 0, right: 100, bottom: 50, zoom: 1, zoomRange: { min: 0.2, max: 5 } }
     
    console.log(rect.width) // => 100
    console.log(rect.height) // => 50
    console.log(rect.area) // => 5000
     
    rect.inflate(10, 20)
    console.log(rectConfig.toString())
    // => RectangleConfig { top: 0, left: 0, right: 110, bottom: 70, zoom: 1, zoomRange: { min: 0.2, max: 5 } }
    console.log(rect.width) // => 110
    console.log(rect.height) // => 70
    console.log(rect.area) // => 7700
  5. A property value, even if it is read-only or hidden, can be updated with the class config object.

    rectConfig.zoom = 0
    console.log(rectConfig.toString())
    // => RectangleConfig { top: 0, left: 0, right: 110, bottom: 70, zoom: 0.2, zoomRange: { min: 0.2, max: 5 } }
    console.log(rect.width) // => 22
    console.log(rect.height) // => 14
    console.log(rect.area) // => 308
     
    rectConfig.right = 160
    rectConfig.bottom = 120
    console.log(rectConfig.toString())
    // => RectangleConfig { top: 0, left: 0, right: 160, bottom: 120, zoom: 0.2, zoomRange: { min: 0.2, max: 5 } }
    console.log(rect.width) // => 32
    console.log(rect.height) // => 24
    console.log(rect.area) // => 768

Manage a config object and interfacial object

A mapping between a config class instance and a interfacial class instance can be managed by ClassConfig.Manager object.

const { Manager } = ClassConfig
 
const manager = new Manager()  // Create a manager
 
manager.set(rectConfig, rect)  // Set a mapping
 
const aConfig = manager.getConfig(rect)  // Get the configure object
const aRect = manager.getObject(rectConfig)  // Get the interfacial object
 
manager.delete(aRect)  // Delete a mapping

Share private data with another config object

A config object can share its private data (config.$private) with another config object, as follows:

const config1 = new RectangleConfig({ top: 1, left: 2, right: 12, bottom: 21 })
const config2 = new RectangleConfig(config1, { sharePrivate: true })

console.log(config1.toString())
// => RectangleConfig { top: 1, left: 2, right: 12, bottom: 21, zoom: 1, zoomRange: { min: 0.2, max: 5 } }
console.log(config2.toString())
// => RectangleConfig { top: 1, left: 2, right: 12, bottom: 21, zoom: 1, zoomRange: { min: 0.2, max: 5 } }

config1.right = 102
console.log(config1.toString())
// => RectangleConfig { top: 1, left: 2, right: 102, bottom: 21, zoom: 1, zoomRange: { min: 0.2, max: 5 } }
console.log(config2.toString())
// => RectangleConfig { top: 1, left: 2, right: 102, bottom: 21, zoom: 1, zoomRange: { min: 0.2, max: 5 } }

API

class ClassConfig

Is a class to configure the target class instance from hiding place.

.constructor (initConfig, defaultConfig, opts) => ClassConfig

Is a constructor to creates an instance of this class. initConfig and defaultConfig are objects and can be nested objects. defaultConfig is to specify the default values and the types of the properties. So if a type of a property in initConfig is different from a type of a corresponding property in defaultConfig, the property value in initConfig is ignored.

Parameters:

Parameter Type Description
initConfig object A configuration object which has initial property values.
defaultConfig object A configuration object which has default property values.
opts object A option object (Optional)

Propeties of opts:

Property Type Description
sharePrivate boolean True, if sharing .$private of initConfig which is ClassConfig object. (By default, falsy)

Returns:

A ClassConfig object.

.configure (instance, descriptors) => Void

Configures the interfaces of the target class instance in its constructor.

Parameters:

Parameter Type Description
instance object A class instance to be configured.
descriptors object A plain object which has descriptors of interfaces of the target class instance.

.defineMorePrivates ($private) => Void

Defines more private data than private data defined in defaultConfig.

Parameters:

Parameter Type Description
$private object The root object to store private data of the config object.

.defineAccessors ($private, config) => object

Returns an object which maps between property key chains and property descriptors. A key chain is a string that concatenates all keys in a key path with dots. A descriptor is a thing used by Object.defineProperty.

This method is used to override accessors of the config class.

Parameters:

Parameter Type Description
$private object The root object to store private data of the config object.
config ClassConfig This config object.

Returns:

A nested plain object which contains property descriptors of accessors of this config object.

.defineInterfaces (config, instance) => Void

Returns an object which maps between property names and property descriptors. A descriptor is a thing used by Object.defineProperty.

This method defines the interfaces of the target class.

Parameters:

Parameter Type Description
config ClassConfig This config object.
instance object The instance of the interfacial class configured by this config object.

[static] .readonly ({ getter [, enumerable ] }) => object

Returns a readonly property descriptor.

Parameters:

Parameter Type Description
getter function A getter for this property.
enumerable boolean A flag to show this property during enumeration of the properties.

Return:

A property descriptor of the target readonly property.

[static] .writable ({ getter, setter, [, enumerable ] [, configurable ] }) => object

Returns a writable property descriptor.

Parameter Type Descriptor
getter function A getter for this property.
setter function A setter for this property.
enumerable boolean A flag to show this property during enumeration of the properties.
configurable boolean A flag to change or delete this property.

Return:

A property descriptor of the target writable property.

[static] .replaceable ({ getter [, enumerable ] }) => object

Returns a replaceable property descriptor.

Parameters:

Parameter Type Description
get function A getter for this property.
enumerable boolean A flag to show this property during enumeration of the properties.

Return:

A property descriptor of the target replaceable property.

[static] .method (fn) : object

Returns a property descriptor for a method.

Parameters:

Parameter Type Description
fn function A method function for this property.

Return:

A property descriptor of the target method property.

class ClassConfig.Manager

Is a manager class which has mappings of a config object and an object configured by it.

.constructor () => ClassConfig.Manager

Creates an instance of this class.

Returns:

A ClassConfig.Manager object.

.set (object, config) => Void

Sets a mapping of a config object and an object configured by it.

Parameters:

Parameter Type Description
object object The object configured by the config object.
config ClassConfig The config object.

.delete (objectOrConfig) => Void

Deletes a mapping of a config object and an object configured by it.

Parameters:

Parameter Type Description
objectOrConfig object |ClassConfig The object or config object to be deleted its mapping from this manager object.

.getConfig (object) => ClassConfig

Gets a config object corresponding to the specified object.

Parameters:

Parameter Type Description
object object The object registered with this manager object.

Returns:

The config object corresponding to the specified object.

.getObject (config) => object

Get an object corresponding to the specified config object.

Parameters:

Parameter Type Description
config ClassConfig The config object registered with this manager object.

Returns:

The object corresponding to the specified config object.

License

Copyright (C) 2017-2018 Takayuki Sato

This program is free software under MIT License. See the file LICENSE in this distribution for more details.

Package Sidebar

Install

npm i class-config-base

Weekly Downloads

210

Version

1.1.0

License

MIT

Unpacked Size

63.6 kB

Total Files

9

Last publish

Collaborators

  • sttk