Browse Source

Merge pull request #1 from Floofies/master

Added `forField`, `subsetOf`, `is`, Refactor
develop
Muthu Kumar 7 years ago
committed by GitHub
parent
commit
9438fe265b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 186
      Select.js
  2. 19
      spec/SelectArraySpec.js
  3. 24
      spec/SelectSpec.js

186
Select.js

@ -1,12 +1,11 @@
'use strict'; 'use strict';
/** /**
* Return a function based on a condition. * Return a function based on a condition.
* Functional alternative to switch-case. * Functional alternative to switch-case.
* @projectname Select-Return * @projectname Select-Return
* @version 1.0.0 * @version 1.0.0
* @author Muthu Kumar (@MKRhere) * @author Muthu Kumar (MKRhere)
*/ */
/** /**
* Creates a SelectValue instance with a value and optional resolve function. * Creates a SelectValue instance with a value and optional resolve function.
@ -23,7 +22,6 @@ class SelectValue {
this.value = value; this.value = value;
if (resolve) this.resolve = (...args) => resolve(...args, value); if (resolve) this.resolve = (...args) => resolve(...args, value);
} }
/** /**
* Default resolve prototype. Returns null when called. * Default resolve prototype. Returns null when called.
* Used in case a resolve is never set. * Used in case a resolve is never set.
@ -36,61 +34,94 @@ class SelectValue {
} }
/** /**
* Creates a SelectIterable instance from an array. * Creates a SelectIterable instance from an array.
* Created internally from Select.prototype.for, and not exported. * Created internally from Select.prototype.for, and not exported.
* @class SelectIterable * @class SelectIterable
*/ * @param {array} values - array created from Select.prototype.for
* @param {Array<function>} tests - array of { test, consequent } objects
* @param {function} tests[].test - test function
* @param {function} tests[].consequent - consequent function
* @constructs SelectIterable
*/
class SelectIterable { class SelectIterable {
/** constructor(values, conditionals) {
* @param {array} values - array created from Select.prototype.for this.values = values.map(value => value instanceof SelectValue ? value : new SelectValue(value));
* @param {Array<function>} tests - array of { test, consequent } objects this.conditionals = conditionals;
* @param {function} tests[].test - test function
* @param {function} tests[].consequent - consequent function
* @constructs SelectIterable
*/
constructor(values, tests) {
this.values = values
.map(x => x instanceof SelectValue
? x
: new SelectValue(x)
);
this.tests = tests;
} }
/** /**
* Accepts a test and consequent function each and returns a new * Accepts a test and consequent function each and returns a new
* SelectIterable instance. * SelectIterable instance.
* @param {Test} test - test callback function * SelectIterable.prototype.for works a little differently than
* @param {function} consequent - consequent callback function * Select.prototype.for, by accumulating the tests and resolving all the
* @returns {SelectIterable} - an instance of SelectIterable * values when .resolve() is called.
* @memberof SelectIterable * @param {callback} predicate A test callback function.
*/ * @callback predicate
for(test, consequent) { * @param {any} value The Selected value.
/* SelectIterable.prototype.for works a little * @returns {boolean} The Boolean result of the test.
differently than Select.prototype.for, * @param {callback} consequent consequent callback function
by accumulating the tests and resolving * @callback consequent
all the values when .resolve() is called */ * @param {Array} args An arbitrary Array of arguments.
* @param {any} value The Selected value.
* @returns {any}
* @returns {SelectIterable} an instance of SelectIterable
* @memberof SelectIterable
*/
if(predicate, consequent) {
return new SelectIterable(this.values, [
...this.conditionals,
{predicate, consequent}
]);
}
forField(...pairs) {
var pair;
var callback;
var even;
pairs.forEach((pair, index) => {
even = index % 2 === 0;
pair = this.conditionals[this.conditionals.length];
if (pair.length === 2) {
this.conditionals.push({});
};
callback = conditionals[loc];
if (typeof callback === "object") {
if (Array.isArray(callback)) {
pair.predicate = callback[0];
pair.consequent = callback[0];
} else {
Object.assign(pair, {
predicate: callback.predicate,
consequent: callback.consequent
});
}
continue;
}
if (even) pair.predicate = callback;
if (!even) pair.consequent = callback;
}, this);
return new SelectIterable( return new SelectIterable(
this.values, this.values,
[ ...this.tests, { test, consequent } ] [...this.conditionals, ...conditionals]
); );
} }
subset(value, consequent) {
resolve(...args) { return this.if(this.value.every(element => element in value))
/* When .resolve() is called, a resolved value }
is generated for each value in the array */ superset(value, consequent) {
return this.values.map(item => { return this.if(value.every(element => element in this.value));
const resolver = this
.tests
.find(x => x.test(item.value)
? x.consequent
: null);
return resolver
? resolver.consequent(...args, item.value)
: null;
});
} }
} }
SelectIterable.prototype.resolve = function (...args) {
return this.values.map(item => {
const resolver = this.conditionals.find(conditional =>
conditional.predicate(item.value)
? conditional.consequent
: null
);
return resolver
? resolver.consequent(...args, this.value)
: null;
}, this);
};
/** /**
* Creates a new Select instance. * Creates a new Select instance.
@ -107,33 +138,46 @@ class Select extends SelectValue {
super(value, resolve); super(value, resolve);
this.iterable = typeof value === "object" && Symbol.iterator in value; this.iterable = typeof value === "object" && Symbol.iterator in value;
} }
/** /**
* Accepts a test and consequent function each and returns a new * Accepts a test and consequent function each and returns a new
* Select or SelectIterable instance. * Select or SelectIterable instance.
* @param {function} test - test callback function * @param {callback} predicate A test callback function.
* @param {function} consequent - consequent callback function * @callback predicate
* @returns {Select|SelectIterable} - Returns a SelectIterable instance * @param {any} value The Selected value.
* if value was array, or a Select instance otherwise * @returns {boolean} The Boolean result of the test.
* @memberof Select * @param {callback} consequent consequent callback function
*/ * @callback consequent
for(test, consequent) { * @param {Array} args An arbitrary Array of arguments.
* @param {any} value The Selected value.
* @returns {any}
* @returns {(Select|SelectIterable)} - Returns a SelectIterable instance
* if value was array, or a Select instance otherwise
* @memberof Select
*/
if(predicate, consequent) {
if (this.iterable) { if (this.iterable) {
/* If the value passed to the constructor is /* If the value passed to the constructor is an
an array, initialise a new SelectIterable iterable, return a new SelectIterable using the
with the array and { test, consequent } pair iterable and { test, consequent } pair.*/
and return */
return new SelectIterable( return new SelectIterable(
Array.from(this.value), Array.from(this.value),
[ { test, consequent } ], [{ predicate, consequent }]
); );
} }
if (test(this.value)) return new Select(this.value, consequent); if (predicate(this.value)) {
return new Select(this.value, consequent);
}
/* If the test doesn't pass, just pass the Select /* If the test doesn't pass, just pass the Select
instance along the chain until a test passes, instance along the chain until a test passes,
or .resolve() is called */ or .resolve() is called */
return this; return this;
} }
is(value, consequent) {
return this.if(value === this.value, consequent);
}
isNot(value, consequent) {
return this.if(value !== this.value, consequent)
}
} }
module.exports = Select; module.exports = Select;

