Slackで動く当番ボットをLuaで作る(2)
kiten.co を使うと、比較的簡単なLuaのコードでHubot風にSlackボットを作成することができます。
この記事ではタイマーで動作する通知ボットを題材にして、kiten上でどのようなコードを書くのかご紹介します。
基本的なプログラミングの経験がある人を対象読者と想定しています。
Luaの知識があるとより理解しやすいです。
第二回目の本記事では実際に当番決めをするところを作成し、それを発言するタイマーの設定をして最終版を作るまでを解説します。
kitenで提供されている機能のドキュメントについては https://docs.kiten.co/ から「リファレンス(Lua)」のメニューをたどってご参照ください。
コード
当番メッセージ生成
さて、前回休日判定ができるようになったので、当番を決めます。
日付を受け取って、「誰が当番か」というメッセージを作る関数を作成します。
朝当番は、予め列挙しておいた担当メンバーが一週間おきにローテーションするようにします。
2016年12月25日(日曜日)を基準日として、当番を判断したい日が基準日から見て何週間後かを計算します。
function message(target, now)
local startDate = os.time({year=2016, month=12, day=25})
local names = {"矢口", "赤坂", "パタースン", "市川"}
local dateDiff = os.difftime(os.time(now), startDate) / (24 * 60 * 60)
local weekDiff = math.floor(dateDiff / 7)
return string.format(
"%sの10時出社当番は%sです。",
target,
names[(weekDiff % #names) + 1]
)
end
ついでに、今週分と来週分のメッセージを作る関数も作っておきます。
function messageForThisWeek(now)
return message("今週", now)
end
function messageForNextWeek(now)
return message("来週", os.date("*t", os.time(now) + 7 * 24 * 60 * 60))
end
キーワードに反応する部分
robot:respond()
を使って、「今週」「来週」「当番」という文字列を含むメッセージに反応するようにしてみます。
「今週」と「来週」は1行で当番を発言させてみます。「当番」は今日の当番、今週の当番、来週の当番を続けて発言させることにします。
robot:respond("今週", function(res) res:send(messageForThisWeek(os.date("*t"))) end)
robot:respond("来週", function(res) res:send(messageForNextWeek(os.date("*t"))) end)
robot:respond("当番", function(res)
local d = os.date("*t")
res:send(message(os.date("%Y/%m/%d(%a)", os.time(d)), d))
res:send(message("今週", d))
res:send(message("来週", os.date("*t", os.time(d) + 7 * 24 * 60 * 60)))
end)
タイマーで起動する部分
newCornJob
というメソッドで、タイマーで起動するジョブを登録します。
cronの時刻指定のところは、一般のcronの記法に追加して、秒を書くカラム(1項目目)があります。またday of month(4項目目)とday of week(6項目目)の両方を指定することはできないので、どちらかに?
を書いて未指定にする必要があります。
チャネル名はbotに発言させたいチャネルを設定します。
週の初めの朝と週の終わりの夕方に発言させたいので、ジョブはこのようなつくりにします。
- 毎朝9:30のタスクの中では、週の初めかどうかを確認し、初めであればその週の当番を発言する
- 毎夕18:30のタスクの中では、週の終わりかどうかを確認し、終わりであれば次週の当番を発言する
robot.newCronJob("0 30 9 ? * 2-6", function(res)
local d = os.date("*t")
if isWeekStart(d) then
robot.messageRoom("channel", messageForThisWeek(d))
end
end, "Asia/Tokyo")
robot.newCronJob("0 30 18 ? * 2-6", function(res)
local d = os.date("*t")
if isWeekEnd(d) then
robot.messageRoom("channel", messageForNextWeek(d))
end
end, "Asia/Tokyo")
全体像
これですべての部品がそろいました。
まとめたコードはこのようになります。
function isHoliday(now)
local holidays = {
"20170109",
"20170320",
"20170503",
"20170504",
"20170505",
"20170717",
"20170811",
"20170918",
"20171009",
"20171103",
"20171123"
}
local additionalHolidays = {
"20170102",
"20170103"
}
local today = os.date("%Y%m%d", os.time(now))
if now.wday == 1 or now.wday == 7 then
return true
end
for _, h in ipairs(holidays) do
if today == h then
return true
end
end
for _, h in ipairs(additionalHolidays) do
if today == h then
return true
end
end
return false
end
function isWeekStart(now)
for i = 1, (now.wday - 1) do
local t = os.date("*t", os.time(now) - (now.wday - i) * 24 * 60 * 60)
if not isHoliday(t) then
return false;
end
end
return not isHoliday(now)
end
function isWeekEnd(now)
for i = (now.wday + 1), 7 do
local t = os.date("*t", os.time(now) + (i - now.wday) * 24 * 60 * 60)
if not isHoliday(t) then
return false;
end
end
return not isHoliday(now)
end
function message(target, now)
local startDate = os.time({year=2016, month=12, day=25})
local names = {"矢口", "赤坂", "パタースン", "市川"}
local dateDiff = os.difftime(os.time(now), startDate) / (24 * 60 * 60)
local weekDiff = math.floor(dateDiff / 7)
return string.format(
"%sの10時出社当番は%sです。",
target,
names[(weekDiff % #names) + 1]
)
end
function messageForThisWeek(now)
return message("今週", now)
end
function messageForNextWeek(now)
return message("来週", os.date("*t", os.time(now) + 7 * 24 * 60 * 60))
end
robot:respond("今週", function(res) res:send(messageForThisWeek(os.date("*t"))) end)
robot:respond("来週", function(res) res:send(messageForNextWeek(os.date("*t"))) end)
robot:respond("当番", function(res)
local d = os.date("*t")
res:send(message(os.date("%Y/%m/%d(%a)", os.time(d)), d))
res:send(message("今週", d))
res:send(message("来週", os.date("*t", os.time(d) + 7 * 24 * 60 * 60)))
end)
robot:respond("%d%d%d%d%d%d%d%d", function(res)
local y, m, d = res.message.text:match("(%d%d%d%d)(%d%d)(%d%d)")
d = {year = tonumber(y), month = tonumber(m), day = tonumber(d)}
d = os.date("*t", os.time(d))
local h = isHoliday(d)
local s = isWeekStart(d)
local e = isWeekEnd(d)
res:send(string.format("isHoliday: %s, isWeekStart: %s, isWeekEnd: %s", tostring(h), tostring(s), tostring(e)))
end)
robot.newCronJob("0 30 9 ? * 2-6", function(res)
local d = os.date("*t")
if isWeekStart(d) then
robot.messageRoom("channel", messageForThisWeek(d))
end
end, "Asia/Tokyo")
robot.newCronJob("0 30 18 ? * 2-6", function(res)
local d = os.date("*t")
if isWeekEnd(d) then
robot.messageRoom("channel", messageForNextWeek(d))
end
end, "Asia/Tokyo")
Author And Source
この問題について(Slackで動く当番ボットをLuaで作る(2)), 我々は、より多くの情報をここで見つけました https://qiita.com/masa_edw/items/fe1facdd85ba9b85b58f著者帰属:元の著者の情報は、元の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 .