Initial commit

master
Sven Slootweg 5 years ago
commit 158c9223b8

2
.gitignore vendored

@ -0,0 +1,2 @@
node_modules
yarn.lock

@ -0,0 +1,127 @@
# dataprog
A few simple utility functions to support a better way of writing Javascript.
Proper documentation coming soon, this is still under development.
## The concept (draft)
Programming is ultimately centered around transforming and deriving data. Purely functional programming languages are centered around that premise, but people often find them impractical to use.
The interesting thing about JS is that it borrows pretty heavily from functional languages, while not being particularly restrictive. This makes it an interesting choice to write your code primarily around data transformations, without a high barrier to entry; however, JS is still missing a few features that would really make it work well.
This library aims to provide some of those features, in the form of utility functions. Ultimately it's up to you to write your code well - more about how to do that will be added to this documentation later - and this library simply serves to provide standardized implementations of a few handy patterns.
## API
### expression(func)
Turn anything into an expression, by wrapping it within an immediately-evaluated function. Especially useful to build the equivalent of match expressions (which JS doesn't have yet) using a regular if/else chain.
```js
const { expression } = require("dataprog");
function speakNumber(number) {
let name = expression(() => {
if (number === 1) {
return "one";
} else if (number === 2) {
return "two";
} else if (number === 3) {
return "three";
} else {
return "unknown";
}
});
console.log(`That number is ${name}`);
}
```
### merge(object, [object], [object], ...)
Merge any amount of objects into a single new one. This works a bit like `Object.assign`, with a few differences:
1. None of the provided objects are mutated.
2. If you pass in *only* `null`/`undefined` values, this function will return `null`. `Object.assign` would have thrown an error.
### syncPipe(value, functions)
A userland implementation of [pipelines](https://github.com/valtech-nyc/proposal-fsharp-pipelines/blob/master/README.md). Handles synchronous operations only, see `ppipe` for a version that supports Promises. Also sometimes known as 'waterfall'.
Specify a value and a series of functions that transform that value into a new value, eventually returning the final value from the `syncPipe` call.
- __value:__ The initial value.
- __functions:__ An array of transformation functions, or a single transformation function (though that is somewhat pointless).
```js
const dateFns = require("date-fns");
const { syncPipe } = require("dataprog");
function msUntilNextMinute() {
return syncPipe(getTime(), [
(_) => dateFns.addMinutes(_, 1),
(_) => dateFns.setSeconds(_, 0),
(_) => dateFns.differenceInMilliseconds(_, getTime())
]);
}
```
The `_` is just a variable name here, you could call it anything you want - but giving it a consistent name will help with readability, as all of the arrow function bodies will be visually aligned.
### asyncPipe(value, functions)
Like `syncPipe`, but each function in `functions` may return either a synchronous value or a Promise, and the call to `ppipe` will *always* return a Promise that resolves to the final value.
- __value:__ The initial value.
- __functions:__ An array of transformation functions, or a single transformation function.
```js
const { asyncPipe } = require("dataprog");
// ...
function getContentType(item) {
return asyncPipe(item, [
(_) => _.getHeaders(),
(_) => _["content-type"]
]);
}
```
For `asyncPipe`, which handles *asynchronous* operations, it can actually be useful to use the single-function syntax to quickly pick a property out of an asynchronously-obtained object:
```js
const { asyncPipe } = require("dataprog");
// ...
function getContentType(item) {
return ppipe(item.getHeaders(), (headers) => headers["content-type"]);
}
```
### objectFind(object, predicate)
Analogous to `Array#find`. Finds the first entry that matches the predicate, and returns its `[ key, value ]`, or `undefined` if there were no matches.
The `predicate` is called *value-first*, since usually the values are what you care about.
```js
const { objectFind } = require("dataprog");
let object = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5
};
let match = objectFind(object, (value, key) => value % 2 === 0);
console.log(match); // [ b, 2 ]
```
### objectIncludes(object, predicate)
Like `objectFind`, but returns `true` or `false` depending on whether the object contained an entry that matches the predicate. Analogous to `Array#some`.

@ -0,0 +1,39 @@
"use strict";
const Promise = require("bluebird");
const assureArray = require("assure-array");
const defaultValue = require("default-value");
module.exports = {
expression: function (func) {
return func();
},
syncPipe: function (value, functions) {
return assureArray(functions).reduce((last, func) => {
return func(last);
}, value);
},
asyncPipe: function (value, functions) {
return Promise.reduce(assureArray(functions), (last, func) => {
return func(last);
}, value);
},
objectFind: function (object, predicate) {
return Object.entries(defaultValue(object, {})).find(([ key, value ]) => {
return predicate(value, key);
});
},
objectIncludes: function (object, predicate) {
return Object.entries(defaultValue(object, {})).some(([ key, value ]) => {
return predicate(value, key);
});
},
merge: function (... objects) {
if (objects.every((obj) => obj == null)) {
return null;
} else {
/* TODO: Eventually disallow conflicting keys? */
return Object.assign({}, ... objects.filter((obj) => obj != null));
}
}
};

@ -0,0 +1,13 @@
{
"name": "dataprog",
"version": "0.1.0",
"main": "index.js",
"repository": "http://git.cryto.net/joepie91/node-dataprog.git",
"author": "Sven Slootweg <admin@cryto.net>",
"license": "WTFPL OR CC0-1.0",
"dependencies": {
"assure-array": "^1.0.0",
"bluebird": "^3.5.5",
"default-value": "^1.0.0"
}
}
Loading…
Cancel
Save