0.1.0 • Published 6 years ago

@geronimus/flatware v0.1.0

Weekly downloads
1
License
BSD-2-Clause
Repository
github
Last release
6 years ago

Contents

Flatware

(As in place settings.) This is a simple library to help you place settings. (eg, Configurations.)

We're trying to keep things simple. Therefore we're sticking with the idea of a one-level (flat) list of values, each of which has a unique name.

flatware defines two kinds of objects - a spec (specification), and a conf (configuration).

spec

Specification

It defines the values you are expecting to get. You can use it to validate a conf.

conf

Configuration

A thin wrapper around a simple value map. But the point is that you can validate it against a spec.

Value Types

You can use these to define the values a spec will accept. For simplicity's sake, we're sticking to a very limited set of value types:

  • boolean : JavaScript's boolean type. true and false are the only values.
  • number : JavaScript's number type, based on the IEEE 754 Floating-Point standard, similar to a type called double in many languages. Can accurately express integer values from -9,007,199,254,740,991 to 9,007,199,254,740,991. Can express real numbers with notably less precision.
  • string : JavaScript's text type.
  • Date : JavaScript's Date type.

Constraints

These are further limitations on what values a spec allows.

  • optionsList : You can define a list (Array) of acceptable values. The chosen value must be one of these. Applies to: ( number, sting, Date )
  • upperBound : The greatest / highest / latest value you will accept. (Inclusive.) Applies to: ( number, Date )
  • lowerBound : The smallest / lowest / earliest value you will accept. (Inclusive.) Applies to: ( number, Date )
  • pattern : A regular expression defining a text pattern that values you accept must match. Applies to: ( string )

Define a spec

