GitHub社謹製! bot開発・実行フレームワーク「Hubot」

第5回 実用的なHubotのスクリプトを書いてみる

この記事を読むのに必要な時間:およそ 5 分

第4回までで,Hubotをセットアップしてチャットツールに接続し,独自のスクリプトを書くことができるようになりました。最終回となる今回は,もう少し複雑なスクリプトの書き方をサンプルコードをベースに紹介します。

定期実行で定時ミーティングの時間を通知する

デイリースクラムの時間を通知すると言った定期的な処理をHubotに行わせたい場合,cronモジュールを使うと便利です。本節では,cronモジュールの導入方法と使用例のサンプルスクリプトを掲載します。

cronモジュールの導入

cronモジュールのようなnpmのモジュールを使用するには,Hubotを導入したディレクトリの直下にあるpackage.jsonファイルのdependenciesにモジュールの情報を追加します。

通常,Hubotをインストールした直後はdependenciesの項目は次のようになっています。

  "dependencies": {
    "hubot":         ">= 2.6.0 < 3.0.0",
    "hubot-scripts": ">= 2.5.0 < 3.0.0"
  },

ここにcronモジュールを追加することでスクリプトからcronモジュールを使用できるようになります。

  "dependencies": {
    "hubot": ">= 2.6.0 < 3.0.0",
    "hubot-scripts": ">= 2.5.0 < 3.0.0",
    "cron": ">= 1.0.4"
  },

サンプルスクリプト

cronモジュールを使って月曜日から金曜日の午前11時にミーティングの開催を呼びかけるスクリプトの例を示します。

cronJob = require('cron').CronJob

module.exports = (robot) ->
  cronjob = new cronJob('0 0 11 * * 1-5', () =>
    envelope = room: "#chatroom"
    robot.send envelope, "デイリースクラムを始めましょう @all"
  )
  cronjob.start()

図1 cronを使ったサンプルスクリプトの実行例

図1 cronを使ったサンプルスクリプトの実行例

見てのとおり,cronモジュールでは,通常のcronと同様の書式で定期処理を書くことができます。

注意点として,普通のhearrespondを使った発言方法ではmsgオブジェクトのsendメソッドなどを使いますが,定期実行のように誰かから話しかけられて返答するのではない場合は,robotオブジェクトのsendメソッドを直接使ってチャットルームに発言することになります。

sendメソッドの第一引数envelopeは発言先のチャットルームや発言対象のユーザの情報を格納したオブジェクトです。この例ではhubot-ircを使ってIRCの#chatroomチャンネルに発言することを想定しています。どのようなenvelopeが必要かは,使用しているAdapterよって異なるため注意が必要です。

cronモジュールの詳しい使い方はリファレンスを参照してください。

永続化機能で投票結果を保存する

Hubotに何かを記憶させようとしたとき,初期状態ではメモリ上に情報を置くことしかできません。そのため,Hubotを再起動すると情報が消えてしまいます。この問題に対して,Hubotではbrainというインターフェースを通じて様々なストレージに情報を永続化できます。

本節では,Redisを使った永続化の方法と,チャット参加者に投票する仕組みを作る例を記します。

redis-brainによるRedis永続化機能の追加

Redisを使った永続化を行うには,HubotからアクセスできるところでRedisが動いている必要があります。Redisの公式サイトなどを参考に予めRedisをインストールして,起動してください。

HubotとRedisを接続するには,hubot-scriptsredis-brain.coffeeを使う方法が簡単です。redis-brain.coffeeを有効化するためには,hubot-scripts.jsonredis-brain.coffeeを読み込み,環境変数で接続先のRedisインスタンスを指定します。

hubot-scripts.json

["redis-brain.coffee"]

run_hubot.sh

#!/bin/bash

# redis://<host>:<port>[/<brain_prefix>]
export REDIS_URL=redis://127.0.0.1:6379/hubot

bin/hubot

このように設定すると,Hubotのbrainから保存したデータを127.0.0.1:6379のRedisにhubot:storageというキーでJSON文字列として保存するようになります。

サンプルスクリプト

brainを使った永続化のサンプルとして,チャット上で何か良いことをしたメンバーに投票する仕組みを作ってみます。

module.exports = (robot) ->
  KEY_SCORE = 'key_score'

  getScores = () ->
    return robot.brain.get(KEY_SCORE) or {}

  changeScore = (name, diff) ->
    source = getScores()
    score = source[name] or 0
    new_score = score + diff
    source[name] = new_score

    robot.brain.set KEY_SCORE, source
    return new_score

  robot.respond /list/i, (msg) ->
    source = getScores()
    console.log source
    for name, score of source
      msg.send "#{name}: #{score}"

  robot.hear /^(.+)\+\+$/i, (msg) ->
    name = msg.match[1]
    new_score = changeScore(name, 1)
    msg.send "#{name}: #{new_score}"

  robot.hear /^(.+)--$/i, (msg) ->
    name = msg.match[1]
    new_score = changeScore(name, -1)
    msg.send "#{name}: #{new_score}"

図2 永続化機能を使ったサンプルスクリプトの実行例

図2 永続化機能を使ったサンプルスクリプトの実行例

brainの詳細については,公式のリファレンスソースコードを参照してみて下さい。

著者プロフィール

大谷和史(おおたにかずふみ)

色々な物を動かして試してみることが好きなWeb開発者。

現在は,メドピア(株)で日本の医療を良くするために働いています。

URL:http://blog.fumiz.me/

コメント

  • ご指摘いただき誠にありがとうございます

    tesujiro様

    ご指摘いただき誠にありがとうございます。
    待たせいたしまして誠に申し訳ございません。

    なお、著者に問い合わせたところ、
    以下のように元の状態で問題ないとのことでございます。

    > ```
    > say "commit: #{commit['message']}"
    > ```
    >
    > については、コミットメッセージを表示している部分ですので、repositoryではなくcommitで問題ありません。

    それでは、これに懲りず、今後とも弊社をよろしくお願い申し上げます。

    Commented : #3  担当編集者 (2014/08/20, 13:54)

  • Re:typo?

    すいません!
    先ほどのtypo指摘間違いでした。失礼しました。

    指摘内容:
    s/#{commit['message']}/#{repository['message']}/

    Commented : #2  tesujiro (2014/08/11, 09:03)

  • typo?

    手元に動作環境がないのでわかりませんが、typoらしきものがありました。

    対象ページ:
    http://gihyo.jp/dev/serial/01/hubot/0005?page=3

    s/#{commit['message']}/#{repository['message']}/

    Commented : #1  tesujiro (2014/08/11, 09:00)

コメントの記入