今いる会社の提供するdirectというチャットサービスではボットの開発ができて、そのsdkがdaab(direct agent assist bot)というらしい。
で、daabチームが専修大学でハッカソンを共催するということで、僕も自分の会社のボットくらい作れないと恥ずかしいなと思ったので1日だけ参加してきました。
daabはhubotをdirect用に改造した感じのもので、次のようなプログラムで簡単にボットが記述できます。
module.exports = robot => { robot.hear(/^today/i, res => { var now = new Date(); res.send(dateFormat(now, "yyyy/mm/dd")); }); };
ところが、困ったことにどういう関数があるのか、何を引数に取るのか、ドキュメントを漁ってもいまいちわかりません。
ドキュメントを漁ってるうちに、Typescriptでhubotを書きたい人なら型定義ファイルを作っているに違いないと思い立って、探してみたら下の記事を見つけました。
この記事にかかれていた型定義をそのままコピってTypescriptでdaabを書いてもいいんだけど、もうひとひねり入れて、ts2ktにかけてKotlinの型情報に変換してdaabをKotlinで書けるようにしてみました。
ts2ktをしてできた型情報(一部省略/修正)
@file:Suppress("INTERFACE_WITH_SUPERCLASS", "OVERRIDING_FINAL_MEMBER", "RETURN_TYPE_MISMATCH_ON_OVERRIDE", "CONFLICTING_OVERLOADS") @file:JsQualifier("hubot") package hubot external interface Robot { fun hear(regex: RegExp, callback: ((res: Response) -> Unit)? = definedExternally /* null */) fun hear(regex: RegExp, options: Function<*>, callback: ((res: Response) -> Unit)? = definedExternally /* null */) fun hear(regex: RegExp, options: Json, callback: ((res: Response) -> Unit)? = definedExternally /* null */) } external interface Response { fun send(vararg strings: String) }
ボット部分のコードは見事に綺麗なKotlinで書けました。
package com.example import hubot.Response import hubot.Robot import kotlin.js.RegExp val app: (Robot) -> Unit = { robot: Robot -> robot.hear(RegExp("now")) { res: Response -> res.send(dateTime()) } }
kotlin-jsはkotlinc-jsではなく、gradleでコンパイルしました。なお、 build.gradle
はこんな感じ
buildscript { ext.kotlin_version = '1.1.2-4' repositories { mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } apply plugin: 'kotlin2js' dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version" } compileKotlin2Js { kotlinOptions.outputFile = "${projectDir}/daab/scripts/lib/daab.js" kotlinOptions.moduleKind = "commonjs" kotlinOptions.sourceMap = true } task generateAppJs { def jsFile = file("$projectDir/daab/scripts/application.js") outputs.file jsFile doLast { def content = """let kotlin = require("kotlin"); let daab = require("./lib/daab"); module.exports = daab.com.example.app; """ jsFile.write(content, 'UTF-8') } } tasks.compileKotlin2Js.dependsOn tasks.foreverIgnore tasks.compileKotlin2Js.finalizedBy tasks.generateAppJs
実行した結果は次のとおり、見事に動かせました
なお、気をつけるところがいくつかあって、KotlinのAPIがJVM環境のプログラムを書く場合のAPIと若干異なっているところです。例えば Date
型はありますが、 java.util.Date
ではなくて、 kotlin.js.Date
になっていて getTime()
メソッドも Long
ではなく、 Double
を返すなど異なっています。
今回の成果をもう少し汎用的にして、かつ、同僚のエンジニアにAPIを確認して型情報を明確にした上でgradleプラグインを出そうかなと思っています。