The simplest way to extend IterableFu
is to use the makeChainableIterable
method to generate your
own version of chainable. You can use your own methods and methods from iterablefu
with makeChainableIterable
.
This section walks through an example that adds a few simple methods to those already provided by iterablefu
.
You can also reduce the number of methods the same way. The README shows a quick example for reducing
bundle size.
Import makeChainableIterable. If you want to use other Iterablefu
methods, import the functional versions of those too: generators, transforms, and reducers.
import { makeChainableIterable, generators, transforms, reducers } from 'iterablefu'
Each generator will appear as a static factory method on your custom class. Your generators can return anything that supports the iterable protocol. Typically, you'll provide generator functions. However, any method that returns an iterable object will work just fine. For example, an ordinary method that returns an Array would work because Array is iterable. Your generators may take any number of parameters, and yield any sort of sequence.
const simpleRange = function * (length) {
for (let i = 0; i < length; i++) {
yield i
}
}
The transform methods will become chainable methods on the chainable iterable class. These functions can return anything that supports the iterable protocol. They do not have to be generator functions. Transform methods can have any number of parameters, but the last one must be the iterable to be transformed.
// This transform method returns an anonymous iterable object just to show
// something different than a generator function.
// The iterable to be transformed must be the last parameter.
const multiply = (n, iterable) => {
return {
* [Symbol.iterator] () {
for (let x of iterable) {
yield n * x
}
}
}
}
// You can implement your method using the functional API methods. Do not use 'this', because
// the generated chainable class methods have a different signature (i.e. no iterable parameter).
// Because map returns an iterable object, byTwo shouldn't be a generator function itself (no asterisk).
const byTwo = function (iterable) {
return transforms.map(x => 2 * x, iterable)
}
Reducer methods become non-chainable methods on the chainable class. Reducer methods can have any number of parameters, but the last one must be the iterable to be reduced. The return value can be anything.
// The last parameter must be the iterable to be reduced
const toSet = function (iterable) {
return new Set(iterable)
}
The makeChainableIterable method requires generators, transforms, and reducers. However, any of those can be empty Objects.
- The generators will have the same method signature as the methods you provide
- The iterable parameter will be removed from the method signatures of the transforms and reducers because the iterable is provided by the chainable class.
// add your methods to the existing ones. In this case, the methods
// are from the examples above.
const customSequences = { ...generators, simpleRange }
const customTransforms = { ...transforms, multiply, byTwo }
const customReducers = { ...reducers, toSet }
const customChainable = makeChainableIterable(customSequences, customTransforms, customReducers)
// Use your new class
const set = customChainable.simpleRange(3).multiply(2).toSet()
Both chainable and ChainableIterable are generated using makeChainableIterable
.
You can extend ChainableIterable
if you wish, but the API for chaining is not public and may change from release to release.
The makeChainableClass
function starts with a super simple class before mixing in the generators, transducers, and reducers.
const Chainable = class {
constructor (iterable) {
this.chainedIterable = iterable
}
* [Symbol.iterator] () {
yield * this.chainedIterable
}
}
Extend the class after calling makeChainableClass
. Then if you want a static factory class do this:
import { makeChainableClass } from 'iterablefu'
import { makeFactory } from '@toolbuilder/make-factory'
const ChainableIterable = makeChainableClass(generators, transforms, reducers)
class Extended extends ChainableIterable {
catch (fn, iterable) {
const doCatch = function * (fn, iterable) {
try { yield * } catch (e) { fn(e) }
}
this.chainedIterable = doCatch(fn, this.chainedIterable)
return this
}
finally (fn, iterable) {
const doFinally = function * (fn, iterable) {
try { yield * iterable } finally { fn() }
}
this.chainedIterable = doFinally(fn, this.chainedIterable)
return this
}
}
const chainable = makeFactory(Extended)
const iterable = chainable([0, 1, 3]).toArray()
Dynamically create a ChainableClass. This differs from makeChainableIterator only in that the class can't be called as a function.
generators
Object Each key is the name of a generator, the value is a generator function.transforms
Object Each key is the name of a transform, the value is a generator function that takes an iterable as the last argument.reducers
Object Each key is the name of a reducer, the value is a function that takes the iterable to reduce as the last argument.
Dynamically create a ChainableIterable class/function.
generators
Object Each key is the name of a generator, the value is a generator function.transforms
Object Each key is the name of a transform, the value is a generator function that takes the iterable to transform as the last argument.reducers
Object Each key is the name of a reducer, the value is a function that takes the iterable to reduce as the last argument.