Skip to content

Commit

Permalink
Merge pull request #310 from svozza/295-deep-prop-access
Browse files Browse the repository at this point in the history
Add S.props
davidchambers authored Dec 30, 2016

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents 01f053e + 0b0ac77 commit 7a2e2c7
Showing 2 changed files with 96 additions and 4 deletions.
30 changes: 26 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
@@ -2787,6 +2787,29 @@
}
S.prop = def('prop', {a: [Accessible]}, [$.String, a, b], prop);

//# props :: Accessible a => Array String -> a -> b
//.
//. Takes a property path (an array of property names) and an object with
//. known structure and returns the value at the given path. If for some
//. reason the path does not exist, a type error is thrown.
//.
//. For accessing property paths of uncertain objects, use [`gets`](#gets)
//. instead.
//.
//. ```javascript
//. > S.props(['a', 'b', 'c'], {a: {b: {c: 1}}})
//. 1
//. ```
function props(path, obj) {
return path.reduce(function(memo, key) {
if (key in memo) return memo[key];
throw new TypeError('‘props’ expected object to have a property at ' +
R.toString(path) + '; ' +
R.toString(obj) + ' does not');
}, Object(obj));
}
S.props = def('props', {a: [Accessible]}, [$.Array($.String), a, b], props);

//# get :: Accessible a => (b -> Boolean) -> String -> a -> Maybe c
//.
//. Takes a predicate, a property name, and an object and returns Just the
@@ -2814,10 +2837,9 @@

//# gets :: Accessible a => (b -> Boolean) -> Array String -> a -> Maybe c
//.
//. Takes a predicate, an array of property names, and an object and returns
//. Just the value at the path specified by the array of property names if
//. such a path exists and the value satisfies the given predicate; Nothing
//. otherwise.
//. Takes a predicate, a property path (an array of property names), and
//. an object and returns Just the value at the given path if such a path
//. exists and the value satisfies the given predicate; Nothing otherwise.
//.
//. See also [`get`](#get).
//.
70 changes: 70 additions & 0 deletions test/props.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
'use strict';

var S = require('..');

var eq = require('./internal/eq');
var throws = require('./internal/throws');


test('props', function() {

eq(typeof S.props, 'function');
eq(S.props.length, 2);

throws(function() { S.props(1); },
TypeError,
'Invalid value\n' +
'\n' +
'props :: Accessible a => Array String -> a -> b\n' +
' ^^^^^^^^^^^^\n' +
' 1\n' +
'\n' +
'1) 1 :: Number, FiniteNumber, NonZeroFiniteNumber, Integer, ValidNumber\n' +
'\n' +
'The value at position 1 is not a member of ‘Array String’.\n');

throws(function() { S.props(['a', 'b', 'c'], null); },
TypeError,
'Type-class constraint violation\n' +
'\n' +
'props :: Accessible a => Array String -> a -> b\n' +
' ^^^^^^^^^^^^ ^\n' +
' 1\n' +
'\n' +
'1) null :: Null\n' +
'\n' +
'‘props’ requires ‘a’ to satisfy the Accessible type-class constraint; the value at position 1 does not.\n');

throws(function() { S.props([true, false], {a: {b: {c: 1}}}); },
TypeError,
'Invalid value\n' +
'\n' +
'props :: Accessible a => Array String -> a -> b\n' +
' ^^^^^^\n' +
' 1\n' +
'\n' +
'1) true :: Boolean\n' +
'\n' +
'The value at position 1 is not a member of ‘String’.\n');

throws(function() { S.props(['a', 'b', 'c'], true); },
TypeError,
'‘props’ expected object to have a property at ["a", "b", "c"]; true does not');

throws(function() { S.props(['a', 'b', 'c'], 1); },
TypeError,
'‘props’ expected object to have a property at ["a", "b", "c"]; 1 does not');

throws(function() { S.props(['a', 'b', 'd'], {a: {b: {c: 1}}}); },
TypeError,
'‘props’ expected object to have a property at ["a", "b", "d"]; {"a": {"b": {"c": 1}}} does not');

throws(function() { S.props(['a', 'b', 'c'], [1, 2, 3]); },
TypeError,
'‘props’ expected object to have a property at ["a", "b", "c"]; [1, 2, 3] does not');

eq(S.props(['a', 'b', 'c'], {a: {b: {c: 1}}}), 1);
eq(S.props(['a', 'b', 'c', '0'], {a: {b: {c: [2, 4, 6]}}}), 2);
eq(S.props(['a', 'b', 'c'], Object.create({a: {b: {c: 1}}})), 1);

});

0 comments on commit 7a2e2c7

Please sign in to comment.