Skip to content

Commit 6274d46

Browse files
committed
feat: Add basic fantasy land support to ArrayElement
1 parent beeddee commit 6274d46

File tree

4 files changed

+136
-1
lines changed

4 files changed

+136
-1
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# Minim Changelog
22

3+
## Master
4+
5+
### Enhancements
6+
7+
- `ArrayElement` now conforms to parts of the [Fantasy
8+
Land](https://github.com/fantasyland/fantasy-land) 3.5 specification.
9+
`Functor`, `Semigroup`, `Monoid`, `Filterable`, `Chain`, and `Foldable` are
10+
now supported.
11+
312
## 0.21.1
413

514
### Bug Fixes

lib/primitives/array-element.js

+43-1
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,43 @@ var ArrayElement = Element.extend({
312312
return this.content.some(function (element) {
313313
return element.equals(value);
314314
});
315-
}
315+
},
316+
317+
// Fantasy Land
318+
319+
empty: function() {
320+
return new this.constructor([]);
321+
},
322+
323+
'fantasy-land/empty': function() {
324+
return this.empty();
325+
},
326+
327+
concat: function(other) {
328+
return new this.constructor(this.content.concat(other.content));
329+
},
330+
331+
'fantasy-land/concat': function(other) {
332+
return this.concat(other);
333+
},
334+
335+
'fantasy-land/map': function(transform) {
336+
return new this.constructor(this.map(transform));
337+
},
338+
339+
'fantasy-land/chain': function(transform) {
340+
return this
341+
.map(function (element) { return transform(element); }, this)
342+
.reduce(function (a, b) { return a.concat(b); }, this.empty());
343+
},
344+
345+
'fantasy-land/filter': function(callback) {
346+
return new this.constructor(this.content.filter(callback));
347+
},
348+
349+
'fantasy-land/reduce': function(transform, initialValue) {
350+
return this.content.reduce(transform, initialValue);
351+
},
316352
}, {}, {
317353
/**
318354
* Returns the length of the collection
@@ -375,6 +411,12 @@ var ArrayElement = Element.extend({
375411
},
376412
});
377413

414+
ArrayElement.empty = function () {
415+
return new this();
416+
};
417+
418+
ArrayElement['fantasy-land/empty'] = ArrayElement.empty;
419+
378420
if (typeof Symbol !== 'undefined') {
379421
ArrayElement.prototype[Symbol.iterator] = function () {
380422
return this.content[Symbol.iterator]();

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
"chai": "^4.0.0",
3636
"coveralls": "^3.0.1",
3737
"eslint": "^4.19.1",
38+
"fantasy-land": "^3.5.0",
3839
"istanbul": "^0.4.5",
3940
"karma": "^2.0.2",
4041
"karma-browserify": "^5.2.0",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
'use strict';
2+
3+
var fl = require('fantasy-land');
4+
var expect = require('../spec-helper').expect;
5+
var namespace = require('../../lib/minim').namespace();
6+
7+
var ArrayElement = namespace.getElementClass('array');
8+
9+
describe('ArrayElement', function() {
10+
var array = new ArrayElement([1, 2, 3, 4]);
11+
12+
describe('Functor', function() {
13+
it('can transform elements into new ArrayElement', function() {
14+
var result = array[fl.map](function(n) {
15+
return new namespace.elements.Number(n.toValue() * 2);
16+
});
17+
18+
expect(result).to.be.instanceof(ArrayElement);
19+
expect(result.toValue()).to.deep.equal([2, 4, 6, 8]);
20+
});
21+
});
22+
23+
describe('Semigroup', function() {
24+
it('can concatinate two array elements', function() {
25+
var result = array[fl.concat](new ArrayElement([5, 6]));
26+
27+
expect(result).to.be.instanceof(ArrayElement);
28+
expect(result.toValue()).to.deep.equal([1, 2, 3, 4, 5, 6]);
29+
});
30+
});
31+
32+
describe('Monoid', function() {
33+
it('can create an empty ArrayElement', function() {
34+
var result = ArrayElement[fl.empty]();
35+
36+
expect(result).to.be.instanceof(ArrayElement);
37+
expect(result.toValue()).to.deep.equal([]);
38+
});
39+
40+
it('can create an empty ArrayElement from another ArrayElement', function() {
41+
var result = array[fl.empty]();
42+
43+
expect(result).to.be.instanceof(ArrayElement);
44+
expect(result.toValue()).to.deep.equal([]);
45+
});
46+
});
47+
48+
describe('Filterable', function() {
49+
it('can filter all elements into equivilent ArrayElement', function() {
50+
var result = array[fl.filter](function() { return true; });
51+
52+
expect(result).to.deep.equal(array);
53+
});
54+
55+
it('can filter into empty ArrayElement', function() {
56+
var result = array[fl.filter](function() { return false; });
57+
58+
expect(result).to.be.instanceof(ArrayElement);
59+
expect(result.isEmpty).to.be.true;
60+
});
61+
});
62+
63+
describe('Chain', function() {
64+
it('can transform and chain results into new ArrayElement', function() {
65+
var duplicate = function(n) { return new ArrayElement([n, n]); };
66+
var result = array[fl.chain](duplicate);
67+
68+
expect(result).to.be.instanceof(ArrayElement);
69+
expect(result.toValue()).to.deep.equal([1, 1, 2, 2, 3, 3, 4, 4]);
70+
});
71+
});
72+
73+
describe('Foldable', function() {
74+
it('can reduce results into new ArrayElement', function() {
75+
var result = array[fl.reduce](function (accumulator, element) {
76+
return accumulator.concat(new ArrayElement([element.toValue(), element.toValue()]));
77+
}, new ArrayElement());
78+
79+
expect(result).to.be.instanceof(ArrayElement);
80+
expect(result.toValue()).to.deep.equal([1, 1, 2, 2, 3, 3, 4, 4]);
81+
});
82+
});
83+
});

0 commit comments

Comments
 (0)