詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

指定された型からswitch文を生成するgo-switchgenと、そのコーディング動画

GitHub - motemen/go-switchgen

ある日 Go で reflect パッケージを使ったプログラムを書きたい! と思い立ち、となると reflect.Kind で swtich したいわけで、ありうる case 節を全部書きつくすのは大変だ、というわけで switch 文を生成する簡単なプログラムを書きました。パッケージ名と型を指定すると、その型における switch … case の候補を列挙してくれます。

普通の switch の場合:

% go-switchgen reflect.Kind
switch {
case reflect.Array:
case reflect.Bool:
...
case reflect.Uintptr:
case reflect.UnsafePointer:
}

type switch の場合:

% go-switchgen go/ast.Node
switch {
case *ast.ArrayType:
case *ast.AssignStmt:
...
case *ast.UnaryExpr:
case *ast.ValueSpec:
}

まあまあ便利そうですね。

そして今回はそのコーディング風景を録画してみました。

Goライブコーディング: go-switchgen(2倍速) - YouTube

少し前に同僚がコーディング動画を公開しているのを見て、自分でもやってみたいと思っていたところで、ちょうどいいサイズのネタを探していたこともあってのことでした。

30分くらいかかったので、2倍速にしています。あとから自分のやったことを見なおして声を当てるのは意外と難しく、あまり意味のあるコメントはつけられませんでした。利用しているパッケージの背景知識も必要になるので、題材としてはあまりよくなかったのかも。次に何しよう……と思いながらドキュメントを眺めているだけのシーンも多く、見ていて面白いコーディング動画を撮るのは一筋縄ではいかなそうです。

録画してみると自分がどんなことを考えながらコードを書いているかが分かって面白いですね(今回はかなり print デバッグしながらのコーディングでした)。あまり恥ずかしいことはできない、という心理もはたらき、エディタの設定を見直したりしていて、少し快適になりました。

# そして公開したあとに go/importer を使えばよかったことに気づき、こっそり修正しました……。

GoogleカレンダーとSlackステータスをワンクリックで連携できるアプリをGoogle Apps Scriptで書いた

Googleカレンダーで現在進行中のイベントをSlackステータスに反映させるようにしておくと、チームメンバーに、移動中や不在やミーティング中といった状況を自然に共有できるので便利ですね。そのように設定している人も多いと思います。

f:id:motemen:20170515184041p:plain
似たアイコンが並んでいるように見えますが一方はモザイクです

巷では Google Apps Script でこの連携を行うような方法が公開されていて、自分でも書いて使ってました。これは一度動かしてしまえば大変便利なんですが、インストールの方法はけっこう面倒で、非エンジニアをふくめ会社のみんなに薦めるには少しハードルが高い。

そこで、Google Apps Script を用いて、(初回のインストール手順を除いて)ワンクリックで Google カレンダーと Slack ステータスの連携を行えるウェブアプリを作りました。

GitHub - motemen/gas-google-calendar-to-slack-status-farm

動作イメージ

明らかにワンクリックですね(実際には Slack 側でもう一回クリックする必要がありました)

f:id:motemen:20170515184113p:plain
クリック前

f:id:motemen:20170515184107p:plain
クリック後

動作要件

  • G Suite(Google Apps)のメンバー向け。そうでない場合も使えるかもしれません
  • Slack App として動きます
  • 認証した人の Google アカウントの個人カレンダーから、現在+5分後に進行中のイベントを Slack ステータスに反映します
  • イベントのタイトルによってステータスの絵文字が変わります(Slack おすすめ設定に準じます)
    • デフォルトでは :spiral_calendar_pad: (🗓)になります
    • イベント名に「早退」「遅刻」と入っている場合は :bus: (🚌) になります
    • イベント名に「休」と入っている場合は :palm_tree: (🌴)になります
    • イベント名に「:hospital:」など任意の emoji が入っている場合はそれがステータスに反映されます

設置方法

Apps Script の作成

  1. script.google.com などから新規 Goolge Apps Script を作成。
  2. [Resources] → [Libraries…] メニューより表示されるダイアログに、1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF を追加。(apps-script-oauth2を利用しています)
    • f:id:motemen:20170515182620p:plain
  3. gas-google-calendar-to-slack-status-farmリポジトリより、Code.jsをコピペ。

Slack App の作成

一人で使うスクリプトであれば個人用のトークン(最近はレガシートークンとらしい)で済ますところなのだけど、他のメンバーにも使ってもらうため Slack App として導入します。

  1. Slack API: Applications | Slackより新しい App を作成。
  2. 「OAuth & Permissions」に関して、以下の項目を設定。
  3. Permission Scopes に users.profile:write を追加。
  4. Redirect URLs には、先ほどのスクリプトの OAuth コールバック先として https://script.google.com/macros/d/{スクリプトID}/usercallback を指定。
    • スクリプトIDはスクリプトの [File] → [Project properties…] メニュー → [Script ID] 欄で確認できます
  5. 「App Credentials」の「Client ID」「Client Secret」を、それぞれスクリプトの SLACK_CLIENT_ID SLACK_CLIENT_SECRET として設定。

