rubico 2.6.2 → 2.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  ![rubico](https://raw.githubusercontent.com/a-synchronous/assets/master/rubico-logo.png)
3
3
  > a shallow river in northeastern Italy, just south of Ravenna
4
4
 
5
- ![Node.js CI](https://github.com/a-synchronous/rubico/workflows/Node.js%20CI/badge.svg?branch=master)
5
+ ![Node.js CI](https://github.com/a-synchronous/rubico/workflows/Node.js%20CI/badge.svg)
6
6
  [![codecov](https://codecov.io/gh/a-synchronous/rubico/branch/master/graph/badge.svg)](https://codecov.io/gh/a-synchronous/rubico)
7
7
  [![npm version](https://img.shields.io/npm/v/rubico.svg?style=flat)](https://www.npmjs.com/package/rubico)
8
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
@@ -26,7 +26,7 @@ pipe(numbers, [
26
26
  ```
27
27
 
28
28
  # Installation
29
- [Core build](https://unpkg.com/rubico/index.js) ([~6.8 kB minified and gzipped](https://unpkg.com/rubico/dist/rubico.min.js))
29
+ [Core build](https://unpkg.com/rubico/index.js) ([~9.8 kB minified and gzipped](https://unpkg.com/rubico/dist/rubico.min.js))
30
30
 
31
31
  with `npm`
32
32
  ```bash
@@ -86,15 +86,12 @@ When you import this library, you obtain the freedom that comes from having thos
86
86
 
87
87
  # Introduction
88
88
 
89
- rubico is a library for async-enabled functional programming in JavaScript. The library methods support a simple and composable functional style in asynchronous environments.
89
+ rubico is a library for async-enabled functional programming in JavaScript. The library supports a simple and composable functional style in asynchronous environments.
90
90
 
91
91
  ```javascript
92
92
  const {
93
93
  // compose functions
94
- pipe, compose,
95
-
96
- // handle effects
97
- tap, forEach,
94
+ pipe, compose, tap,
98
95
 
99
96
  // control flow
100
97
  switchCase,
@@ -102,9 +99,12 @@ const {
102
99
  // handle errors
103
100
  tryCatch,
104
101
 
105
- // handle objects
102
+ // compose data
106
103
  all, assign, get, set, pick, omit,
107
104
 
105
+ // iterate
106
+ forEach,
107
+
108
108
  // transform data
109
109
  map, filter, reduce, transform, flatMap,
110
110
 
@@ -119,7 +119,7 @@ const {
119
119
  } = rubico
120
120
  ```
121
121
 
122
- With async-enabled, or [a]synchronous, functional programming, functions provided to the rubico methods may be asynchronous and return a Promise. Any promises in argument position are also resolved before continuing with the operation.
122
+ With async-enabled, or [a]synchronous, functional programming, functions provided to the rubico operators may be asynchronous and return a Promise. Any promises in argument position are also resolved before continuing with the operation.
123
123
 
124
124
  ```javascript [playground]
125
125
  const helloPromise = Promise.resolve('hello')
@@ -133,7 +133,7 @@ pipe(helloPromise, [ // helloPromise is resolved for 'hello'
133
133
  ])
134
134
  ```
135
135
 
136
- Most methods support both an eager and a lazy API. The eager API takes all required arguments and executes at once, while its lazy API takes only the non-data arguments and executes lazily, returning a function that expects the data arguments. This dual API supports a natural and composable code style.
136
+ All rubico operators support both an eager and a lazy API. The eager API takes all required arguments and executes at once, while its lazy API takes only the non-data arguments and executes lazily, returning a function that expects the data arguments. This dual API supports a natural and composable code style.
137
137
 
138
138
  ```javascript [playground]
139
139
  const myObj = { a: 1, b: 2, c: 3 }
@@ -150,7 +150,7 @@ console.log(myDuplicatedSquaredObject)
150
150
  // { a: [1, 1], b: [4, 4], c: [9, 9] }
151
151
  ```
152
152
 
153
- The rubico methods are versatile and act on a wide range of vanilla JavaScript types to create declarative, extensible, and async-enabled function compositions. The same operator `map` can act on an array and also a `Map` data structure.
153
+ The rubico operators are versatile and act on a wide range of vanilla JavaScript types to create declarative, extensible, and async-enabled function compositions. The same operator `map` can act on an array and also a `Map` data structure.
154
154
 
155
155
  ```javascript [playground]
156
156
  const { pipe, tap, map, filter } = rubico
@@ -203,7 +203,7 @@ pipe(todoIDs, [
203
203
  ])
204
204
  ```
205
205
 
206
- rubico offers transducers in its `Transducer` module. You can consume these transducers with the `transform` and `compose` methods. You should use `compose` over `pipe` to chain a left-to-right composition of transducers.
206
+ rubico offers transducers in its `Transducer` module. You can consume these transducers with the `transform` and `compose` operators. You should use `compose` over `pipe` to chain a left-to-right composition of transducers.
207
207
 
208
208
  ```javascript [playground]
209
209
  const isOdd = number => number % 2 == 1
@@ -227,12 +227,12 @@ pipe(generateNumbers(), [
227
227
  ])
228
228
  ```
229
229
 
230
- For advanced asynchronous use cases, some of the methods have property functions that have different asynchronous behavior, e.g.
230
+ For advanced asynchronous use cases, some of the operators have property functions that have different asynchronous behavior, e.g.
231
231
  * `map` - apply a mapper function concurrently
232
232
  * `map.pool` - apply a mapper function concurrently with a concurrency limit
233
233
  * `map.series` - apply a mapper function serially
234
234
 
235
- For more functions beyond the core methods, please visit `rubico/x`. You can find the full documentation at [rubico.land/docs](https://rubico.land/docs).
235
+ For more functions beyond the core operators, please visit `rubico/x`. You can find the full documentation at [rubico.land/docs](https://rubico.land/docs).
236
236
 
237
237
  # Benchmarks
238
238
  Please find the published benchmark output inside the [benchmark-output](https://github.com/a-synchronous/rubico/tree/master/benchmark-output) folder. You can run the benchmarks on your own system with the following command:
@@ -251,7 +251,7 @@ For more information please see [CONTRIBUTING.md](/CONTRIBUTING.md)
251
251
  rubico is [MIT Licensed](https://github.com/a-synchronous/rubico/blob/master/LICENSE).
252
252
 
253
253
  # Support
254
- * minimum Node.js version: 12
254
+ * minimum Node.js version: 16
255
255
  * minimum Chrome version: 63
256
256
  * minimum Firefox version: 57
257
257
  * minimum Edge version: 79
@@ -48,7 +48,7 @@ const arrayMapPoolAsync = async function (
48
48
  *
49
49
  * @synopsis
50
50
  * ```coffeescript [specscript]
51
- * arrayMapPool(array Array, concurrency number, f function) -> Promise|string
51
+ * arrayMapPool(array Array, concurrency number, f function) -> Promise|array
52
52
  * ```
53
53
  *
54
54
  * @description
@@ -0,0 +1,85 @@
1
+ const curry3 = require('./curry3')
2
+ const __ = require('./placeholder')
3
+ const isPromise = require('./isPromise')
4
+ const promiseAll = require('./promiseAll')
5
+ const sleep = require('./sleep')
6
+
7
+ /**
8
+ * @name arrayMapRate
9
+ *
10
+ * @synopsis
11
+ * ```coffeescript [specscript]
12
+ * arrayMapRate(
13
+ * array Array,
14
+ * rate number,
15
+ * f function,
16
+ * ) -> Promise<Array>
17
+ * ```
18
+ */
19
+ const arrayMapRate = async function (array, rate, f) {
20
+ const length = array.length
21
+ const result = Array(length)
22
+ const minPeriodMs = 1 / rate * 1000
23
+ let index = -1
24
+ let lastExecutionTime = 0
25
+ const totalStart = performance.now()
26
+ while (++index < length) {
27
+ if (index > 0 && lastExecutionTime < minPeriodMs) {
28
+ await sleep(minPeriodMs - lastExecutionTime)
29
+ }
30
+ const start = performance.now()
31
+ let resultItem = f(array[index], index, array)
32
+ if (isPromise(resultItem)) {
33
+ resultItem = await resultItem
34
+ }
35
+ const end = performance.now()
36
+ const executionTime = end - start
37
+ lastExecutionTime = executionTime
38
+ result[index] = resultItem
39
+ }
40
+ const totalEnd = performance.now()
41
+ return result
42
+ }
43
+
44
+ /**
45
+ * @name range
46
+ *
47
+ * @synopsis
48
+ * ```coffeescript [specscript]
49
+ * range(lower number, upper number) -> numbers Array<number>
50
+ * ```
51
+ */
52
+ const range = function (lower, upper) {
53
+ const result = []
54
+ let start = lower
55
+ while (start <= upper) {
56
+ result.push(start)
57
+ start += 1
58
+ }
59
+ return result
60
+ }
61
+
62
+ /*
63
+ const start = performance.now()
64
+ arrayMapRate(
65
+ range(0, 10),
66
+ 2,
67
+ async n => {
68
+ const duration = Math.random() * 1000
69
+ console.log('duration', duration)
70
+ // const duration = 500
71
+ await sleep(duration)
72
+ return n ** 2
73
+ }
74
+ async n => {
75
+ console.log('n', n)
76
+ return n ** 2
77
+ },
78
+ ).then(result => {
79
+ const end = performance.now()
80
+ console.log('average period:', (end - start) / result.length)
81
+ console.log(result)
82
+ })
83
+ */
84
+
85
+ module.exports = arrayMapRate
package/all.js CHANGED
@@ -113,12 +113,22 @@ const _allValues = function (values) {
113
113
  * getAndLogUserById('1') // Got user {"_id":1,"name":"George"} by id 1
114
114
  * ```
115
115
  *
116
- * Values passed in resolver position are set on the result object or array directly. If any of these values are promises, they are resolved for their values before being set on the result object or array.
116
+ * Values may be provided along with functions, in which case they are set on the result object or array directly. If any of these values are promises, they are resolved for their values before being set on the result object or array.
117
117
  *
118
118
  * ```javascript [playground]
119
- * all({}, [
119
+ * all({}, {
120
+ * a: Promise.resolve(1),
121
+ * b: 2,
122
+ * c: () => 3,
123
+ * d: async () => 4,
124
+ * }).then(console.log) // { a: 1, b: 2, c: 3, d: 4 }
125
+ *
126
+ * all([], [
120
127
  * Promise.resolve(1),
121
- * ])
128
+ * 2,
129
+ * () => 3,
130
+ * async () => 4,
131
+ * ]).then(console.log) // [1, 2, 3, 4]
122
132
  * ```
123
133
  *
124
134
  * Any promises passed in argument position are resolved for their values before further execution. This only applies to the eager version of the API.
@@ -161,26 +171,6 @@ const all = function (...args) {
161
171
  return isArray(resolversOrValues)
162
172
  ? functionArrayAll(resolversOrValues, argValues)
163
173
  : functionObjectAll(resolversOrValues, argValues)
164
-
165
- /*
166
- ////////////////////////////////////////////////////////////////
167
- const funcs = args.pop()
168
- if (args.length == 0) {
169
- return isArray(funcs)
170
- ? curryArgs2(functionArrayAll, funcs, __)
171
- : curryArgs2(functionObjectAll, funcs, __)
172
- }
173
-
174
- if (areAnyValuesPromises(args)) {
175
- return isArray(funcs)
176
- ? promiseAll(args).then(curry2(functionArrayAll, funcs, __))
177
- : promiseAll(args).then(curry2(functionObjectAll, funcs, __))
178
- }
179
-
180
- return isArray(funcs)
181
- ? functionArrayAll(funcs, args)
182
- : functionObjectAll(funcs, args)
183
- */
184
174
  }
185
175
 
186
176
  /**
package/map.js CHANGED
@@ -53,39 +53,39 @@ const symbolAsyncIterator = require('./_internal/symbolAsyncIterator')
53
53
  * ```
54
54
  */
55
55
 
56
- const _map = function (value, mapper) {
56
+ const _map = function (value, f) {
57
57
  if (isArray(value)) {
58
- return arrayMap(value, mapper)
58
+ return arrayMap(value, f)
59
59
  }
60
60
  if (value == null) {
61
61
  return value
62
62
  }
63
63
 
64
64
  if (typeof value.then == 'function') {
65
- return value.then(mapper)
65
+ return value.then(f)
66
66
  }
67
67
  if (typeof value.map == 'function') {
68
- return value.map(mapper)
68
+ return value.map(f)
69
69
  }
70
70
  if (typeof value == 'string' || value.constructor == String) {
71
- return stringMap(value, mapper)
71
+ return stringMap(value, f)
72
72
  }
73
73
  if (value.constructor == Set) {
74
- return setMap(value, mapper)
74
+ return setMap(value, f)
75
75
  }
76
76
  if (value.constructor == Map) {
77
- return mapMap(value, mapper)
77
+ return mapMap(value, f)
78
78
  }
79
79
  if (typeof value[symbolIterator] == 'function') {
80
- return MappingIterator(value[symbolIterator](), mapper)
80
+ return MappingIterator(value[symbolIterator](), f)
81
81
  }
82
82
  if (typeof value[symbolAsyncIterator] == 'function') {
83
- return MappingAsyncIterator(value[symbolAsyncIterator](), mapper)
83
+ return MappingAsyncIterator(value[symbolAsyncIterator](), f)
84
84
  }
85
85
  if (value.constructor == Object) {
86
- return objectMap(value, mapper)
86
+ return objectMap(value, f)
87
87
  }
88
- return mapper(value)
88
+ return f(value)
89
89
  }
90
90
 
91
91
  /**
@@ -106,7 +106,7 @@ const _map = function (value, mapper) {
106
106
  * ```
107
107
  *
108
108
  * @description
109
- * Applies a synchronous or asynchronous mapper function concurrently to each item of a collection, returning the results in a new collection of the same type. If order is implied by the collection, it is maintained in the result. `map` accepts the following collections:
109
+ * Applies a synchronous or asynchronous mapper function `f` concurrently to each item of a collection, returning the results in a new collection of the same type. If order is implied by the collection, it is maintained in the result. `map` accepts the following collections:
110
110
  *
111
111
  * * `Array`
112
112
  * * `Object`
@@ -115,7 +115,7 @@ const _map = function (value, mapper) {
115
115
  * * `Iterator`/`Generator`
116
116
  * * `AsyncIterator`/`AsyncGenerator`
117
117
  *
118
- * With arrays (type `Array`), `map` applies the mapper function to each item of the array, returning the transformed results in a new array ordered the same as the original array.
118
+ * With arrays (type `Array`), `map` applies the mapper function `f` to each item of the array, returning the transformed results in a new array ordered the same as the original array.
119
119
  *
120
120
  * ```javascript [playground]
121
121
  * const square = number => number ** 2
@@ -131,7 +131,7 @@ const _map = function (value, mapper) {
131
131
  * ) // [1, 4, 9, 16, 25]
132
132
  * ```
133
133
  *
134
- * With objects (type `Object`), `map` applies the mapper function to each value of the object, returning the transformed results as values in a new object ordered by the keys of the original object
134
+ * With objects (type `Object`), `map` applies the mapper function `f` to each value of the object, returning the transformed results as values in a new object ordered by the keys of the original object
135
135
  *
136
136
  * ```javascript [playground]
137
137
  * const square = number => number ** 2
@@ -147,7 +147,7 @@ const _map = function (value, mapper) {
147
147
  * ) // { a: 1, b: 4, c: 9, d: 16, e: 25 }
148
148
  * ```
149
149
  *
150
- * With sets (type `Set`), `map` applies the mapper function to each value of the set, returning the transformed results unordered in a new set.
150
+ * With sets (type `Set`), `map` applies the mapper function `f` to each value of the set, returning the transformed results unordered in a new set.
151
151
  *
152
152
  * ```javascript [playground]
153
153
  * const square = number => number ** 2
@@ -163,7 +163,7 @@ const _map = function (value, mapper) {
163
163
  * ) // [1, 4, 9, 16, 25]
164
164
  * ```
165
165
  *
166
- * With maps (type `Map`), `map` applies the mapper function to each value of the map, returning the results at the same keys in a new map. The entries of the resulting map are in the same order as those of the original map
166
+ * With maps (type `Map`), `map` applies the mapper function `f` to each value of the map, returning the results at the same keys in a new map. The entries of the resulting map are in the same order as those of the original map
167
167
  *
168
168
  * ```javascript [playground]
169
169
  * const square = number => number ** 2
@@ -179,7 +179,7 @@ const _map = function (value, mapper) {
179
179
  * ) // Map { 'a' => 1, 'b' => 4, 'c' => 9, 'd' => 16, 'e' => 25 }
180
180
  * ```
181
181
  *
182
- * With iterators (type `Iterator`) or generators (type `Generator`), `map` applies the mapper function lazily to each value of the iterator/generator, creating a new iterator with transformed iterations.
182
+ * With iterators (type `Iterator`) or generators (type `Generator`), `map` applies the mapper function `f` lazily to each value of the iterator/generator, creating a new iterator with transformed iterations.
183
183
  *
184
184
  * ```javascript [playground]
185
185
  * const capitalize = string => string.toUpperCase()
@@ -199,7 +199,7 @@ const _map = function (value, mapper) {
199
199
  * console.log([...ABCGenerator2]) // ['A', 'B', 'C']
200
200
  * ```
201
201
  *
202
- * With asyncIterators (type `AsyncIterator`, or `AsyncGenerator`), `map` applies the mapper function lazily to each value of the asyncIterator, creating a new asyncIterator with transformed iterations
202
+ * With asyncIterators (type `AsyncIterator`, or `AsyncGenerator`), `map` applies the mapper function `f` lazily to each value of the asyncIterator, creating a new asyncIterator with transformed iterations
203
203
  *
204
204
  * ```javascript [playground]
205
205
  * const capitalize = string => string.toUpperCase()
@@ -258,16 +258,16 @@ const map = function (arg0, arg1) {
258
258
  : _map(arg0, arg1)
259
259
  }
260
260
 
261
- // _mapEntries(value Object|Map, mapper function) -> Object|Map
262
- const _mapEntries = (value, mapper) => {
261
+ // _mapEntries(value Object|Map, f function) -> Object|Map
262
+ const _mapEntries = (value, f) => {
263
263
  if (value == null) {
264
264
  throw new TypeError('value is not an Object or Map')
265
265
  }
266
266
  if (value.constructor == Object) {
267
- return objectMapEntries(value, mapper)
267
+ return objectMapEntries(value, f)
268
268
  }
269
269
  if (value.constructor == Map) {
270
- return mapMapEntries(value, mapper)
270
+ return mapMapEntries(value, f)
271
271
  }
272
272
  throw new TypeError('value is not an Object or Map')
273
273
  }
@@ -285,10 +285,10 @@ const _mapEntries = (value, mapper) => {
285
285
  * collection EntriesMappable
286
286
  * )=>(resultItem Promise|any)
287
287
  *
288
- * map.entries(value Promise|EntriesMappable, mapper Mapper)
288
+ * map.entries(value Promise|EntriesMappable, f Mapper)
289
289
  * -> Promise|EntriesMappable
290
290
  *
291
- * map.entries(mapper Mapper)(value EntriesMappable)
291
+ * map.entries(f Mapper)(value EntriesMappable)
292
292
  * -> Promise|EntriesMappable
293
293
  * ```
294
294
  *
@@ -512,4 +512,24 @@ map.pool = function mapPool(arg0, arg1, arg2) {
512
512
  : _mapPool(arg0, arg1, arg2)
513
513
  }
514
514
 
515
+ /**
516
+ * @name map.rate
517
+ *
518
+ * @synopsis
519
+ * ```coffeescript [specscript]
520
+ * type Mappable = Array|Object|Set|Map
521
+ *
522
+ * map.rate(
523
+ * rate number,
524
+ * f (value any)=>Promise|any,
525
+ * )(collection Mappable) -> result Promise|Array
526
+ *
527
+ * map.rate(
528
+ * collection Mappable,
529
+ * rate number,
530
+ * f (value any)=>Promise|any,
531
+ * ) -> result Promise|Array
532
+ * ```
533
+ */
534
+
515
535
  module.exports = map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rubico",
3
- "version": "2.6.2",
3
+ "version": "2.6.4",
4
4
  "description": "[a]synchronous functional programming",
5
5
  "author": "Richard Tong",
6
6
  "license": "MIT",