Skip to content

Instantly share code, notes, and snippets.

@sebinsua
Created May 10, 2015 14:13
Show Gist options
  • Save sebinsua/01a0c5dc0a4c372fdc51 to your computer and use it in GitHub Desktop.
Save sebinsua/01a0c5dc0a4c372fdc51 to your computer and use it in GitHub Desktop.
var j = require('./lib');
var makeSelector = require('./selector').makeSelector;
var selectors = require('./selectors');
var transformers = require('./transformers');
var sel = makeSelector;
for (var selectorKey in selectors) {
sel[selectorKey] = selectors[selectorKey];
}
j.sel = sel;
j.trans = transformers;
module.exports = j;
'use strict';
/* eslint no-underscore-dangle: 0 */
var R = require('ramda');
var makeSelector = require('./selector').makeSelector;
var Selector = require('./selector').Selector;
var isSelector = R.is(Selector);
var isObjectLiteral = function isObject(v) {
return R.is(Object, v) && v.constructor === Object;
};
var get = R.curry(function get(selector, obj) {
if (!isSelector(selector)) {
selector = makeSelector(selector);
}
return selector.get(obj);
});
var transform = R.curry(function (fn, obj) {
return R.cond(
[R.isArrayLike, R.map(transform(fn))],
[isObjectLiteral, R.mapObj(transform(fn))],
[R.T, fn]
)(obj);
});
var deepPick = R.curry(function deepPick(def, obj) {
var getValue = get(R.__, obj);
var newObj = transform(getValue, def);
return newObj;
});
// Takes in an object of selectors.
// Use a selector on its own if you wish take in a
// single string or array of strings.
var j = R.curry(function j(def, obj) {
var keys = R.keys(def) || [];
var picker = keys.length ? deepPick(def) : R.identity;
return picker(obj);
});
module.exports = j;
module.exports.Selector = Selector;
'use strict';
var R = require('ramda');
var isSelector = R.is(Selector);
var isArray = R.is(Array);
var isNotNil = R.pipe(R.isNil, R.not);
var DEFAULT_VALUE = null;
function selectorToPath(selector, separator) {
selector = selector || '';
separator = separator || '/';
return selector.trim().split(separator);
}
function Selector (selector, transformFn) {
if (isArray(selector)) {
var selectorsToPaths = R.map(selectorToPath);
this.paths = selectorsToPaths(selector);
} else {
this.path = selectorToPath(selector);
}
this.transformation = transformFn || R.identity;
}
Selector.prototype.get = function (obj) {
var getValue = R.bind(this.getValue, this),
transformValue = R.bind(this.transformValue, this);
var getAndTransform = R.pipe(getValue, transformValue);
// We cannot curry without losing `this` so this is our best option.
return obj ? getAndTransform(obj) : getAndTransform;
};
Selector.prototype.getValue = function (obj) {
var value = DEFAULT_VALUE;
if (this.paths) {
value = R.pipe(R.map(function (path) {
return R.path(path, obj);
}), R.filter(isNotNil))(this.paths);
} else {
value = R.path(this.path, obj);
}
return value;
};
Selector.prototype.transformValue = function (value) {
var transformation = this.transformation;
value = transformation(value);
return typeof value !== 'undefined' ? value : DEFAULT_VALUE;
};
// The selector argument may be a string or an array of strings.
function makeSelector(selector, transformFn) {
return new Selector(selector, transformFn);
}
module.exports.makeSelector = makeSelector;
module.exports.Selector = Selector;
'use strict';
var R = require('ramda');
var makeSelector = require('./selector').makeSelector;
var transformers = require('./transformers');
module.exports = R.mapObj(function (transformer) {
return function (selector/*, ... */) {
var otherArguments = R.tail(arguments);
var t = otherArguments.length ? transformer.apply(transformers, otherArguments) : transformer;
return makeSelector(selector, t);
};
}, transformers);
#!/usr/bin/env node
'use strict';
var R = require('ramda');
var j = require('.');
var def = {
a: 'test',
b: 'cat',
somethingOfValue: {
within: {
obj: j.sel.exists('a/thing')
}
}
};
var obj = {
test: 9,
cat: 11,
a: {
thing: 'thing'
}
};
console.log(j.sel('a/thing'));
console.log(j.sel('a/thing').get(obj));
console.log(j.sel.exists('a/thing').get(obj));
console.log(j.sel('a/thing', j.trans.exists).get(obj));
var map = j(def);
var output = map(obj);
console.log(JSON.stringify(output, null, 2));
var otherDef = {
a: j.sel.defaultsTo('tes', 'defaultValue'),
b: j.sel.first(['other', 'cat']),
somethingOfValue: j.sel.isNotEmpty('obj')
};
var list = [
{ test: 5, other: 7, obj: { somethingOfValue: 9001 } },
{ test: 9, cat: 11, obj: {} }
];
var mapper = R.map(j(otherDef));
var out = mapper(list);
console.log(out);
As for jstruct itself:
- [ ] [Implement this as another kind of pluggable selector.](https://github.com/sebinsua/jstruct/blob/master/jstruct.js#L10)
- [ ] [Add error validations back in.](https://github.com/sebinsua/jstruct/blob/master/jstruct.js#L69)
- [ ] [Implement a deep/recursive cross between this, reduce and struct#deepPick.](https://github.com/sebinsua/jstruct/blob/master/jstruct.js#L121)
* clean readme.
Write es6 example.
---
* integrate into jstruct
* obj may be value, or object or array.
* write tests
* See if I can reconfigure with a new Selector.
## ADVANCED
* selector may contain a $key to pick up the key.
* selector may return multiple values.
* key may be a selector if it contains the separator.
* filters, key selectors, grouping???!!??
sel(selector, [filterObject, ] transformFn)
filter keys can be within the selector like [:filter-key].
[*] is what it looks like. So is [prop].
* group by is magical. It looks like:
"activities": {
"person/interests[*]/type": "person/interests[$k]/name"}
'use strict';
var R = require('ramda');
var exists = R.pipe(R.isNil, R.not);
var first = R.head;
var isNotEmpty = R.pipe(R.keys, R.isEmpty, R.not);
var defaultsTo = function defaultsTo(defaultValue) {
return R.ifElse(exists, R.identity, R.always(defaultValue));
};
module.exports.exists = exists;
module.exports.first = first;
module.exports.isNotEmpty = isNotEmpty;
module.exports.defaultsTo = defaultsTo;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment