Collectionとは

この機能の説明は、collectをひととおり理解している前提で書かれています。

collection とは、フィルタで値のリストを提供することに特化した機能です。

以下は、従来のフィルタのおさらいです。

単純なフィルタの定義
filter_mute do |world, yielder|
  if world == 'hoge'
    yielder << 'toshi_a'
  end
  [yielder]
end

:muteコレクションフィルタです。

コレクションフィルタは、第二引数に << メソッドで値を挿入することで、複数のプラグインが :mute イベントの結果に値を加えることができるのでした。

Collectionが解決すること

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を定義すると、自動的に以下のようなストリームイベントが定義されます。

イベント名 引数 説明

???__add

コレクション引数ストリーム引数に置き換えたもの

Pluggaloid::Collection追加 された値を列挙するストリームイベント

???__delete

コレクション引数ストリーム引数に置き換えたもの

Pluggaloid::Collectionから 削除 された値を列挙するストリームイベント

`Plugin.filtering`でフィルタを定義した場合、コレクション引数の中身の変化を監視する

Collectionの定義

collection

collection(event_slug, *rest) { |collector| …​ } → nil

引数名 意味

event_slug

Symbol

提供するフィルタの識別子

*rest

-

コレクション引数以外の引数

collector

[pluggaloid-collection]

コレクションフィルタの結果に含める値を管理するオブジェクト

collector に格納されている値をフィルタの結果に追加するフィルタ event_slug を定義します。

フィルタの event_slug が一致してかつ、 *restコレクション引数以外の引数と等しい場合にのみ collector に格納されている値を挿入します。。ここでいう「等しい」とはObject#hashの結果が等しいものです。

Pluggaloid::Collection

collection(event_slug, *rest) { |collector| …​ } → nil のブロックの引数に渡されるオブジェクトです。 このオブジェクトに、以下のメソッドを使って値を格納/削除することで、以下の効果があります。

self << object → self

引数名 意味

object

Object

Pluggaloid::Collectionに格納するオブジェクト

戻り値

Pluggaloid::Collection

self

コレクションに一つ値を格納します。

add(*objects) → self

引数名 意味

objects

-

Pluggaloid::Collectionに格納するオブジェクト

戻り値

Pluggaloid::Collection

self

コレクションに値を格納します。

いっぺんに複数の値を格納する時、self << object → selfでは:

collector << a << b

と書かなければならないのに対し、このメソッドでは:

collector.add(a, b)

と書くことができます。また、1つなら同じですが、2つ以上のオブジェクトをいっぺんに格納するなら、add(*objects) → selfのほうが高速です。

delete(*objects) → self

引数名 意味

objects

-

Pluggaloid::Collectionから削除するオブジェクト

戻り値

Pluggaloid::Collection

self

コレクションから、引数に渡された値のいずれかと等しい値を削除します。

値の同一性はObject\#eql?により評価されます。

rewind { |ary| …​ } → self

引数名 意味

ary

Array

Pluggaloid::Collectionに格納されているオブジェクトの配列

ブロックの戻り値

Array

置き換える配列

戻り値

Pluggaloid::Collection

self

現在レシーバに格納されている値を配列にしてブロックに渡して実行します。

その後、格納されている値をそのブロックの戻り値で全て置き換えます。

同時に複数の値を追加・削除するときには、Arrayとして扱えるので便利です。