monocle-decorators
Version:
385 lines (282 loc) • 8.05 kB
Markdown
<img src="http://rawgit.com/caiogondim/monocle-decorators.js/master/logo/banner.svg">
<h1>monocle-decorators</h1>
<div>
<img src="https://travis-ci.com/caiogondim/monocle-decorators.js.svg?token=rC867oquXMnLzSZmNcfx&branch=master" alt="Travis CI"> <img src="http://img.badgesize.io/caiogondim/monocle-decorators.js/master/dist/monocle-decorators.js?compression=gzip" alt="File size"> <img src="https://coveralls.io/repos/github/caiogondim/monocle-decorators.js/badge.svg?branch=master" alt="Code coverage"> <a href="https://www.npmjs.com/package/monocle-decorators"><img src="https://img.shields.io/npm/v/monocle-decorators.svg" /></a>
</div>
<br>
Tiny library with most common/useful decorators. Think of it as
[underscore.js](http://underscorejs.org/), but with class.
## Table of contents
- **Decorators for classes**
- [freeze](#_ofreeze)
- [mixin](#_omixin)
- [seal](#_oseal)
- **Decorators for instance methods/properties**
- [bind](#_obind)
- [debounce](#_odebounce)
- [throttle](#_othrottle)
- [deprecate](#_odeprecate)
## Installation
```bash
npm install monocle-decorators --save
```
## Decorators for classes
### `.mixin`
Extends decorated class with all enumerable properties from `ArrayOfMixins`
passed as argument.
> 💡 **Tip**
>
> Prefer composability over inheritance.
#### As decorator `.mixin(ArrayOfMixins)`
```js
import _o from 'monocle-decorators'
class Walkable {
walk() {
const speed = 5
this.distanceFromOrigin += speed
}
}
class Runnable {
run() {
const speed = 10
this.distanceFromOrigin += speed
}
}
.mixin([Walkable, Runnable])
class Thing {
constructor() {
this.distanceFromOrigin = 0
}
}
const foo = new Thing()
foo.walk() // method from Walkable class
foo.run() // method from Runnable class
foo.distanceFromOrigin // => 15
```
> 💡 **Tip**
>
> Array of mixins can also be an array of objects, if you don't feel classy.
```js
import _o from 'monocle-decorators'
const walkable = {
walk() {
const speed = 5
this.distanceFromOrigin += speed
}
}
const runnable = {
run() {
const speed = 10
this.distanceFromOrigin += speed
}
}
.mixin([walkable, runnable])
class Thing {
constructor() {
this.distanceFromOrigin = 0
}
}
const foo = new Thing()
foo.walk() // method from Walkable class
foo.run() // method from Runnable class
foo.distanceFromOrigin // => 15
```
#### As function `_o.mixin(TargetClass, ArrayOfMixins)`
```js
import _o from 'monocle-decorators'
_o.mixin(Thing, [Walkable, Runnable])
const foo = new Thing()
foo.walk() // method from Walkable class
foo.run() // method from Runnable class
foo.distanceFromOrigin // => 15
```
### `.freeze`
Freezes every new instance of decorated class.
<!-- Text originally from MDN -->
A frozen object prevents:
- new properties from being added to it
- existing properties from being removed
- existing properties, or their enumerability, configurability, or
writability, from being changed
> 💡 **Tip**
>
> `.seal` and `.freeze` makes it easier to work with objects, since you
> have to declare beforehand all properties and methods an object has and will
> have in it's lifecycle, concentrating in one single place the definition of
> the object structure.
#### As decorator `.freeze`
```js
import _o from 'monocle-decorators'
.freeze
class Dummy {
constructor() {
this.a = 1
this.b = 2
}
}
const foo = new Dummy()
foo.c = 3 // throws Error
```
#### As function `_o.freeze(TargetClass)`
```js
import _o from 'monocle-decorators'
const DummyFrozen = _o.freeze(Dummy)
const foo = new DummyFrozen()
foo.c = 3 // throws Error
```
### `.seal`
Seals every new instance of decorated class.
<!-- Text originally from MDN -->
A sealed object prevents:
- new properties from being added to it
- marking all existing properties as non-configurable
Values of present properties can still be changed as long as they are writable.
> 💡 **Tip**
>
> `.seal` and `.freeze` makes it easier to work with objects, since you
> have to declare beforehand all properties and methods an object has and will
> have in it's lifecycle, concentrating in one single place the definition of
> the object structure.
#### As decorator `.seal`
```js
import _o from 'monocle-decorators'
.seal
class Dummy {
constructor() {
this.a = 1
this.b = 2
}
}
const foo = new Dummy()
foo.c = 3 // throws Error
```
#### As function `_o.freeze(TargetClass)`
```js
import _o from 'monocle-decorators'
const DummySealed = _o.seal(Dummy)
foo.c = 3 // throws Error
```
## Decorators for instance methods/properties
### `.bind`
Autobind the decorated method to it's owner, so `this` will always refer to the
object that owns the method.
> 💡 **Tip**
>
> This decorator avoids the verbose `<button onClick={this.handleClick.bind(this)}></button>` idiom,
> using only `<button onClick={this.handleClick}></button>`.
#### As decorator `.bind`
```js
import _o from 'monocle-decorators'
class Dummy {
.bind
handleClick() {
// ...
}
render() {
return (
<div onClick={this.handleClick}>Lorem ipsum</div>
)
}
}
```
#### As function `_o.bind(targetMethod, context)`
```js
import _o from 'monocle-decorators'
const obj = {
handleClick() {
// ...
}
}
_o.bind(obj.handleClick, obj)
element.addEventListener('click', obj.handleClick)
```
### `.debounce`
<!-- Text originally from underscore.js -->
Debounces decorated method, which will postpone its execution until after
`wait` milliseconds have elapsed since the last time it was invoked.
> 💡 **Tip**
>
> Useful for implementing behavior that should only happen after the input has
> stopped arriving. For example: rendering a preview of a Markdown comment,
> recalculating a layout after the window has stopped being resized, and so on.
#### As decorator `.debounce(wait)`
```js
import _o from 'monocle-decorators'
class Dummy {
.debounce(150)
onScroll() {
// ...
}
}
```
#### As function `_o.debounce(targetMethod, wait)`
```js
import _o from 'monocle-decorators'
const onScroll = _o.debounce(() => {
// ...
}, 150)
```
### `.throttle`
<!-- Text originally from underscore.js -->
Throttles decorated method, that, when invoked repeatedly, will only actually
call the original function at most once per every `wait` milliseconds.
> 💡 **Tip**
>
> Useful for rate-limiting events that occur faster than you can keep up with.
#### As decorator `.throttle(wait)`
```js
import _o from 'monocle-decorators'
class Dummy {
.throttle(150)
onScroll() {
// ...
}
}
```
> 💡 **Tip**
>
> To have the same behavior as a hypothetical `.once`,
> use `.throttle(Infinity)`.
#### As function `_o.throttle(targetMethod, wait)`
```js
import _o from 'monocle-decorators'
const onScroll = _o.throttle(() => {
// ...
}, 150)
```
### `.deprecate`
Calls `opts.logger` with `msg` as depreciation message.
By default `opts.logger` is `console.warn` and `msg` is `${target.constructor.name}.${key} is deprecated.`. Both are optional.
#### As decorator `.deprecate(msg, { logger })`
```js
import _o from 'monocle-decorators'
class Dummy {
a() {
// ...
}
.deprecate('`dummy.b` is deprecated. Use `dummy.a`')
b() {
// ...
}
}
```
#### As function `_o.deprecate(target, key, msg, { logger })`
```js
import _o from 'monocle-decorators'
const dummy = _o.deprecate({
a() {},
b() {}
}, 'b', '`dummy.b` is deprecated. Use `dummy.a`')
```
### Why monocle?
Because you import it as `_o` and use it as ``.
Classy decorators.
## Reference
- Icon by Ben Iconator from The Noun Prokect
## Sponsor
If you found this library useful and are willing to donate, consider
transferring some bitcoins to `1BqqKiZA8Tq43CdukdBEwCdDD42jxuX9UY`.
---
[caiogondim.com](https://caiogondim.com) ·
GitHub [](https://github.com/caiogondim) ·
Twitter [](https://twitter.com/caio_gondim)