Skip to content

Commit

Permalink
Merge pull request #199 from refractproject/kylef/fantasyland
Browse files Browse the repository at this point in the history
Add basic fantasy land support to ArrayElement
  • Loading branch information
kylef committed Dec 6, 2018
2 parents beeddee + 52249ae commit 54f08e9
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 2 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Minim Changelog

## 0.22.0

### Enhancements

- `ArrayElement` now conforms to parts of the [Fantasy
Land](https://github.com/fantasyland/fantasy-land) 3.5 specification.
`Functor`, `Semigroup`, `Monoid`, `Filterable`, `Chain`, and `Foldable` are
now supported.

## 0.21.1

### Bug Fixes
Expand Down
44 changes: 43 additions & 1 deletion lib/primitives/array-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,43 @@ var ArrayElement = Element.extend({
return this.content.some(function (element) {
return element.equals(value);
});
}
},

// Fantasy Land

empty: function() {
return new this.constructor([]);
},

'fantasy-land/empty': function() {
return this.empty();
},

concat: function(other) {
return new this.constructor(this.content.concat(other.content));
},

'fantasy-land/concat': function(other) {
return this.concat(other);
},

'fantasy-land/map': function(transform) {
return new this.constructor(this.map(transform));
},

'fantasy-land/chain': function(transform) {
return this
.map(function (element) { return transform(element); }, this)
.reduce(function (a, b) { return a.concat(b); }, this.empty());
},

'fantasy-land/filter': function(callback) {
return new this.constructor(this.content.filter(callback));
},

'fantasy-land/reduce': function(transform, initialValue) {
return this.content.reduce(transform, initialValue);
},
}, {}, {
/**
* Returns the length of the collection
Expand Down Expand Up @@ -375,6 +411,12 @@ var ArrayElement = Element.extend({
},
});

ArrayElement.empty = function () {
return new this();
};

ArrayElement['fantasy-land/empty'] = ArrayElement.empty;

if (typeof Symbol !== 'undefined') {
ArrayElement.prototype[Symbol.iterator] = function () {
return this.content[Symbol.iterator]();
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "minim",
"version": "0.21.1",
"version": "0.22.0",
"description": "A library for interacting with JSON through Refract elements",
"main": "lib/minim.js",
"scripts": {
Expand Down Expand Up @@ -35,6 +35,7 @@
"chai": "^4.0.0",
"coveralls": "^3.0.1",
"eslint": "^4.19.1",
"fantasy-land": "^3.5.0",
"istanbul": "^0.4.5",
"karma": "^2.0.2",
"karma-browserify": "^5.2.0",
Expand Down
83 changes: 83 additions & 0 deletions test/primitives/array-element-fantasy-land-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict';

var fl = require('fantasy-land');
var expect = require('../spec-helper').expect;
var namespace = require('../../lib/minim').namespace();

var ArrayElement = namespace.getElementClass('array');

describe('ArrayElement', function() {
var array = new ArrayElement([1, 2, 3, 4]);

describe('Functor', function() {
it('can transform elements into new ArrayElement', function() {
var result = array[fl.map](function(n) {
return new namespace.elements.Number(n.toValue() * 2);
});

expect(result).to.be.instanceof(ArrayElement);
expect(result.toValue()).to.deep.equal([2, 4, 6, 8]);
});
});

describe('Semigroup', function() {
it('can concatinate two array elements', function() {
var result = array[fl.concat](new ArrayElement([5, 6]));

expect(result).to.be.instanceof(ArrayElement);
expect(result.toValue()).to.deep.equal([1, 2, 3, 4, 5, 6]);
});
});

describe('Monoid', function() {
it('can create an empty ArrayElement', function() {
var result = ArrayElement[fl.empty]();

expect(result).to.be.instanceof(ArrayElement);
expect(result.toValue()).to.deep.equal([]);
});

it('can create an empty ArrayElement from another ArrayElement', function() {
var result = array[fl.empty]();

expect(result).to.be.instanceof(ArrayElement);
expect(result.toValue()).to.deep.equal([]);
});
});

describe('Filterable', function() {
it('can filter all elements into equivilent ArrayElement', function() {
var result = array[fl.filter](function() { return true; });

expect(result).to.deep.equal(array);
});

it('can filter into empty ArrayElement', function() {
var result = array[fl.filter](function() { return false; });

expect(result).to.be.instanceof(ArrayElement);
expect(result.isEmpty).to.be.true;
});
});

describe('Chain', function() {
it('can transform and chain results into new ArrayElement', function() {
var duplicate = function(n) { return new ArrayElement([n, n]); };
var result = array[fl.chain](duplicate);

expect(result).to.be.instanceof(ArrayElement);
expect(result.toValue()).to.deep.equal([1, 1, 2, 2, 3, 3, 4, 4]);
});
});

describe('Foldable', function() {
it('can reduce results into new ArrayElement', function() {
var result = array[fl.reduce](function (accumulator, element) {
return accumulator.concat(new ArrayElement([element.toValue(), element.toValue()]));
}, new ArrayElement());

expect(result).to.be.instanceof(ArrayElement);
expect(result.toValue()).to.deep.equal([1, 1, 2, 2, 3, 3, 4, 4]);
});
});
});

0 comments on commit 54f08e9

Please sign in to comment.