-
-
Notifications
You must be signed in to change notification settings - Fork 95
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add S.keys, S.values and S.pairs #214
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,8 @@ | |
//. | ||
//. R.map(S.toUpper, S.head(words)) | ||
//. | ||
//. Sanctuary is designed to work in Node.js and in ES5-compatible browsers. | ||
//. | ||
//. ## Types | ||
//. | ||
//. Sanctuary uses Haskell-like type signatures to describe the types of | ||
|
@@ -2746,6 +2748,52 @@ | |
return filter(is(type), Just(x)); | ||
}); | ||
|
||
//# keys :: StrMap a -> Array String | ||
//. | ||
//. Returns the keys of the given string map, in arbitrary order. | ||
//. | ||
//. ```javascript | ||
//. > S.keys({b: 2, c: 3, a: 1}).sort() | ||
//. ['a', 'b', 'c'] | ||
//. ``` | ||
S.keys = | ||
def('keys', | ||
{}, | ||
[$.StrMap(a), $.Array($.String)], | ||
Object.keys); | ||
|
||
//# values :: StrMap a -> Array a | ||
//. | ||
//. Returns the values of the given string map, in arbitrary order. | ||
//. | ||
//. ```javascript | ||
//. > S.values({a: 1, c: 3, b: 2}).sort() | ||
//. [1, 2, 3] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's |
||
//. ``` | ||
S.values = | ||
def('values', | ||
{}, | ||
[$.StrMap(a), $.Array(a)], | ||
function(strMap) { | ||
return Object.keys(strMap).map(function(key) { return strMap[key]; }); | ||
}); | ||
|
||
//# toPairs :: StrMap a -> Array (Pair String a) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'll fix this shortly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
//. | ||
//. Returns the key–value pairs of the given string map, in arbitrary order. | ||
//. | ||
//. ```javascript | ||
//. > S.pairs({b: 2, a: 1, c: 3}).sort() | ||
//. [['a', 1], ['b', 2], ['c', 3]] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another way to do this that would be to list the elements in each of the functions' examples in an obviously out of order sequence. That way we don't clutter the docs with things that really aren't related to the functions: S.keys({a: 1, b: 2, c: 3}) // => [c, b, a]
S.values({a: 1, b: 2, c: 3}) // => [1, 3, 2]
S.toPairs({a: 1, b: 2, c: 3}) //=> [['b', 2], ['a', 1], ['c', 3]] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The root problem is that we're using an ordered collection for something with no inherent order. When comparing two arrays for equality, order is of course significant. To ensure the doctests pass, we have two options:
Thinking about this again, I believe the best approach is to jumble the keys in the input: > S.keys({c: 3, a: 1, b: 2}).sort()
['a', 'b', 'c']
> S.values({c: 3, a: 1, b: 2}).sort()
[1, 2, 3]
> S.pairs({c: 3, a: 1, b: 2}).sort()
[['a', 1], ['b', 2], ['c', 3]] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Of course, I'd forgotten about the doc tests. ⚡ |
||
//. ``` | ||
S.pairs = | ||
def('pairs', | ||
{}, | ||
[$.StrMap(a), $.Array($.Pair($.String, a))], | ||
function(strMap) { | ||
return Object.keys(strMap).map(function(k) { return [k, strMap[k]]; }); | ||
}); | ||
|
||
//. ### Number | ||
|
||
//# negate :: ValidNumber -> ValidNumber | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
'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({}), []); | ||
eq(S.keys({a: 1, b: 2, c: 3}).sort(), ['a', 'b', 'c']); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's worth noting that sorted keys would be useful here. ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure how it would have made it any easier to copy and paste this test from Ramda's. ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's also test |
||
}); | ||
|
||
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']); | ||
}); | ||
|
||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
'use strict'; | ||
|
||
var throws = require('assert').throws; | ||
|
||
var eq = require('./utils').eq; | ||
var errorEq = require('./utils').errorEq; | ||
var S = require('..'); | ||
|
||
|
||
describe('toPairs', function() { | ||
|
||
var comparePairsAsc = function(a, b) { | ||
return a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0; | ||
}; | ||
|
||
it('is a unary function', function() { | ||
eq(typeof S.pairs, 'function'); | ||
eq(S.pairs.length, 1); | ||
}); | ||
|
||
it('type checks its arguments', function() { | ||
throws(function() { S.pairs('xxx'); }, | ||
errorEq(TypeError, | ||
'Invalid value\n' + | ||
'\n' + | ||
'pairs :: StrMap a -> Array (Pair String 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.pairs({a: '1', b: 2, c: '3'}); }, | ||
errorEq(TypeError, | ||
'Type-variable constraint violation\n' + | ||
'\n' + | ||
'pairs :: StrMap a -> Array (Pair String 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 with the key value pairs of each property of the object', function() { | ||
eq(S.pairs({}), []); | ||
eq(S.pairs({a: 1, b: 2, c: 3}).sort(comparePairsAsc), [['a', 1], ['b', 2], ['c', 3]]); | ||
}); | ||
|
||
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.pairs(obj).sort(comparePairsAsc), [['c', 3], ['d', 4]]); | ||
}); | ||
|
||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
'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({}), []); | ||
eq(S.values({a: 1, b: 2, c: 3}).sort(), [1, 2, 3]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's also test |
||
}); | ||
|
||
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]); | ||
}); | ||
|
||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add
.sort()
to the input, both to ensure determinism and to reinforce the comment about arbitrary ordering.