From f984324bba7f12731a1dbb12fe119b9b4a85d149 Mon Sep 17 00:00:00 2001 From: Stefano Vozza Date: Sun, 8 May 2016 23:04:35 +0100 Subject: [PATCH] add S.keys and S.values --- index.js | 42 ++++++++++++++++++++++++++++++++++++ test/keys.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/values.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 test/keys.js create mode 100644 test/values.js diff --git a/index.js b/index.js index 7ca1f215..680b58cf 100644 --- a/index.js +++ b/index.js @@ -166,6 +166,8 @@ var sentinel = {}; + var hasOwnProperty = Object.prototype.hasOwnProperty; + // _type :: a -> String var _type = function(x) { return x != null && R.type(x['@@type']) === 'String' ? x['@@type'] @@ -362,6 +364,14 @@ } }); + // keys :: StrMap a -> Array String + var keys = function(strMap) { + if(typeof Object.keys === 'function') return Object.keys(strMap); + var ks = []; + for (var k in strMap) if (hasOwnProperty(k, strMap)) ks.push(k); + return ks; + }; + //. ### Classify //# type :: a -> String @@ -2683,6 +2693,38 @@ return filter(is(type), Just(x)); }); + //# keys :: StrMap a -> Array String + //. + //. Returns a list containing the keys of the supplied StrMap. + //. + //. ```javascript + //. > S.keys({a: 1, b: 2, c:3}) + //. ['a', 'b', 'c'] + //. ``` + S.keys = + def('keys', + {}, + [$.StrMap(a), $.Array($.String)], + keys); + + //# values :: StrMap a -> Array a + //. + //. Returns a list containing the values of the supplied StrMap. + //. + //. ```javascript + //. > S.values({a: 1, b: 2, c:3}) + //. [1, 2, 3] + //. ``` + S.values = + def('values', + {}, + [$.StrMap(a), $.Array(a)], + function(obj) { + return keys(obj).map(function(key) { + return obj[key]; + }); + }); + //. ### Number //# negate :: ValidNumber -> ValidNumber diff --git a/test/keys.js b/test/keys.js new file mode 100644 index 00000000..3eb58a09 --- /dev/null +++ b/test/keys.js @@ -0,0 +1,58 @@ +'use strict'; + +var throws = require('assert').throws; + +var eq = require('./utils').eq; +var errorEq = require('./utils').errorEq; +var S = require('..'); + + +describe('keys', function() { + + it('is a unary function', function() { + eq(typeof S.keys, 'function'); + eq(S.keys.length, 1); + }); + + it('type checks its arguments', function() { + throws(function() { S.keys('xxx'); }, + errorEq(TypeError, + 'Invalid value\n' + + '\n' + + 'keys :: StrMap a -> Array String\n' + + ' ^^^^^^^^\n' + + ' 1\n' + + '\n' + + '1) "xxx" :: String\n' + + '\n' + + 'The value at position 1 is not a member of ‘StrMap a’.\n')); + + throws(function() { S.keys({a: '1', b: 2, c: '3'}); }, + errorEq(TypeError, + 'Type-variable constraint violation\n' + + '\n' + + 'keys :: StrMap a -> Array String\n' + + ' ^\n' + + ' 1\n' + + '\n' + + '1) "1" :: String\n' + + ' 2 :: Number, FiniteNumber, NonZeroFiniteNumber, Integer, ValidNumber\n' + + ' "3" :: String\n' + + '\n' + + 'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n')); + }); + + it("returns an array of the given object's own keys", function() { + eq(S.keys({a: 1, b: 2, c: 3}).sort(), ['a', 'b', 'c']); + }); + + it('does not include prototype properties', function() { + var proto = {a: 1, b: 2}; + var obj = Object.create(proto); + obj.c = 3; + obj.d = 4; + + eq(S.keys(obj).sort(), ['c', 'd']); + }); + +}); diff --git a/test/values.js b/test/values.js new file mode 100644 index 00000000..96aafbca --- /dev/null +++ b/test/values.js @@ -0,0 +1,58 @@ +'use strict'; + +var throws = require('assert').throws; + +var eq = require('./utils').eq; +var errorEq = require('./utils').errorEq; +var S = require('..'); + + +describe('values', function() { + + it('is a unary function', function() { + eq(typeof S.values, 'function'); + eq(S.values.length, 1); + }); + + it('type checks its arguments', function() { + throws(function() { S.values('xxx'); }, + errorEq(TypeError, + 'Invalid value\n' + + '\n' + + 'values :: StrMap a -> Array a\n' + + ' ^^^^^^^^\n' + + ' 1\n' + + '\n' + + '1) "xxx" :: String\n' + + '\n' + + 'The value at position 1 is not a member of ‘StrMap a’.\n')); + + throws(function() { S.values({a: '1', b: 2, c: '3'}); }, + errorEq(TypeError, + 'Type-variable constraint violation\n' + + '\n' + + 'values :: StrMap a -> Array a\n' + + ' ^\n' + + ' 1\n' + + '\n' + + '1) "1" :: String\n' + + ' 2 :: Number, FiniteNumber, NonZeroFiniteNumber, Integer, ValidNumber\n' + + ' "3" :: String\n' + + '\n' + + 'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n')); + }); + + it("returns an array of the given object's own values", function() { + eq(S.values({a: 1, b: 2, c: 3}).sort(), [1, 2, 3]); + }); + + it('does not include prototype values', function() { + var proto = {a: 1, b: 2}; + var obj = Object.create(proto); + obj.c = 3; + obj.d = 4; + + eq(S.values(obj).sort(), [3, 4]); + }); + +});