Skip to content

Commit

Permalink
add prop function
Browse files Browse the repository at this point in the history
  • Loading branch information
svozza committed Mar 11, 2016
1 parent cf77e4f commit 86808cf
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 11 deletions.
44 changes: 36 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,20 @@
});
};

var prop =
def('prop',
{a: [Accessible]},
[$.String, a, b],
function(key, obj) {
var boxed = Object(obj);
if (key in boxed) {
return boxed[key];
} else {
throw new TypeError('‘prop’ expected object to have a property ' +
'named ‘' + key + '’; ' + R.toString(obj) + ' does not');
}
});

//. ### Classify

//# type :: a -> String
Expand Down Expand Up @@ -1007,7 +1021,7 @@
method('Maybe#toBoolean',
{},
[$Maybe(a), $.Boolean],
R.prop('isJust'));
prop('isJust'));

//# Maybe#toString :: Maybe a ~> String
//.
Expand Down Expand Up @@ -1094,7 +1108,7 @@
def('isNothing',
{},
[$Maybe(a), $.Boolean],
R.prop('isNothing'));
prop('isNothing'));

//# isJust :: Maybe a -> Boolean
//.
Expand All @@ -1111,7 +1125,7 @@
def('isJust',
{},
[$Maybe(a), $.Boolean],
R.prop('isJust'));
prop('isJust'));

//# fromMaybe :: a -> Maybe a -> a
//.
Expand Down Expand Up @@ -1515,7 +1529,7 @@
method('Either#toBoolean',
{},
[$Either(a, b), $.Boolean],
R.prop('isRight'));
prop('isRight'));

//# Either#toString :: Either a b ~> String
//.
Expand Down Expand Up @@ -1604,7 +1618,7 @@
def('isLeft',
{},
[$Either(a, b), $.Boolean],
R.prop('isLeft'));
prop('isLeft'));

//# isRight :: Either a b -> Boolean
//.
Expand All @@ -1621,7 +1635,7 @@
def('isRight',
{},
[$Either(a, b), $.Boolean],
R.prop('isRight'));
prop('isRight'));

//# either :: (a -> c) -> (b -> c) -> Either a b -> c
//.
Expand Down Expand Up @@ -1698,7 +1712,7 @@
//. > S.encaseEither(S.I, JSON.parse, '[')
//. Left(new SyntaxError('Unexpected end of input'))
//.
//. > S.encaseEither(R.prop('message'), JSON.parse, '[')
//. > S.encaseEither(S.prop('message'), JSON.parse, '[')
//. Left('Unexpected end of input')
//. ```
S.encaseEither =
Expand Down Expand Up @@ -2369,6 +2383,20 @@

//. ### Object

//# prop :: Accessible a => String -> a -> b
//.
//. Takes a property name and an object and returns the value of the
//. specified field. If for some reason the record lacks the specified field,
//. a type error is thrown.
//.
//. For accessing properties of uncertain objects, use [`get`](#get) instead.
//.
//. ```javascript
//. > S.prop('a', {a: 1, b: 2})
//. 1
//. ```
S.prop = prop;

//# get :: Accessible a => TypeRep b -> String -> a -> Maybe b
//.
//. Takes a [type representative](#type-representatives), a property
Expand All @@ -2379,7 +2407,7 @@
//. The `Object` type representative may be used as a catch-all since most
//. values have `Object.prototype` in their prototype chains.
//.
//. See also [`gets`](#gets).
//. See also [`gets`](#gets) and [`prop`](#prop).
//.
//. ```javascript
//. > S.get(Number, 'x', {x: 1, y: 2})
Expand Down
70 changes: 67 additions & 3 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2089,7 +2089,7 @@ describe('either', function() {
});

it('applies the first argument to the Error', function() {
eq(S.encaseEither(R.prop('message'), factorial, -1),
eq(S.encaseEither(S.prop('message'), factorial, -1),
S.Left('Cannot determine factorial of negative number'));
});

Expand Down Expand Up @@ -2135,7 +2135,7 @@ describe('either', function() {
});

it('applies the first argument to the Error', function() {
eq(S.encaseEither2(R.prop('message'), rem, 42, 0),
eq(S.encaseEither2(S.prop('message'), rem, 42, 0),
S.Left('Cannot divide by zero'));
});

Expand Down Expand Up @@ -2182,7 +2182,7 @@ describe('either', function() {
});

it('applies the first argument to the Error', function() {
eq(S.encaseEither3(R.prop('message'), area, 2, 2, 5),
eq(S.encaseEither3(S.prop('message'), area, 2, 2, 5),
S.Left('Impossible triangle'));
});

Expand Down Expand Up @@ -3330,6 +3330,70 @@ describe('list', function() {

describe('object', function() {

describe('prop', function() {

it('is a binary function', function() {
eq(typeof S.prop, 'function');
eq(S.prop.length, 2);
});

it('type checks its arguments', function() {
assert.throws(function() { S.prop(1); },
errorEq(TypeError,
'‘prop’ expected a value of type String ' +
'as its first argument; received 1'));

assert.throws(function() { S.prop('a', null); },
errorEq(TypeError,
'‘prop’ requires ‘a’ to implement Accessible; ' +
'Null does not'));

assert.throws(function() { S.prop('a', true); },
errorEq(TypeError,
'‘prop’ expected object to have a property ' +
'named ‘a’; true does not'));

assert.throws(function() { S.prop('a', 1); },
errorEq(TypeError,
'‘prop’ expected object to have a property ' +
'named ‘a’; 1 does not'));

});

it('throws when the key is not present', function() {
assert.throws(function() { S.prop('map', 'abcd'); },
errorEq(TypeError,
'‘prop’ expected object to have a property ' +
'named ‘map’; "abcd" does not'));

assert.throws(function() { S.prop('c', {a: 0, b: 1}); },
errorEq(TypeError,
'‘prop’ expected object to have a property ' +
'named ‘c’; {"a": 0, "b": 1} does not'));

assert.throws(function() { S.prop('xxx', [1, 2, 3]); },
errorEq(TypeError,
'‘prop’ expected object to have a property ' +
'named ‘xxx’; [1, 2, 3] does not'));
});

it('retrieves the specified key', function() {
eq(S.prop('a', {a: 0, b: 1}), 0);
eq(S.prop('0', [1, 2, 3]), 1);
eq(S.prop('length', 'abc'), 3);

var proto = {x: 1, y: 2};
var obj = Object.create(proto);
eq(S.prop('x', obj), 1);
});

it('is curried', function() {
eq(S.prop('a').length, 1);
eq(S.prop('a')({a: 0, b: 1}), 0);
});

});

describe('get', function() {

it('is a ternary function', function() {
Expand Down

0 comments on commit 86808cf

Please sign in to comment.