Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nature

Package Overview
Dependencies
Maintainers
1
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nature - npm Package Compare versions

Comparing version 0.2.5 to 0.3.0

boil/README.hbs

25

Gruntfile.js
var yuidoc2md = require("yuidoc2md");
var docs = yuidoc2md.getMarkdown("lib/nature.js") + yuidoc2md.getMarkdown("lib/Thing.js") + yuidoc2md.getMarkdown("lib/PropertyDefinition.js");
module.exports = function(grunt){

@@ -8,20 +10,17 @@ grunt.initConfig({

options: {
templateData: {
APIdocs: yuidoc2md.getMarkdown([
"lib/nature.js",
"lib/Thing.js",
"lib/PropertyDefinition.js"
])
}
data: { APIdocs: docs }
},
create: {
name: "README.md",
content: grunt.file.read("tasks/boil/readme.hbs")
}
src: "boil/README.hbs",
dest: "README.md"
}
},
jshint: {
options: { jshintrc: true },
all: ['Gruntfile.js', 'lib/*.js', 'test/*.js']
}
});
grunt.loadNpmTasks("grunt-boil");
grunt.loadNpmTasks("grunt-boil");
grunt.loadNpmTasks("grunt-contrib-jshint");
grunt.registerTask("default", "boil");
};

@@ -1,2 +0,3 @@

var util = require("util");
"use strict";
var wodge = require("wodge");

