ScalaとSlickで発言数順位表示と名言記録をするIRCボットを作りました
【blog.soichiro.orgの閉鎖にともない転載しました】
最近IRCボットを書いたりすることが多いのですが、また汎用的なものを一つ書いてみたので公開します。今回は初めてORMとしてSlick、組み込みDBとしてH2を使ってみましたが。Slickは内部処理がわかりにくいが関数言語的にかける特徴的なORM、H2はSqliteよりも軽快でWebベースのGUIがデフォルトで用意されていて非常に使いやすい印象でした。
今回のビルド可能なソースコードは、GitHubにて公開しています。
今回作ったRanking Ircbotについて
IRCの発言数ランキングと名言の登録、及び登録数のランキングをチャンネルごとに設定できるIRCのボットです。 複数のチャンネルに参加し、kickされても戻ってきたり、 オペレーター権限を与えられている場合、他の参加者にオペレーター権限を分け与えたりする機能があります。
ビルド方法
java(jdk6以上)とsbt(0.12.2)をインストールの上、
$ sbt
> assembly
以上を実行することで、targetディレクトリの中に、ranking_ircbot-assembly-2.X.jarがビルドされます。
使い方
ranking_ircbot-assembly-2.X.jarと同じディレクトリに、 ranking_ircbot_template.propertiesを正しく編集して、 ranking_ircbot.propertiesというファイル名で保存ください。 さらに、ranking_ircbot_empty.h2.dbを ranking_ircbot.h2.dbという名前に変更してください。
irc.address = hostname
irc.channel = #channelname1 #channelname2
irc.nickname = ranking_ircbot
irc.charset = UTF-8
db.url = jdbc:h2:file:ranking_ircbot
db.driver = org.h2.Driver
以上のようにチャンネルはスペース区切りで複数設定することができます。 日本語のチャンネル名は、native2asciiのwebサービスなどを利用して 入力することができます。
設定の後、
$java -jar ranking_ircbot-assembly-2.X.jar
で実行することができます。 またIRCのボットが入っているチャンネルにて
とするとWorking now.とnoticeを返して動作確認をすることができます。
使い方
ranking_ircbotが参加しているチャンネルにて以下のメッセージを打つと様々な機能が利用できます。
hourlyranking>
1時間の発言数ランキングの表示dailyranking>
24時間の発言数ランキングの表示weeklyranking>1週間の発言数ランキングの表示
monthlyranking>
30日間の発言数ランキングの表示yearlyranking>
1年間の発言数ランキングの表示覚えろ:{nickname} {message}
そのチャンネルで{nickname}の名言を保存{nickname} 曰く
そのチャンネルで保存している{nickname}の名言をランダムで発言消して:{nickname} {message}
そのチャンネルで{nickname}で発言登録された{message}を全て削除wiseranking>
そのチャンネルで保存されている名言の個数のランキングを表示ping {ircbot_nickname}
Working now. > {nickname} https://github.com/sifue/ranking_ircbot
と発言します。
以上のような機能を持っています。
Slickについて
今までScalaのORMにSquerylを使っていたのですが、今回はじめて、ScalaQueryの後継でtypesafeが作っているORMのSlickがScala2.10で使えるということで使ってみました。
今までのORMっぽくなく、かなり関数型言語っぽく書けるORMです。結構戸惑ったのは
このようにlist()を一度でも読んでしまうと、count関数がうまく流れないのではと思っていたら、ちゃんとselect count(*)が流れるように最適化されていたりするところが、ちょっとわかりにくかったところでした。
あと、GroupByの書き方がちょっと特殊でした。
のようにタプルで受け取る形式となります。このように短く取り扱おうと思うとタブルで受け取る形式になるので、このへんはうまく書かないとわかりにくくなってしまうかもしれません。確かに短くて済むのですがコードの可読性を保つためにはちょっと工夫が必要かなと思いました。
H2 databaseについて
ダウンロードして、梱包されているh2.shを実行して、dbのURLを入力してログインすると。
以上のようなUIが実行できて、自由に編集することができます。今まで使って来なかったのでこの親切さにおどろきました。すばらしい。
しかも実行速度もsqliteよりも速く、とても気に入ってしまいました。今後もH2は組み込みDBとして利用していければと思っています。
Play2.1でsbtのマルチプロジェクトビルド機能を利用してDDDのレイヤードアーキテクチャを強制する方法
【blog.soichiro.orgの閉鎖にともない転載しました - 2.2でも問題なく動くと思います】
Play2.1でDDDのレイヤードアーキテクチャをプロジェクトに強制して、大規模開発で誰かがうっかりルール違反が起こせないようにする仕組みを紹介します。
レイヤードアーキテクチャについては、じゅんいち☆かとうさんのスライドなどがオススメです。
http://www.slideshare.net/j5ik2o/ss-6227801
元々Play frameworkはMVCで作られることが前提とされていたため、デフォルトでは、
- controllers
- models
- views
というパッケージに全てを入れるようになっており、これらのパッケージは相互参照できるようになっていました。
ただPlay2系になってから、MVCのどの要素も任意の名前空間のパッケージに入れることが可能になったため、DDDの構成をパッケージ名として利用できるようになりました。
- org.hogehoge.ui
- org.hogehoge.application
- org.hogehoge.domain
- org.hogehoge.infrastructure
また、更にsbtの持つマルチプロジェクト機能を用いればサブディレクトリ内に複数のプロジェクトとを存在させ、それら個々に正しい依存関係だけのパスを通してビルドすることができるようになっています。
つまりこれを利用して、ドメイン層からはインフラストラクチャー層のクラスを参照できるが、インフラストラクチャ層からはドメイン層のクラスを参照できず、さらに、IntelliJ IDEA等のコードアシストにも出てこないようにすることができます。つまり、下の層から上の層を参照させないというDDDのルールを強制することができるのです。
なおこのたび紹介する方法は、
https://github.com/sifue/play2-layered-sample
にサンプルコードをpushしてあります。なおIDEはIntelliJ IDEAにしか対応させていません。
まず内容を説明する前に、DDDをplay2ではじめる方は最初に、全てのレイヤをそれぞれのjarにして、mavenリポジトリに入れてしまえば良いと考えるかもしれませんが、実は効率的ではない面もあります。それは、まずIntelliJ IDEAのワークスペースにマルチモジュール用意して、それぞれパスを通して回らないといけないからです。
そのため、jar分割数が増え10以上のモジュール(プロジェクト)を扱うようになると、開発環境構築コストが非常に高くなってしまします。なおEclipseにはpsfというチームプロジェクトセットという機能がありますが、そもそもEclipse自体がScalaのIDEとしておしいという問題があります。
その点、このsbtのマルチプロジェクトビルドを使った方法は、すべてのコードをサブディレクトリに入れて依存関係を構築します。
そして、"play idea"コマンドで、パスを一瞬で通し終えてくれます。逆にこの方法は、サブディレクトリでなくてはいけないのですが、利点として一つのgitプロジェクトで管理することもできるようになり。ニーズがあれば、gitのsubmodule機能などを利用してサブプロジェクトも別リポジトリで管理、それぞれパブリッシュしたり、sbt pacackageやsbt testをすることも可能となります。
ただこの方法、2つだけ制約があって、その2つは、
- UI層とアプリケーション層は分離できない点。これは、テンプレートの仕組みが同じビルド空間にないとコントローラーのクラスから利用できないという制約からきています。
- 次にUI・アプリケーション層を担当するプロジェクトは、play2のプラグインのモジュールとして作る必要があるという点。これは、UI・アプリケーション層ではPlay2のライブラリを参照しなくてはいけないからです。
なお、Play2のプラグインモジュールの作成方法は、
http://www.objectify.be/wordpress/?p=363
を参考にしました。とは言え基本的に、application.confを空にしたただのplayのプロジェクトを作っているだけとなります。
最終的に以下の様なフォルダ構成になります。
そして肝となるproject/Build.scalaの内容は、
Play2.1でレイヤー化アーキテクチャを強制するBuild.scala
のようになります。重要な部分は、settingsにideaのプラグインの設定をそれぞれのプロジェクトに引き継がせることと、ちゃんと一つ一つのプロジェクトの依存関係を定義することとなります。ちなみにdependsOnだけでも大丈夫なのですが、テスト時もサブプロジェクトのテストが実行されるようにaggregateとaggregate in Test := trueも追加してあります。
なおこの方法を拡張すれば、さらにドメイン層をコアドメインと汎用サブドメインにプロジェクト分割したい際にもうまくその依存関係方向の制約をプロジェクトに課すことも可能です。
この設定で、playのideaコマンドによる統合開発環境用の設定ファイルの作成、run起動、プロダクション用のstart起動、リリース用のzipに固めるdistコマンド、testコマンドによるspecs2のテストの実行などもできるようになっています。
また、最初のプロジェクトを作った状態からどのような変更を加えればこのようにするようにできるかもgithubのヒストリを見ればわかりますので、参考にしてみてください。
https://github.com/sifue/play2-layered-sample/commits/master
追伸
play test時にサブプロジェクトのテストまで実行するために、dependsOnに加えてaggregateでもプロジェクトを追加していますが。ファンクショナルテスト(結合テスト)しかしないつもりであれば、dependsOnだけでも大丈夫です。なお、aggregateだけではコンパイルが通りません。(じゅんいち☆かとうさん指摘ありがとうございます)
追伸の追伸
なお、サブモジュール内のspecs2のテストやScalaスクリプトを、IntelliJから実行する際に、コンパイルのエラーが発生する場合があります。それに関しては、以下の図のようにuse external buildのチェックボックスをオフにすることで回避することができます。
では良いScalaライフを!
FF14新生のチャットログを棒読みちゃんで読み上げるツールを作りました
【blog.soichiro.orgの閉鎖にともない転載しました】
プレイ中チャットログを見ずにボス戦をしたり、シャウトの募集待ちを読み上げたり、生放送実況をしながらFF14新生をプレイするために、チャットログを棒読みちゃんに読み上げてもらうツールを作成しました。
ダウンロードはこちらから↓
FF14Rep棒読みちゃん Ver1.0.5
https://github.com/sifue/ff14repbouyomi/raw/master/ff14repbouyomi-1.0.5-jar-with-dependencies.zip
使い方について
使い方は、まずJava7以上をインストール。
http://java.com/ja/download/
以上のサイトを見ながらインストール。
その後、棒読みちゃんをインストールして起動しておきます。
http://chi.usamimi.info/Program/Application/BouyomiChan/
以上のサイトのdownloadのページを見ながらインストールして、起動。
最後にFF14Repをインストールして起動しておきます。
http://xivparser.blogspot.jp/
以上のサイトのdownloadのページを見ながらインストールして、起動。
最初の起動直後に求められるFF14新生のドキュメント>My Games以下の更に二階層下のlogフォルダ設定をお忘れなく。
その後、右上の†のアイコンの設定から、
リアルタイムログ検出をONに。
ログファイル自動更新間隔を0.2秒にしておきます。
最後にこのサイトからダウンロードしたzipを解凍し
ff14repbouyomi-X.X.X-jar-with-dependencies.jar
をダブルクリック。
FF14Repのログフォルダの選択をして、開始ボタンを押します。
プレイヤー名を読み上げるたり、各ログの種類を読み上げるオプションはご随意に。
ちなみによく質問があるFATEやボスやNPCのログはsayに分類されています(わかりにくいっすね)。
なお含むテキストは、そのテキストを含む時だけ読み上げるようになります。空だとすべて読み上げます。また、正規表現で記述することもできます。
実行するとタイトルに実行中と表示されます。
終了はウインドウを終了すると終了します。
では、快適なエオルゼアライフを!
新生FF14攻略情報 エオルゼアガイドhttp://www.dopr.net/sinseiff14kouryaku/%E3%83%84%E3%83%BC%E3%83%AB%E7%B4%B9%E4%BB%8B
以上のサイトにて紹介していただきました~。
【開発者向け】 ソースコードについて
ちなみにソースコードはこちらでMITライセンスで公開しています。
https://github.com/sifue/ff14repbouyomi
言語は簡単なJavaで書かれていますので、少し心得のある方でしたら好きに変更してmavenでビルドし直すことができると思います。
更新履歴
2013/11/04 含むテキストのみを読み上げることができる機能を追加した1.0.5をリリース
Erlangの開発環境をWindows上のCentOS6.4に整える
仕事ではMacを使っているけれども、プライベートで使うPCは大抵ゲームのためにWindowsPCだったりするので、vagrant上のCentOS6.4開発環境を作るための手順をまとめておく。
VirturalBoxをインストール
vagrantをインストール
boxファイルは、
から好きなものを利用する。本番環境でもCentOS6.4を使うつもりなら
CentOS 6.4 x86_64 Minimal (VirtualBox Guest Additions 4.2.16, Chef 11.6.0, Puppet 3.2.3)
このあたりの構成が良さそう。
ターミナルエミュレーターは、
Tera Term
http://sourceforge.jp/projects/ttssh2/
configureするためにgccとは必要になりそうになものはsudu yum install gccで予めインストールしておく。
https://gist.github.com/voluntas/8911384
を参考にインストール。
これでerlコマンドやerlcコマンドが使えるようになる。
あと、vimも整備する。
vimは7.3以上をインストールしたいので
http://qiita.com/muniere/items/0569d05d470c5d3dc51b
をインストール
バージョン管理としてNeoBundleをインストール
https://github.com/Shougo/neobundle.vim
そして以下の設定をvimrcに追加。
erlang開発用に足すvimrc(NeoBundle前提)
を追加して
:NeoBundleInstall
する。
その後、
~/.vim/bundle/vim-erlang-runtime
のtest_syntax.erlがちゃんとシンタックスハイライトで表示されるか確認する。
ちなみに以下のコードはこんなかんじに表示される。
無論、makeの設定もしたので、:makeでシンタックスチェックもしてくれるようになる。とりあえずこれだけあれば最低限の開発はなんとか、大丈夫そう。
ただ、Linux上のvimの開発にこだわらないのであれば、IntelliJ IDEA UtlimateのErlangプラグイン使ったほうが楽そうではある。
個人用にIntelliJ IDEA Utlimate13のライセンスを買うかは悩ましいところ。
まだErlang入門仕立てなので、またビルドツールrebarとの連携が入ってきたら追記していきたい。
Scalaでの切り出したい処理が処理の中間にあるメソッド同士の重複行排除のやり方
最近Scalaを書く人が増えてきたこともあっていろいろ教える機会も増えてきたのですが、その中でよくScala初心者がつまづきやすいポイントである、切り出したい処理が、処理の中間にあるメソッド同士の重複行排除のリファクタリングの例を書こうと思います。
重複のあるサンプルコードとしてはこのような感じになります。
例として、ランダムに文字列のテンプレートを選択してその中にメッセージを埋め込んだあと、そのバイト数と内容を出力するメソッドと、その文字数と内容を出力するメソッドを用意してみます。
RandomTemplateProviderはテンプレートをランダムに渡すオブジェクトです。2つのメソッドは見ての通り仕様をそのまま実行していますが、printByteLengthAndContentメソッドとprintCharLengthAndContentメソッドには4行の重複行が含まれています。
こういう切り出したい処理が処理の真ん中に挟まっている場合の重複行排除は、関数を第一級オブジェクトでかけるScalaではこのようになります。
切り出したい処理が処理の中間にあるメソッド同士の重複行排除の例
関数をオブジェクトとして扱うことに慣れない方は、一瞬ん?とおもうかもしれませんが、このコードでは、printTargetLengthAndContentというメソッドを最下部で新たに定義し、そこでは、targetLengthProviderという関数を受け取って実行するという処理をしています。
この渡すtargetLengthProvider関数の中に切り出したい関数を元々のメソッドに設定すればよく、Scalaで簡単に匿名関数を作ることができる{}という記法を用いて上記のように表現してやることができます。これで見た目もわかりやすく存在していた重複行を排除することができました。
これでCPDなどのチェッカーなどに引っかかった時も柔軟に対応することができます。実際の業務のコードではこの重複行の長さが10行を超えるものである場合がほとんどですが、ぜひ応用にチャレンジしてみてください。
ちなみに、Java8になったことで、このような関数オブジェクトを使った重複行排除のリファクタリングが、Javaでもずいぶん書きやすくなっています。その例はまたの機会に。
Developers Summit 2014 で「Play2/Scalaでドメイン駆動設計を利用した大規模Webアプリケーションのスクラム開発の勘所」という内容で発表してきました
あまりにタイトルが長すぎるだろうと各所から突っ込まれ、あまりにも詰め込んだ内容で発表してしまったとちょっと反省しています。
お話としては、現在ニコニコ生放送の内部をPHPからScalaへ書きなおしているよ、というお話でした。
発表内容はこちら。
これらの内容は、これからScalaを使ってWebサイトを構築、運営してみようとしているリーダーさん向けに書いたものとなっています。Play2/Scalaやドメイン駆動設計、またスクラム開発の導入への足がかりにの情報となっていれば幸いです。
こんな雪の中わざわざ聞きに来てくださった皆様、そしてこの書き直しを着想するにあたってお世話になった特にじゅんいちかとうさん(id:j5ik2o)さんには多大な感謝を申し上げます。
追伸
もともと blog.soichiro.org にブログを移転していたのですが、もし大量にアクセスが有った時にさくらVPSだとさばけないと思いこちらに記載することとしました。