Skip to content

Commit

Permalink
add flatten & remove Iterum delegation (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
xgbuils committed Feb 9, 2017
1 parent a2422f5 commit 6c243b5
Show file tree
Hide file tree
Showing 24 changed files with 85 additions and 229 deletions.
37 changes: 3 additions & 34 deletions src/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ function factory (options) {
return function (object) {
let generator
if (object instanceof IterumClass) {
generator = object[Symbol.iterator]
generator = object[Symbol.iterator].bind(object)
} else if (typeof object === 'function') {
generator = transformGenerator(object, this)
generator = object
} else {
generator = transformGenerator(object[Symbol.iterator], object)
generator = object[Symbol.iterator].bind(object)
}
return Object.create(IterumClass.prototype, {
[Symbol.iterator]: {
Expand Down Expand Up @@ -68,37 +68,6 @@ function factory (options) {
})
})

function transformGenerator (generator, iterum) {
const rawGenerator = generator.bind(iterum)
return function* () {
let iterator = rawGenerator()
const stack = []

while (true) {
let done
let value
let pop
let push
do {
const state = iterator.next()
;({value, done} = state)
pop = done && stack.length > 0
push = !done && value instanceof Iterum
if (pop) {
iterator = stack.pop()
} else if (push) {
stack.push(iterator)
iterator = value[Symbol.iterator]()
}
} while (pop || push)
if (done) {
return
}
yield value
}
}
}

return Iterum
}

Expand Down
35 changes: 35 additions & 0 deletions src/fn/flatten.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const Iterable = require('../core/iterable')
const validation = [['Number', 'Undefined']]

function* flatten (n = 1) {
let iterator = this[Symbol.iterator]()
const stack = []

while (true) {
let done
let value
let pop
let push
do {
const state = iterator.next()
;({value, done} = state)
pop = done && stack.length > 0
push = !done && value instanceof Iterable && stack.length < n
if (pop) {
iterator = stack.pop()
} else if (push) {
stack.push(iterator)
iterator = value[Symbol.iterator]()
}
} while (pop || push)
if (done) {
return
}
yield value
}
}

module.exports = {
gen: flatten,
validation
}
2 changes: 1 addition & 1 deletion src/fn/repeat.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const validation = [['Number', 'Undefined']]

function* repeat (times = Infinity) {
for (let i = 0; i < times; ++i) {
yield this
yield* this
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const filter = require('./fn/filter')
const find = require('./fn/find')
const findEntry = require('./fn/findEntry')
const findIndex = require('./fn/findIndex')
const flatten = require('./fn/flatten')
const forEach = require('./fn/forEach')
const indexOf = require('./fn/indexOf')
const map = require('./fn/map.js')
Expand Down Expand Up @@ -42,6 +43,7 @@ const Iterum = factory({
drop,
dropWhile,
filter,
flatten,
map,
repeat,
slice,
Expand Down
16 changes: 1 addition & 15 deletions test/constructors/cartesian_test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const {expect} = require('chai')
const Iterum = require('../../src/index.js')
const {cartesian, range} = Iterum
const {cartesian} = Iterum

describe('Iterum.cartesian', function () {
describe('given 2 lists, it makes cartesian product of these lists', function () {
Expand Down Expand Up @@ -113,20 +113,6 @@ describe('Iterum.cartesian', function () {
})
})

describe('If value is a iterum instance', function () {
describe('this value is interpreted as a sequence of values of this iterum instance', function () {
it('using Iterum.range and iterum instance values inside Iterum.cartesian params', function () {
const values = [...cartesian([range(1, 2)], [Iterum([3]), 4])]
expect(values).to.be.deep.equal([[1, 3], [1, 4], [2, 3], [2, 4]])
})

it('using cartesian instance and call repeat then', function () {
const values = [...cartesian([2], [3]).repeat(2)]
expect(values).to.be.deep.equal([[2, 3], [2, 3]])
})
})
})

describe('converting iterum instance to array', function () {
it('returns the same as converting [Symbol.iterator]() iterator to array', function () {
const cartesianIterable = cartesian([1, 3], [6, 10])
Expand Down
10 changes: 0 additions & 10 deletions test/fn/concat_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,6 @@ describe('concat', function () {
})
})

describe('If it exists value that is an iterum instance,', function () {
describe('this value is interpreted as a sequence of values of this iterum instance', function () {
it('passing iterum instance in concat method', function () {
const values = [...Iterum([8])
.concat(Iterum([100, range(1, 5)]))]
expect(values).to.be.deep.equal([8, 100, 1, 2, 3, 4, 5])
})
})
})

describe('bad arguments', function () {
it('throws an exception when the first argument is not a function or Iterum', function () {
function foo () {
Expand Down
10 changes: 0 additions & 10 deletions test/fn/dropWhile_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,6 @@ describe('dropWhile', function () {
})
})

describe('If it exists value that is an iterum instance,', function () {
it('this value is interpreted as a sequence of values of this iterum instance', function () {
const iterum = Iterum([1, range(1, 3).repeat(2), 8])
.dropWhile(function (e) {
return e < 3
})
expect([...iterum]).to.be.deep.equal([3, 1, 2, 3, 8])
})
})

describe('bad arguments', function () {
it('throws an exception when the first argument is not a function', function () {
function foo () {
Expand Down
8 changes: 0 additions & 8 deletions test/fn/drop_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,6 @@ describe('drop', function () {
})
})

describe('If it exists value that is an iterum instance,', function () {
it('this value is interpreted as a sequence of values of this iterum instance', function () {
const iterum = Iterum([1, Iterum([3, 100, 5]), 8])
.drop(3)
expect([...iterum]).to.be.deep.equal([5, 8])
})
})

describe('bad arguments', function () {
it('throws an exception when the first argument is not a function', function () {
function foo () {
Expand Down
10 changes: 0 additions & 10 deletions test/fn/every_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,16 +50,6 @@ describe('every', function () {
})
})

describe('If it exists value that is an iterum instance,', function () {
it('this value is interpreted as a sequence of values of this iterum instance', function () {
const value = Iterum([100, Iterum([]), 100])
.every(function (e) {
return e === 100
})
expect(value).to.be.deep.equal(true)
})
})

describe('bad arguments', function () {
it('throws an exception when the first argument is not a function', function () {
function foo () {
Expand Down
10 changes: 0 additions & 10 deletions test/fn/filter_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,6 @@ describe('filter', function () {
})
})

describe('If it exists value that is an iterum instance,', function () {
it('this value is interpreted as a sequence of values of this iterum instance', function () {
const values = [...Iterum([range(1, 5)])
.filter(function (e) {
return e <= 3
})]
expect(values).to.be.deep.equal([1, 2, 3])
})
})

describe('bad arguments', function () {
it('throws an exception when the first argument is not a function', function () {
function foo () {
Expand Down
10 changes: 0 additions & 10 deletions test/fn/findEntry_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,6 @@ describe('findEntry', function () {
})
})

describe('If it exists value that is an iterum instance,', function () {
it('this value is interpreted as a sequence of values of this iterum instance', function () {
const index = Iterum([100, range(2, 1, -1), 100])
.findEntry(function (e) {
return e === 1
})
expect(index).to.be.deep.equal([2, 1])
})
})

describe('bad arguments', function () {
it('throws an exception when the first argument is not a function', function () {
function foo () {
Expand Down
10 changes: 0 additions & 10 deletions test/fn/findIndex_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,6 @@ describe('findIndex', function () {
})
})

describe('If it exists value that is an iterum instance,', function () {
it('this value is interpreted as a sequence of values of this iterum instance', function () {
const index = Iterum([100, range(2, 1, -1), 100])
.findIndex(function (e) {
return e === 2
})
expect(index).to.be.deep.equal(1)
})
})

describe('bad arguments', function () {
it('throws an exception when the first argument is not a function', function () {
function foo () {
Expand Down
10 changes: 0 additions & 10 deletions test/fn/find_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,6 @@ describe('find', function () {
})
})

describe('If it exists value that is an iterum instance,', function () {
it('this value is interpreted as a sequence of values of this iterum instance', function () {
const value = Iterum([100, range(2, -Infinity, -1), 55])
.find(function (e) {
return e < 0
})
expect(value).to.be.equal(-1)
})
})

describe('bad arguments', function () {
it('throws an exception when the first argument is not a function', function () {
function foo () {
Expand Down
43 changes: 43 additions & 0 deletions test/fn/flatten_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const {expect} = require('chai')
const Iterum = require('../../src/index.js')

describe('flatten', function () {
it('flatten 0 returns iterable that iterate over the same values', function () {
const iterable = [1, [2, 3, 4], 5]
const nonFlattenedIterable = Iterum(iterable)
.flatten(0)
expect([...nonFlattenedIterable]).to.be.deep.equal([...iterable])
})

it('flatten (n = 1)', function () {
const iterable = [[[1], 2], 3, [4, 5], [[6], 7]]
const expectedIterable = [[1], 2, 3, 4, 5, [6], 7]
const flattenedIterable = Iterum(iterable)
.flatten(1)
expect([...flattenedIterable]).to.be.deep.equal([...expectedIterable])
})

it('flatten has n = 1 by default', function () {
const iterable = [[[1], 2], 3, [4, 5], [[6], 7]]
const expectedIterable = [[1], 2, 3, 4, 5, [6], 7]
const flattenedIterable = Iterum(iterable)
.flatten()
expect([...flattenedIterable]).to.be.deep.equal([...expectedIterable])
})

it('flatten (n = 4)', function () {
const iterable = [1, [2, [3, [4, [5, [6, [7]]]]]]]
const expectedIterable = [1, 2, 3, 4, 5, [6, [7]]]
const flattenedIterable = Iterum(iterable)
.flatten(4)
expect([...flattenedIterable]).to.be.deep.equal([...expectedIterable])
})

it('flatten (n = Infinity)', function () {
const iterable = [[[[[[[7], 6], 5], 4], 3], 2], 1, [2, [3, [4, [5, [6, [7]]]]]]]
const expectedIterable = [7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 7]
const flattenedIterable = Iterum(iterable)
.flatten(Infinity)
expect([...flattenedIterable]).to.be.deep.equal([...expectedIterable])
})
})
14 changes: 0 additions & 14 deletions test/fn/forEach_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,4 @@ describe('forEach', function () {
[10, 5, iterum]
])
})

describe('If it exists value that is an iterum instance,', function () {
it('this value is interpreted as a sequence of values of this iterum instance', function () {
const cb = sinon.spy()
const iterum = Iterum([5, 10]).repeat(2)
iterum.forEach(cb)
expect(cb.args).to.be.deep.equal([
[5, 0, iterum],
[10, 1, iterum],
[5, 2, iterum],
[10, 3, iterum]
])
})
})
})
7 changes: 0 additions & 7 deletions test/fn/indexOf_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,6 @@ describe('indexOf', function () {
expect(index).to.be.deep.equal(-1)
})

describe('If it exists value that is an iterum instance,', function () {
it('this value is interpreted as a sequence of values of this iterum instance', function () {
const index = new Iterum([0, range(5, 10, 1)]).indexOf(6)
expect(index).to.be.deep.equal(2)
})
})

describe('iterating over iterum instance', function () {
it('does not mutate the behaviour of indexOf', function () {
const elem = 8
Expand Down
21 changes: 0 additions & 21 deletions test/fn/map_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,6 @@ describe('.map', function () {
})
})

describe('If it exists value that is an iterum instance,', function () {
it('this value is interpreted as a sequence of values of this iterum instance', function () {
const values = [...Iterum([0, range(5, 2, 1), 100]).map(function (e) {
return e + 2
})]
expect(values).to.be.deep.equal([2, 102])
})
})

describe('inmutability', function () {
it('map method does not mutate object', function () {
const x = range(8, 3, -1)
Expand Down Expand Up @@ -81,18 +72,6 @@ describe('.map', function () {
})
})

describe('when map returns iterum instance as value,', function () {
describe('this value is converted in a sequence of values that represent the iterum instance', function () {
it('given a iterum range', function () {
const values = [...Iterum([1, 1, 2, 3, 5, 8])
.map(function (e) {
return Iterum([e, 0])
})]
expect(values).to.be.deep.equal([1, 0, 1, 0, 2, 0, 3, 0, 5, 0, 8, 0])
})
})
})

describe('bad arguments', function () {
it('throws an exception when the first argument is not a function', function () {
function foo () {
Expand Down

0 comments on commit 6c243b5

Please sign in to comment.