@@ -10,12 +11,84 @@ /**

var self = this,
_value,
_valueTest,
_type,
_validType,
_validValue,
_required = properties.required || false,
_invalidMsg = properties.invalidMsg,
_type = properties.type,
_valueTest = properties.valueTest,
_value = properties.value,
_valid,
_validationMessages = [];
if (!properties.name)
throw new Error("must specify a name on the PropertyDefinition");
function addValidationMessage(msg){
_validationMessages.push(msg);
}
function validateValue(){
if (_required){
if (!_value) {
addValidationMessage("Missing required value");
}
}
if (_value !== undefined){
if (typeof _type === "string"){
if (typeof _value !== _type){
addValidationMessage(_value + " is not a string");
}
} else if (typeof _type === "function"){
if (!(_value instanceof _type)){
addValidationMessage("Value is not an instance of " + _type.name);
}
}
wodge.arrayify(_valueTest).forEach(function(valueTest){
if(valueTest instanceof RegExp){
/*
tested value must not be null or undefined, as `/\w+/.test(undefined)` returns true
*/
if (_value){
if (!valueTest.test(_value)){
addValidationMessage("Failed valueTest: " + _value);
}
} else {
addValidationMessage("Failed valueTest: no value to test");
}
} else if(typeof valueTest === "function"){
try{
var extras = {
addValidationMessage: addValidationMessage,
thing: properties.parent
};
var result = valueTest.call(extras, _value);
if (!result){
addValidationMessage("Failed valueTest function: " + _value);
}
} catch(e){
addValidationMessage("valueTest function crashed: " + e);
}
} else {
if (_value !== valueTest){
addValidationMessage("value does not match valueTest");
}
}
});
}
}
function validate(){
_valid = true;
_validationMessages.splice(0);
validateValue();
if (_validationMessages.length){
_valid = false;
if (self.invalidMsg) addValidationMessage(self.invalidMsg);
if (self.throwOnInvalid){
console.log("Property: " + self.name);
console.log(_validationMessages.join("\n"));
throw new Error("INVALID");
}
}
}
/**

@@ -26,33 +99,33 @@ Gets/sets the property value. Will attempt to convert values to Number for definitions of `type` "number".

*/
Object.defineProperty(this, "value", { get: getValue, set: setValue, enumerable: true });
function getValue(){
return _value;
}
function setValue(newValue){
// attempt to convert newValue to Number
if (this.type === "number" && !isNaN(parseInt(newValue))){
_value = Number(newValue);
Object.defineProperty(this, "value", {
enumerable: true,
get: function(){ return _value; },
set: function(newValue){
// typecast to Number
if (this.type === "number" && wodge.isNumber(newValue)){
_value = Number(newValue);
// on an Array, attempt to convert newValue to string and split it
} else if (this.type === Array && newValue && !Array.isArray(newValue)){
if (typeof newValue === "object"){
_value = [ newValue ];
// typecast to Array
} else if (this.type === Array && newValue && !Array.isArray(newValue)){
if (typeof newValue === "object"){
_value = [ newValue ];
} else {
_value = newValue.toString().split(",").map(function(val){ return val.trim(); });
}
// typecast to RegExp
} else if (this.type === RegExp && typeof newValue === "string"){
try{
_value = new RegExp(newValue);
} catch(e) {
_value = newValue;
}
// every other case, just set the value
} else {
_value = newValue.toString().split(",").map(function(val){ return val.trim() });
}
// cast newValue to RegExp
} else if (this.type === RegExp && typeof newValue === "string"){
try{
_value = RegExp(newValue);
} catch(e) {
_value = newValue;
}
// every other case, just set the value
} else {
_value = newValue;
validate();
}
validate();
}
});

@@ -70,10 +143,10 @@ /**

*/
Object.defineProperty(this, "type", { enumerable: true, get: getType, set: setType });
function setType(newValue){
_type = newValue;
validate();
}
function getType(){
return _type;
}
Object.defineProperty(this, "type", {
enumerable: true,
get: function(){ return _type; },
set: function(newValue){
_type = newValue;
validate();
}
});

@@ -99,39 +172,37 @@ /**

*/
Object.defineProperty(this, "valueTest", { get: getValueTest, set: setValueTest, enumerable: true });
function getValueTest(){
return _valueTest;
}
function setValueTest(newValue){
_valueTest = newValue;
validate();
}
Object.defineProperty(this, "valueTest", {
enumerable: true,
get: function(){ return _valueTest; },
set: function(newValue){
_valueTest = newValue;
validate();
}
});
function validate(){
_validationMessages.splice(0);
_validType = isValidType(self.value, self.type);
if (!_validType){
_validationMessages.push(self.typeFailMsg || "Invalid type: " + self.value);
/**
Thing instance will remain invalid until a value is set
@property required
@type Boolean
*/
Object.defineProperty(this, "required", {
enumerable: true,
get: function(){ return _required; },
set: function(newValue){
_required = newValue;
validate();
}
});
if (self.value === undefined){
if (self.required){
_validValue = false;
_validationMessages.push(self.valueFailMsg || "Missing required value");
} else {
_validValue = true;
}
} else {
_validValue = isValidValue(self.value, self.valueTest, properties.parent, _validationMessages);
if (!_validValue){
_validationMessages.push(self.valueFailMsg || "Invalid value: " + self.value);
}
/**
@property invalidMsg
@type string
*/
Object.defineProperty(this, "invalidMsg", {
enumerable: true,
get: function(){ return _invalidMsg; },
set: function(newValue){
_invalidMsg = newValue;
validate();
}
if (self.throwOnInvalid && (!_validValue || !_validType)){
console.log("Property: " + self.name);
console.log(_validationMessages.join("\n"));
throw new Error("INVALID");
}
}
});

@@ -142,19 +213,15 @@ /**

*/
Object.defineProperty(this, "valid", { get: getValid, enumerable: true });
function getValid(){
return _validType && _validValue;
}
Object.defineProperty(this, "valid", {
enumerable: true,
get: function(){ return _valid; },
});
/**
The default value to set on instantiation
@property default
@type Any
*/
this.default = properties.default;
/**
@property validationMessages
@type Array
*/
this.validationMessages = _validationMessages;
Object.defineProperty(this, "validationMessages", {
enumerable: true,
get: function(){ return _validationMessages; },
});

@@ -172,12 +239,6 @@ /**

*/
if (!properties.name) throw new Error("must specify a name on the PropertyDefinition");
this.name = properties.name;
/**
Thing instance will remain invalid until a value is set
@property required
@type Boolean
*/
this.required = properties.required || false;
/**
if unnamed values are passed to thing.set(), set them AS AN ARRAY on this property

@@ -195,17 +256,2 @@ @property defaultOption

/**
@property typeFailMsg
@type string
*/
this.typeFailMsg = properties.typeFailMsg;
/**
@property valueFailMsg
@type string
*/
this.valueFailMsg = properties.valueFailMsg;
this.type = properties.type;
this.valueTest = properties.valueTest;
this.value = properties.value || properties.default;
this.throwOnInvalid = properties.throwOnInvalid;

@@ -216,41 +262,2 @@

function isValidType(value, type){
if (value === undefined){
return true;
} else if (typeof type === "string"){
return typeof value === type;
} else if (typeof type === "function"){
return value instanceof type;
} else {
return true;
}
}
function isValidValue(value, validTests, thing, validationMessages){
if (!Array.isArray(validTests)) validTests = [ validTests ];
function addValidationMessage(msg){
validationMessages.push(msg);
}
return validTests.every(function(validTest){
if(validTest instanceof RegExp){
return validTest.test(value);
} else if(typeof validTest === "function"){
try{
var extras = {
addValidationMessage: addValidationMessage,
thing: thing
};
return validTest.call(extras, value);
} catch(e){
addValidationMessage("valid test function crashed: " + e);
return false;
}
} else {
return true;
}
});
}
module.exports = PropertyDefinition;
module.exports = PropertyDefinition;

@@ -6,2 +6,3 @@ "use strict";

_ = require("underscore"),
wodge = require("wodge"),
PropertyDefinition = require("./PropertyDefinition"),

@@ -12,2 +13,21 @@ EventEmitter = require("events").EventEmitter;

function initInstanceVars(thing, options){
if (!thing._definitions){
Object.defineProperty(thing, "_definitions", { enumerable: false, configurable: false, value: {} });
}
if (!thing._errors) {
Object.defineProperty(thing, "_errors", { enumerable: false, configurable: false, value: [] });
}
Object.defineProperty(thing, "_throwOnInvalid", {
enumerable: false, configurable: false, writable: false,
value: options && options.throwOnInvalid
});
}
function error(thing, err){
initInstanceVars(thing);
thing._errors.push(err);
thing.emit("error", err);
}
/**

@@ -120,3 +140,3 @@ The base class for some Thing. Example things:

function Thing(options){
initInstanceVars.call(this, options);
initInstanceVars(this, options);
}

@@ -140,10 +160,10 @@ util.inherits(Thing, EventEmitter);

Thing.prototype.define = function(){
var definition, groupName,
var definition,
self = this;
initInstanceVars.call(this);
initInstanceVars(this);
if (arguments.length === 0){
error.call(this, new Error("missing definition"));
} else if (arguments.length == 1 ){
error(this, new Error("missing definition"));
} else if (arguments.length === 1 ){
// define(propertyDefinition)

@@ -162,6 +182,6 @@ if (typeof arguments[0] === "object" && !Array.isArray(arguments[0])){

} else {
error.call(this, new Error("Please pass a single or array of property definitions"));
error(this, new Error("Please pass a single or array of property definitions"));
}
} else if (arguments.length == 2){
} else if (arguments.length === 2){
var groups = Array.isArray(arguments[0])

@@ -187,5 +207,5 @@ ? arguments[0]

definition.parent = this;
definition.throwOnInvalid = this.throwOnInvalid;
definition.throwOnInvalid = this._throwOnInvalid;
if (!(definition instanceof PropertyDefinition)){

@@ -200,7 +220,7 @@ definition = new PropertyDefinition(definition);

if (typeof existingDef !== "undefined"){
delete this._definitions[existingDef.alias]
delete this._definitions[existingDef.alias];
delete this._definitions[name];
}
if (definition.alias && typeof this._definitions[definition.alias] !== "undefined"){
error.call(this, Error("Cannot create property, alias already exists: " + definition.alias));
error(this, new Error("Cannot create property, alias already exists: " + definition.alias));
}

@@ -215,12 +235,10 @@

function getter(){
return this.get(name);
}
function setter(val){
return this.set(name, val);
}
Object.defineProperty(this, name, { enumerable: true, configurable: true, get: getter, set: setter });
Object.defineProperty(this, name, {
enumerable: true,
configurable: true,
get: function(){ return this.get(name); },
set: function(val){ return this.set(name, val); }
});
return this;
}
};

@@ -233,4 +251,4 @@ /**

Thing.prototype.definition = function(propertyName){
initInstanceVars.call(this);
if (!propertyName) error.call(this, new Error("please supply an propertyName"));
initInstanceVars(this);
if (!propertyName) error(this, new Error("please supply an propertyName"));

@@ -250,15 +268,70 @@ var item = this._definitions[propertyName];

*/
Object.defineProperty(Thing.prototype, "definitions", { get: definitions, enumerable: true });
function definitions(){
initInstanceVars.call(this);
var output = {};
for (var prop in this._definitions){
var def = this._definitions[prop];
if (typeof def !== "string"){
output[prop] = def;
Object.defineProperty(Thing.prototype, "definitions", {
enumerable: true,
get: function(){
initInstanceVars(this);
var output = {};
for (var prop in this._definitions){
var def = this._definitions[prop];
if (typeof def !== "string"){
output[prop] = def;
}
}
return output;
}
return output;
};
});
function setThing(incoming, target){
incoming.properties.forEach(function(propertyName){
target.set(propertyName, incoming.get(propertyName));
});
}
function setPlainObject(incoming, target){
Object.keys(incoming).forEach(function(key){
target.set(key, incoming[key]);
});
}
function setArray(incoming, target){
var arrayItems = incoming.slice(0),
item,
defaultValues = [];
if (incoming === process.argv && path.basename(arrayItems[0]) === "node"){
arrayItems.splice(0, 2);
}
while (typeof (item = arrayItems.shift()) !== "undefined"){
var propertyPattern = /^-{1,2}/,
property = "";
if(propertyPattern.test(item)){
property = item.replace(propertyPattern, "");
var def = target.definition(property);
if (def){
if(def.type === "boolean"){
target.set(property, true);
} else if (arrayItems.length) {
target.set(property, arrayItems.shift());
}
} else {
error(target, new Error("invalid property: " + property));
}
} else {
defaultValues.push(item);
}
}
if (defaultValues.length > 0){
wodge.each(target._definitions, function(definition, propertyName){
if (definition.defaultOption){
// always sets an array - need a "setter" property on PropertyDefinition to fix this
if (definition.type === Array){
target.set(propertyName, defaultValues);
} else {
target.set(propertyName, defaultValues[0]);
}
}
});
}
}
/**

@@ -273,59 +346,14 @@ Set a value on the specified property

var self = this;
initInstanceVars.call(this);
initInstanceVars(this);
if (property){
if (property instanceof Thing){
var thing = property;
thing.properties.forEach(function(propertyName){
self.set(propertyName, thing.get(propertyName));
});
setThing(property, this);
} else if (wodge.isPlainObject(property)){
setPlainObject(property, this);
} else if (typeof property === "object" && !Array.isArray(property)){
var properties = property;
_.each(properties, function(value, key){
self.set(key, value);
})
} else if (Array.isArray(property)){
var arrayItems = property.slice(0),
item,
defaultValues = [];
if (property === process.argv && path.basename(arrayItems[0]) === "node"){
arrayItems.splice(0, 2);
}
while (typeof (item = arrayItems.shift()) !== "undefined"){
var propertyPattern = /^-{1,2}/;
if(propertyPattern.test(item)){
property = item.replace(propertyPattern, "");
var def = this.definition(property);
if (def){
if(def.type === "boolean"){
this.set(property, true);
} else if (arrayItems.length) {
this.set(property, arrayItems.shift());
}
} else {
error.call(this, new Error("invalid property: " + property));
}
} else {
defaultValues.push(item);
}
}
if (defaultValues.length > 0){
var defaultOptionName = "";
_.each(this._definitions, function(definition, propertyName){
if (definition.defaultOption){
// always sets an array - need a "setter" property on PropertyDefinition to fix this
if (definition.type === Array){
self.set(propertyName, defaultValues);
} else {
self.set(propertyName, defaultValues[0]);
}
}
});
}
setArray(property, this);
} else {

@@ -344,3 +372,3 @@ if (this._definitions[property] !== undefined){

} else {
error.call(this, new Error("invalid property: " + property));
error(this, new Error("invalid property: " + property));
}

@@ -357,9 +385,12 @@ }

*/
Object.defineProperty(Thing.prototype, "valid", { get: getValid, enumerable: true, configurable: true });
function getValid() {
initInstanceVars.call(this);
return this._errors.length === 0 && _.every(this.definitions, function(def){
return def.valid;
});
}
Object.defineProperty(Thing.prototype, "valid", {
enumerable: true,
configurable: true,
get: function() {
initInstanceVars(this);
return this._errors.length === 0 && wodge.every(this.definitions, function(def, name){
return def.valid;
});
}
});

@@ -373,31 +404,30 @@ /**

enumerable: true,
get: getValidationMessages
});
function getValidationMessages(){
var output = [],
self = this,
validationMessages;
this.properties.forEach(function(property){
validationMessages = self.definition(property).validationMessages;
if (validationMessages.length){
output = output.concat({
property: property,
validationMessages: validationMessages
get: function(){
var output = [],
self = this,
validationMessages;
this.properties.forEach(function(property){
validationMessages = self.definition(property).validationMessages;
if (validationMessages.length){
output = output.concat({
property: property,
validationMessages: validationMessages
});
}
});
output.toString = function(){
var toString = "";
this.forEach(function(prop){
prop.validationMessages.forEach(function(msg){
toString += prop.property + ":\t" + msg + "\n";
});
});
}
});
return toString;
};
output.toString = function(){
var toString = "";
this.forEach(function(prop){
prop.validationMessages.forEach(function(msg){
toString += prop.property + ":\t" + msg + "\n";
});
});
return toString;
return output;
}
});
return output;
}
/**

@@ -408,8 +438,7 @@ A annoy of defined properties

*/
Object.defineProperty(Thing.prototype, "properties", { enumerable: true, get: getProperties });
function getProperties(){
return Object.keys(this.definitions);
}
Object.defineProperty(Thing.prototype, "properties", {
enumerable: true,
get: function(){ return Object.keys(this.definitions); }
});
/**

@@ -444,3 +473,3 @@ Groups a property

return this;
}
};

@@ -467,3 +496,3 @@ /**

} else {
error.call(this, new Error("property does not exist: " + propertyName));
error(this, new Error("property does not exist: " + propertyName));
}

@@ -483,7 +512,14 @@ });

@method where
@param Object filterOptions
@return Thing
@param {Object} filterOptions Mongo style query
@return {Thing} A new Thing instance with the filters applied
@example
var excludeProperties = thing.where({
name: { $ne: ["preset-list", "help", "scan", "title" ] }
});
var certainGroup = thing.where({ group: "handbrake" });
*/
Thing.prototype.where = function(filterOptions){
var result = new Thing();
var result = new Thing(),
isTruthy = function(i){ return i; };

@@ -501,7 +537,7 @@ for (var propertyName in this.definitions){

if ("$ne" in query){
tests.push(query["$ne"].indexOf(definition.name) == -1)
tests.push(query.$ne.indexOf(definition.name) === -1);
}
}
if (tests.every(function(i){ return i; })){
if (tests.every(isTruthy)){
result.define(definition);

@@ -512,3 +548,3 @@ }

return result;
}
};

@@ -529,3 +565,3 @@ /**

}
if (quote) pair[1] = '"' + pair[1] + '"';
if (quote) pair[1] = "\"" + pair[1] + "\"";
});

@@ -586,6 +622,6 @@ output = _.flatten(output);

} else {
error.call(this, new Error("mixIn: must pass in an instance of Thing"));
error(this, new Error("mixIn: must pass in an instance of Thing"));
}
return this;
}
};

@@ -599,3 +635,3 @@ /**

var clone = new Thing();
_.each(this.definitions, function(def, propertyName){
_.each(this.definitions, function(def){
clone.define(_.clone(def));

@@ -630,18 +666,2 @@ });

function error(err){
initInstanceVars.call(this);
this._errors.push(err);
this.emit("error", err);
}
function initInstanceVars(options){
if (!this._definitions){
Object.defineProperty(this, "_definitions", { enumerable: false, configurable: false, value: {} });
}
if (!this._errors) {
Object.defineProperty(this, "_errors", { enumerable: false, configurable: false, value: [] });
}
this.throwOnInvalid = options && options.throwOnInvalid;
}
module.exports = Thing;
{
"name": "nature",
"version": "0.2.5",
"version": "0.3.0",
"description": "Classify the things in your world and how they interact.",

@@ -14,3 +14,4 @@ "main": "lib/nature.js",

"dependencies": {
"underscore": "~1.5.2"
"underscore": "~1.5.2",
"wodge": "~0.1.0"
},

@@ -21,4 +22,5 @@ "devDependencies": {

"yuidoc2md": "~0.2.2",
"grunt-boil": "~0.5.0"
"grunt-boil": "~0.6.0",
"grunt-contrib-jshint": "~0.8.0"
}
}

@@ -53,97 +53,53 @@ [![NPM version](https://badge.fury.io/js/nature.png)](http://badge.fury.io/js/nature)

=================
#PropertyDefinition
#nature
Enforces strict type and value checking on thing properties
Nature, a library to help classify the things (models) in your world (app). Take charge of Nature, design Things that do stuff.
##Properties
* Things can be instantiated with data directly from the command line, environment, an object literal or file.
* Once classified, Things can be re-used across your apps
* Removes all input validation code from your app
###value
Synopsis
Gets/sets the property value. Will attempt to convert values to Number for definitions of `type` "number".
Enables you to write API methods like: (`YoungMan` and `FlammableCar` are derivitives of `Thing`)
**type**: Any
###type
**type**: String | Function
####Example
thing.define({ name: "name", type: "string" });
thing.define({ name: "created", type: Date });
thing.define({ name: "onComplete", type: "function" });
thing.define({ name: "data", type: JobData });
thing.define({ name: "properties", type: Object });
thing.define({ name: "files", type: Array });
###valueTest
A regular expression, function or Array containing one or more of each. A value
must return true for all to be valid.
**type**: Regexp | Function | Array
####Example
thing.define({ name: "name", type: "string", valueTest: /\w{3}/ })
thing.define({ name: "age", type: "number", valueTest: function(value){ return value > 16; } })
thing.define({
name: "colours",
type: Array,
valueTest: [
/red/,
function(colours){
return colours.length > 0;
exports.burnCar = function(arsonist){
var youngMan = new YoungMan(arsonist);
if (!youngMan.valid){
throw new Error(youngMan.validationMessages.join("\n"));
// throws:
// The arsonist supplied must be a young man.
// Invalid age 29: Must be between 11 and 19.
// Over 5 litres Gasoline required
// Less compassion necessary.
} else {
var car = new FlammableCar(process.env);
if (car.valid){
// the Vauxhall Astra supplied in the environment is indeed flammable
youngMan.igniteCar(astra);
}
]
});
}
}
###valid
Client code for the above is straight forward:
**type**: Boolean
var outdoors = require("outdoor-activity");
outdoors.burnCar(process.argv);
###default
Then a simple command executes the outdoor activity:
The default value to set on instantiation
$ CAR_MAKE=Vauxhall CAR_MODEL=Astra node outdoors.js --name Alfie --age 11 --litres 13 --compassion unknown
**type**: Any
See the Thing docs for more detail..
###validationMessages
##Properties
**type**: Array
###Thing
###groups
**type**: Thing
tags
###PropertyDefinition
**type**: Array
**type**: PropertyDefinition
###name
**type**: string
###required
Thing instance will remain invalid until a value is set
**type**: Boolean
###defaultOption
if unnamed values are passed to thing.set(), set them AS AN ARRAY on this property
**type**: Boolean
###alias
**type**: string
###typeFailMsg
**type**: string
###valueFailMsg
**type**: string
#Thing

@@ -359,10 +315,17 @@

**Returns**: __ - Thing
**Returns**: _Thing_ - A new Thing instance with the filters applied
**Params**:
* Object __
* filterOptions _Object_
filterOptions
Mongo style query
####Example
var excludeProperties = thing.where({
name: { $ne: ["preset-list", "help", "scan", "title" ] }
});
var certainGroup = thing.where({ group: "handbrake" });
###toArray

@@ -440,53 +403,99 @@

#nature
#PropertyDefinition
Nature, a library to help classify the things (models) in your world (app). Take charge of Nature, design Things that do stuff.
Enforces strict type and value checking on thing properties
* Things can be instantiated with data directly from the command line, environment, an object literal or file.
* Once classified, Things can be re-used across your apps
* Removes all input validation code from your app
##Properties
Synopsis
###value
Enables you to write API methods like: (`YoungMan` and `FlammableCar` are derivitives of `Thing`)
Gets/sets the property value. Will attempt to convert values to Number for definitions of `type` "number".
exports.burnCar = function(arsonist){
var youngMan = new YoungMan(arsonist);
if (!youngMan.valid){
throw new Error(youngMan.validationMessages.join("\n"));
// throws:
// The arsonist supplied must be a young man.
// Invalid age 29: Must be between 11 and 19.
// Over 5 litres Gasoline required
// Less compassion necessary.
} else {
var car = new FlammableCar(process.env);
if (car.valid){
// the Vauxhall Astra supplied in the environment is indeed flammable
youngMan.igniteCar(astra);
**type**: Any
###type
**type**: String | Function
####Example
thing.define({ name: "name", type: "string" });
thing.define({ name: "created", type: Date });
thing.define({ name: "onComplete", type: "function" });
thing.define({ name: "data", type: JobData });
thing.define({ name: "properties", type: Object });
thing.define({ name: "files", type: Array });
###valueTest
A regular expression, function or Array containing one or more of each. A value
must return true for all to be valid.
**type**: Regexp | Function | Array
####Example
thing.define({ name: "name", type: "string", valueTest: /\w{3}/ })
thing.define({ name: "age", type: "number", valueTest: function(value){ return value > 16; } })
thing.define({
name: "colours",
type: Array,
valueTest: [
/red/,
function(colours){
return colours.length > 0;
}
}
}
]
});
Client code for the above is straight forward:
###valid
var outdoors = require("outdoor-activity");
outdoors.burnCar(process.argv);
**type**: Boolean
Then a simple command executes the outdoor activity:
###default
$ CAR_MAKE=Vauxhall CAR_MODEL=Astra node outdoors.js --name Alfie --age 11 --litres 13 --compassion unknown
The default value to set on instantiation
See the Thing docs for more detail..
**type**: Any
##Properties
###validationMessages
###Thing
**type**: Array
**type**: Thing
###groups
###PropertyDefinition
tags
**type**: PropertyDefinition
**type**: Array
###name
**type**: string
###required
Thing instance will remain invalid until a value is set
**type**: Boolean
###defaultOption
if unnamed values are passed to thing.set(), set them AS AN ARRAY on this property
**type**: Boolean
###alias
**type**: string
###typeFailMsg
**type**: string
###valueFailMsg
**type**: string
[![NPM](https://nodei.co/npm-dl/nature.png?months=3)](https://nodei.co/npm/nature/)

@@ -0,154 +1,66 @@

"use strict";
var assert = require("assert"),
Definition = require("../lib/PropertyDefinition");
Definition = require("../lib/PropertyDefinition"),
def = null,
l = console.log,
d = function(def){ return JSON.stringify(def, null, "\t"); };
var CustomClass = function(){};
function lessThan10(value) {
return value < 10;
}
function allLessThan10(arr){
return arr.every(lessThan10);
}
function allFamily(arr){
return arr.every(function(member){
return (/^(dad|sister|brother|mother)$/).test(member);
});
}
function allFamilyElse(arr){
var self = this;
return arr.every(function(member){
if(/^(dad|sister|brother|mother)$/.test(member)){
return true;
} else {
self.addValidationMessage("this one is invalid: " + member);
return false;
}
});
}
function broken(){
throw new Error("error");
}
function factory(name){
var definitions = {
name: { name: "one" },
string: { name: "one", type: "string" },
number: { name: "one", type: "number" },
bool: { name: "one", type: "boolean" },
func: { name: "one", type: "function" },
obj: { name: "one", type: "object" },
array: { name: "one", type: Array },
custom: { name: "one", type: CustomClass },
date: { name: "one", type: Date },
regex: { name: "one", type: RegExp }
};
return new Definition(definitions[name]);
}
describe("PropertyDefinition", function(){
describe("properties: ", function(){
it("access to `this.config` in a `valid` function must fail if config is not set");
it("should be ok to have an option with no defined type");
it("should be ok to have an definition with no defined type");
it("type: [Array, Function] should allow a type of either");
describe("validation", function(){
it("type validation summary", function(){
var def = new Definition({ name: "one", type: "string", value: "ok" });
assert.strictEqual(def.valid, true);
assert.strictEqual(def.validationMessages.length, 0);
def = new Definition({ name: "one", type: "number", value: "not ok" });
assert.strictEqual(def.valid, false);
assert.strictEqual(def.validationMessages.length, 1);
def = new Definition({ name: "one", type: RegExp, value: /ok/ });
describe(".valid", function(){
it("valid if no type specified", function(){
def = factory("name");
assert.strictEqual(def.valid, true);
assert.strictEqual(def.validationMessages.length, 0);
// "ok" parses by RegExp
def = new Definition({ name: "one", type: RegExp, typeFail: "pass a regex", value: "ok" });
assert.strictEqual(def.valid, true);
assert.strictEqual(def.validationMessages.length, 0);
// "+++" does not parse by RegExp
def = new Definition({ name: "one", type: RegExp, typeFail: "pass a regex", value: "+++" });
assert.strictEqual(def.valid, false);
assert.strictEqual(def.validationMessages.length, 1);
});
it("a number string should typecast to a Number type automatically", function(){
var def = new Definition({ name: "one", type: "number" }) ;
def.value = "3";
assert.strictEqual(def.value, 3);
assert.strictEqual(def.valid, true);
def.value = "0";
assert.strictEqual(def.value, 0);
assert.strictEqual(def.valid, true);
def.value = "-1";
assert.strictEqual(def.value, -1);
assert.strictEqual(def.valid, true);
def.value = -1.5345;
assert.strictEqual(def.value, -1.5345);
assert.strictEqual(def.valid, true);
def.value = "-1.5345";
assert.strictEqual(def.value, -1.5345);
assert.strictEqual(def.valid, true);
def.value = "a";
assert.strictEqual(def.value, "a");
assert.strictEqual(def.valid, false);
def.value = "";
assert.strictEqual(def.value, "");
assert.strictEqual(def.valid, false);
def.value = true;
assert.strictEqual(def.value, true);
assert.strictEqual(def.valid, false);
def.value = function(){};
assert.strictEqual(def.valid, false);
def.value = null;
assert.strictEqual(def.value, null);
assert.strictEqual(def.valid, false);
def.value = undefined;
assert.strictEqual(def.value, undefined);
assert.strictEqual(def.valid, true); // if an option is not required an undefined value is ok
});
it("a regex string should typecast to a RegExp", function(){
var def = new Definition({ name: "one", type: RegExp, value: "\\w{4}" });
assert.ok(def.value instanceof RegExp, def.value);
assert.deepEqual(def.value, /\w{4}/);
});
it("value validation summary", function(){
var def = new Definition({
name: "relative",
type: "string",
value: "dog",
valueTest: /^(dad|sister|brother|mother)$/,
valueFail: "invalid relative"
});
assert.strictEqual(def.valid, false);
assert.strictEqual(def.validationMessages.length, 1);
def.value = "dad";
assert.strictEqual(def.valid, true);
assert.strictEqual(def.validationMessages.length, 0);
def = new Definition({
name: "family",
type: Array,
value: ["dad", "sister", "dog"],
valueTest: /(dad|sister|brother|mother)/
});
assert.strictEqual(def.valid, true);
def = new Definition({
name: "family",
type: Array,
value: ["dad", "sister", "dog"],
valueTest: function(family){
return family.every(function(member){
return /^(dad|sister|brother|mother)$/.test(member);
});
},
valueFail: "every member must be valid"
});
assert.strictEqual(def.valid, false);
assert.strictEqual(def.validationMessages.length, 1);
def = new Definition({
name: "family",
type: Array,
value: ["dad", "sister", "dog"],
valueTest: function(family){
var self = this;
return family.every(function(member){
if (/^(dad|sister|brother|mother)$/.test(member)){
return true;
} else {
self.addValidationMessage("this one is invalid: " + member);
return false;
}
});
},
valueFail: "every member must be valid"
});
assert.strictEqual(def.valid, false);
assert.strictEqual(def.validationMessages.length, 2);
});
it("`valid` should return true if no type specified", function(){
var def = new Definition({ name: "one" });
assert.strictEqual(def.valid, true);
});
it("`valid` should return true when `typeof value === type`", function(){
var def = new Definition({ name: "one", type: "string" });
assert.strictEqual(def.valid, true);
it("valid when value matches type", function(){
def = factory("string");
def.value = 123;

@@ -166,5 +78,4 @@ assert.strictEqual(def.valid, false);

assert.strictEqual(def.valid, false);
def = new Definition({name: "one", type: "number"});
assert.strictEqual(def.valid, true);
def = factory("number");
def.value = 123;

@@ -185,4 +96,3 @@ assert.strictEqual(def.valid, true);

def = new Definition({name: "one", type: "boolean"});
assert.strictEqual(def.valid, true);
def = factory("bool");
def.value = 123;

@@ -203,4 +113,3 @@ assert.strictEqual(def.valid, false);

def = new Definition({name: "one", type: "function"});
assert.strictEqual(def.valid, true);
def = factory("func");
def.value = 123;

@@ -220,5 +129,4 @@ assert.strictEqual(def.valid, false);

assert.strictEqual(def.valid, false);
def = new Definition({name: "one", type: "object"});
assert.strictEqual(def.valid, true);
def = factory("obj");
def.value = 123;

@@ -239,6 +147,5 @@ assert.strictEqual(def.valid, false);

});
it("`valid` should return true if `value instanceof type`", function(){
var def = new Definition({ name: "one", type: Array });
assert.strictEqual(def.valid, true);
it("valid when value instanceof type", function(){
def = factory("array");
def.value = 123;

@@ -260,5 +167,3 @@ assert.strictEqual(def.valid, true); // converted to Array

var CustomClass = function(){};
var def = new Definition({ name: "one", type: CustomClass });
assert.strictEqual(def.valid, true);
def = factory("custom");
def.value = 123;

@@ -273,80 +178,184 @@ assert.strictEqual(def.valid, false);

var def = new Definition({ name: "one", type: Date });
assert.strictEqual(def.valid, true);
def = factory("date");
def.value = new Date();
assert.strictEqual(def.valid, true);
});
it("`valid` should be true with an empty value and not `required`", function(){
var def = new Definition({ name: "one", type: "string" });
it("valid with .required", function(){
/*
required means 'value should be truthy'.
not required permits a value to be undefined.
*/
def = factory("string");
assert.strictEqual(def.valid, true);
def = new Definition({ name: "one", type: "string", required: true });
def.required = true;
assert.strictEqual(def.valid, false);
def.value = "";
assert.strictEqual(def.valid, false);
def.value = " ";
assert.strictEqual(def.valid, true);
var def = new Definition({ name: "one", type: "number" });
def = factory("number");
assert.strictEqual(def.valid, true);
def = new Definition({ name: "one", type: "number", required: true });
def.required = true;
assert.strictEqual(def.valid, false);
def.value = 0;
assert.strictEqual(def.valid, false);
def.value = 1;
assert.strictEqual(def.valid, true);
def = factory("array");
assert.strictEqual(def.valid, true);
def.required = true;
assert.strictEqual(def.valid, false);
def = factory("custom");
assert.strictEqual(def.valid, true);
def.required = true;
assert.strictEqual(def.valid, false);
});
it("valid with .required and .valueTest", function(){
def = factory("string");
assert.strictEqual(def.valid, true);
def.valueTest = /test/;
assert.strictEqual(def.valid, true);
def.value = "clive"
assert.strictEqual(def.valid, false);
def.value = "test"
assert.strictEqual(def.valid, true);
def.value = "";
assert.strictEqual(def.valid, false);
def.value = undefined;
assert.strictEqual(def.valid, true);
def.required = true;
assert.strictEqual(def.valid, false);
def = factory("number");
assert.strictEqual(def.valid, true);
def.valueTest = lessThan10;
assert.strictEqual(def.valid, true);
def.value = "clive"
assert.strictEqual(def.valid, false);
def.value = 9
assert.strictEqual(def.valid, true);
def.value = 0;
assert.strictEqual(def.valid, true);
def.value = undefined;
assert.strictEqual(def.valid, true);
def.required = true;
assert.strictEqual(def.valid, false);
def.value = 0;
assert.strictEqual(def.valid, false);
var def = new Definition({ name: "one", type: Array });
def = factory("string");
assert.strictEqual(def.valid, true);
def.valueTest = /test/;
assert.strictEqual(def.valid, true);
def.valueTest = 1;
assert.strictEqual(def.valid, true);
def.valueTest = lessThan10;
assert.strictEqual(def.valid, true);
def = new Definition({ name: "one", type: Array, required: true });
assert.strictEqual(def.valid, false);
def = factory("number");
assert.strictEqual(def.valid, true);
def.valueTest = /test/;
assert.strictEqual(def.valid, true);
def.valueTest = 1;
assert.strictEqual(def.valid, true);
def.valueTest = lessThan10;
assert.strictEqual(def.valid, true);
var def = new Definition({ name: "one", type: "string", valueTest: /test/ });
def = factory("func");
assert.strictEqual(def.valid, true);
def.valueTest = /test/;
assert.strictEqual(def.valid, true);
def.valueTest = 1;
assert.strictEqual(def.valid, true);
def.valueTest = lessThan10;
assert.strictEqual(def.valid, true);
def = new Definition({ name: "one", type: "string", valueTest: /test/, required: true });
assert.strictEqual(def.valid, false);
def = factory("array");
assert.strictEqual(def.valid, true);
def.valueTest = /test/;
assert.strictEqual(def.valid, true);
def.valueTest = 1;
assert.strictEqual(def.valid, true);
def.valueTest = lessThan10;
assert.strictEqual(def.valid, true);
});
it("`valid` RegExp should work with primitive types", function(){
var def = new Definition({ name: "one", type: "string", default: "test", valueTest: /es/ });
assert.strictEqual(def.valid, true, JSON.stringify(def));
def.valueTest = /as/;
it("valid with RegExp .valueTest", function(){
/*
any definition with a valueTest should always be tested. Required is implied.
*/
def = factory("string");
def.valueTest = /test/;
def.required = true;
assert.strictEqual(def.valid, false);
def.value = "test";
assert.strictEqual(def.valid, true);
def.valueTest = /tast/;
assert.strictEqual(def.valid, false);
def = new Definition({ name: "one", type: "boolean", default: false, valueTest: /false/ });
def.valueTest = /^(dad|sister|brother|mother)$/;
def.value = "dog";
assert.strictEqual(def.valid, false);
def.value = "dad";
assert.strictEqual(def.valid, true);
def.type = Array;
def.valueTest = /(dad|sister|brother|mother)/;
def.value = ["dad", "sister", "dog"];
assert.strictEqual(def.valid, true);
});
it("valid with primitive .valueTest", function(){
def = factory("bool");
def.valueTest = false;
def.value = false;
assert.strictEqual(def.valid, true);
def.valueTest = /true/;
assert.strictEqual(def.valid, false);
def.valueTest = "false";
assert.strictEqual(def.valid, false);
def = factory("number");
def.valueTest = 5;
def.value = 5;
assert.strictEqual(def.valid, true);
def.valueTest = 4;
assert.strictEqual(def.valid, false);
def.valueTest = "5";
assert.strictEqual(def.valid, false);
});
it("`valid` Function should work with primitive and object types", function(){
function smallNumber(value) {
return value < 10;
}
var def = new Definition({ name: "one", type: "number", default: 4, valueTest: smallNumber });
it("valid with function .validTest", function(){
def = factory("number");
def.valueTest = lessThan10;
def.value = 4;
assert.strictEqual(def.valid, true);
def.value = 11;
assert.strictEqual(def.valid, false);
function smallArray(a){
return a.length < 10;
}
def = new Definition({ name: "one", type: Array, default: [0,4,6], valueTest: smallArray });
def = factory("array");
def.valueTest = allLessThan10;
def.value = [0,4,6];
assert.strictEqual(def.valid, true);
def.value = [1,2,3,4,5,6,7,5,4,3,2,1,0];
def.value = [0,4,16];
assert.strictEqual(def.valid, false);
def.valueTest = allFamily;
def.value = ["dad", "sister", "dog"];
assert.strictEqual(def.valid, false);
});
it("`valid` should accept and test an array of functions");
it("`valid` should return false if option `required` with no value set", function(){
var def = new Definition({ name: "one", type: "number", required: true });
assert.strictEqual(def.valid, false);
def = new Definition({ name: "one", type: "number", required: true, default: 1 });
assert.strictEqual(def.valid, true);
});
describe("bad usage", function(){
it("`valid` should return `false` if `valueTest` function threw", function(){
var def = new Definition({ name: "one", type: Array, required: true, valueTest: function(files){
throw new Error("error");
}});
it("valid with function .validTest - function throws", function(){
def = factory("array");
def.valueTest = broken;
def.value = ["test"];

@@ -356,62 +365,92 @@ assert.strictEqual(def.valid, false);

});
it("custom invalid msg with type `number`", function(){
function validTest(value){
return value > 10;
}
var def = new Definition({name: "one", type: "number", valueTest: validTest, valueFailMsg: "must supply a value over 10" });
def.value = 1;
assert.deepEqual(def.validationMessages, ["must supply a value over 10"]);
});
def.value = 11;
assert.deepEqual(def.validationMessages, []);
describe(".validationMessages", function(){
it("with no .invalidMsg", function(){
def = factory("string");
def.value = "ok";
assert.strictEqual(def.validationMessages.length, 0);
def.type = "number";
assert.strictEqual(def.validationMessages.length, 1);
def.type = RegExp;
assert.strictEqual(def.validationMessages.length, 1);
});
it("custom invalid msg with type `Array`", function(){
function validArray(values){
return values.every(function(val){
return val > 10;
});
}
var def = new Definition({
name: "one",
type: Array,
valueTest: validArray,
valueFailMsg: "every value must be over 10"
});
def.value = [1];
assert.deepEqual(def.validationMessages, ["every value must be over 10"]);
it("with .invalidMsg", function(){
def = factory("array");
def.valueTest = allLessThan10;
def.invalidMsg = "every value must be less than 10";
def.value = [11];
assert.strictEqual(def.validationMessages[1], "every value must be less than 10");
def.value = [1];
assert.deepEqual(def.validationMessages, []);
def = factory("regex");
def.invalidMsg = "pass a regex";
def.value = "ok";
assert.strictEqual(def.validationMessages.length, 0);
def.value = "+++";
assert.strictEqual(def.validationMessages.length, 2);
assert.strictEqual(def.validationMessages[1], "pass a regex");
});
it("inserting error messages from a `valid` function", function(){
function validArray(values){
var valid = true, self = this;
values.forEach(function(val){
if (val < 10){
valid = false;
self.addValidationMessage("less than 10: " + val);
}
});
return valid;
}
var def = new Definition({
name: "one",
type: Array,
valueTest: validArray,
valueFailMsg: "every value must be over 10"
});
def.value = [1];
assert.deepEqual(def.validationMessages, ["less than 10: 1", "every value must be over 10"]);
it("raised from .validTest function", function(){
def = factory("array");
def.value = ["dad", "sister", "dog"];
def.valueTest = allFamilyElse;
def.invalidMsg = "every member must be valid";
assert.strictEqual(def.valid, false);
assert.strictEqual(def.validationMessages.length, 3);
});
});
def.value = [11];
assert.deepEqual(def.validationMessages, []);
describe(".value", function(){
it("typecasting with number", function(){
def = factory("number");
def.value = "3";
assert.strictEqual(def.value, 3);
def.value = "0";
assert.strictEqual(def.value, 0);
def.value = "-1";
assert.strictEqual(def.value, -1);
def.value = -1.5345;
assert.strictEqual(def.value, -1.5345);
def.value = "-1.5345";
assert.strictEqual(def.value, -1.5345);
def.value = "a";
assert.strictEqual(def.value, "a");
def.value = "";
assert.strictEqual(def.value, "");
def.value = true;
assert.strictEqual(def.value, true);
def.value = CustomClass;
assert.strictEqual(def.value, CustomClass);
def.value = null;
assert.strictEqual(def.value, null);
def.value = undefined;
assert.strictEqual(def.value, undefined);
});
it("typecasting with RegExp", function(){
def = factory("regex");
def.value = "\\w{4}";
assert.ok(def.value instanceof RegExp, def.value);
assert.deepEqual(def.value, /\w{4}/);
def.value = "ok";
assert.ok(def.value instanceof RegExp);
assert.deepEqual(def.value, /ok/);
def.value = "+++";
assert.ok(!(def.value instanceof RegExp));
assert.strictEqual(def.value, "+++");
});
});
});
});
var assert = require("assert"),
_ = require("underscore"),
Thing = require("../lib/Thing"),
PropertyDefinition = require("../lib/PropertyDefinition");
PropertyDefinition = require("../lib/PropertyDefinition"),
l = console.log;
it("should toArray()");
it("should list defined properties");
it("should be compatible with --property=value style");
it("passing required:true should test for defaultOption.length > 0")
it("this case should be invalid straight after definition: { type: Array, valueTest: function(a){ return a.length > 0; }}");
it("should throw when a none-existent property is accessed, e.g. console.log(properties.dfkdshl)");
it("free usage on --help");
it("should protect from defining properties with reserved names like clone, toJSON, mixIn etc");
describe("Thing", function(){
it("should toArray()");
it("should list defined properties");
it("should be compatible with --property=value style");
it("passing required:true should test for defaultOption.length > 0");
it("this case should be invalid straight after definition: { type: Array, valueTest: function(a){ return a.length > 0; }}");
it("should throw when a none-existent property is accessed, e.g. console.log(properties.dfkdshl)");
it("free usage on --help");
it("should protect from defining properties with reserved names like clone, toJSON, mixIn etc");
it("should throw on empty property, i.e. 'rename -' or '--'");
it("should expose _errors array on Thing instance API, same as 'validationMessages'");
it("needs consistent error handling.. some errors emit, some throw (like 'renamer -').. should all errors just set valid=false?");
it("should throw on empty property, i.e. 'rename -' or '--'");
it("should expose _errors array on Thing instance API, same as 'validationMessages'");
it("needs consistent error handling.. some errors emit, some throw (like 'renamer -').. should all errors just set valid=false?");
it("should valueTest run on get, so function can refer to other set values in this.config? e.g. if (this.config.regex) then ...");
it("a 'post-set' hook, so setting '**/*.txt' on 'files' can be expanded");
it("scrap constructor to remove need for Thing.call(this)");
it("should emit 'invalid' when thing changes from valid to invalid");
it("should valueTest run on get, so function can refer to other set values in this.config? e.g. if (this.config.regex) then ...");
it("a 'post-set' hook, so setting '**/*.txt' on 'files' can be expanded");
it("scrap constructor to remove need for Thing.call(this)");
it("should emit 'invalid' when thing changes from valid to invalid");
var _thing;
beforeEach(function(){
_thing = new Thing();
});
var _thing;
beforeEach(function(){
_thing = new Thing();
});
describe("Thing API", function(){
describe("properties:", function(){
it("valid - should return true only when all property values are valid", function(){
_thing.define({ name: "one", type: "number", default: 1 });
assert.strictEqual(_thing.valid, true);
_thing.define({ name: "two", type: "number", default: -1034.1 });
assert.strictEqual(_thing.valid, true);
_thing.define({ name: "three", type: "number", default: "Cazzo" });
assert.strictEqual(_thing.valid, false);
describe(".valid", function(){
it("return true when all values valid", function(){
_thing.define({ name: "one", type: "number", value: 1 });
assert.strictEqual(_thing.valid, true);
_thing.define({ name: "two", type: "number", value: -1034.1 });
assert.strictEqual(_thing.valid, true);
_thing.define({ name: "three", type: "number", value: "Cazzo" });
assert.strictEqual(_thing.valid, false);
});
});
it("validationMessages - should return an array of msgs", function(){
_thing.define({ name: "one", type: Array, default: 1 });
_thing.define({ name: "two", type: "string", default: 1 });
_thing.define({ name: "three", type: RegExp, default: 1 });
_thing.define({ name: "four", type: "string", default: "clive", valueTest: /test/ });
_thing.define({ name: "five", type: Array, default: "clive", valueTest: function (val){
return val.length == 0;
}});
_thing.define({ name: "six",type: "number", value: 1 });
assert.ok(_thing.validationMessages.length == 4, JSON.stringify(_thing.validationMessages));
describe(".validationMessages", function(){
it("return array of invalid messages", function(){
_thing.define({ name: "one", type: Array, value: 1 });
_thing.define({ name: "two", type: "string", value: 1 });
_thing.define({ name: "three", type: RegExp, value: 1 });
_thing.define({ name: "four", type: "string", value: "clive", valueTest: /test/ });
_thing.define({ name: "five", type: Array, value: "clive", valueTest: function (val){
return val.length === 0;
}});
_thing.define({ name: "six",type: "number", value: 1 });
assert.ok(_thing.validationMessages.length === 5, JSON.stringify(_thing.validationMessages));
});
});
it("definitions", function(){
var def1 = new PropertyDefinition({ name: "one", type: Array, default: 1 }),
def2 = new PropertyDefinition({ name: "two", type: "string", default: 1 }),
def3 = new PropertyDefinition({ name: "three", type: RegExp, default: 1 });
_thing.define([ def1, def2, def3 ]);
assert.strictEqual(Object.keys(_thing.definitions).length, 3);
assert.strictEqual(_thing.definitions.one, def1);
assert.strictEqual(_thing.definitions.two, def2);
assert.strictEqual(_thing.definitions.three, def3);
describe(".definitions", function(){
it("return hash of PropertyDefinitions", function(){
var def1 = new PropertyDefinition({ name: "one", type: Array, value: 1 }),
def2 = new PropertyDefinition({ name: "two", type: "string", value: 1 }),
def3 = new PropertyDefinition({ name: "three", type: RegExp, value: 1 });
_thing.define([ def1, def2, def3 ]);
assert.strictEqual(Object.keys(_thing.definitions).length, 3);
assert.strictEqual(_thing.definitions.one, def1);
assert.strictEqual(_thing.definitions.two, def2);
assert.strictEqual(_thing.definitions.three, def3);
});
});
it("properties", function(){
_thing.define({ name: "one", type: Array, default: 1 });
_thing.define({ name: "two", type: "string", default: 1 });
_thing.define({ name: "three", type: RegExp, default: 1 });
assert.deepEqual(_thing.properties, [ "one", "two", "three" ]);
})
describe(".properties", function(){
it("return array of property name strings", function(){
_thing.define({ name: "one", type: Array, value: 1 });
_thing.define({ name: "two", type: "string", value: 1 });
_thing.define({ name: "three", type: RegExp, value: 1 });
assert.deepEqual(_thing.properties, [ "one", "two", "three" ]);
});
});
});
describe("methods: ", function(){
describe("defining properties", function(){
describe(".define", function(){
it("define(definition) and definition(name) should set and retrieve", function(){
var definition = { name: "one", type: "string", default: "one" };
var definition = { name: "one", type: "string", value: "one" };
_thing.define(definition);
assert.strictEqual(definition.type, _thing.definition("one").type);
assert.strictEqual(definition.default, _thing.definition("one").default);
assert.strictEqual(definition.value, _thing.definition("one").value);
assert.strictEqual(_thing.get("one"), "one");
});
it("define(existingDefinition) should redefine definition", function(){

@@ -92,7 +101,7 @@ _thing.define({ name: "one", type: "number", alias: "a" });

});
it("define(PropertyDefinition) and retrieve with definition(name)", function(){
var def = new PropertyDefinition({ name: "one", "type": "number" });
_thing.define(def);
assert.strictEqual(def, _thing.definition("one"));

@@ -104,3 +113,3 @@ });

_thing.define({ name: "one", "type": "number", alias: "o", valueTest: testValid });
assert.strictEqual(_thing.definition("one").type, "number");

@@ -111,8 +120,38 @@ assert.strictEqual(_thing.definition("o").type, "number");

});
it("define() should work the same with a `definition.value` as set()");
it("grouping", function(){
_thing
.define("group1", [
{ name: "one", type: "boolean" },
{ name: "two", type: "string" }
])
.define("group2", { name: "three", type: "number"});
assert.deepEqual(_thing.definition("one").groups, ["group1"]);
assert.deepEqual(_thing.definition("two").groups, ["group1"]);
assert.deepEqual(_thing.definition("three").groups, ["group2"]);
});
it("define(definition) should not throw on duplicate property, updating it instead", function(){
_thing.define({ name: "yeah", type: "string" });
assert.doesNotThrow(function(){
_thing.define({ name: "yeah", type: "boolean", validTest: /\w+/ });
});
assert.strictEqual(_thing.definition("yeah").type, "boolean");
// assert.strictEqual(_thing.definition("yeah").validTest, /\w+/);
});
it("define(definition) should throw on duplicate alias", function(){
_thing.define({ name: "three", alias: "t" });
assert.throws(function(){
_thing.define({ name: "four", alias: "t" });
});
});
});
describe("hasValue()", function(){
describe(".hasValue", function(){
it("hasValue(propertyName) should return true if property has value", function(){

@@ -130,3 +169,3 @@ _thing.define({ name: "one" });

assert.strictEqual(_thing.hasValue(["one", "two"]), false);
_thing.set("one", 1);

@@ -139,24 +178,42 @@ assert.strictEqual(_thing.hasValue(["one", "two"]), true);

});
it("should unset() an property, and its alias", function(){
_thing.define({ name: "one", type: "number", default: 1, alias: "K" });
assert.strictEqual(_thing.get("one"), 1);
assert.strictEqual(_thing.get("K"), 1);
_thing.unset("one");
assert.strictEqual(_thing.get("one"), undefined);
assert.strictEqual(_thing.get("K"), undefined);
describe(".unset", function(){
it("should set a property and its alias to undefined", function(){
_thing.define({ name: "one", type: "number", alias: "K", value: 1 });
assert.strictEqual(_thing.get("one"), 1);
assert.strictEqual(_thing.get("K"), 1);
_thing.unset("one");
assert.strictEqual(_thing.get("one"), undefined);
assert.strictEqual(_thing.get("K"), undefined);
});
});
it("should remove() an property and its alias");
describe("setting and getting values", function(){
it("should set(property, value) and get(property) an array", function(){
describe(".get", function(){
it("get(property) with no value set", function(){
_thing.define({ name: "one", type: "number" });
assert.strictEqual(_thing.get("one"), undefined);
});
it("get(property, default)", function(){
_thing.define({ name: "one", type: "number", value: 1 });
assert.strictEqual(_thing.get("one"), 1);
});
it("get(property) should return undefined on unregistered property", function(){
assert.strictEqual(_thing.get("yeah", "test"), undefined);
});
});
describe(".set", function(){
it("set(property, array)", function(){
_thing.define({ name: "one", type: Array });
_thing.set("one", [0, 1]);
assert.deepEqual(_thing.get("one"), [0, 1]);
})
it("should set(property, value) and get(property) a string", function(){
_thing.define({ name: "test", type: "string", alias: "d" });
it("set(property, string)", function(){
_thing.define({ name: "test", type: "string" });
_thing.set("test", "testset");

@@ -167,160 +224,188 @@

it("should set(alias, value) then get(alias) and get(property)", function(){
_thing.define({ name: "archiveDirectory", type: "string", alias: "d" });
_thing.set("d", "testset");
it("set(alias, string)", function(){
var val = "test";
_thing.define({ name: "test", type: "string", alias: "d" });
_thing.set("d", val);
assert.strictEqual(_thing.get("d"), "testset");
assert.strictEqual(_thing.get("archiveDirectory"), "testset");
assert.strictEqual(_thing.get("d"), val);
assert.strictEqual(_thing.get("test"), val);
});
it("should set default property() value", function(){
_thing.define({ name: "one", type: "number", default: 1 });
assert.strictEqual(_thing.get("one"), 1);
it("set(string) on a type Array", function(){
_thing.define({ name:"one", type: Array });
_thing.set(["--one", "test ,1 , false"]);
assert.deepEqual(_thing.get("one"), ["test", "1", "false"]);
_thing.set("one", "test , 2 , false");
assert.deepEqual(_thing.get("one"), ["test", "2", "false"]);
});
it("set(propertiesHash) should set properties in bulk", function(){
_thing.define({ name: "one", type: "number", alias: "1" })
.define({ name: "two", type: "number", alias: "t" })
.define({ name: "three", type: "number", alias: "3" });
assert.strictEqual(_thing.get("one"), undefined);
assert.strictEqual(_thing.get("t"), undefined);
assert.strictEqual(_thing.get("3"), undefined);
describe("set values in bulk", function(){
it("set(object)", function(){
_thing.define({ name: "one", type: "number" })
.define({ name: "two", type: "number" })
.define({ name: "three", type: "number" });
_thing.set({ one: 1, t: 2, 3: 3 });
assert.strictEqual(_thing.get("one"), 1);
assert.strictEqual(_thing.get("two"), 2);
assert.strictEqual(_thing.get("three"), 3);
});
_thing.set({ one: 1, two: 2, three: 3 });
it("set(configInstance) should set properties in bulk", function(){
_thing.define({ name: "one", type: "number", alias: "1" })
.define({ name: "two", type: "number", alias: "t" })
.define({ name: "three", type: "number", alias: "3" });
assert.strictEqual(_thing.get("one"), undefined);
assert.strictEqual(_thing.get("t"), undefined);
assert.strictEqual(_thing.get("3"), undefined);
assert.strictEqual(_thing.get("one"), 1);
assert.strictEqual(_thing.get("two"), 2);
assert.strictEqual(_thing.get("three"), 3);
});
var config2 = new Thing()
.define({ name: "one", type: "number", default: -1 })
.define({ name: "two", type: "number", default: -2 })
.define({ name: "three", type: "number", default: -3 })
it("set(thing)", function(){
_thing.define({ name: "one", type: "number" })
.define({ name: "two", type: "number" })
.define({ name: "three", type: "number" });
_thing.set(config2);
assert.strictEqual(_thing.get("one"), -1);
assert.strictEqual(_thing.get("two"), -2);
assert.strictEqual(_thing.get("three"), -3);
});
it("set(propertiesArray) should set properties in bulk", function(){
var argv = ["-d", "--preset", "dope", "--recurse", "music", "film", "documentary"];
_thing
.define({ name: "detailed", alias: "d", type: "boolean" })
.define({ name: "recurse", type: "boolean" })
.define({ name: "preset", type: "string" })
.define({ name: "files", type: Array, defaultOption: true })
.set(argv);
assert.strictEqual(_thing.get("detailed"), true, JSON.stringify(_thing.toJSON()));
assert.strictEqual(_thing.get("recurse"), true, JSON.stringify(_thing.toJSON()));
assert.strictEqual(_thing.get("preset"), "dope");
assert.deepEqual(_thing.get("files"), ["music", "film", "documentary"]);
});
it("set(process.argv) should set properties in bulk", function(){
process.argv = ["node", "test.js", "-d", "--preset", "dope", "--recurse", "music", "film", "documentary"];
_thing
.define({ name: "detailed", alias: "d", type: "boolean" })
.define({ name: "recurse", type: "boolean" })
.define({ name: "preset", type: "string" })
.define({ name: "files", type: Array, defaultOption: true })
.set(process.argv);
var thing2 = new Thing()
.define({ name: "one", type: "number", value: -1 })
.define({ name: "two", type: "number", value: -2 })
.define({ name: "three", type: "number", value: -3 })
assert.strictEqual(_thing.get("detailed"), true, JSON.stringify(_thing.toJSON()));
assert.strictEqual(_thing.get("recurse"), true, JSON.stringify(_thing.toJSON()));
assert.strictEqual(_thing.get("preset"), "dope");
assert.deepEqual(_thing.get("files"), ["music", "film", "documentary"]);
});
_thing.set(thing2);
it("set(process.argv) should set correct defaults", function(){
process.argv = [
"/usr/local/bin/node", "/usr/local/bin/rename", "file1.test","file2.test",
"file3.test", "file4.test", "file5.test",
"-d", "-r"
];
_thing
.define({
name: "files",
type: Array,
required: true,
defaultOption: true,
default: []
})
.define({ name: "find", type: "string", alias: "f" })
.define({ name: "make", type: "string", alias: "m", default: "pie" })
.define({ name: "num", type: "number" })
.define({ name: "num2", type: "number", default: 10 })
.define({ name: "replace", type: "string", alias: "r", default: "" })
.define({ name: "dry-run", type: "boolean", alias: "d" })
.set(process.argv);
assert.strictEqual(_thing.make, "pie", JSON.stringify(_thing.toJSON()));
assert.strictEqual(_thing.replace, "", JSON.stringify(_thing.toJSON()));
assert.strictEqual(_thing.num, undefined, JSON.stringify(_thing.toJSON()));
assert.strictEqual(_thing.num2, 10, JSON.stringify(_thing.toJSON()));
assert.strictEqual(_thing["dry-run"], true, JSON.stringify(_thing.toJSON()));
assert.deepEqual(_thing.files, ["file1.test", "file2.test", "file3.test", "file4.test", "file5.test"]);
});
it("set(propertiesArray) with a type Array", function(){
_thing.define({ name:"one", type: Array });
assert.strictEqual(_thing.get("one"), -1);
assert.strictEqual(_thing.get("two"), -2);
assert.strictEqual(_thing.get("three"), -3);
_thing.set(["--one", "test", 1, false]);
assert.deepEqual(_thing.get("one"), ["test"]);
});
_thing.set(["--one", "test ,1 , false"]);
assert.deepEqual(_thing.get("one"), ["test", "1", "false"]);
});
it("set(['--property', '--value']) should set correctly, where 'property' expects a value", function(){
_thing.define({ name: "one", type: "string" });
_thing.set([ "--one", "--23" ]);
assert.deepEqual(_thing.one, "--23");
_thing.set([ "--one", "" ]);
assert.deepEqual(_thing.one, "");
});
it("set(array)", function(){
var argv = ["-d", "--preset", "dope", "--recurse", "music", "film", "documentary"];
_thing
.define({ name: "detailed", alias: "d", type: "boolean" })
.define({ name: "recurse", type: "boolean" })
.define({ name: "preset", type: "string" })
.define({ name: "files", type: Array, defaultOption: true })
.set(argv);
it("set(propertiesArray) with a `defaultOption` of type Array", function(){
_thing.define({ name: "one", type: Array, defaultOption: true });
_thing.set(["test", 1, false]);
assert.deepEqual(_thing.get("one"), ["test", 1, false]);
});
assert.strictEqual(_thing.get("detailed"), true);
assert.strictEqual(_thing.get("recurse"), true);
assert.strictEqual(_thing.get("preset"), "dope");
assert.deepEqual(_thing.get("files"), ["music", "film", "documentary"]);
});
it("set(propertiesArray) with a `defaultOption` of type 'string'", function(){
_thing.define({ name: "one", type: "string", defaultOption: true });
_thing.set(["test", 1, false]);
assert.strictEqual(_thing.get("one"), "test");
it("set(process.argv)", function(){
process.argv = ["node", "test.js", "-d", "--preset", "dope", "--recurse", "music", "film", "documentary"];
_thing
.define({ name: "detailed", alias: "d", type: "boolean" })
.define({ name: "recurse", type: "boolean" })
.define({ name: "preset", type: "string" })
.define({ name: "files", type: Array, defaultOption: true })
.set(process.argv);
assert.strictEqual(_thing.get("detailed"), true);
assert.strictEqual(_thing.get("recurse"), true);
assert.strictEqual(_thing.get("preset"), "dope");
assert.deepEqual(_thing.get("files"), ["music", "film", "documentary"]);
});
it("set(process.argv) should set correct defaults", function(){
process.argv = [
"/usr/local/bin/node", "/usr/local/bin/rename", "file1.test","file2.test",
"file3.test", "file4.test", "file5.test",
"-d", "-r"
];
_thing
.define({
name: "files",
type: Array,
required: true,
defaultOption: true,
value: []
})
.define({ name: "find", type: "string" })
.define({ name: "make", type: "string", value: "pie" })
.define({ name: "num", type: "number" })
.define({ name: "num2", type: "number", value: 10 })
.define({ name: "replace", type: "string", alias: "r", value: "" })
.define({ name: "dry-run", type: "boolean", alias: "d" })
.set(process.argv);
assert.strictEqual(_thing.make, "pie");
assert.strictEqual(_thing.replace, "");
assert.strictEqual(_thing.num, undefined);
assert.strictEqual(_thing.num2, 10);
assert.strictEqual(_thing["dry-run"], true);
assert.deepEqual(_thing.files, ["file1.test", "file2.test", "file3.test", "file4.test", "file5.test"]);
});
it("set(['--property', '--value']) should set correctly, where 'property' expects a value", function(){
_thing.define({ name: "one", type: "string" });
_thing.set([ "--one", "--23" ]);
assert.deepEqual(_thing.one, "--23");
_thing.set([ "--one", "" ]);
assert.deepEqual(_thing.one, "");
});
it("set(array) with a defaultOption of type Array", function(){
_thing.define({ name: "one", type: Array, defaultOption: true });
_thing.set(["test", 1, false]);
assert.deepEqual(_thing.get("one"), ["test", 1, false]);
});
it("set(array) with a defaultOption of type string", function(){
_thing.define({ name: "one", type: "string", defaultOption: true });
_thing.set(["test", 1, false]);
assert.strictEqual(_thing.get("one"), "test");
});
it("set(array) with a `defaultOption` of type number", function(){
_thing.define({ name: "one", type: "number", defaultOption: true });
_thing.set([1, 4, 5]);
assert.strictEqual(_thing.get("one"), 1);
});
it("warn if set(array) produces defaultValues with no defaultOption set");
});
it("set(propertiesArray) with a `defaultOption` of type number", function(){
_thing.define({ name: "one", type: "number", defaultOption: true });
_thing.set([1, 4, 5]);
assert.strictEqual(_thing.get("one"), 1);
describe("Error handling", function(){
it("set(property, value) should emit 'error' on unregistered property", function(){
assert.throws(function(){
_thing.set("yeah", "test");
});
assert.strictEqual(_thing.valid, false);
assert.strictEqual(_thing._errors.length, 1);
});
it("catching 'error' surpresses throw on bad set()", function(){
_thing.on("error", function(err){
assert.ok(err);
});
assert.doesNotThrow(function(){
_thing.set("yeah", "test");
});
assert.strictEqual(_thing.valid, false);
assert.strictEqual(_thing._errors.length, 1);
});
it("set([--property, value]) should emit 'error' on unregistered property", function(){
assert.throws(function(){
_thing.set(["--asdklfjlkd"]);
});
assert.strictEqual(_thing.valid, false);
assert.strictEqual(_thing._errors.length, 1);
});
it("set(propertiesArray) should not alter propertiesArray itself", function(){
var args = [ "--one", 1, "--two", 2, "--three", 3 ];
_thing
.define({ name: "one", type: "number", value: -1 })
.define({ name: "two", type: "number", value: -2 })
.define({ name: "three", type: "number", value: -3 });
assert.deepEqual(args, [ "--one", 1, "--two", 2, "--three", 3 ]);
_thing.set(args);
assert.deepEqual(args, [ "--one", 1, "--two", 2, "--three", 3 ]);
});
});
it("warn if set(propertiesArray) produces defaultValues with no defaultOption set");
})
});
it("should clone()", function(){
_thing.define({ name: "one", type: "number", default: 1 })
.define({ name: "two", type: "number", default: 2 });
it(".clone()", function(){
_thing.define({ name: "one", type: "number", value: 1 })
.define({ name: "two", type: "number", value: 2 });
var config2 = _thing.clone();

@@ -331,52 +416,55 @@ assert.notStrictEqual(_thing, config2);

});
it("properties() should return Array of property names");
it("mixin(config)", function(){
_thing.define({ name: "year", type: "number", default: 2013 });
var config2 = new Thing().define({ name: "month", type: "string", default: "feb", alias: "m" });
var config3 = new Thing().define({ name: "day", type: "string", default: "Sunday", alias: "d" })
_thing.mixIn(config2);
_thing.mixIn(config3);
assert.strictEqual(_thing.get("year"), 2013);
assert.strictEqual(_thing.get("month"), "feb");
assert.strictEqual(_thing.get("day"), "Sunday");
assert.strictEqual(_thing.get("m"), "feb");
assert.strictEqual(_thing.get("d"), "Sunday");
});
it("mixin() must fail on duplicate propertyName or alias");
it("mixin(config, groups)", function(){
_thing.define({ name: "year", type: "number", default: 2013 });
var config2 = new Thing().define({ name: "month", type: "string", default: "feb", alias: "m" });
var config3 = new Thing().define({ name: "day", type: "string", default: "Sunday", alias: "d" })
_thing.mixIn(config2, "config2");
_thing.mixIn(config3, ["config2", "config3"]);
assert.strictEqual(_thing.get("year"), 2013);
assert.deepEqual(_thing.definition("year").groups, []);
assert.strictEqual(_thing.get("month"), "feb");
assert.deepEqual(_thing.definition("month").groups, ["config2"]);
assert.strictEqual(_thing.get("day"), "Sunday");
assert.deepEqual(_thing.definition("day").groups, ["config2", "config3"]);
it(".properties() should return Array of property names");
describe(".mixin", function(){
it("mixin(thing)", function(){
_thing.define({ name: "year", type: "number", value: 2013 });
var config2 = new Thing().define({ name: "month", type: "string", value: "feb", alias: "m" });
var config3 = new Thing().define({ name: "day", type: "string", value: "Sunday", alias: "d" })
_thing.mixIn(config2);
_thing.mixIn(config3);
assert.strictEqual(_thing.get("year"), 2013);
assert.strictEqual(_thing.get("month"), "feb");
assert.strictEqual(_thing.get("day"), "Sunday");
assert.strictEqual(_thing.get("m"), "feb");
assert.strictEqual(_thing.get("d"), "Sunday");
});
it("mixin() must fail on duplicate propertyName or alias");
it("mixin(thing, groups)", function(){
_thing.define({ name: "year", type: "number", value: 2013 });
var config2 = new Thing().define({ name: "month", type: "string", value: "feb", alias: "m" });
var config3 = new Thing().define({ name: "day", type: "string", value: "Sunday", alias: "d" })
_thing.mixIn(config2, "config2");
_thing.mixIn(config3, ["config2", "config3"]);
assert.strictEqual(_thing.get("year"), 2013);
assert.deepEqual(_thing.definition("year").groups, []);
assert.strictEqual(_thing.get("month"), "feb");
assert.deepEqual(_thing.definition("month").groups, ["config2"]);
assert.strictEqual(_thing.get("day"), "Sunday");
assert.deepEqual(_thing.definition("day").groups, ["config2", "config3"]);
});
});
it("definition(property) should return correct def for full name and alias", function(){
_thing.define({ name: "one", type: Array, default: [1,2], required: true, alias: "a" });
assert.strictEqual(_thing.definition("one").type, Array);
assert.strictEqual(_thing.definition("a").type, Array);
assert.deepEqual(_thing.definition("one").default, [1,2]);
assert.deepEqual(_thing.definition("a").default, [1,2]);
assert.strictEqual(_thing.definition("one").required, true);
assert.strictEqual(_thing.definition("a").required, true);
assert.strictEqual(_thing.definition("one").alias, "a");
assert.strictEqual(_thing.definition("a").alias, "a");
describe(".definition", function(){
it("definition(property) should return correct def for full name and alias", function(){
_thing.define({ name: "one", type: Array, value: [1,2], required: true, alias: "a" });
assert.strictEqual(_thing.definition("one").type, Array);
assert.strictEqual(_thing.definition("a").type, Array);
assert.deepEqual(_thing.definition("one").value, [1,2]);
assert.deepEqual(_thing.definition("a").value, [1,2]);
assert.strictEqual(_thing.definition("one").required, true);
assert.strictEqual(_thing.definition("a").required, true);
assert.strictEqual(_thing.definition("one").alias, "a");
assert.strictEqual(_thing.definition("a").alias, "a");
});
});
describe("grouping", function(){
describe(".group", function(){
it("grouping summary", function(){

@@ -389,3 +477,3 @@ // set group after defining

.group("group1", ["one", "two", "three"]);
// group during define

@@ -399,22 +487,22 @@ _thing

.define("group3", { name: "title", type: "number"});
// group during mixin
var config2 = new Thing().define({ name: "seven" });
_thing.mixIn(config2, "group4");
// ungroup specific properties
_thing.ungroup("group1", ["one", "two"]);
// ungroup all
_thing.ungroup("group2");
// retrieve group
_thing.where({ group: "group3" }).toJSON();
});
it("group(groupName, propertyNameArray)", function(){
_thing
.define({ name: "one", type: "number", alias: "1", default: 1 })
.define({ name: "two", type: "number", alias: "t", default: 2 })
.define({ name: "three", type: "number", alias: "3", default: 3 })
.define({ name: "one", type: "number", alias: "1", value: 1 })
.define({ name: "two", type: "number", alias: "t", value: 2 })
.define({ name: "three", type: "number", alias: "3", value: 3 })
.group("everything", ["one", "two", "three"])

@@ -424,3 +512,3 @@ .group("everything2", ["one", "two", "three"])

.group("not the smallest", ["two", "three"]);
assert.deepEqual(_thing.where({ group: "everything" }).toJSON(), {one: 1, two:2, three:3 });

@@ -431,13 +519,13 @@ assert.deepEqual(_thing.where({ group: "everything2" }).toJSON(), {one: 1, two:2, three:3 });

});
it("group(groupName) groups all properties", function(){
_thing
.define({ name: "one", type: "number", alias: "1", default: 1 })
.define({ name: "two", type: "number", alias: "t", default: 2 })
.define({ name: "three", type: "number", alias: "3", default: 3 })
.define({ name: "one", type: "number", alias: "1", value: 1 })
.define({ name: "two", type: "number", alias: "t", value: 2 })
.define({ name: "three", type: "number", alias: "3", value: 3 })
.group("everything");
assert.deepEqual(_thing.where({ group: "everything" }).toJSON(), {one: 1, two:2, three:3 });
})
it("ungroup(groupName) should remove all properties from groupName", function(){

@@ -449,6 +537,6 @@ _thing

assert.deepEqual(_thing.where({ group: "group1"}).properties, ["one", "two"]);
_thing.ungroup("group1");
assert.deepEqual(_thing.where({ group: "group1"}).properties, []);
});

@@ -463,3 +551,3 @@

assert.deepEqual(_thing.where({ group: "group1"}).properties, ["one", "two", "four"]);
_thing.ungroup("group1", "one");

@@ -471,10 +559,10 @@ assert.deepEqual(_thing.where({ group: "group1"}).properties, ["two", "four"]);

});
it("where({group: groupName}) returns a Thing clone, with reduced properties", function(){
_thing
.define({ name: "one", type: "number", alias: "1", default: 1 })
.define({ name: "two", type: "number", alias: "t", default: 2 })
.define({ name: "three", type: "number", alias: "3", default: 3 })
.define({ name: "one", type: "number", alias: "1", value: 1 })
.define({ name: "two", type: "number", alias: "t", value: 2 })
.define({ name: "three", type: "number", alias: "3", value: 3 })
.group("group", ["two", "three"]);
assert.strictEqual(_thing.where({ group: "group" }).get("one"), undefined);

@@ -487,9 +575,9 @@ assert.strictEqual(_thing.where({ group: "group" }).get("two"), 2);

});
it("where({ name: {$ne: []}}) should exclude named properties", function(){
_thing
.define({ name: "one", type: "number", alias: "1", default: 1 })
.define({ name: "two", type: "number", alias: "t", default: 2 })
.define({ name: "three", type: "number", alias: "3", default: 3 });
.define({ name: "one", type: "number", alias: "1", value: 1 })
.define({ name: "two", type: "number", alias: "t", value: 2 })
.define({ name: "three", type: "number", alias: "3", value: 3 });
assert.throws(function(){

@@ -503,5 +591,5 @@ assert.strictEqual(_thing.where({ name: { $ne: ["one", "two"] }}).get("one"), 1);

});
it("define() with groups and subgroups");
it("define(groupName, definitionArray) with groups", function(){

@@ -522,5 +610,5 @@ _thing

{
name: "start-at",
type: "string",
valid: /duration|frame|pts/,
name: "start-at",
type: "string",
valid: /duration|frame|pts/,
invalidMsg: "please specify the unit, e.g. --start-at duration:10 or --start-at frame:2000"

@@ -532,6 +620,6 @@ },

valid: /duration|frame|pts/,
invalidMsg: "please specify the unit, e.g. --stop-at duration:100 or --stop-at frame:3000"
invalidMsg: "please specify the unit, e.g. --stop-at duration:100 or --stop-at frame:3000"
}
]);
assert.deepEqual(_thing.definition("no group").groups, []);

@@ -542,65 +630,5 @@ assert.deepEqual(_thing.definition("title").groups, ["source"], JSON.stringify(_thing.definition("title")));

});
});
});
});
describe("Error handling", function(){
it("define(definition) should not throw on duplicate property", function(){
_thing.define({ name: "yeah", type: "string" });
assert.doesNotThrow(function(){
_thing.define({ name: "yeah", type: "boolean" });
});
assert.strictEqual(_thing.definition("yeah").type, "boolean");
});
it("define(definition) should throw on duplicate alias", function(){
_thing.define({ name: "three", alias: "t" });
assert.throws(function(){
_thing.define({ name: "four", alias: "t" });
});
});
it("set(property, value) should emit 'error' on unregistered property", function(){
assert.throws(function(){
_thing.set("yeah", "test");
});
assert.strictEqual(_thing.valid, false);
assert.strictEqual(_thing._errors.length, 1);
});
it("catching 'error' surpresses throw on bad set()", function(){
_thing.on("error", function(err){
assert.ok(err);
});
assert.doesNotThrow(function(){
_thing.set("yeah", "test");
});
assert.strictEqual(_thing.valid, false);
assert.strictEqual(_thing._errors.length, 1);
});
it("set([--property, value]) should emit 'error' on unregistered property", function(){
assert.throws(function(){
_thing.set(["--asdklfjlkd"]);
});
assert.strictEqual(_thing.valid, false);
assert.strictEqual(_thing._errors.length, 1);
});
it("get(property) should return undefined on unregistered property", function(){
assert.strictEqual(_thing.get("yeah", "test"), undefined);
});
it("set(propertiesArray) should not alter propertiesArray itself", function(){
var args = [ "--one", 1, "--two", 2, "--three", 3 ];
_thing
.define({ name: "one", type: "number", default: -1 })
.define({ name: "two", type: "number", default: -2 })
.define({ name: "three", type: "number", default: -3 });
assert.deepEqual(args, [ "--one", 1, "--two", 2, "--three", 3 ]);
_thing.set(args);
assert.deepEqual(args, [ "--one", 1, "--two", 2, "--three", 3 ]);
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc