プロジェクト

全般

プロフィール

バグ #1357

完了

定義にブロックを伴う抽出条件に対して演算子「=」を使用すると、抽出条件のブロックが評価されない

Shibafu Midorino さんがほぼ5年前に追加. ほぼ5年前に更新.

ステータス:
終了
優先度:
通常
対象バージョン:
プラグイン名:
extract
クラッシュする:
いいえ

説明

defextractcondition でブロックを伴う抽出条件を定義し、抽出タブの絞り込み条件で演算子に「=」を使用するとその抽出条件が評価されなくなります。
この際、評価結果は偽の扱いになりますので、常にその条件ではマッチしなかったことになってしまいます。

経緯

1. 以下のようなプラグインを開発していたところ、debugオプションで起動してもnoticeが出力されておらず、ブロックが全く評価されていないことに気づく。

# -*- coding: utf-8 -*-

Plugin.create(:extract_retweeter) do
  defextractcondition(:retweeter, name: 'リツイートしたユーザ名', operator: true, args: 1) do |argument, message: raise, operator: raise, &compare|
    notice "|||||||| eval extract_retweeter ||||||||" 
    message.retweeted_by.any? { |u| compare.(u.idname, argument) }
  end
end

2. Slackにて情報交換を行い、演算子「=」に問題がある可能性が浮上する。

原因

ブロックを伴う抽出条件の評価に使用されている、extract.rb の Plugin::Extract::Calc クラスが == 演算子を期待通りに処理できていません。

上記経緯のコードで作成された抽出条件を使用し、このような絞り込み条件を設定したとします。
  • いずれかにマッチする: ON
  • リツイートしたユーザ名 = miku (条件1)
  • リツイートしたユーザ名 ≠ yukari (条件2)

すると、extract.rb の compile メソッド内ではMIKU関係の処理を経由して以下のコードが生成されます。

lambda{ |message|
retweeter = Plugin::Extract::Calc.new(message, extract_condition[:retweeter])
  if retweeter == "miku" 
  true
else
  true

  if retweeter.__send__(:!=, "yukari")

    true

  else

    true

    nil

  end
end
}

先に上手く動く方をおさらいすると、条件2は retweeter.__send__(:!=, "yukari") という式になり Plugin::Extract::Calc#method_missing を経由して抽出条件のブロックが評価されます。
(あまり読み込めていないのですが __send__ の第1引数として、演算子が指定されていることと推測しています。)

一方、条件1は retweeter "miku" とコンパイルされています。この場合 Plugin::Extract::Calc#method_missing ではなく演算子の既定動作である Object# のほうが呼ばれてしまいます。
そのため、この式で抽出条件のブロックが評価されることはなく、結果は常に偽となります。

どうしたいか

Plugin::Extract::Calc#== のオーバーライドが必要なのでは?と考えていますが、抽出プラグインの仕組みの理解が浅いので実装には踏み切れていません。
原因と修正先が正しいかをチェックしていただきたいです。

toshi_a 初音 さんがほぼ5年前に更新

  • ステータス分類待ち から 実装待ち に変更

再現しました。

以下、やるとき用メモ

BasicObject#== がある以上、これをmethod_missingでトラップするのは不可能なので、Plugin::Extract::Calcに必要なメソッドを動的に定義する。

多分一番楽なのがPlugin::Extract::Calcが初期化されるたびに、インスタンスに動的にdefine_methodなどでメソッドを定義するやり方。Plugin::Extract::Calcは使い捨てられるので、プラグインのロードによってあとからPlugin::Extarct::ExtensibleConditionが増えても問題ない。

高速化するならPlugin::Extarct::ExtensibleConditionが増減するたびに(compileが呼ばれるタイミングで良さそう)Plugin::Extract::Calcの無名サブクラスを作って、そちらでメソッドをオーバライドする方法。これならMessage受信のたびに払うオーバーヘッドを縮小できるかもしれない。

toshi_a 初音 さんがほぼ5年前に更新

  • ステータス実装待ち から レビュー待ち に変更
  • 担当者Shibafu Midorino にセット
  • ブランチtopic/1357-catch-up-yukari-query にセット

お願いします

Shibafu Midorino さんがほぼ5年前に更新

  • ステータスレビュー待ち から マージ待ち に変更

RTを待つのはつらいので、以下のプラグインを利用しつつあひるを焼いて検証しました。問題なく動作しています!

Plugin.create(:extract_body_ruby) do
  defextractcondition(:body_ruby, name: '本文 (Ruby)', operator: true, args: 1) do |argument, message: raise, operator: raise, &compare|
    compare.(message.to_s, argument)
  end
end

toshi_a 初音 さんがほぼ5年前に更新

  • ステータスマージ待ち から 終了 に変更

merged.

他の形式にエクスポート: Atom PDF