collection
Collectionとは
この機能の説明は、collectをひととおり理解している前提で書かれています。
collection とは、フィルタで値のリストを提供することに特化した機能です。
以下は、従来のフィルタのおさらいです。
filter_mute do |world, yielder|
if world == 'hoge'
yielder << 'toshi_a'
end
[yielder]
end
:mute
はコレクションフィルタです。
コレクションフィルタは、第二引数に <<
メソッドで値を挿入することで、複数のプラグインが :mute
イベントの結果に値を加えることができるのでした。
Collectionが解決すること
collectionはコレクションフィルタを提供する単純なフィルタの定義のコードを簡潔にすることを目的とします。以下が単純なフィルタの定義をcollectionを使って書き換えた例です。
Pluggaloid::Plugin.create(:event) do
defevent :followings, prototype: [String, Pluggaloid::COLLECT]
collection(:followings) do |collector|
on_followings_add do |users|
users.each { |user| collector.add(user) }
end
on_followings_remove do |users|
users.each { |user| collector.delete(user) }
end
end
end
この例は、 followings_add
というイベントで配列を受け取ると、collectionの引数の collector
という値を使って、add(*objects) → selfを呼び出しています。
Pluggaloid::Collectionは、add(*objects) → selfで追加されたオブジェクトを全て記録しています。
そして、collectionは呼び出されると自動的にフィルタリスナを定義し、Pluggaloid::Collectionに追加された全ての値をコレクション引数に挿入するようになります。
処理が実行されるのが追加・削除時のみ
`Plugin.filtering`でも同じものを実装した場合、`Plugin.filtering`が呼ばれる度に`Plugin.filtering` ブロックが実行されます。
従って、`Plugin.filtering` ブロックの中で少しでも時間のかかる処理をすると、mikutter全体の動作に致命的な影響を与える可能性があります。
対策は、フィルタが呼ばれた時に必要な情報を集めるのではなく、プラグインスコープの変数にArrayを確保しておいて、常にそこに返すべきオブジェクトを集めておき、呼ばれたときにはそのArrayの内容をそのまま返すという実装にすることです。実際、標準添付プラグインをはじめ、多くのプラグインで頻出するパターンです。
collectionはまさに、そのようなパターンを簡単に実装するためのものです。
追加・削除をストリームで購読できる
collectionを定義すると、自動的に以下のようなストリームイベントが定義されます。
イベント名 | 引数 | 説明 |
---|---|---|
|
Pluggaloid::Collectionに 追加 された値を列挙するストリームイベント |
|
|
Pluggaloid::Collectionから 削除 された値を列挙するストリームイベント |
`Plugin.filtering`でフィルタを定義した場合、コレクション引数の中身の変化を監視する
Collectionの定義
collection
collection(event_slug, *rest) { |collector| … } → nil
引数名 | 型 | 意味 |
---|---|---|
event_slug |
提供するフィルタの識別子 |
|
*rest |
- |
コレクション引数以外の引数 |
collector |
コレクションフィルタの結果に含める値を管理するオブジェクト |
collector
に格納されている値をフィルタの結果に追加するフィルタ event_slug
を定義します。
フィルタの event_slug
が一致してかつ、 *rest
がコレクション引数以外の引数と等しい場合にのみ collector
に格納されている値を挿入します。。ここでいう「等しい」とはObject#hashの結果が等しいものです。
Pluggaloid::Collection
collection(event_slug, *rest) { |collector| … } → nil のブロックの引数に渡されるオブジェクトです。 このオブジェクトに、以下のメソッドを使って値を格納/削除することで、以下の効果があります。
-
対象のコレクションフィルタのコレクション引数の中に含まれる値に、collectionに格納されている値が挿入される
add(*objects) → self
引数名 | 型 | 意味 |
---|---|---|
objects |
- |
Pluggaloid::Collectionに格納するオブジェクト |
戻り値 |
self |
コレクションに値を格納します。
いっぺんに複数の値を格納する時、self << object → selfでは:
collector << a << b
と書かなければならないのに対し、このメソッドでは:
collector.add(a, b)
と書くことができます。また、1つなら同じですが、2つ以上のオブジェクトをいっぺんに格納するなら、add(*objects) → selfのほうが高速です。
delete(*objects) → self
引数名 | 型 | 意味 |
---|---|---|
objects |
- |
Pluggaloid::Collectionから削除するオブジェクト |
戻り値 |
self |
コレクションから、引数に渡された値のいずれかと等しい値を削除します。
値の同一性はObject\#eql?により評価されます。
rewind { |ary| … } → self
引数名 | 型 | 意味 |
---|---|---|
ary |
Pluggaloid::Collectionに格納されているオブジェクトの配列 |
|
ブロックの戻り値 |
置き換える配列 |
|
戻り値 |
self |
現在レシーバに格納されている値を配列にしてブロックに渡して実行します。
その後、格納されている値をそのブロックの戻り値で全て置き換えます。
同時に複数の値を追加・削除するときには、Arrayとして扱えるので便利です。