バグ #1357
完了定義にブロックを伴う抽出条件に対して演算子「=」を使用すると、抽出条件のブロックが評価されない
説明
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#==
のオーバーライドが必要なのでは?と考えていますが、抽出プラグインの仕組みの理解が浅いので実装には踏み切れていません。
原因と修正先が正しいかをチェックしていただきたいです。