Skip to content

Commit

Permalink
feat: Take now can return a sync iterator
Browse files Browse the repository at this point in the history
Bonus: removed the example from the readme, wasn’t better than our api examples
  • Loading branch information
reconbot committed Feb 21, 2019
1 parent c2709d3 commit 02c04cc
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 61 deletions.
52 changes: 4 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# streaming-iterables 🏄‍♂️

[![Build Status](https://travis-ci.org/reconbot/streaming-iterables.svg?branch=master)](https://travis-ci.org/reconbot/streaming-iterables) [![Try streaming-iterables on RunKit](https://badge.runkitcdn.com/streaming-iterables.svg)](https://npm.runkit.com/streaming-iterables) [![install size](https://packagephobia.now.sh/badge?p=streaming-iterables)](https://packagephobia.now.sh/result?p=streaming-iterables)
[![Build Status](https://travis-ci.org/bustle/streaming-iterables.svg?branch=master)](https://travis-ci.org/bustle/streaming-iterables) [![Try streaming-iterables on RunKit](https://badge.runkitcdn.com/streaming-iterables.svg)](https://npm.runkit.com/streaming-iterables) [![install size](https://packagephobia.now.sh/badge?p=streaming-iterables)](https://packagephobia.now.sh/result?p=streaming-iterables)

A Swiss army knife for [async iterables](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of). Designed to help replace your streams. These utilities have a comparable speed, friendlier error handling, and are easier to understand than most stream based workloads.

Expand All @@ -15,50 +15,6 @@ There are no dependencies.
npm install streaming-iterables
```

## Example

Download a bunch of pokemon ([try it here!](https://npm.runkit.com/streaming-iterables))

```ts
const { buffer, flatten, pipeline, transform } = require('streaming-iterables')
const got = require('got')

// A generator to fetch all the pokemon from the pokemon api
const pokedex = async function* () {
let offset = 0
while(true) {
const url = `https://pokeapi.co/api/v2/pokemon/?offset=${offset}`
const { body: { results: pokemon } } = await got(url, { json: true })
if (pokemon.length === 0) {
return
}
offset += pokemon.length
yield pokemon
}
}

// lets buffer two pages so they're ready when we want them
const bufferTwo = buffer(2)

// a transform iterator that will load the monsters two at a time and yield them as soon as they're ready
const pokeLoader = transform(2, async ({ url }) => {
const { body } = await got(url, { json: true })
return body
})

// string together all our functions
const pokePipe = pipeline(pokedex, bufferTwo, flatten, pokeLoader)

// lets do it team!
const run = async () => {
for await (const pokemon of pokePipe){
console.log(`${pokemon.name} ${pokemon.sprites.front_default}`)
}
}

run().then(() => console.log('caught them all!'))
```

## Overview
Every function is curryable, you can call it with any number of arguments. For example:

Expand Down Expand Up @@ -473,10 +429,10 @@ Reduces an iterable to a value which is the accumulated result of running each v

### take
```ts
function take<T>(count: number, iterable: AnyIterable<T>): AsyncIterableIterator<T>
function take<T>(count: number, iterable: AsyncIterable<T>): AsyncIterableIterator<T>
function take<T>(count: number, iterable: Iterable<T>): IterableIterator<T>
```

Returns a new iterator that reads a specific number of items from `iterable`. When used with generators it advances the generator, when used with arrays it always starts from the beginning.
Returns a new iterator that reads a specific number of items from `iterable`. When used with generators it advances the generator, when used with arrays it gets a new iterator and starts from the beginning.

### tap
```ts
Expand Down
12 changes: 6 additions & 6 deletions lib/take-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,24 @@ describe('take', () => {
}
assert.deepEqual(values, [1, 2])
})
it('Returns the first n elements of the given sync iterable', async () => {
it('Returns the first n elements of the given sync iterable', () => {
const values: number[] = []
for await (const val of take(2, [1, 2, 3])) {
for (const val of take(2, [1, 2, 3])) {
values.push(val)
}
assert.deepEqual(values, [1, 2])
})
it('lets you ask for more', async () => {
it('lets you ask for more', () => {
const values: number[] = []
for await (const val of take(99, [1, 2, 3])) {
for (const val of take(99, [1, 2, 3])) {
values.push(val)
}
assert.deepEqual(values, [1, 2, 3])
})
it('lets you curry the count', async () => {
it('lets you curry the count', () => {
const values: any[] = []
const take1 = take(1)
for await (const val of take1([1, 2, 3])) {
for (const val of take1([1, 2, 3])) {
values.push(val)
}
assert.deepEqual(values, [1])
Expand Down
35 changes: 28 additions & 7 deletions lib/take.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
import { AnyIterable } from './types'

async function* _take<T>(count: number, iterable: AnyIterable<T>) {
async function* _take<T>(count: number, iterable: AsyncIterable<T>) {
let taken = 0
for await (const val of iterable as AsyncIterable<T>) {
for await (const val of iterable) {
yield await val
taken++
if (taken >= count) {
return
}
}
}
export function take<T>(count: number): (iterable: AnyIterable<T>) => AsyncIterableIterator<T>
export function take<T>(count: number, iterable: AnyIterable<T>): AsyncIterableIterator<T>
export function take(count, iterable?) {

function* _syncTake<T>(count: number, iterable: Iterable<T>) {
let taken = 0
for (const val of iterable) {
yield val
taken++
if (taken >= count) {
return
}
}
}

export function take<T>(
count: number
): {
(curriedIterable: AsyncIterable<T>): AsyncIterableIterator<T>
(curriedIterable: Iterable<T>): IterableIterator<T>
}
export function take<T>(count: number, iterable: AsyncIterable<T>): AsyncIterableIterator<T>
export function take<T>(count: number, iterable: Iterable<T>): IterableIterator<T>
export function take<T>(count: number, iterable?: AnyIterable<T>) {
if (iterable === undefined) {
return curriedIterable => _take(count, curriedIterable)
return curriedIterable => take(count, curriedIterable)
}
if (iterable[Symbol.asyncIterator]) {
return _take(count, iterable as AsyncIterable<T>)
}
return _take(count, iterable)
return _syncTake(count, iterable as Iterable<T>)
}

0 comments on commit 02c04cc

Please sign in to comment.