Apps Script のデプロイ

スクリプトの [Publish] → [Deploy as web app…] メニューより、ウェブアプリとしてデプロイ。

  • 「Execute the app as」は「User accessing the web app」に
  • 「Who has access to the app」は G Suite のドメインのメンバーに公開、などとするとよさそう。

ダイアログに表示されている URL にアクセスすると、ウェブ UI が表示されているのが確認できると思います。「Slack連携する」ボタンをクリックすると1分おきに実行されるトリガが作成されます。カレンダーにイベントを作成するなどして確かめてみてください。

付記

  • スクリプトは Google の OAuth も自動的に利用しますが、その際スクリプト名に「Google」という文字列が含まれていると OAuth アプリ名として利用されない気がしました。
  • スクリプト中の SLACK_LOG_WEBHOOK_URL に Slack の Incoming Webhook の URL を設定すると、ちょっとしたログがチャンネルに流れてきます。

技術的な内容

仕組み

最初にこれを作ろうと思ったとき頭によぎったのは Google Apps Script でやれば(Google 側のユーザ認証やカレンダー情報の取得など)簡単だが、Slack 側のユーザ認証情報や時間ベーストリガの実行権限の管理がうまくおこなえるのか? ということでした。apps-script-oauth2 ライブラリは PropertiesService.getUserProperties() というユーザごとのストレージに OAuth2 トークンを保存できるのですが、1分おきに実行されるトリガがスクリプト作成者の権限で実行されてしまうと、ユーザ別の認証情報にアクセスできなくなってしまうわけです。

結論から言うとこの心配はしなくてよくて、ScriptApp.newTrigger() を使うとそれを実行したユーザのトリガが作られるため、うまいことボタンをクリックしたユーザの権限でステータスの更新のための処理が実行できるのでした。その代わり、スクリプトの所有者からトリガを一覧したり操作したりできません。ここが困りポイントで、現状ではログから設定したユーザを見つけて、声をかけていくしかない……。

TypeScript 型定義ファイル

今回もGoogle Apps Script の TypeScript 型定義ファイルを作った - 詩と創作・思索のひろばで作った型定義ファイルを使ったけど、いくつかミスが見つかったのでとりあえず as any でしのぎつつ Pull Request も送っています

はてな記法 ⇔ Markdownコンバータ(pandoc のはてな記法対応)

最近の若者ははてな記法を書けないらしい……などと言っているだけではアレなのでコンバータを書いてみた。リストを書こうとして見出し(*)になっちゃうんですよね。あるある。

タイトルにあるとおり、pandoc という有名なマークアップコンバータにはてな記法を実装してみた形です。

github.com

フォークした1ブランチとしてソースコードがあるのみで、バイナリの配布とかはしてない。Haskell 製なので Stack をインストール(Homebrew なら haskell-stack)しておいて、make したらビルドできると思います。

pandoc の reader(マークアップの読み取り)および writer(マークアップの書き出し)として hatena を追加しているので、

pandoc -f hatena -t markdown_github < file.hatena

のように引数に指定して記法を変換できます。Markdown と書いたけど、pandoc がすごいので HTML や他のフォーマットにも変換可能。

parsec の思い出

pandoc の記法リーダの実装は parsec というライブラリに依っている。自分は Pugs という Haskell で書かれた Perl6 実装が話題になったころに Haskell でナイーブな JavaScript のインタプリタを書いてみたときに使って、そのとき以来触った覚えはなかったのだけど、意外とハマることも少なくすんなり実装できた。パフォーマンスはともかく。

調べてみたら Pugs は 10 年も前の話で、その頃の知識が今もまだ使えていることになんだか不思議な感じがある。

ミニマルはてな記法

先日のそうだGo、京都。でも話があったらしいが、はてな記法は実装の数だけ存在していて、単純なマークアップの範疇を越える仕事もしているので(:title による自動ページタイトル取得など)簡単に統一することはできないのだけど、そうは言っても実装する人たちの中で共通している認識はあるはずだと思っている。それをミニマルはてな記法と勝手に呼んで、それを実装してみた。公式なものではありません。

できれば仕様を書きたかったのだけど、大変なので、さしあたり以下のサンプルを用意した。これを意図通りに読み書きできるようなものとして実装した。pandoc を使って Markdown に変換したものもあわせて Gist に載せているので、どんなふうに解釈されるかわかりやすいと思う。