0.1.1 ā€¢ Published 3 years ago

simple-stupid-match v0.1.1

Weekly downloads
-
License
MIT
Repository
github
Last release
3 years ago

Simple stupid matching library for JS

It uses for simple stupid pattern matching, nice replacement for switch/case, if/else or mapping patterns.

Examples

Runing specific callback, if user group in one of the states:

import { match } from 'simple-stupid-match';

const matching = match([
 ['owner', addFullGrant],
 ['assistant', addPartialGrant],
 [/:guest$/i, addSmallGrant]
], () => {
  throw new Error('Nothing matched');
});

// ...

// Matching `user.group`, and pass `user` object into matched callback
// Then seting returned value of callback into result constant
const result = matching(user.group, user);

Creating reducer:

const matching = match({
  ['bot/create'](state, action) {
    const bot = action.payload;
    return {
      ...state,
      bots: {
        ...state.bots,
        [bot.id]: bot
      }
    }
  },
  ['bot/remove'](state, action) {
    const id = action.payload;
    const nextState = { ...state };
    delete nextState[id];
    return nextState
  }
}, (state) => return state);

const reducer = (state, action) => matching(action.type, state, action);
// ...

const nextState = reducer(state, action);

Usage

Sneak peek

Import the match function:

import { match } from 'simple-stupid-match';

Create a reusable pattern-matching function:

const matching = match(patterns, onDefault);

Use it for find result or run specific functions:

const result = matching(value, ...argumentsForCallbacks);

Patterns

Patterns must be an object, an array of arrays or a Map instance

When patterns is an object

Then key should be a string pattern, and the function will compare the values using the Object.is.

Value should be a callback function or another value. If it the callback, it will be called, and matching function will return the result of callback. If it another value, matching function will return this value.

Patterns as objects are a nice replacement for mappings patterns through the object.

// We can replace:
const petWords = {
  'cow': 'Moo',
  'cat': 'Mew',
  'dog': 'Bark'
};

let result = petWords['cow']; // Moo
result = petWords['dog']; // Bark
result = petWords['slug']; // undefined

// With:
const matching = match({
  'cow': 'Moo',
  'cat': 'Mew',
  'dog': 'Bark'
}, 'Alien growl from abbys');

result = matching('cow'); // Moo
result = matching('dog'); // Bark
result = matching('slug'); // Alien growl from abbys

Or switch/case:

// Lets replace:
const doSound = (animal) => {
  switch (animal) {
    case 'cow':
      return doMoo(animal);
    case 'cat':
      return doMew(animal);
    case 'dog':
      return doBark(animal);
    default:
      return doAnotherSound(animal);
  }
}

// With:
const doSound = match({
  cow: doMoo,
  cat: doMew,
  dog: doBark
}, doAnotherSound);
// where doMoo, doMew, doBark, doAnotherSound is functions

doSound('cow'); // calls doMoo with 'cow' as argument
doSound('cat'); // calls doMew with 'cat' as argument
doSound('slug'); // calls doAnotherSound with 'slug argument'

When patterns is an instance of Map

Then matching becomes smarter. With instance of Map, key should be:

  • plain string, just like in object patterns;
  • regular expression;
  • boolean function, for complex patterns;
  • any other value for comparing through Object.is.
const matching = match(new Map([
  ['/robot/build', buildRobot,]
  ['/robot/run' runRobot],
  [/^\/robot\/custom\/.+?/,  processRobotCustom]
]), () => {
  throw new RobotHttpError(
    400, RobotHttpError.NO_ACTION_FOUND
  );
});

matching(req.path, req, res);

With boolean functions we can check complex patterns:

const cast = match(new Map([
  [isString, castFromString],
  [isNumber, castFromNumber],
  [isObject, castFromObject]
]));

cast(42); // castFromNumber(42)
cast('answer'); // castFromString('answer')
cast({ answer: 42 }); // castFromObject({ answer: 42 })
cast(undefined); // nothing to do

When patterns is an array of arrays

It's just shortcut for an instance of Map:

// No need in `new Map`
const cast = match([
  [isString, castFromString],
  [isNumber, castFromNumber],
  [isObject, castFromObject]
]);

Additional arguments for callback

There may be additional arguments in the matching function, they will be delivered to the head arguments of callback.

const updateAdmin = (group, user) => {
  // do something with group and user
}

const updatePlain = (group, user) => {
  // do something with group and user
}

const updateGroup = match({
  'admin': updateAdmin,
  'plain': updatePlain
});

updateGroup(user.group, groups.get(user.group), user);

ā†‘ If user.group is "admin", matcher calls updateAdmin with three arguments in following order: 1. result of groups.get(user.group) 2. user 3. at last user.group

i. e. the first argument of matching function always becomes the last argument of callback function.

Install

It requires lodash

Yarn

yarn add simple-stupid-match lodash

NPM

npm install simple-stupid-match lodash

Using pre-builded version in browser or NodeJS

If your environment does not support native ESModules, you should use pre-builded version:

import { match } from 'simple-stupid-match/build/match.js';
// Or CommonJS
const { match } = require('simple-stupid-match/build/match');