19
spec/SelectArraySpec.js

@ -11,14 +11,15 @@ describe("Select", () => {
const a = [ 10, 20, 0, 'UnexpectedString' ]; const a = [ 10, 20, 0, 'UnexpectedString' ];
const result = new Select(a) const result = new Select(a)
.for(x => x > 10, () => 'Greater than 10') .if(x => x > 10, () => 'Greater than 10')
.for(x => x < 10, () => 'Lesser than 10') .if(x => x < 10, () => 'Lesser than 10')
.for(x => x === 10, () => `Is 10`); .if(x => x === 10, () => `Is 10`);
console.log(result.resolve());
expect(result.resolve()) expect(result.resolve()).toEqual([
.toEqual([ 'Is 10', 'Is 10',
'Greater than 10', 'Greater than 10',
'Lesser than 10', 'Lesser than 10',
null ]); null
]);
}); });
}); });

24
spec/SelectSpec.js

@ -9,9 +9,9 @@ describe("Select", () => {
const a = 10; const a = 10;
const result = new Select(a) const result = new Select(a)
.for(x => x > 10, () => 'Greater than 10') .if(x => x > 10, () => 'Greater than 10')
.for(x => x < 10, () => 'Lesser than 10') .if(x => x < 10, () => 'Lesser than 10')
.for(x => x === 10, () => 'Is 10'); .if(x => x === 10, () => 'Is 10');
expect(result.resolve()).toBe('Is 10'); expect(result.resolve()).toBe('Is 10');
}); });
@ -20,9 +20,9 @@ describe("Select", () => {
const a = 1; const a = 1;
const result = new Select(a) const result = new Select(a)
.for(x => x > 10, () => 'Greater than 10') .if(x => x > 10, () => 'Greater than 10')
.for(x => x < 10, () => 'Lesser than 10') .if(x => x < 10, () => 'Lesser than 10')
.for(x => x === 10, () => `Is 10`); .if(x => x === 10, () => `Is 10`);
expect(result.resolve()).toBe('Lesser than 10'); expect(result.resolve()).toBe('Lesser than 10');
}); });
@ -31,9 +31,9 @@ describe("Select", () => {
const a = 100; const a = 100;
const result = new Select(a) const result = new Select(a)
.for(x => x > 10, () => 'Greater than 10') .if(x => x > 10, () => 'Greater than 10')
.for(x => x < 10, () => 'Lesser than 10') .if(x => x < 10, () => 'Lesser than 10')
.for(x => x === 10, () => `Is 10`); .if(x => x === 10, () => `Is 10`);
expect(result.resolve()).toBe('Greater than 10'); expect(result.resolve()).toBe('Greater than 10');
}); });
@ -42,9 +42,9 @@ describe("Select", () => {
const a = 'UnexpectedString'; const a = 'UnexpectedString';
const result = new Select(a) const result = new Select(a)
.for(x => x > 10, () => 'Greater than 10') .if(x => x > 10, () => 'Greater than 10')
.for(x => x < 10, () => 'Lesser than 10') .if(x => x < 10, () => 'Lesser than 10')
.for(x => x === 10, () => `Is 10`); .if(x => x === 10, () => `Is 10`);
expect(result.resolve()).toBe(null); expect(result.resolve()).toBe(null);
}); });

Loading…
Cancel
Save