Skip to content

Commit

Permalink
3 predicate handling (#8)
Browse files Browse the repository at this point in the history
* #3 feat: wrap lodash functions in own functions

* #3 feat: export specs and preds under spec
  • Loading branch information
prayerslayer committed Nov 28, 2016
1 parent 8569449 commit 6776e9f
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 30 deletions.
10 changes: 5 additions & 5 deletions example.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as spec from './index'
import { spec, valid, explain, conform } from './index'

const point = spec.map({
x: spec.int,
Expand All @@ -16,11 +16,11 @@ const point_or_line = spec.or({
const p = {
x: 0
}
spec.valid(point_or_line, p)
valid(point_or_line, p)
// => false

// what is wrong?
spec.explain(point_or_line, p)
explain(point_or_line, p)
// value fails spec via Or(point, line), point, Map, Keys(x, y) at [y]: hasKey failed for undefined
// value fails spec via Or(point, line), line, Map, Keys(p1, p2) at [p1]: hasKey failed for undefined
// value fails spec via Or(point, line), line, Map, Keys(p1, p2) at [p2]: hasKey failed for undefined
Expand All @@ -31,9 +31,9 @@ const p2 = {
y: 0
}

spec.valid(point_or_line, p2)
valid(point_or_line, p2)
// => true

// but which spec did it match?
spec.conform(point_or_line, p2)
conform(point_or_line, p2)
// => [ 'point', { x: 0, y: 0 } ]
18 changes: 11 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import * as specs from './lib/spec'
import * as predicates from './lib/predicates'
import getIn from 'lodash.get'

export * from './lib/spec'
export * from './lib/predicates'
const specsAndPreds = Object.assign({}, specs, predicates)

export { specsAndPreds as spec }

export * from './lib/symbols'
export * from './lib/registry'
export { valid } from './lib/util'
Expand All @@ -13,13 +15,15 @@ export function conform(spec, value) {
return (util.specize(spec)).conform(value)
}

export function explain(spec, value) {
util.explainData(spec, value)
export function explainData(spec, value) {
return util.explainData(spec, value)
.map(problem => {
problem.predicateName = util.getName(problem.predicate)
return problem
})
.forEach(problem => {
console.log(`${problem.via.join(" -> ")}: ${problem.predicateName} failed for ${getIn(value, problem.path)} at [${problem.path.join(", ")}].`)
})
}

export function explain(spec, value) {
explainData(spec, value)
.forEach(problem => console.log(`${problem.via.join(" -> ")}: ${problem.predicateName} failed for ${getIn(value, problem.path)} at [${problem.path.join(", ")}].`))
}
69 changes: 53 additions & 16 deletions lib/predicates.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,70 @@
import { optional } from './symbols'

import set from 'lodash.isset'
import number from 'lodash.isnumber'
import fn from 'lodash.isfunction'
import obj from 'lodash.isplainobject'
import { optional } from './symbols'
import nil from 'lodash.isnil'
import bool from 'lodash.isboolean'
import date from 'lodash.isdate'
import int from 'lodash.isinteger'
import str from 'lodash.isstring'
import sym from 'lodash.issymbol'
import finite from 'lodash.isfinite'

const isArray = Array.isArray

function isNil(x) {
return nil(x)
}

function isNumber(x) {
return finite(x) && number(x)
}

function isFunction(x) {
return fn(x)
}

function isObject(x) {
return obj(x)
}

function isSet(x) {
return set(x)
}

// metadata symbols
function isBoolean(x) {
return bool(x)
}

function isDate(x) {
return date(x)
}

function isInteger(x) {
return finite(x) && int(x)
}

function isString(x) {
return str(x)
}

function isSymbol(x) {
return sym(x)
}

// primitives
export { default as nil } from 'lodash.isnil'
export { default as number } from 'lodash.isnumber'
export { default as fn } from 'lodash.isfunction'
export { default as bool, default as boolean } from 'lodash.isboolean'
export { default as date } from 'lodash.isdate'
export { default as int, default as integer } from 'lodash.isinteger'
export { default as str, default as string } from 'lodash.isstring'
export { default as sym, default as symbol } from 'lodash.issymbol'
export { default as finite } from 'lodash.isfinite'
export { default as set } from 'lodash.isset'
export { default as obj, default as object } from 'lodash.isplainobject'
export const array = Array.isArray
export { isNil as nil, isNumber as number, isFunction as fn, isObject as obj, isObject as object, isSet as set, isBoolean as bool, isBoolean as boolean, isDate as date, isInteger as int, isInteger as integer, isString as str, isString as string, isSymbol as sym, isSymbol as symbol, isArray as array }

// predicates for collections
export function coll(maybeCollection) {
return array(maybeCollection) || set(maybeCollection)
return isArray(maybeCollection) || isSet(maybeCollection)
}

// convenience predicates on primitives

// i think even is useless for real-world apps but removing
// it would break all my tests, so it stays.
export function even(nr) {
return number(nr) && nr % 2 === 0
}
Expand Down
7 changes: 5 additions & 2 deletions test/predicates.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ import * as p from '../lib/predicates'

describe("predicate", () => {
describe("number", () => {
[-10, 0, 10, 20000, 3.14, 1 / 2, Infinity, -Infinity].forEach(nr => it(`returns true for ${nr}`, () => {
[-10, 0, 10, 20000, 3.14, 1 / 2, Number.MAX_VALUE, Number.MIN_VALUE].forEach(nr => it(`returns true for ${nr}`, () => {
expect(p.number(nr)).to.be.true
}))
}));
[-Infinity, Infinity, true, false, "string", {}, [], null, undefined].forEach(nr => it(`returns false for ${nr}`, () => {
expect(p.number(nr)).to.be.false
}));
})
})

Expand Down

0 comments on commit 6776e9f

Please sign in to comment.