Chromeで「サードパーティのCookieとサイトデータをブロックする」をオンにしているとはてなブログにログイン出来ない
例外的にblog.hatena.ne.jpをサードパーティ許可したらログインできるようになったが、釈然としない。
scala irc botでのbotの作り方
はじめに
この記事は、私がGitHubで公開しているscala-irc-botというプログラムの使い方とボットの書き方のチュートリアルです。 ScalaでIRCボットを書きたいという需要が非常に少ない目的のために書きました。
目次
scala irc botの紹介
scala irc botってなんですか
https://github.com/scala-irc-bot
私がScalaでirc botを書けるように作成しているプログラムです。 実際にIRCに接続するのにはPircBotというJava製のIRCクライアントを使用しています。
現在の最新バージョンは0.2.0-SNAPSHOTです。バージョンは大きく設計が変わるときに更新されます。プラグインに影響のない修正ではバージョンを上げません(mavenリポジトリの更新が面倒だからです)。
現在の使い方は sbt run
によって起動させるのを推奨しています。
性質的に常時起動しておくプログラムなのでデーモンのように使うほうがいいのかなあ。。。
irc botってなんですか
IRCでの誰かの発言などのイベントなどに反応して発言したり作業したり愛したり恋したりしてくれるプログラムです。 ときには喧嘩して殴りあったりするけれど、でもそんなお前のこと、そんなに嫌いじゃないぜ?っていう人格を持っています。
ircってなんですか
つ RFC1459
デプロイ方法
次のものを用意してください。
- sbt
- git
git clone
本体のコードはgithubで管理しているので、cloneで持ってきます。
git clone https://github.com/scala-irc-bot/scala-irc-bot.git
設定ファイルの記述
cloneしたディレクトリに移動し、configディレクトリの中に、Config.scalaというファイルを作成します。
Config.scala
import net.mtgto.irc.Config import net.mtgto.irc.config.BotConfig new Config { val hostname = "irc.example.com" // IRCサーバの名前 val port = 6667 // IRCサーバのポート val password = None // 必要ならSome("password")のように記述する val encoding = "utf-8" // 使用するエンコーディング val messageDelay = 2000 // メッセージ間の遅延(ミリ秒) val timerDelay = 60000 // タイマーイベント間隔(ミリ秒) val nickname = "scala-irc-bot" // ボットのニックネーム val username = "scala-irc-bot" // ボットのログイン名 val realname = "mtgto@example.com" // ボットのリアルネーム // channels val channels = Array("#mtgto", "#test") // JOINさせたいチャンネル // bots val bots = Array[(String, Option[BotConfig])]( // ここにプラグインの設定を記述する ) }
起動する
コンソールからsbt
で起動します。
sbt run
(初回のみ)コンパイルが実行され、設定ファイルやネットワークなどに問題が起きなければ、しばらく経つとIRCサーバにscala irc botが接続してきます。
ですが今のままではボットプラグインを何も入れてないので、何もしてくれません。
コンソール画面にexit
と入力して終了させましょう。
プラグインの作成方法 (シンプル)
ここからはまずはシンプルなプラグインを作成していきます。 ここでいうシンプルなプラグインというのは、
- 設定ファイルでボットプラグインごとのオプションを設定できない
っていう前提のものです。下の方にオプションを使う方法も載せてあります。
Scala + sbtで作る
今回作る環境は、
- sbt (バージョンはユーザの環境に依る)
- Scala 2.10.0
- PircBot 1.8.0
です。
最小構成では build.sbt
Echobot.scala
の2ファイルで構成されます。
echobot/build.sbt
// -*- scala -*- name := "EchoBot" organization := "net.mtgto" version := "0.1.0-SNAPSHOT" scalaVersion := "2.10.0" resolvers += "mtgto repos" at "http://scala-irc-bot.github.com/scala-irc-bot/maven/" libraryDependencies := Seq( "net.mtgto" %% "scala-irc-bot" % "0.2.0-SNAPSHOT" % "provided" ) scalacOptions ++= Seq("-deprecation", "-unchecked", "-encoding", "UTF8")
echobot/Echobot.scala
package net.mtgto import net.mtgto.irc.{Bot, Client} import net.mtgto.irc.event._ /** * 受け取ったメッセージをNOTICEで送り返すボット */ class Echobot extends Bot { /** * 誰かがPRIVMSGを書いた時に通知される */ override def onMessage(client: Client, message: Message) = { // メッセージが送信されたチャンネルに同じメッセージをNOTICEで送り返す client.sendNotice(message.channel, message.text) } }
ファイルを置いたら、
sbt package
と実行すると、 target/scala-2.10.0/echobot_2.10.0-0.1.0-SNAPSHOT.jar
が作成されます。
このjarファイルがコンパイルされたプラグインです。
プラグインをインストール
まず、作成した echobot_2.10.0-0.1.0-SNAPSHOT.jar
を scala-irc-bot/bots
フォルダの中に置いてください。
次に config/Config.scala
にボットプラグインの設定を記述します。
val bots = Array[(String, Option[BotConfig])]( // ここにプラグインの設定を記述する ("net.mtgto.Echobot", None) )
sbt run
すると画像のようにこちらの発言をNOTICEで繰り返してくれるようになります。
botテンプレートを使う (g8)
giter8用のテンプレートを作ってあるので、これを使うこともできます。
g8 scala-irc-bot/bot
version [0.1.0-SNAPSHOT]: organization [com.example]: net.mtgto name [IRC Bot Project]: EchoBot
こちらは先ほどの手順で作成した時に加えて、テスト用にSpecs2、ビルド用にsbt-assemblyの設定をしてあります。 慣れてきた場合や他ライブラリに依存するプラグインを作るときにはこちらをおすすめします。
プラグインの作成方法 (設定可能)
設定ファイルでボットプラグインごとのオプションを設定することができます。
設定ファイルに書いたオプションを読み込むには、net.mtgto.irc.config.BotConfig
を実装したクラスを作り、そのオブジェクトをプラグインのメインクラスのコンストラクタにもたせてあげればよいです。
実例を示してみます。今回は設定ファイルに書いたキーワードが書かれた時だけ反応するようにしてみましょう。 KeywordEchobotを作成します。
KeywordEchobot.scala
package net.mtgto import net.mtgto.irc.{Bot, Client} import net.mtgto.irc.event._ import net.mtgto.irc.config.BotConfig /** * BotConfigを実装したクラスを定義する必要がある。 */ case class KeywordEchobotConfig( val keywords: Seq[String] ) extends BotConfig /** * 特定のメッセージをNOTICEで送り返すボット * * コンストラクタでEchobotConfigを受け取る */ class KeywordEchobot(val config: KeywordEchobotConfig) extends Bot { /** * 誰かがPRIVMSGを書いた時に通知される */ override def onMessage(client: Client, message: Message) = { if (config.keywords.contains(message.text)) { // メッセージが送信されたチャンネルに同じメッセージをNOTICEで送り返す client.sendNotice(message.channel, message.text) } } }
これを先ほどと同じように sbt package
でビルドして、target/scala-2.9.2/keywordechobot_2.10.0-0.1.0-SNAPSHOT.jar
を scala-irc-bot/bots
にコピーします。
あとは config/Config.scala
に設定を書いてあげます。
val bots = Array[(String, Option[BotConfig])]( ("net.mtgto.Echobot", Some(net.mtgto.KeywordEchobotConfig(Seq("こんばんは", "おはようございます")))) )
Seqに好きな言葉を列挙してあげます。
あとは sbt run
すると、設定ファイルにある言葉が書かれた時にだけ応答してくれるようになります。
まとめ
簡単でしたが、scala irc botの導入方法とプラグインの作成方法を書きました。 多分ここまで読んでいる方はいらっしゃらないと思うのですが、さらにプラグインを作ってみたいという奇特な方がいらっしゃるようでしたらこの上なく幸せです。 まだサンプルプログラムが少ないのですが、私も幾つかプラグインを作っているのでよろしければそれを見てみてください。
CocoaPodsでGHUnit + OCMockなiOS開発環境を構築する
なにこれ
新しいプロジェクト作るたびにいつも構築手順を忘れてるのでメモ。 おまけでコンソールからのテスト実行(Jenkinsとの統合が目的)のやり方も書いた。
対象者
- Objective-CによるiOS開発者
- CocoaPodsを知っている・使いたい
- GHUnitを知っている・使いたい
- (JenkinsでCIしたい)←必須じゃない
検証環境
2012年12月9日時点で最新のもの。
手順
1. Xcodeでプロジェクト作成
Unit TestはGHUnitを使うので不要。
このドキュメントでは MyProject
とする。
2. 新しいターゲット作成
プロジェクト設定を開いて、テスト実行用のターゲットを作成する。
ターゲットの種類はiOSのEmpty Application、名前は Tests
にしておく。
名前は変更してもいいけど、以下の説明で Tests
と出てきたら自分で読み替えること。
自動生成されるファイルのうち、次のものだけ残して全部消す(ファイルごと)
Tests-Info.plist
InfoPlist.strings
main.m
Tests-Prefix.pch
3. Podfile作成
MyProject.xcodeproj
と同じ所に Podfile
を作成する。
platform :ios, '5.0' pod 'AFNetworking', '~> 1.0.1' pod 'CocoaLumberjack', '~> 1.6' target :Tests, :exclusive => true do pod 'GHUnitIOS', '~> 0.5.5' pod 'OCMock', '~> 2.0.1' end
一行目でiOS 5.0以上を指定しているが、実際には作成するプロジェクトに合わせて指定する。
AFNetworkingとCocoaLumberjackは実際に作ったPodfileから取ってきただけのただのサンプル。実際に必要な物を指定して欲しい。
このとき target :Tests
を2.で作ったターゲット名にするのを忘れないこと。
終わったらコンソールからworkspaceを作成してもらう。
pod install
4. xcodeproj閉じてxcworkspace開く
両方同じxcodeprojを参照するのでわけわからないことになる前に xcodeproj
を閉じる。
5. ターゲット Tests
の Build Settings
いじる
Other Linker Flags
に -ObjC
-all_load
を追加する。
俺の環境では -ObjC
はすでに追加されていた。
6. main.m
いじる
// // main.m // Tests // // Created by <ユーザ名> on 12/8/12. // Copyright (c) 2012 <組織名>. All rights reserved. // #import <UIKit/UIKit.h> int main(int argc, char *argv[]) { @autoreleasepool { return UIApplicationMain(argc, argv, nil, @"GHUnitIOSAppDelegate"); } }
ここまでやってiPhone Simulatorで起動するとGHUnitのテスト実行画面が表示される。
7. ユニットテスト作ってみる
GHUnit
ここまでうまくいってるか確認するために一個テスト作ってみる。
Tests
に一個Objective-Cのクラスを作る。
GHUnitのガイド にあるコードのままだとコンパイルが通らないのでちょいと手直し。
MyTest.h
#import <GHUnitIOS/GHUnit.h> @interface MyTest : GHTestCase @end
MyTest.m
#import "MyTest.h" @implementation MyTest - (void)testStrings { NSString *string1 = @"a string"; GHTestLog(@"I can log to the GHUnit test console: %@", string1); // Assert string1 is not NULL, with no custom error description GHAssertNotNil(string1, nil); // Assert equal objects, add custom error description NSString *string2 = @"a string"; GHAssertEqualObjects(string1, string2, @"A custom error message. string1 should be equal to: %@.", string2); } @end
修正前はGHAssertNotNULLを使ってたのでGHAssertNotNilに変えた。
もっかいiPhone Simulator起動してみてテストできることを確認する。
OCMockも確認する
MyMockTest.h
#import <GHUnitIOS/GHUnit.h> #import <OCMock/OCMock.h> @interface MyTest : GHTestCase @end
MyMockTest.m
#import "MyMockTest.h" @implementation MyMockTest - (void)testMock { id mock = [OCMockObject mockForClass:[NSString class]]; [[[mock stub] andReturnValue:OCMOCK_VALUE((NSUInteger){100})] length]; GHAssertEquals(100U, [mock length], @"ocmock works"); } @end
iPhone Simulator起動してみてテストできることを確認する。
8. コンソールからテスト実行してみる
Jenkins用なんで興味ない人はスルー。 基本は GHUnitのガイド 通り。
i. シェルスクリプトを取ってくる
xcodeproj, xcworkspaceがあるところで以下を実行。
wget https://raw.github.com/gabriel/gh-unit/master/Scripts/RunTests.sh wget https://raw.github.com/gabriel/gh-unit/master/Scripts/RunIPhoneSecurityd.sh
ii. テスト実行時にスクリプトを実行するようにする
プロジェクト設定内のTests
のBuild Phases
を開き、Add Build Phase
-> Add Run Script
を選択。
入力欄にsh RunTests.sh
と入れる。
iii. Makefile
GHUnitのドキュメントにはworkspaceのときの例がないのでそのままだと動かない。 適当に作ってみる。
clean: -rm -rf build/* test: GHUNIT_CLI=1 xcodebuild ONLY_ACTIVE_ARCH=NO -workspace <xcworkspaceファイルへのパス> -scheme Tests -configuration Debug -sdk iphonesimulator build
ワークスペースへのパスに書き換えるのを忘れないこと。 連続空白に見えるところはタブ文字にすること。
iv. (Base SDKが6.0のときのみ) main.mの修正
2012年12月9日現在、iOS SDKが6.0だと、コンソールから動かせない問題がある(GHUnitのIssue at GitHub)。 暫定措置だが一番下のgfxさんのコメント通りにmain.mを書き換えるとコンソールから動かせるようになる。
v. テストを実行する
make test
echo $?
して0だったら、おめでとう。すべてのテストをパスしたぞ!
9. Jenkinsからテスト実行
まず前章で作ったRunTests.sh
, RunIPhoneSecurityd.sh
, Makefile
をgit commitしておく。
公開前提のプロジェクトだと、git cloneしたユーザにpod install
を実行させるのでxcworkspaceをソースコードリポジトリ管理しないと思う。
なのでその流儀に則り、Jenkinsでもpod install
することにする。
i. ジョブを作る
名前はMyProject
にしてみた。フリースタイル・プロジェクトを選択。
ii. 設定
ソースコード管理システムでソースの位置を指定する。
俺はローカルホストにJenkinsを立ててるので、GitのRepository URLがfile:///
からはじまる。
ビルドに シェルの実行
を追加する。
WORKSPACE_FILE=MyProject.xcworkspace if [ ! -d "$WORKSPACE_FILE" ]; then pod install open -R "$WORKSPACE_FILE" echo "We need to init the workspace file. Please try re-run test after you open workspace file." exit 1 fi make clean && WRITE_JUNIT_XML=YES JUNIT_XML_DIR=tmp/test-results make test
最初のビルドではxcworkspaceの初期化が終わっていないため、
xcodebuild: error: The workspace 'MyProject' does not contain a scheme named 'Tests'.
と失敗してしまう。
少し悩んだが、ユーザにXcodeでxcworkspaceを開かせることにした。 一度Xcodeで開いてしまえばもうこの作業はやらなくてOKだ。
※open -R <ファイルパス>
はFinderでファイルを表示するコマンド。
ビルド後の処理
から JUnitテスト結果の集計
を選び、tmp/test-results/*.xml
と指定する。
ビルドしてみると一回目は失敗すると思う。 xcworkspaceがFinderで表示されていると思うので、ダブルクリックして初期化してから再度ビルドすればテストが実行されるはずだ。
このへんはバッドノウハウなんで、もっといい方法あるって人は教えて欲しい。
サンプル
https://github.com/mtgto/CocoaPodsSample
ここまでの説明があってるかの確認のために作ってみた。
参考
全部英語のページ。