block_given?

ジャングル ブロック ナイ アルノハ jump ダケ。CC-BY-SA 3.0

阿吽の呼吸でChatOps、標準入力と標準出力でハンドラがつくれるruboty-aunをつくった

標準入力にチャットの発言をすっと入れる。標準出力をふっと出せばハンドラーの出来上がり。Rubyでハンドラー書かなくてもいい。

f:id:block_given:20141106012733p:plain

使い方

Gemfileに以下を書いてbundle install

gem 'ruboty-aun'

Rubotyと同じディレクトリの下にaunを作って、その中に実行ファイルを置く。例えば、こんな感じ。

$ mkdir aun
$ cat > aun/aun
#!/usr/bin/env php
<?php
$body = trim(fgets(STDIN));
if ($body == 'あ') {
  fwrite(STDOUT, 'うん');
}
$ chmod u+x aun/aun

イデア

なぜ阿吽

阿吽 - Wikipedia

阿は口を開いて最初に出す音、吽は口を閉じて出す最後の音であり、そこから、それぞれ宇宙の始まりと終わりを表す言葉とされた。

今日でひとくぎり

Rubotyプラグインを1ヶ月かけて0b00011111個つくった。バイナリ的にもぞろ目で切りがいいので、毎日作るのはこれで最後にする。明日になればまた書いているかもしれないけど。 次は0b0111日で0b0001個gemをつくるチャレンジしようかな。 Rubotyを書いていて、wsgiのタマネギ画像みたいなbotフレームワークが欲しくなったので、またbotを書くかもしれない。

wsgiのタマネギ

まとめ

Rubybotが書けてとても楽しかった。Ruboty awesome!

Rubotyが信ずる者の言葉にしか耳を貸さなくなるruboty-trust_meをつくった

簡単な名前による認証を提供します。

f:id:block_given:20141104221228p:plain

つくろうと思った理由

いい話

RubotyはRuboty自身のことを信じている

Redisのメモリ使用量を表示するruboty-redis-infoつくった

brainを結構つかうようになったのでRedisの使用率が気になった。

litaからぱくった

f:id:block_given:20141103174857p:plain

わからなかったこと

何MBまで使える、みたいな情報とれないのかな

余談

ruboty-gen g redis-infoすると生成されるgemがダメ。夜気分が乗ったら-対応しよう。

おまえは今までOpsしたChatをおぼえているのか? ruboty-statsをつくりました

rubotyが反応したアクションを覚えていてくれる。

f:id:block_given:20141102153844p:plain

反応したチャットの文言、発言主などを表示できる。

まとめ

Module#prependだいすき

「ちょっとマイクラ鯖の様子みてくる」ruboty-minecraft_statusつくりました

機能的にはblockgiven/minecraft_logged_in_notifierとほぼいっしょ。

> @ruboty minecraft status minecraft.example.com
A Minecraft Server (0/20):
> @ruboty minecraft status minecraft.example.com
A Minecraft Server (1/20): blockgiven

JRubyかくぞ

Minecraftプラグインを書くために環境を整えている。

まとめ

まとめたいことがとくにないひもある

暇なとき、チャットでよおよお! ruboty-yo!!

f:id:block_given:20141101041727p:plain

つかいかた

よ usaboty/yo usabotyとかくとYoが飛ぶよ。

恋の病の人向けの使い方

君のこと好きだよ usabotyでもYoが飛ぶよ。Yoしか伝わらないから安心だよ。

テスト

yo.featureを書いた。

vcrはじめて使ったけどそれなりにべんりだった。use_cassetteのキーの指定の仕方と録音の仕方がキモだと思う。

今回は出来なかったけど

# こういう感じの`shared_context`を定義しておくと便利そう
RSpec.shared_context 'VCR', :vcr do
  around do |example|
    # metadataで指定する、あるいはfull_descriptionを使うとよさそう
    VCR.use_cassette(example.metadata[:cassette]) do
      example.run
    end
  end
end

RSpec.describe 'AKB48', :vcr, cassette: 'akb48' do
  # 〜
end

RSpec.describe 'perfume', :vcr, cassette: 'perfume' do
  # 〜
end

WebAPI

どこでstubするか。シナリオを通して投げるリクエストが決まっているならvcr便利だと思う。 ざっとみた感じ録音したデータには秘密にしておかないとまずいデータも録音されてしまう。 今回は別途Rakefileにタスクを定義して、漏れるとまずそうな部分をマスクしてからコミットした。

APIのクライアントライブラリ

今回はライブラリをつかわず適当に実装した。最低限ひつYoなエンドポイントだけたたける。 自分で作るか、ライブラリ使うかでテストのやりかたが違ってきそう。

ハマったところ

  • api tokenを間違えてなかなかYoできなかった。
  • 無効なapi tokenを送った場合のエラーメッセージから「api tokenが違う」ことが読み取れなかった。

まとめ

Yoではつたわらないこともあるよ

なんでも肯定してくれるruboty-yesを公開した

f:id:block_given:20141031020525p:plain

ハマった

  • RSpecのTurnipを使うRakeタスクの定義
  • Rubotyのreply時のto/fromの扱い
  • Rubotyのテストをどうかくとうまくいくのか考える時間

Turnipのシナリオ

最初シナリオで使う人物名を実在の人物名にしてしまった。 架空の名前を考えてシナリオを書くのは難しい。

Rubotyのテスト

今回は受け入れテストだけ書いてみた。 テスト中で実際にRuboty::Robotを作成し、動かしている。

Ruboty::Adapters::Baseを継承したアダプタを定義すると、最後に定義されたアダプタが使われるようになる。今回はMockアダプタを定義した。Mockアダプタは特に何もしない。

Ruboty::Robotの発言を監視するためRuboty::Robotを拡張するRuboty::Testableモジュールをprependした。今回は、Rubotyの発言の記録を取れればいいので、sayを奪った、それに合わせて最小限のインターフェイスを定義してやった。

saidを直接のぞいてる部分はsaid?で置き換えた方がうまくいきそうだなぁと書き終わってから気づいた。

まとめ

今回は簡単なテキスト処理のようなものなので、受け入れテストのみ書いた。 ハンドラーやアクションの中でもう少し複雑なことをしている場合は、個々のハンドラー/アクションのユニットテストも書いた方がよいかもしれない。

しかし基本的にはRubotyはチャットをインターフェイスにして動いているので、チャットをベースにした受け入れテストをしっかり書くのがいいんじゃないかと思っている。

READMEがそのままテストとして実行できる夢をみた。