Rubotyでbot宛てのメッセージじゃなくても反応して欲しくてコードを読んだ話
概要
社内で「rubotyってメッセージの文頭にbot名ないと反応してくれないんですか?」
と聞かれたので、これはOSSコミットチャンスか!?
とテンション上がって色々しらべたときのお話。
調査
ドキュメントを読む
ドキュメントを一通り眺めてみる。
それっぽい言葉は無い。
きっと対応していないのだろう。
あんまり用途無いしな。
よ〜し、ちゃんと読んで、きれいに実装するぞ〜!!
そういう気持ちでコードリーディングを開始する。
コードリーディング開始
adapter
何度かコードを読んで、大体仕組みは把握している。
仕組みに興味がある人はtbpgrさんの、このあたりの投稿を読まれると良いだろう。
メッセージ周りは、adapterを読めば良いのだろう。
adapterは、chat toolとrubotyをつなぐためのプラグインである。
今回はshell.rbを読んでいく。
def listen
step until stopped?
rescue Interrupt
stop
end
def step
case body = read
when "exit", "quit", nil
stop
else
robot.receive(body: body, source: SOURCE)
end
end
ふむ。全てのメッセージをrobot.receiveで受け取っているらしいな。
ということは、メッセージの文頭にbot名無くても大丈夫そう。
次は、robot.rbを読もう。
robot.rb
robot.rbのreceiveを読む。
どうやら、handlersを総なめして、条件にヒットしたものをcallしてるらしい。
ということで、handlerを読もう。
(ちなみに missing: trueのときのみに、handlerの中身は処理される)
def receive(attributes)
message = Message.new(attributes.merge(robot: self))
unless handlers.inject(false) { |matched, handler| matched | handler.call(message) }
handlers.each do |handler|
handler.call(message, missing: true)
end
end
end
handlers/base.rb
handlerはrubotyで実行する各種タスクの条件を記載しているclassである。
# pingタスクの例
module Ruboty
module Handlers
class Ping < Base
on(/ping\z/i, name: "ping", description: "Return PONG to PING")
def ping(message)
Ruboty::Actions::Ping.new(message).call
end
end
end
end
さて、handlersのcallを読んでいく。
handlers/base.rbにあるようだ。
def call(message, options = {})
self.class.actions.inject(false) do |matched, action|
matched | action.call(self, message, options)
end
end
ふむ。ここでも別classをcallしているようだ。
どこかで配列actionsに値を代入しているメソッドがあるのだろう。
ということで、actionsに対して値を代入しているメソッドを探す。
どうやら、onメソッドのようだ。Action インスタンスを代入しているらしい。
ということで、次はaction.rbを読む。
def on(pattern, options = {})
actions << Action.new(pattern, options)
end
lib/ruboty/action.rb
もう何度目のcallだろうか。
そういう気持ちでcallメソッドを読んでいく。
ふむふむ。pattern_withで引っかかったやつは実行されるようだ。
def call(handler, message, options = {})
if !!options[:missing] == missing? && message.match(pattern_with(handler.robot.name))
!!handler.send(name, message)
else
false
end
end
そしてなんと....
あれ? all?
え、その正規表現は.....
def all?
!!options[:all]
end
# 省略
private
def pattern_with(robot_name)
if all?
/\A#{pattern}/
else
/#{self.class.prefix_pattern(robot_name)}#{pattern}/
end
end
結論
handlerのonメソッドに対して、optionでall: trueを入れれば解決。
on(/hear\z/i, name: "hear", description: "", all: true)
うむ....既に機能としてありました。さすがです。
ありがたく使わせていただこうと思います。
Author And Source
この問題について(Rubotyでbot宛てのメッセージじゃなくても反応して欲しくてコードを読んだ話), 我々は、より多くの情報をここで見つけました https://qiita.com/selmertsx/items/e49d1039a4276b11a0de著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .