iPX社員によるブログ

iPX社員が"社の動向"から"自身の知見や趣味"、"セミナーなどのおすすめ情報"に至るまで幅広い話題を投下していくブログ。社の雰囲気を感じ取っていただけたら幸いです。

YammerでHubotを利用する(Hubotプログラミング入門編)

前書き

2本目の投稿です。iPXのabikoです。
前回から引き続きHubot〆の記事としてお送りします。

前回の記事
Re:YammerでHubotを利用する(環境構築編2) - iPX社員によるブログ

さて今回の記事は...

Hubotの応答をカスタマイズしてみよう!
という目標の下、下記のカスタマイズを試してみようと思います。

Hello Worldする
・おみくじを引けるようにする

下準備

EC2とローカルでファイルのやり取りをする場合は、WinSCPなどのツールがあると便利です。
(viなどで直接編集する方は不要です。)

WinSCPでEC2に接続するには、Putty同様ホスト名・ユーザ名・秘密鍵の設定をする必要があります。
秘密鍵の設定箇所は「設定」から「SSH」>「認証」の「秘密鍵」の項目です。
ここにEC2にアクセスするために使用している.ppkファイルのパスを指定すれば完了です。

スクリプトの配置場所とサンプルの利用

作成したスクリプトは Hubotのルートディレクトリ/scripts に置いていきましょう。
(これまでの私の記事ですと ~/YAMMERBOT/script)

ここにはサンプルとして example.coffee が入っております。
このファイルのコメントアウトを外しながら少しずつ改変していくと手っ取り早く理解が進むのではないでしょうか。
(私はCoffeeScriptはおろかJavaScriptの経験も乏しく、どうしてもサンプル頼りです)

また、以降の私のスクリプトを試したい場合には、 example.coffeeに下記「ここに追加」箇所に追加することで試せます。
CoffeeScriptはインデントの階層でブロック(C言語で言う 中括弧{})を表現します。追加の際はお気をつけください。

module.exports = (robot) ->

  (ここに追加)

  # robot.hear /badger/i, (res) ->
  #   res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"
  ・・・(略)

CoffeeScriptは最終的にJavaScriptに変換されて実行される、JavaScriptを簡潔に記述できるようにした言語です。
なんとJavaScriptと比べ1/2~1/3の記述量で済むとか何とか。(利点は他にも色々あるようですが、ざっくり)
下記のページの上部メニュー「TryCoffeeScript」に移動すると、右側に書いたCoffeeScriptがリアルタイムでJavaScriptに変換され左側に出力されます。
CoffeeScriptになじみの無い方は使用してみるとイメージがつかめるかもしれません。

CoffeeScript

いざ、Hello World!

これは基本のping→pongの発言内容が変わったバージョンですね。

  robot.respond /Hello/i, (res) ->
    res.send "World!"

サーバに編集したファイルを配置したらHubotを起動します。
スクリプトの読み込みはHubotの起動時に行われ、コードに記述ミスなどの不備があると起動できずにエラーになります。
つまり、コードを書き直すたびにHubotの再起動が必要です。
また、コードを試すだけであればYammerで発言しなくともコンソール上で確認可能です。

$ ./bin/hubot
・・・(略)
YAMMERBOT> YAMMERBOT Hello
YAMMERBOT> World!

動作の確認が取れたので、YammerでもHelloしてみます。

無事動きました!

かならずYAMMERBOTってつけないとダメなの?

YAMMERBOT ~ って書くのが煩わしいぞ!会話を自然にしたい!
と思ったそこのあなた、
robot.respond を robot.hear に変えて試してみましょう

  robot.hear /Hello/i, (res) ->
    res.send "World!"

実行してみます。

$ ./bin/hubot
・・・(略)
YAMMERBOT> Hello
YAMMERBOT> World!

要望はかないましたが、デメリットもあります。
文中にHelloが含まれていても反応するのです。

YAMMERBOT> HogeHogeHelloFugaFuga
YAMMERBOT> World!

よく使われるワードを使用すると、意図しない発言に反応してしまう可能性があるので注意が必要です。
また、respondとhearで受け取った発言内容を返したい場合、若干実装が異なってきます。

  #hearの場合のコード
  robot.hear/Hello/i, (res) ->
    res.send res.match[0]

    #実行結果
    YAMMERBOT> Hello
    YAMMERBOT> Hello

  #respond の場合のコード
  robot.respond /Hello/i, (res) ->
    res.send res.match[0]

    #実行結果
    YAMMERBOT> YAMMERBOT Hello
    YAMMERBOT> YAMMERBOT Hello

msg.match[0] と書くと、発言内容の「全文」を取得できます。
そのため、respondで使用すると、呼び出しの文句(YAMMERBOT)まで取れてしまいました。
なんといいますか、このままでは使い勝手が悪そうです。

この問題については、括弧でくくる、と解決します。
respondやhearの引数になっている /~/ は正規表現で解釈されるため、(Hello) とくくることによって、Hello が正規表現の1つめの要素になるんですね。
あとはmsg.match[1]として1つめを取得すると、hearと同じ様な結果が得られるようになる、というわけです。

  #respond で呼び出し文を除いて発言内容を返答
  robot.respond /(Hello)/i, (res) ->
    res.send res.match[1]

    #実行結果
    YAMMERBOT> YAMMERBOT Hello
    YAMMERBOT> Hello

では相手の発言の一部を返答に組み込む例をひとつ
#{}でくくると変数の中身を展開できることも利用します。

  #相手の発言内容の一部を返答に組み込む
  robot.respond /Hello, I am ([a-z]+)/i, (res) ->
    res.send "Hi, #{res.match[1]}! I am YAMMERBOT!"

    #実行結果
    YAMMERBOT> YAMMERBOT Hello, I am abiko.
    YAMMERBOT> Hi, abiko! I am YAMMERBOT!
    YAMMERBOT> YAMMERBOT Hello, I am HogeHoge.
    YAMMERBOT> Hi, HogeHoge! I am YAMMERBOT!

中学校の教科書の最初に出てきそうな受け答えができました!
ちなみに /~/i の i は大文字小文字を無視する(ignore)意味があります。
これまでの紹介してきたコードの場合、呼び出しの文句を含め大文字にする必要は無いのです。
[a-z]としていても、大文字小文字によらず英字を判定してくれます。

おみくじ

続いておみくじの実装に入ります。
実はこの課題、とてもコード上は簡単なんです。

  robot.hear /おみくじ/i, (res) ->
    res.send res.random ["大吉", "吉", "凶", "大凶"]

random の引数にランダムにしたい配列の内容を渡すだけなんですね。
拍子抜け、と言うほどあっという間におみくじができてしまいました。
では、早速確認してみます。

$ ./bin/hubot
・・・(略)
YAMMERBOT> おみくじ
YAMMERBOT> 大吉

大吉でした!(ヤッタネ!)
scriptに日本語を書く場合は、ファイルの文字コードUTF-8にする必要があるようです。
SJISだと反応が返ってきませんでした。)

終わりに

ここまででHello Worldを含め、Hubotを一通り動作させることができました。
スクリプトについては超入門レベルでしたが、目標は達せられたかなと思います。
様々苦戦しましたが、その甲斐もあり?いい勉強になりました。
今のままだと常時稼動できないようなのでデーモン化するなど課題もでてきますが、次回取り上げるかは未定です。

ここまでお付き合い頂きありがとうございました。
それではまた、次の記事でお会いしましょう。