Ruby on Rails の delegate
メソッド的なインターフェースで、他オブジェクトに処理を以上するためのライブラリを作ってみた。
使い方
import { delegate, $delegate } from 'relegater';
const baseObj = {
a: 1, b: 'b'
};
const delegated = {
c: () => 'c',
d: {
e: true
}
};
// delegate()は baseObj を拡張した新しいオブジェクトを新たに生成する。
// 基となった baseObj は一切更新されない。
var result = delegate(baseObj).to(delegated, 'c', 'd').self;
result.a // 1
result.b // 'b'
result.c() // 'c'
result.d.e // true
baseObj.a // 1
baseObj.b // 'b'
baseObj.c // undefined
baseObj.d // undefined
// $delegate() は baseObj を破壊的に変更する。
// baseObjそのものは書き換えるが、baseObjのprototypeは更新しない
$delegate(baseObj).to(delegated, 'c', 'd');
baseObj.a // 1
baseObj.b // 'b'
baseObj.c() // 'c'
baseObj.d.e // true
経緯
- 業務中にAオブジェクトからBオブジェクトに処理を移譲するコードを書いていた時、「一々グルーコード書くのメンドくせー」ということで、作ってみた
- その愚痴が頭に浮かんだ時、ちょうどプライベートでRails5でAPIサーバーをゴリゴリ書いていて、「Railsのdelegateメソッドみたいな感じでサクッと移譲を書けたら便利じゃね?」から、Railsのdelegateを模したインタフェースで実装
- 業務でTypescriptを使っていて便利だったので、環境構築も含めて全部TSで始めてみたかった。
実装で困ったこと
- 最初は「delegatedとして渡されたオブジェクトを、baseObjのprototypeとして差し込めばイケる?」と思って始めたが、「delegated自体がprototypeチェーン持ってたらどーすんのよ」ということで断念
-
Object.defineProperty
による実装に変更
-
- 「オブジェクト直接書き換えるのは、その方が嬉しい場合も有るけど基本行儀悪いよな・・・」「書き換えるやつと書き換えないパターン両方用意しよう!」「書き換えないパターンの時、どうやって新しいオブジェクト取ろう・・・」 -> delegate(...).self というキモいAPI爆誕
- もっと良い名前有る気もする
- 最終的に行儀悪いやつの方が使い勝手良くなりそうな皮肉
- 「Typescriptで使う場合は色々なIFのオブジェクト受け取る必要が有るけど、ジェネリクス使えば柔軟に対応できるよね!」「Typescriptで使う時、型キャストが不可避になったンゴ・・・」
- ジェネリクス + 直行型 etc の活用で、将来的には回避できるようになりそうな気がするようなしないような
作ってみた感想
- Typescript超便利。誰かエラい人が言ってた気がするけど、全てのjsライブラリはTSで実装されるべき
- npmに公開する時、名前と用途の被りが激しくて困った。下調べの時点ではDOMイベントの移譲ライブラリが多い印象だったけど、近いことはみんな考えてる法則。
- ついでに、前々から気になっていた色々な開発ツール(TravisCI,Coveralls,mocha + chai)にも手を出してみた結果、開発が超快適に。
- 正直Travisのビルドが回ってるの眺めるだけでも楽しい段階
- CircleCIとかも気になってきた
- Jenkinsも、どっかのタイミングでAWSかGoogleCloud?とかに構築してみたい
- 英語ヤバい
- README書いている段階で瀕死