Our example defines an imaginary configuration for a video game called Rescue . (Tom Spreen's unlicensed Star Trek: The Next Generation adventure for Apple computers in the mid 1990s.)

const spec = flatware.spec.fromObject({
  includeCubeShip: {
    type: "boolean",
    desc: "Determines whether or not the Borg ship will be included as one of the enemies.",
  },
  enemies: {
    type: "number",
    desc: "The number of enemy ships to include on the map.",
    lowerBound: 3,
    upperBound: 30,
    optionsList: [
      3, 6, 9, 12, 15, 18, 21, 24, 27, 30
    ]
  },
  skillLevel: {
    type: "string",
    desc: "Defines the attack strategies that enemies will use.",
    optionsList: [
      "The Cadet's Game",
      "The Captain's Game",
      "The Admiral's Game"
    ]
  },
  userName: {
    type: "string",
    desc: "The name we will display on the scoreboard for high-scoring games. Must be a string of between one and seven characters, without any whitespace.",
    pattern: /[^\s]{1,7}/
  },
  gameStartTime: {
    type: "Date",
    desc: "The date on which the game's timer starts. Must be during the second half of the 24th century.",
    lowerBound: new Date( "2350-01-01 00:00:00.000Z" ),
    upperBound: new Date( "2399-12-31 23:59:59.999Z" )
  }
});

You don't have to include descriptions, but they are helpful. Especially if you choose to generate a template.

Templates

Once you have a spec defined, you can use it to generate a template:

spec.getTemplate();

The template is a JSON string, (eg, You can easily save it as a text file.), Each setting will have all of its defined properties, as well as a value property, which users can set to any value, in order to define a configuration.

Here is an example of what a fragment of the template that the example spec we gave above might include:

{
  "skillLevel": {
    "type": "string",
    "desc": "Defines the attack strategies that enemies will use.",
    "optionsList": [
      "The Cadet's Game",
      "The Captain's Game",
      "The Admiral's Game"
    ],
    "value": null
  },

  ...
}

You can define either a conf, or a spec, (or both), using a valid template.

eg,

let conf;
let spec;

fs.readFile( "./template.json", ( error, template ) => {
  if ( error )
    throw error;
  else {
    conf = flatware.conf.fromTemplate( template );
    spec = flatware.spec.fromTemplate( template );
  }
});

Configurations

You can also define a conf using a simple object:

const conf = flatware.conf.fromObject({
  includeCubeShip: true,
  enemies: 15,
  skillLevel: "The Captain's Game",
  userName: "Picard",
  gameStartTime: "2366-06-18 01:00:00.000Z"
});

Or from a JSON file:

let conf;

fs.readFile( "./conf.json", ( error, confJSON ) => {
  if ( error )
    throw error;
  else
    conf = flatware.conf.fromJSON( confJSON );
});

Validation

You can use a spec to validate a conf object.

These methods give you a detailed report on the differences between your conf and your spec. But it will not throw any errors. You're free to determine how to use it.

conf.adheresTo( spec )

adheresTo requires the conf to exactly match the spec. Any missing, illegal, or extra values will give a false result.

{
  result: false,
  missing: [ includeCubeShip ],
  illegal: { enemies: 1 },
  extra: { starbases: 9 },
  okay: {
    skillLevel: "The Captain's Game",
    gameStartTime: Tue Jun 05 2379 21:52:31 GMT (Greenwhich Mean Time)
  }
}

conf.conformsWith( spec )

conformsWith requires the conf to not contradict the spec's definition of any of the settings it uses. It only reports false in the case of a type or constraint violation. Missing and extra values are allowed.

{
  result: true,
  missing: [ includeCubeShip ],
  illegal: {},
  extra: { starbases: 9 },
  okay: {
    enemies: 15,
    skillLevel: "The Captain's Game",
    gameStartTime: Tue Jun 05 2379 21:52:31 GMT (Greenwhich Mean Time)
  }
}

API

There is also a full, programmatic application programming interface for defining specs and confs. We present it below.

flatware

The parent object. The only thing you need to import. ALl fo the functionality springs from this namespace.

flatware.conf

The conf interface. (See below(### setting.desc).)

flatware.conf.new() : conf

Create a new blank conf object.

flatware.conf.fromObject( obj : Object ) : conf

Create a conf object defined by an object representation.

`obj`: Any key-value map, represented as a JavaScript object. If you want this to adhere to - or conform to - a spec, then the values should belong to ___flatware___'s legal value types. (See above.)

returns

A conf object.

flatware.conf.fromJSON( jsonText : JSONString ) : conf

Create a conf object defined by a JSON representation. This should work in the same way as flatware.conf.fromObject without having parse the JSON representation of an object.

`jsonText`: The valid JSON string defining the configuration.

returns

A conf object.

flatware.conf.fromTemplate( template : JSONString ) : conf

Create a conf object defined by a template representation. This should work in the same way as flatware.conf.fromObject, except that it takes template JSON representations. It ignores the spec properties, and only uses the value property.

`template`: The valid JSON string defining the template.

returns

A conf object.

flatware.parseTemplate( template : JSONString ) : Object

Takes a valid template (see above) represented as a JSON string, and returns an object containing both the spec and the conf objects that the template defines.i (Available as spec and conf respectively.)

`template`: The valid JSON string defining the template.

flatware.spec

The spec interface. (See below( ### setting.desc ).)

flatware.spec.new() : conf

Create a new blank spec object.

flatware.spec.fromObject( obj : Object ) : conf

Create a spec object defined by an object representation.

`obj`: A JavaScript object where each key defines one or more settings, each of which contain the following properties:

- __type__: _Required_ One of ( `boolean`, `number`, `string`, `Date` )
- __desc__: _Optional_ The textual description of the setting's meaning.
- __optionsList__: _Optional_ You can define a list (Array) of acceptable values. The chosen value must be one of these. Applies to: ( _number_, _sting_, _Date_ )
- __upperBound__: _Optional_ The greatest / highest / latest  value you will accept. (Inclusive.) Applies to: ( _number_, _Date_ )
- __lowerBound__: _Optional_ The smallest / lowest / earliest value you will accept. (Inclusive.) Applies to: ( _number_, _Date_ )
- __pattern__: _Optional_ A [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) defining a text pattern that values you accept must match. Applies to: ( _string_ )

returns

A spec object.

flatware.spec.fromJSON( jsonText : JSONString ) : conf

Create a spec object defined by a JSON representation. This should work in the same way as flatware.spec.fromObject without having to parse the JSON representation of an object.

`jsonText`: The valid JSON string defining the specification.

returns

A spec object.

flatware.spec.fromTemplate( template : JSONString ) : spec

Create a spec object defined by a template representation. This should work in the same way as flatware.spec.fromObject, except that it takes template JSON representations. It ignores the value property and just uses the values that define a spec. (See above.)

`template`: The valid JSON string defining the template.

returns

A spec object.

conf.adheresTo( spec : spec ) : confReport

Does this configuration match the specification exactly? Takes a valid spec object and returns a confReport object detailing the matched properties and violations. (If any.) To obtain a simple boolean result, call conf.adheresTo( spec ).result.

returns

A confReport object, with the following model:

- __result : boolean__ Whether or not the ___conf___ matches the ___spec___ exactly.
- __missing : Array[ string ]__ Lists any property names from the ___spec___ which are not implemented in the ___conf___.
- __extra : object__ Lists any properties found in the ___conf___ that are not defined in the ___spec___.
- __illegal : object__ Lists any properties from the ___conf___ that do not adhere to the type or constraints defined for the same name in the ___spec___.
- ___okay : object___ Lists all properties from the ___conf___ that match the type and constraints from the ___spec___ exactly.

Example:

{
  result: false,
  missing: [ includeCubeShip ],
  illegal: { enemies: 1 },
  extra: { starbases: 9 },
  okay: {
    skillLevel: "The Captain's Game",
    gameStartTime: Tue Jun 05 2379 21:52:31 GMT (Greenwhich Mean Time)
  }
}

conf.conformsWith( spec : spec ) : confReport

Of all of the properties this configuration defines, do the ones defined by the specification match it? Otherwise stated, this is like the method conf.adheresTo( spec : spec ) : confReport, except that it tolerates extra properties not defined by the specification, and missing properties that the specification defines, but the configuration does not implement. Takes a valid spec object and returns a confReport object detailing the matched properties and violations. (If any.) To obtain a simple boolean result, call conf.conformsWith( spec ).result.

returns

A confReport object, with the following model:

- __result : boolean__ Whether or not the properties in this ___conf___ that are defined by the ___spec___ match the ___spec___'s type and constraints.
- __missing : Array[ string ]__ Lists any property names from the ___spec___ which are not implemented in the ___conf___.
- __extra : object__ Lists any properties found in the ___conf___ that are not defined in the ___spec___.
- __illegal : object__ Lists any properties from the ___conf___ that do not adhere to the type or constraints defined for the same name in the ___spec___.
- ___okay : object___ Lists all properties from the ___conf___ that match the type and constraints from the ___spec___ exactly.

Example:

{
  result: true,
  missing: [ includeCubeShip ],
  illegal: {},
  extra: { starbases: 9 },
  okay: {
    enemies: 15,
    skillLevel: "The Captain's Game",
    gameStartTime: Tue Jun 05 2379 21:52:31 GMT (Greenwhich Mean Time)
  }
}

conf.values.get( name : string ) : any

If name has been defined in this conf, returns the value associated with that name. Otherwise, it returns undefined.

conf.values.list() : object

Returns an object containing all of the names and values defined in this conf object.

conf.values.remove( name : string ) : void

Deletes the named property (and its value) from the conf object.

conf.values.set( name : string, value : boolean | number | string | Date ) : void

If the name does not already exist in the conf, creates value you provide associated with the name. If the name already exists, it associates the value you provide with it.

spec.asObject() : specObject

Returns the object representation of the spec.

Example:

{
  includeCubeShip: {
    type: "boolean",
    desc: "Determines whether or not the Borg ship will be included as one of the enemies.",
  },
  enemies: {
    type: "number",
    desc: "The number of enemy ships to include on the map.",
    lowerBound: 3,
    upperBound: 30,
    optionsList: [
      3, 6, 9, 12, 15, 18, 21, 24, 27, 30
    ]
  },
  skillLevel: {
    type: "string",
    desc: "Defines the attack strategies that enemies will use.",
    optionsList: [
      "The Cadet's Game",
      "The Captain's Game",
      "The Admiral's Game"
    ]
  },
  userName: {
    type: "string",
    desc: "The name we will display on the scoreboard for high-scoring games. Must be a string of between one and seven characters, without any whitespace.",
    pattern: /[^\s]{1,7}/
  },
  gameStartTime: {
    type: "Date",
    desc: "The date on which the game's timer starts. Must be during the second half of the 24th century.",
    lowerBound: new Date( "2350-01-01 00:00:00.000Z" ),
    upperBound: new Date( "2399-12-31 23:59:59.999Z" )
  }
}

spec.getTemplate() : string

Returns the object representation of the spec, with an additional value property for each defined name. You can use this to produce a template file, which you can use as a self-documenting config file, instantiating a conf with flatware.conf.fromTemplate( templateJSON ), or even a spec, with flatware.spec.fromTemplate( templateJSON ). (Or even both, using flatware.parseTemplate( templateJSON ).)

spec.settings.define( name : string, type : string ) : setting

Creates a new setting within the spec, for the name you provide, and of the type you specifiy. The new setting has no description or constraints or yet. This method returns the setting object, so that you can begin to specify them immediately.

  • name A string of one of more non-whitespace characters.
  • type One of: "boolean", "number", "string", or "Date". (Throws an error if the type is an illegal value.)

returns

A setting object. (See below( ### setting.desc ).)

spec.settings.fromObject( name : string, obj : object ) : setting

Accepts a name and an object defining (obligatorily) and (optionally) a description and a list of constraints. Returns the setting that the object defined.

  • name A string, consisting of at least one non-whitespace character, which will be the name of the defined setting.
  • obj An object defining the properties type (mandatory), desc, and constraints (optional).

Example:

{
  type: "number",
  desc: "The number of enemy ships to include on the map.",
  lowerBound: 3,
  upperBound: 30,
  optionsList: [
    3, 6, 9, 12, 15, 18, 21, 24, 27, 30
  ]
}

returns

A setting object. (See below( ### setting.desc ).)

spec.settings.get( settingName : string ) : setting

Returns the setting identified by the settingName you provide, if it exists. Otherwise, throws an error.

returns

A setting object. (See below( ### setting.desc ).)

spec.settings.list() : Array string

Returns an Array of the setting names defined by the spec.

spec.settings.remove( settingName : string ) : void

Deletes the setting with the name settingName from the spec. (If it exists.)

setting.asObject() : object

Get the object representation of the setting.

returns

The object representation of a setting.

Example:

{
  type: "number",
  desc: "The number of enemy ships to include on the map.",
  lowerBound: 3,
  upperBound: 30,
  optionsList: [
    3, 6, 9, 12, 15, 18, 21, 24, 27, 30
  ]
}

setting.desc

Read-write property. Gets or sets the description of this setting. Must be a string of at least three words.

setting.getConstraint( constraint : string ) : constraint

Returns the definition of the constraint you specify.

returns

A constraint object.

  • optionsList ( number, string, Date ) An array of values of the settting's type.
  • lowerBound ( number, Date ) The minimum acceptable value for a number or Date.
  • upperBound ( number, Date ) The maximum acceptable value for a number or Date.
  • pattern ( string ) A regular expression (pattern) specifying acceptable string values.

setting.listConstraints() : object

Returns an object, where the keys are the constraint names, and the values are the constraint definitions.

  • optionsList ( number, string, Date ) An array of values of the settting's type.
  • lowerBound ( number, Date ) The minimum acceptable value for a number or Date.
  • upperBound ( number, Date ) The maximum acceptable value for a number or Date.
  • pattern ( string ) A regular expression (pattern) specifying acceptable string values.

setting.name

Read-only property. The name of the setting.

setting.redefineType( newType : string ) : setting

Changes the type of an existing setting. Resets its description and constraints.

  • newType ( "boolean" | "number" | "string" | "Date" ) The type that this setting will now become.

returns

The new setting. Remember, any existing desc and constraint information will be erased.

setting.rename( newName : string ) : setting

Changes the name of this setting within its spec.

  • newName A string consisting of a least one non-whitespace character.

returns

The spec object, as defined by its new name.

setting.type

Read-only property. The type of the property.

0.1.0

6 years ago