Skip to content

Commit b0e8d00

Browse files
committed
feat(lang): include callable class object
includes a class object that produces objects that can be called to execute custom functions without additional API methods
1 parent 232c21e commit b0e8d00

File tree

3 files changed

+94
-0
lines changed

3 files changed

+94
-0
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ in a clean and consitent fashion. Nothing more, and nothing less.
4545
* [`slugify`(text: String [, separator: String = '-']): String](#slugifytext-string--separator-string----string)
4646
* [`typecast`(text: String): Object](#typecasttext-string-object)
4747
* [`typeOf`(element: `any`): String](#typeofelement-any-string)
48+
* [`Callable`: Class](#callable-class)
4849
* [Authors](#authors)
4950
* [Contributors ✨](#contributors-)
5051

@@ -376,6 +377,32 @@ typeOf(() => {}) // function
376377
typeOf(new Set()) // set
377378
```
378379

380+
### `Callable`: [Class][]
381+
382+
A class object whose instances are derived from [Function][] and can be called.
383+
When exteded, a [Symbol][] function defined by `Symbol.for('call')` will be executed
384+
with any arguments that were passed
385+
386+
##### Example
387+
388+
```javascript
389+
const {Callable} = require('@logdna/stdlib')
390+
const __call__ = Symbol.for('call')
391+
class Hello extends Callable {
392+
constructor(opts) {
393+
this.yell = !!opts.yell
394+
}
395+
[__call__](name) {
396+
const output = `Hello, ${name}`
397+
console.log(this.yell ? `${output.toUpperCase()}!` : output)
398+
}
399+
}
400+
401+
const screamAt = new Hello({yell: true})
402+
403+
screamAt('bill') // HELLO, BILL!
404+
```
405+
379406
## Authors
380407

381408
* [**Eric Satterwhite**](mailto:eric.satterwhite@logdna.com) <eric.satterwhite@logdna.com>
@@ -388,6 +415,8 @@ typeOf(new Set()) // set
388415
[Number]: https://mdn.io/number
389416
[Object]: https://mdn.io/object
390417
[Function]: https://mdn.io/function
418+
[Class]: https://mdn.io/class
419+
[Symbol]: https://mdn.io/symbol
391420
[Generator]: https://mdn.io/generator
392421
[itertools]: https://docs.python.org/3.7/library/itertools.html
393422

lib/callable.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
'use strict'
2+
/**
3+
* @module lib/callable
4+
* @author Eric Satterwhite
5+
**/
6+
7+
/**
8+
* A class object whose instances are also callable
9+
* To define a callable object, extend this class and gif it a symbol function
10+
* using Symbol.for("call")
11+
* @constructor
12+
* @alias module:lib/callable
13+
* @extends Function
14+
* @example
15+
* class Message extends Callable {
16+
* constructor(name) {
17+
* super()
18+
* this.name = name
19+
* }
20+
*
21+
* [__call__]() {
22+
* return `Hello ${this.name}`
23+
* }
24+
* }
25+
*
26+
* const bob = new Message('bob')
27+
* bob.name // bob
28+
* bob() // Hello bob
29+
**/
30+
class Callable extends Function {
31+
get [Symbol.toStringTag]() {
32+
return 'Callable'
33+
}
34+
35+
constructor() {
36+
super('...args', 'return this._bound[Symbol.for("call")](...args)')
37+
this._bound = this.bind(this)
38+
return this._bound
39+
}
40+
}
41+
42+
module.exports = Callable

test/unit/callable.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict'
2+
3+
const {test, threw} = require('tap')
4+
const typeOf = require('../../lib/type-of.js')
5+
const Callable = require('../../lib/callable.js')
6+
7+
test('callable', async (t) => {
8+
t.test('string representation', async (t) => {
9+
t.equal(typeOf(new Callable()), 'callable', 'identifies as callable')
10+
})
11+
12+
t.test('extensbility', async (t) => {
13+
const __call__ = Symbol.for('call')
14+
class Sum extends Callable {
15+
[__call__](a, b = 1) {
16+
return a + b
17+
}
18+
}
19+
20+
const sum = new Sum()
21+
t.equal(sum(10, 3), 13, 'call function executed')
22+
})
23+
}).catch(threw)

0 commit comments

Comments
 (0)