├── .eslintrc ├── .gitignore ├── .travis.yml ├── README.md ├── examples.js ├── index.js ├── package.json └── test.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-airbnb-es5" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.12 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Mr. Checkbox 2 | ============ 3 | 4 | [![Build Status](https://travis-ci.org/ryanaghdam/mr-checkbox.svg?branch=master)](https://travis-ci.org/ryanaghdam/mr-checkbox) 5 | 6 | Validates a value against a given set of requirements. Named after a former 7 | colleague. 8 | 9 | Mr. Checkbox (the function, not the person) is curried; validators can be 10 | created with partially-applied invocation. 11 | 12 | 13 | Domain 14 | ------ 15 | 16 | A `Requirement` is an object with an `error` and `validator`. An 17 | `error` is any value, usually a string, that is used to identify any values 18 | that fail to meet the requirement. A `validator` is a function that accepts a 19 | value as input and returns `true` if the requirement is met; `false` if it is 20 | not met. 21 | 22 | ``` 23 | { 24 | error: 'minimumLength', 25 | validator: function (value) { return value.length > 8; } 26 | } 27 | ``` 28 | 29 | Mr. Checkbox produces an array of `error` values. If the string `abc` were 30 | validated against the requirements above, the result would be: 31 | `['minimumLength']`. 32 | 33 | 34 | Usage & Examples 35 | ---------------- 36 | 37 | Using partial-application. 38 | 39 | ```javascript 40 | var mrCheckbox = require('mr-checkbox'); 41 | 42 | function isPalindrome(value) { 43 | return value === value.split('').reverse().join(''); 44 | } 45 | 46 | var validatePassword = mrCheckbox([ 47 | { 48 | error: 'Password must 8 characters or longer', 49 | validator: function (value) { return value.length > 7; } 50 | }, 51 | { 52 | error: 'Password must be 50 characters or shorter', 53 | validator: function (value) { return value.length < 51; } 54 | }, 55 | { 56 | error: 'Password cannot be "password"', 57 | validator: function (value) { return value !== 'password'; } 58 | }, 59 | { 60 | error: 'Password cannot start with the letter Q.', 61 | validator: function (value) { return value.charAt(0) !== 'Q'; } 62 | }, 63 | { 64 | error: 'Password must be a palindrome.', 65 | validator: isPalindrome 66 | } 67 | ]); 68 | 69 | validatePassword('password'); 70 | => [ 71 | 'Password cannot be "password"', 72 | 'Password must be a palindrome.'; 73 | ] 74 | 75 | 76 | validatePassword('abc'); 77 | => [ 78 | 'Password must 8 characters or longer', 79 | 'Password must be a palindrome.' 80 | ] 81 | 82 | validatePassword('QhannahhannahQ'); 83 | => [ 'Password cannot start with the letter Q.' ] 84 | 85 | validatePassword('iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii'); 86 | => [ 'Password must be 50 characters or shorter' ] 87 | 88 | validatePassword('hannahhannah'); 89 | => [] 90 | 91 | ``` 92 | 93 | 94 | Or, non-curried invocation. 95 | 96 | ```javascript 97 | var mrCheckbox = require('mr-checkbox'); 98 | 99 | function isPalindrome(value) { 100 | return value === value.split('').reverse().join(''); 101 | } 102 | 103 | var requirements = [ 104 | { 105 | error: 'Password must 8 characters or longer', 106 | validator: function (value) { return value.length > 7; } 107 | }, 108 | { 109 | error: 'Password must be 50 characters or shorter', 110 | validator: function (value) { return value.length < 51; } 111 | }, 112 | { 113 | error: 'Password cannot be "password"', 114 | validator: function (value) { return value !== 'password'; } 115 | }, 116 | { 117 | error: 'Password cannot start with the letter Q.', 118 | validator: function (value) { return value.charAt(0) !== 'Q'; } 119 | }, 120 | { 121 | error: 'Password must be a palindrome.', 122 | validator: isPalindrome 123 | } 124 | ]; 125 | 126 | mrCheckbox(requirements, 'password'); 127 | => [ 128 | 'Password cannot be "password"', 129 | 'Password must be a palindrome.'; 130 | ] 131 | 132 | 133 | mrCheckbox(requirements, 'abc'); 134 | => [ 135 | 'Password must 8 characters or longer', 136 | 'Password must be a palindrome.' 137 | ] 138 | 139 | mrCheckbox(requirements, 'QhannahhannahQ'); 140 | => [ 'Password cannot start with the letter Q.' ] 141 | 142 | mrCheckbox(requirements, 'iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii'); 143 | => [ 'Password must be 50 characters or shorter' ] 144 | 145 | mrCheckbox(requirements, 'hannahhannah'); 146 | => [] 147 | 148 | ``` 149 | 150 | Changelog 151 | --------- 152 | 153 | - v1.1.2: Adds `patch-`, `minor-`, and `major-release` NPM scripts (6/23/16) 154 | - v1.1.1: Adds eslint to project (6/21/16) 155 | - v1.1.0: Replaces Ramda's curry with auto-curry (3/14/16) 156 | - v1.0.0: Initial commit (3/11/16) 157 | -------------------------------------------------------------------------------- /examples.js: -------------------------------------------------------------------------------- 1 | /* eslint func-names: 0, no-console: 0 */ 2 | var mrCheckbox = require('./'); 3 | var R = require('ramda'); 4 | 5 | function isPalindrome(value) { 6 | return value === value.split('').reverse().join(''); 7 | } 8 | 9 | var validatePassword = mrCheckbox([ 10 | { 11 | error: 'Password must 8 characters or longer', 12 | validator: function(value) { return value.length > 7; } 13 | }, 14 | { 15 | error: 'Password must be 50 characters or shorter', 16 | validator: function(value) { return value.length < 51; } 17 | }, 18 | { 19 | error: 'Password cannot be "password"', 20 | validator: function(value) { return value !== 'password'; } 21 | }, 22 | { 23 | error: 'Password cannot start with the letter Q.', 24 | validator: function(value) { return value.charAt(0) !== 'Q'; } 25 | }, 26 | { 27 | error: 'Password must be a palindrome.', 28 | validator: isPalindrome 29 | } 30 | ]); 31 | 32 | var printResult = R.compose(console.log, validatePassword); 33 | 34 | [ 35 | 'password', 36 | 'abc', 37 | 'QhannahhannahQ', 38 | 'iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii', 39 | 'hannahhannah' 40 | ].forEach(printResult); 41 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var autoCurry = require('auto-curry'); 4 | 5 | function validateRequirements(requirements, value) { 6 | function validateRule(acc, requirement) { 7 | if (!requirement.validator(value)) { 8 | acc.push(requirement.error); 9 | } 10 | 11 | return acc; 12 | } 13 | 14 | return requirements.reduce(validateRule, []); 15 | } 16 | 17 | module.exports = autoCurry(validateRequirements); 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mr-checkbox", 3 | "version": "1.1.2", 4 | "description": "Validates a value against a given set of requirements.", 5 | "main": "index.js", 6 | "scripts": { 7 | "mocha": "mocha test.js", 8 | "eslint": "eslint *.js", 9 | "test": "npm run eslint && npm run mocha", 10 | "patch-release": "npm test && npm version patch && npm publish && git push --follow-tags", 11 | "minor-release": "npm test && npm version minor && npm publish && git push --follow-tags", 12 | "major-release": "npm test && npm version major && npm publish && git push --follow-tags" 13 | }, 14 | "author": "Ryan Aghdam ", 15 | "license": "MIT", 16 | "dependencies": { 17 | "auto-curry": "^0.2.0" 18 | }, 19 | "devDependencies": { 20 | "babel-eslint": "^6.0.5", 21 | "eslint": "^2.13.1", 22 | "eslint-config-airbnb-es5": "^1.0.9", 23 | "eslint-plugin-react": "^5.2.2", 24 | "mocha": "^2.4.5", 25 | "ramda": "^0.19.1" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/ryanaghdam/mr-checkbox/issues", 29 | "email": "ryan@ryanaghdam.com" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/ryanaghdam/mr-checkbox.git" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node, mocha */ 2 | /* eslint func-names: 0 */ 3 | 'use strict'; 4 | 5 | var assert = require('assert'); 6 | var mrCheckbox = require('./'); 7 | 8 | var never = function() { return false; }; 9 | var always = function() { return true; }; 10 | 11 | describe('Mr. Checkbox', function() { 12 | context('fully-applied invocation', function() { 13 | it('should return an empty array if all requirements are met', function() { 14 | var requirements = [{validator: always}]; 15 | var result = mrCheckbox(requirements, 'abc'); 16 | assert(result.length === 0); 17 | }); 18 | 19 | it('should return an array with error values of unmet requirements', function() { 20 | var requirements = [{validator: never, error: 'abc'}]; 21 | var result = mrCheckbox(requirements, '123'); 22 | assert(result.length === 1 && result[0] === 'abc'); 23 | }); 24 | }); 25 | 26 | context('partially-applied invocation (curried)', function() { 27 | it('should return a function when called with a single argument', function() { 28 | assert(typeof mrCheckbox([]) === 'function'); 29 | }); 30 | 31 | it('should return an empty array if all requirements are met', function() { 32 | var validator = mrCheckbox([{validator: always}]); 33 | var result = validator('abc'); 34 | assert(result.length === 0); 35 | }); 36 | 37 | it('should return an array with error values of unmet requirements', function() { 38 | var validator = mrCheckbox([{validator: never, error: 'abc'}]); 39 | var result = validator('123'); 40 | assert(result.length === 1 && result[0] === 'abc'); 41 | }); 42 | }); 43 | }); 44 | --------------------------------------------------------------------------------