rubyenvの設定
今回のボットでは他のライブラリを利用しないが、Xchatプラグインにおいて他のライブラリをrequireするには、rubyenvというファイルを作成しなければならない。なので、おまじないのように次のコマンドを実行しよう。ruby -e 'puts $:' > ~/.xchat2/rubyenv
チャンネルで発言する
挨拶をするというこことは、チャンネル上で発言をするということである。通常、Xchatを利用している場合、発言は単に入力エリアにメッセージを入力し、Enterで確定するだけであるが、実際にはその裏で/SAYというコマンドが発行されている。Xchatプラグインで発言を行うには、次のようにcommandメソッドを使おう。def say(words) command("SAY #{words}") endcommandメソッドは、先頭のスラッシュ(/)を除いた一行のコマンド文字列を引数にとる。わざわざsayメソッドを作ることもないが、上のようにしておけばわかり易いだろう。
他のコマンドも同様の方法で実行することができる。どのようなコマンドがあるかは、Xchat上で/HELPコマンドを実行すれば分かるが、Xchat上で調べるのは一覧性に欠けるので、次のページなどを参照するといいだろう。
https://toxin.jottit.com/xchat_help_commands
誰かがチャンネルに入室した!
挨拶をするボットと言っても、闇雲に挨拶すればいいというものではない。例えばチャンネルに入室したタイミングなどが、挨拶をするのに適しているだろう。そのようなイベントに応答して何らかの処理を実行するにはフックを設定する必要がある。前回はChannel Messageなどのイベントにフックを設定したが、チャンネル参加時はJoinにフックを仕掛ける。フックを仕掛ける場所はinitializeメソッド中がいいだろう。def initialize ... hook_print("Join", XCHAT_PRI_NORM, method(:join_hook), "Join.") ... endここでは、join_hookというメソッドにフックをしかけている。誰かがチャンネルにJoin(入室)すると、join_hookメソッドが呼ばれるのだ。join_hookは好きなように定義すればいい。「自動挨拶ボット」では次のようにしている。
def join_hook(words, data) return XCHAT_EAT_NONE if away? unless @greet_channel_list.include? words[1] return XCHAT_EAT_NONE end say_greetings_or_wb(normalize_nick(words[0])) return XCHAT_EAT_NONE endJoinフックでは、words[0]に新たに参加した人のニックネームが、words[1]にチャンネルが格納される。
オマケだが、IRCを利用している人の中にはニックネームをfoo-awayなどのように変更して長時間離籍する人もいる。そのような人がチャンネルに復帰したことを検知するには、ニックネームの変更を追跡する必要があるだろう。そうするには、"Change Nick"イベントにフックを仕掛ければ良い。
def nick_change_hook(words, data) return XCHAT_EAT_NONE if away? unless @greet_channel_list.include? words[1] return XCHAT_EAT_NONE end away_re = /[\|\_](afk|away|awy|zzz|bbl|brb|out)/i if words[0] =~ away_re and not words[1] =~ away_re say_greetings_or_wb(normalize_nick(words[1])) end return XCHAT_EAT_NONE endwords[0]には変更前のニックネームが、words[1]には変更後のニックネームが格納されている。
在籍中か否か。
前述の例にはaway?という名前のメソッドが登場した。これは何かというと、自分がaway(離席中)かどうかを調べるメソッドである。Xchatプラグインでは、get_infoというメソッドで各種情報を取得できるようになっている。そのまんまやんけ!とツッコミをいれたくメソッド名であるが、気にせず利用しよう。get_infoは調べたい対象を文字列引数としてとる。自分がawayかどうかを調べるには、get_info('away')という具合に利用する。以下はボットプラグインで定義されているaway?メソッドの中身である。def away? return ((not get_info('away').nil?) or\ (get_info('nick') =~ /awa?y$|out$|afk$|bb[sl]$|lunch$/)) endget_info('away')は、away中であればその理由を文字列で返す。get_info('nick')は自分のニックネームである。自分もmikiya|awayなどというニックネームに変更して離籍することがあるので、そのような場合にはawayであると判定しなければならない。
get_infoで取得できる情報の詳細は、次のページを参照して欲しい。
http://xchat.org/docs/xchat2-perl.html#xchat_get_info
ディレイを入れる
誰かがチャンネルに参加したとき、電光石火で挨拶をしたらすぐにボットだと分かってしまうだろう。人間にはそのような離れ業は出来ないからだ。常識的に考えると、誰かがチャンネルに入ったのを見て、挨拶をタイプするという所作には、少なくとも数秒は掛かるはずである。しかし、ここで注意しなければならないのは、sleepしてはいけないということだ。sleepすると、Xchatの反応が止まってしまう。sleepせずに応答を遅らせるには、hook_timerを使う。def timed_print(words) hook_timer(@delay * 1000, method(:say), words) endこのようにすると、@delay秒後に、sayメソッドが呼ばれる。その時の引数はwordsである。hook_timerの第一引数の単位はミリ秒である。
追記:hook_timerにより発動したイベントでは、フック登録時のコンテキスト(サーバーやチャンネルなど)が失われ、現在のチャンネルにメッセージが出力されることが分かった。フック登録時のコンテキストを利用するには、次のようにget_contextでコンテキストを保存し、set_contextを使ってコンテキストを復元しよう。
def timed_print(words) ctx = XChatRuby::XChatRubyEnvironment.get_context() data = { :words => words, :ctx => ctx, } hook_timer(@delay * 1000, method(:say_with_context), data) end def say_with_context(data) ctx = data[:ctx] XChatRuby::XChatRubyEnvironment.set_context(ctx) unless ctx.nil? say(data[:words]) end
チャンネル参加者一覧
get_infoは単一の情報を取得するためのメソッドであり、「今このチャンネルには参加者がどれだけいるか?」というようなリストを返す問いには答えることが出来ない。他の言語用のプラグインではget_listという関数を用いることが出来るのだが、Rubyプラグインではget_listはXChatRubyListというクラスでラッピングされている。次のメソッドは、現在のチャンネルに居る参加者の一覧を得るものである。def get_users users = [] cur = XChatRuby::XChatRubyList.new("users") while cur.next do users.push(cur.str('nick')) end users.sort end下手にラッピングされているのでRubyっぽくないコードになってしまうが、気にせずカーソルを回して情報をゲッツしよう。
独自コマンドの定義
プラグインに命令を伝えるには、独自のコマンドを定義するのが一番の近道である。独自のコマンドを定義するのは非常に簡単だ。次のようにhook_commandメソッドを使って未定義のコマンドにフックを仕掛ければ良い。def initialize ... hook_command("GREET", XCHAT_PRI_NORM, method(:handle_command), "Usage: Greetこの例ではGREETというコマンドを新たに定義して、handle_commandメソッドをコールバックしている。, see /greet help for more info") ... end
def handle_command(words, words_eol, data) if words.size < 2 display_help else case words[1].downcase when "help" display_help when "" display_help when "all" greet_all when "status" print_status when "list" list_nicks when "config" show_config end end return XCHAT_EAT_NONE endwords[0]にはGREETという文字列が、words[1]には一つめの引数が格納されている。words_eolは便利な引数で、コマンドの引数が長い場合、引数全体からwords[x-1]までの部分を取り除いた残りが格納される。words_eol[0]はコマンド全体を表す。
0 件のコメント:
コメントを投稿