Hatena::ブログ(Diary)

しふーのブログ このページをアンテナに追加 RSSフィード Twitter

2013年03月12日

2013年03月04日

Twitter検索結果をIRCにnoticeで転送し、閾値を超えるとmessageするボット

Scala2.9→2.10に移行するにあたって、公開することで誰かが使えるかもしれないScalaのツールがあったので、GitHub公開しましたTwitter APIも1.0の廃止が近いので1.1への対応をしてあります


https://github.com/sifue/twisearch_ircbot


使う用途は主にIRC上でのtwitter監視ですねw 内部的にStreaming APIではなくRESTのSearch APIを使っているので、ANDやOR、その他の検索指定演算子を利用することができますhttp://blog.fkoji.com/2009/10191119.html の解説が丁寧です。


なおScala2.10といいつつ、akkaへの移行が大変だったりとか、長期間検証をしなくていはいけないとかがあり、こいつはactorをそのまま使っています。build.sbtに

libraryDependencies <+= scalaVersion("org.scala-lang" % "scala-actors" % _)

を書くことでactorをそのまま使い続けられますid:xuweiさん、情報ありがとうございました。

なお内部的には、twitter4jとsircを梱包しており、assemblyコマンドビルドすることでjava -jarコマンドで実行できるjarになります

$ git clone git@github.com:sifue/twisearch_ircbot.git

を利用して、思い思いにコードを変更してご利用ください。


ビルド方法は、以下のとおり


ビルド方法

javaとsbtをインストールの上、

$ sbt
> assembly

これでtargetディレクトリの中に、twisearch_ircbot-assembly-2.0.jarビルドされます

使い方

twisearch_ircbot-assembly-2.0.jarと同じディレクトリに、 twisearch_ircbot_template.propertiesを正しく編集して、 twisearch_ircbot.propertiesというファイル名で保存ください。

irc.address = hostname
irc.channel = #channelname
irc.nickname = twisearch_ircbot
irc.charset = UTF-8
limitCount = 3
intervalSec = 60
keyword = #MT2
messageFormat = interval:%1$s keyword:%2$s count:%3$s
noticeFormat = @%1$s %2$s %3$s
consumerKey = consumerKey
consumerSecret = consumerSecret
accessToken = acessToken
accessTokenSecret = accessTokenSecret

twisearch_ircbot.propertiesの内容のうち、consumerKey、consumerSecret、accessToken、accessTokenSecretはTwitter Developpers https://dev.twitter.com/ より、ログインの後、アプリケーション作成してaccessTokenを発行してご利用ください。

なお日本語などを入れたい場合には、javaのnative2asciiコマンドを利用してascii化する必要がありますhttp://symfo.web.fc2.com/js-sample/jq/sample2.html 以上のようなサイトでも変換できます


設定の後、

$java -jar twisearch_ircbot-assembly-2.0.jar

で実行することができます。 またIRCボットが入っているチャンネルにて


ping nickname

とするとWorking now.とnoticeを返します

コードの中身

メインルーチンは、

TwitterSeacher.scala

  def act() = loop {
    val query = new Query
    query.setQuery(keyword)
    query.setSinceId(maxId)
    query.setResultType(Query.RECENT);
    val tweets = twitter.search(query).getTweets().reverse
    if(maxId != 0L) tweets.filter(t => t.getId() > maxId).foreach(sendNoticeToIRC)
    val count = tweets.filter(t => t.getId() > maxId).size
    if(count > limitCount && maxId != 0L) sendMessageToIRC(count)
    tweets.foreach(t => {if(t.getId() > maxId) maxId = t.getId()})
    TimeUnit.SECONDS.sleep(intervalSec)
  }

これだけで表現できています。あとは設定の読込と例外ハンドルだけ。やっぱりScalaは短く書けて良いです。

2013年03月02日

Scala2.9から2.10への移行作業の健忘録

ただの作業ログです。

build.sbtのscalaVersionを2.10.0に変更

scalaVersion := "2.10.0"

以上のようにする。

Seq#firstをSeq#headに置換

盲目的に置き換え。

Squerylを2.10対応の最新バージョンに。でもリポジトリURLおかしいので直接追加

libraryDependencies  ++=  Seq(
  "org.squeryl" %% "squeryl" % "0.9.5-6" from "http://repo1.maven.org/maven2/org/squeryl/squeryl_2.10/0.9.5-6/squeryl_2.10-0.9.5-6.jar",
  "mysql" % "mysql-connector-java" % "5.1.21"
)

actor使えなくなるのでakkaへの乗り換え。実装量大。

object actors is not a member of package scala

[error] import scala.actors.Actor

悲しい...。build.sbtに

resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"
 
libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.1.1"

を追加して、あとはakkaのAPIを見ながら実装していきます

というかActorの作り方も、実装の仕方や例外のハンドリングなんかも基本全然違うのでakkaに合わせて書きなおさないと、変な感じになってしまう。というか書きなおしたほうが早い。


まとめ

結構コード量があったこと、元々Actorを使いたくてScalaを選んでいたところもあるので、2.9からの移行はそれなりに大変でした。というか全部終わらず、無理にバージョンアップさせる必要はないと感じました...。辛すぎる。せめてコードコンバーターとかあれば。


まだ生まれて10年経ってない言語の辛さだなぁ。まだ2.11と3.0でも大きく変わりそうだし。しゃーなし。

2013年02月24日

ssh上でマウススクロールも使える大規模PHP開発向けvim+tmux環境の構築

全体で数百万行、1ファイル1万行超のPHPファイルも一秒以内で開き、開発していくことのできる大規模開発向けのvim+tmux環境を紹介しようと思います。この設定この環境半年ぐらい安定して利用できています(無論そんな1万行あるファイルや数千行で複雑性循環度500超のメソッド作るなよという話もあるんですが、すでに存在する魔獣とは向き合わなければならないのです...)

なので数百万行レベルの大規模開発となると重すぎて使えない設定やプラグインもあります。そのようなものはきちんと外してあります(PHPの関数折りたたみ機能、デフォルトのPHPシンタクスハイライトneocomplcache.vim、ツリーの構成に時間のかかるproject.vimなど)。

基本的にはターミナルエミュレーターとして、macならばiTerm2、windowsならばTeraTermまたはPuttyを利用することを想定しています

ただ自分自身は、普段はチームでのペアプロ環境維持のためにSublimeText2を利用しており、ssh上で作業する時にのみvimを利用しています。基本的にはマルチカーソルなど独特なものを除きSublimeText2でできることは大抵vimでもできるようにしてあります


スクリーンショットはこのような感じです。

f:id:sifue:20130224220402p:image

以上の例では、上のペインではvimを塋割で利用して、下にも2つペインを用意して、一つはSymfony2phpunitテストの実行、もうひとつはtopの監視をしています


実際に現在自分が利用しているtmux及びvimの設定の全体は、

https://github.com/sifue/dotfiles/blob/master/.tmux.conf

https://github.com/sifue/dotfiles/blob/master/.vimrc

以上のようになっています


なお、仮想端末になぜscreenでなくtmuxを使うかというと、既存セッションへのアタッチが高速(1秒以内)であること、マウス操作が優秀なこと、単一セッションを複数のマシンからデフォルトで使えることなどがあります。(screenでも設定で複数マシンからというのはできるそうですが...)


最終的にはssh上からの利用で以下のようなことができます


基本的にレンタルサーバーなどでも利用できるようにホームディレクトリ以下にローカルインストールする前提で~/local以下にインストールします。サーバー自体にインストールされる方は、~/localを/usr/localと読み替えて下さい。

そのため、利用しているシェルで~/local/binと~/local/libにパスを通してください。

特に自分の使っているシェルがわからないよという方は、デフォルトシェルbashパスを通すように、

$ echo "export PATH=/usr/local/bin/:/usr/local/lib/:\$PATH" >> $HOME/.bashrc
$ source  $HOME/.bashrc

以上を実行して始めて頂ければと思います


説明の順番は

  1. インストールと使い方
  2. 大規模開発の際に使えるvimテクニック

となっています


インストールと使い方

tmuxのインストール

まずはtmuxをインストールします。

http://web.sfc.keio.ac.jp/~t10078si/wpx/?p=615

を参考に。libeventの適切なバージョンが無いこともあるので一緒にインストールしていまいます

$ cd
$ mkdir -p ~/local/source
$ cd ~/local/source
$ wget http://downloads.sourceforge.net/project/tmux/tmux/tmux-1.7/tmux-1.7.tar.gz
$ wget https://github.com/downloads/libevent/libevent/libevent-2.0.17-stable.tar.gz
$ tar zxvf tmux-1.7.tar.gz
$ tar zxvf libevent-2.0.17-stable.tar.gz
$ cd libevent-2.0.17-stable
$ ./configure --prefix=$HOME/local
$ make
$ cd ../tmux-1.7
$ /configure --prefix=$HOME/local CPPFLAGS="-I$HOME/local/include -I$HOME/local/include/ncurses" LDFLAGS="-static -L$HOME/local/include -L$HOME/local/ncurses -L$HOME/local/lib"
$ make
$ make install
$ cd ~
$ wget "https://raw.github.com/sifue/dotfiles/b14f380ad667bc02a1fcad402d2cbf4a3eb0e36a/.tmux.conf"
$ tmux

これでOK。設定はgithubにおいてあるものを取得して早速起動していますセッションを抜けるのには、ctrl+t d、また引き続き続けるにはtmux aコマンドでOKです。

詳しい設定の内容、各種ショートカットの説明は以下の通り。

~/.tmux.conf

# Prefix
set-option -g prefix C-t
unbind-key C-b
bind-key C-t send-prefix

## disable ESC delay
set -s escape-time 0

# View
set -g status-interval 1
set -g status-left-length 16
set -g status-right-length 50

set -g status-bg black
set -g status-fg white
set -g status-left '#[fg=cyan,bold][#14H:#S]#[default]]'
set -g status-right '|#[fg=magenta,bold]#(load.sh)#[default]| #[fg=blue,bold][%a %m/%d %H:%M:%S]#[default]'
set -g message-attr bold
set -g message-fg white
set -g message-bg red

set  -g pane-active-border-fg cyan
set  -g pane-active-border-bg black
setw -g window-status-current-fg blue

set-window-option -g mode-bg white
set-window-option -g mode-fg black
set-window-option -g window-status-fg white
set-window-option -g window-status-bg black
set-window-option -g window-status-current-bg black
set-window-option -g window-status-current-fg green

# Option
set-window-option -g utf8 on
set-window-option -g mode-keys vi
set-window-option -g automatic-rename off
set-window-option -g mode-mouse on
set-window-option -g mouse-resize-pane on
set-window-option -g mouse-select-pane on
set-option -g base-index 1

# KeyBindings
unbind ^C

bind r source-file ~/.tmux.conf; display-message "Reload Config!!"

bind c new-window
bind p previous-window
bind n next-window
bind t last-window

bind k kill-pane
bind K kill-window
bind y copy-mode
bind P paste-buffer

ショートカットですがキーインはCtrl-tになっています

Ctrl-tを入力したい際には、Ctrl-t Ctrl-tです。


機能ショートカット
横分割Ctrl-t "
縦分割Ctrl-t %
ペインを除去Ctrl-t k
ペインを移動Ctrl-t o
ペインを交換Ctrl-t Ctrl-o
セッションを抜けるCtrl-t d
セッション再開コマンドでtmux a
ウインドウ作成Ctrl-t c
ウインドウを除去Ctrl-t K
ウインドウ名を編集Ctrl-t ,
次のウインドウCtrl-t n
前のウインドウCtrl-t p
好きな番目のウインドウCtrl-t 数字
直前のウインドウCtrl-t t
マウスで選択したバッファを貼り付けるCtrl-t P
設定を読み込むCtrl-t r
ショートカット一覧を見るCtrl-t ?

こんな感じの設定になっています。詳しくはCtrl-t ?で起動するショートカット一覧を見ててみてください。もちろんタイトルや色なども自由に設定することができます


gitとctagsとvimのインストール

http://d.hatena.ne.jp/sifue/20120406/1333738754

を参考にしています。gitは各種vimのプラグインクローンしてくる際に必要だったりするので、入れておきます。また、ctagsの日本語版も利用するのでインストールしておきます

$ mkdir -p ~/local/source
$ cd ~/local/source
$ wget http://git-core.googlecode.com/files/git-1.8.1.3.tar.gz
$ tar zxvf git-1.8.1.3.tar.gz
$ cd git-1.8.1.3
$ make prefix=$HOME/local
$ make prefix=$HOME/local install
$ cd ..
$ wget http://hp.vector.co.jp/authors/VA025040/ctags/downloads/ctags-5.8j2.tar.gz
$ tar zxvf ctags-5.8j2.tar.gz
$ cd ctags-5.8j2
$ ./configure --prefix=$HOME/local
$ make
$ make install
$ cd ..
$ wget ftp://ftp.vim.org/pub/vim/unix/vim-7.3.tar.bz2
$ tar -jxf vim-7.3.tar.bz2
$ cd vim73
$ ./configure --enable-multibyte --enable-xim --enable-fontset --with-features=big --prefix=$HOME/local
$ make
$ make install
$ wget "https://raw.github.com/sifue/dotfiles/2e722bb2e186ace5ca8f1587cae86d45a99df83b/essential/.vimrc"
$ mkdir -p ~/.vim/bundle
$ export GIT_SSL_NO_VERIFY=true
$ git clone https://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim

最後にある程度の設定がしてある、.vimrcを取得し、neobundleをgitでインストールして完了です。

まず、vimを起動して、:NeoBundleInstallと入力して、必要なプラグインインストールしましょう。

$ vim
:NeoBundleInstall

無事インストールが終われば、それぞれのプラグインの全機能を使うことができます

基本的には各プラグインの使い方は、各webサイトの最新や、~/.vim/bundlesの中の各プラグインフォルダ内にあるドキュメントを参照お願いします。ちょっと説明をすると


neobundle

基本的には、.vimrcにインストールしたいgithubおよびvim online上のプラグインプロジェクト名を記述して:NeoBundleInstallを実行する使い方しかしません。プラグインを最新のものバージョンアップする際は、:NeoBundleInstall!、アンインストールする際は、設定を消した後に:NeoBundleCleanを実行するだけです。

プラグイン管理されてると、簡単にいろんなプラグインの相性を試せるので本当に楽です。


unite

下の.vimrcで設定しているショートカット(ファイルなら;uf、履歴なら;umなど)で、各種リソースを開くことができます

起動後、文字を入力するとマッチするものに絞りこまれますが、Escしてカーソルを動かし、tabを押して実行したいコマンド選ぶモードにいくこともできますキャンセルはqとなっています。ちなみに絞込み時には*を利用したワイルドカードも利用できます。大規模プロジェクトでは複数階層検索する**/を入力すると大抵落ちるのでそれだけは注意です。

詳しくは、

https://github.com/Shougo/unite.vim/blob/master/doc/unite.txt

を参考に。


snipMate

PHPの各種スニペットをtabキーで展開することができます

たとえばforと入力してtabキーを押すと

for ($i = 0; $i < count; $i++) {
     // code...
}

のように展開されます

~/.vim/bundles/snipMate/snippets

以上のフォルダ内に利用できるスニペットの一覧が入っています

自作スニペットも登録することが可能です。

詳しくは、

http://www.vim.org/scripts/script.php?script_id=2540


ctrlp

Ctrl+pでカレントフォルダ以下のファイルをファジー検索をすることができます

まさにSublimeText2のCtrl+pと同じ役割となっていますUniteよりもファジーに検索してくれ巨大なプロジェクトにおいても高速です。


unite-outline

下記に説明してあるctagsコマンドでtagsファイル作成の後、設定したショートカット(Ctrl+o)でメソッド一覧などを表示してくれます


vcscommand

:VCSで始まる様々なバージョン管理システムの機能を利用することができます

詳しくは、

http://www.vim.org/scripts/script.php?script_id=90

特に:VCSLogと:VCSBlame、:VCSDiffはよく使うのではないかと思います


マウススクロールの使い方について

説明は不要かと思いますが、tmuxのペインの区切り、ペインの選択、vimのタブ、vimの文章、ダブルクリックでvimの単語編集でき、マウススクロールも効くのではないかと思いますトラックパッドや慣性スクロールをつかっていると、でかいファイルでもスルーっとなめらかにスクロールできます


.vimrcについて

なお~/.vimrcの内容は以下のようになっています。それぞれの設定の説明に、どのような意味なのか、どのようなショートカットで読み出せるかコメントで書いてありますので確認ください。

ほとんどのPHP開発で、必要な設定になっているのではないかと思います。なお、でかいファイルを開くのに障害になる設定や、JavaScriptHTML用のプラグインや設定は省いてあります

"VimをなるべくVi互換にする
set nocompatible

""""""""""" NeoBundle設定  """""""""""{{{
" https://github.com/Shougo/neobundle.vim
" インストール
" $ mkdir -p ~/.vim/bundle
" $ export GIT_SSL_NO_VERIFY=true
" $ git clone https://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim
" :NeoBundleInstall でプラグインインストール :NeoBundleInstall! で更新
filetype plugin indent off     " required!
if has('vim_starting')
  set runtimepath+=~/.vim/bundle/neobundle.vim/
  call neobundle#rc(expand('~/.vim/bundle/'))
endif

" gitを使ったプラグインマネージャ 基本Vundleと一緒
NeoBundle 'Shougo/neobundle.vim'

"""""""" github
" Uniteコマンドによるフィルタ付き読み出し等
NeoBundle 'Shougo/unite.vim'
" Uniteコマンドでアウトラインを表示
NeoBundle 'h1mesuke/unite-outline'
" PHP5.4にも対応している新しいPHPのシンタックスハイライト
NeoBundle 'shawncplus/php.vim'
" ctrl+pで起動するファジー検索に対応したファイラー
NeoBundle 'kien/ctrlp.vim'

" SVNやgitなど http://blog.blueblack.net/item_144 :VCS* で実行
NeoBundle 'vcscommand.vim'
" tabでスニペット補完
NeoBundle 'snipMate'

filetype on
filetype indent on
filetype plugin on
"}}}
""""""""""" プラグインごとの設定 """""""""""{{{
" Unite起動時にインサートモードで開始
let g:unite_enable_start_insert = 1

" Uniteの各種ショートカット設定
" バッファ一覧
nnoremap <silent> ;ub :<C-u>Unite buffer<CR>
" ファイル一覧
nnoremap <silent> ;uf :<C-u>UniteWithBufferDir -buffer-name=files file<CR>
" レジスタ一覧
nnoremap <silent> ;ur :<C-u>Unite -buffer-name=register register<CR>
" 最近使用したファイル一覧
nnoremap <silent> ;um :<C-u>Unite file_mru<CR>
" 全部乗せ
nnoremap <silent> ;ua :<C-u>UniteWithBufferDir -buffer-name=files buffer file_mru bookmark file<CR>

" Ctrl +  o でタグアウトラインを表示
nnoremap <C-o> :<C-u>Unite outline<CR>

"}}}
""""""""""" Vimの基本的な設定  """""""""""{{{
"バックスペースキーの動作を決定する
"2:indent,eol,startと同じ
set backspace=2

"行数表示
set number

"新しい行を開始したときに、新しい行のインデントを現在行と同じ量にする
set autoindent

"検索で小文字なら大文字を無視、大文字なら無視しない設定
set smartcase

"(no)検索をファイルの末尾まで検索したら、ファイルの先頭へループする
set nowrapscan

"インクリメンタルサーチを行う
set incsearch

"highlight matches with last search pattern
set hlsearch

"閉じ括弧が入力されたとき、対応する括弧を表示する
set showmatch

"カーソルが何行目の何列目に置かれているかを表示する
set ruler

"新しい行を作ったときに高度な自動インデントを行う
set smartindent

"保存しないで他のファイルを表示することが出来るようにする
set hidden

"カレントバッファ内のファイルの文字エンコーディングを設定する
set fileencoding=utf-8

"Insertモードで<Tab> を挿入するのに、適切な数の空白を使う
set expandtab
set ts=4

"ファイル内の <Tab> が対応する空白の数
set tabstop=4

"自動インデントの各段階に使われる空白の数
set shiftwidth=4

"行頭の余白内で Tab を打ち込むと、'shiftwidth' の数だけインデントする
"set smarttab

"強調表示(色付け)のON/OFF設定
syntax on

"ステータスラインを表示するウィンドウを設定する
"2:常にステータスラインを表示する
set laststatus=2

"ステータス行の表示内容を設定する
set statusline=%<%f\ %m%r%h%w%{'['.(&fenc!=''?&fenc:&enc).']['.&ff.']'}G8%=%l,%c%V%8P

"vimのバックアップファイルとスワップファイル
set nobackup
set noswapfile

"バッファをクリップボードにコピー(for OSX)
set clipboard=unnamed,autoselect

"自動改行オフ
set tw=0

" マウスモード有効
set mouse=a

" xtermとscreen対応
set ttymouse=xterm2

"MacVimやGVimを利用する際にIMEがモードの切替でオフとなる設定
set imdisable

"UTF-8文字化け対応
set termencoding=utf-8
set encoding=utf-8
set fileencoding=utf-8
set fileencodings=utf-8,cp932


"}}}
""""""""""" 効率化UPのための設定 """""""""""{{{
" <Leader>を\にリマッップ
nnoremap \ <Leader>
vnoremap \ <Leader>

"全角スペースを で表示
highlight JpSpace cterm=underline ctermfg=Blue guifg=Blue
au BufRead,BufNew * match JpSpace / /

"タブを見えるように設定
set list
set listchars=tab:>-,trail:-

" サーチハイライトををESC二回で消す
nnoremap <Esc><Esc> :nohlsearch<CR><Esc>

" 挿入モードとノーマルモードでステータスラインの色を変更する
au InsertEnter * hi StatusLine guifg=DarkBlue guibg=DarkYellow gui=none ctermfg=Blue ctermbg=Yellow cterm=none
au InsertLeave * hi StatusLine guifg=Black guibg=White gui=none ctermfg=Black ctermbg=White cterm=none

"バイナリ編集(xxd)モード(vim -b での起動、もしくは *.bin で発動します)
augroup BinaryXXD
	autocmd!
	autocmd BufReadPre  *.bin let &binary =1
	autocmd BufReadPost * if &binary | silent %!xxd -g 1
	autocmd BufReadPost * set ft=xxd | endif
	autocmd BufWritePre * if &binary | %!xxd -r
	autocmd BufWritePre * endif
	autocmd BufWritePost * if &binary | silent %!xxd -g 1
	autocmd BufWritePost * set nomod | endif
augroup END

" ヴィジュアルモードで選択したテキストをnで検索する(レジスタv使用)
vnoremap <silent> n "vy/\V<C-r>=substitute(escape(@v,'\/'),"\n",'\\n','g')<CR><CR>

" gfでカーソル下のファイル名を新しいタブで開く
nnoremap gf :tabe <cfile><CR>
vnoremap gf :tabe <cfile><CR>

" 検索語が画面中央にくるように
nmap n nzz
nmap N Nzz

" ヤンク、切り取り時にレジスタ"の値をzにもコピーしておく(連続貼付可に使う)
vnoremap <silent> y y:let @z=@"<CR>
vnoremap <silent> d d:let @z=@"<CR>

" ビジュアルモードで選択したテキストを消してレジスタzの内容を貼付ける(連続貼付可)
vnoremap <silent> p x"zP

" vimrcの新しいタブでの編集と読み込みのショートカット設定
nnoremap ;s :source $MYVIMRC<CR>
nnoremap ;v :tabe $MYVIMRC<CR>
nnoremap ;g :tabe $MYGVIMRC<CR>
nnoremap ;l :tabe ~/.vimrc.local<CR>

" :makeや:grepをした際に自動的にquickfixが開くようにする
autocmd QuickfixCmdPost make,grep,grepadd,vimgrep,vimgrepadd if len(getqflist()) != 0 | cw | endif

" テキストファイル専用の設定
augroup ettext
	autocmd!
	autocmd BufRead,BufNewFile *.txt setlocal expandtab nolist nonumber tw=0
augroup END

" ファイルを開いたときに前回の編集箇所に移動
autocmd BufReadPost * if line("'\"") > 0 && line("'\"") <= line("$") | exe "normal g`\"" | endif


"}}}
""""""""""" 言語ごとの設定 """""""""""{{{
"ctagsのファイルをカレントディレクトリから検索して上位にあるもの読み込む
if has('path_extra')
	set tags+=tags;
endif

""""" VIM用設定 """"""""
" vimファイルに関して{と}による折りたたみ設定をする
au FileType vim setlocal foldmethod=marker

""""" PHP用設定 """"""""
" :makeでPHP構文チェック
au FileType php setlocal makeprg=php\ -l\ %
au FileType php setlocal errorformat=%m\ in\ %f\ on\ line\ %l

" PHPの関数やクラスの折りたたみ(非常に重い)
let php_folding = 0

" 文字列の中のSQLをハイライト
let php_sql_query = 1

" Baselibメソッドのハイライト
let php_baselib = 1

" HTMLもハイライト
let php_htmlInStrings = 1

" <? を無効にする→ハイライト除外にする
let php_noShortTags = 1

" ] や ) の対応エラーをハイライト
let php_parent_error_close = 1
let php_parent_error_open = 1


"}}}

以上で環境構築自体は完了となります。変えたい部分は随時設定などしてみてください。

実際に設定を一つ一つ確認しながら、使ってみて頂ければと思います。個人の好みなどがあると思いますので、カラースキームなどの設定は予め外してあります


なおctagsだけは、必要になった後にタグを付けたいPHPのプロジェクトフォルダルートにて、

$ rm tags
$ ctags -R --langmap=PHP:.php.inc --php-types=c+f+d+v+i;

を実行ください。これで、古いtagsファイルが消し、新たにtagsファイルが作られます

そのフォルダ以下のファイルをvimで開く際に自動的にtagsファイルが読み込まれ、Ctrl+]で関数定義元にジャンプCtrl+t Ctrl+t(tmuxのキーバインドとかぶっているため)で戻ってくることができます。また、Ctrl+pやCtrl+nで表示する補完候補にもこのctagsの情報が使われるようになります

後はvimのタグジャンプヘルプなどを読んで使ってみてください。


大規模開発の際に使えるvimテクニック

最後に大規模開発でよく使うテクニックを紹介します。

一応、vimはvimtutorで説明される使い方は基本的に使えることを前提とします。その上で開発するのに便利なvimのデフォルト機能を紹介します。


1. コピペモード :set paste

これをやっておけば貼りつけた際にインデントがくずれたりすることがありません。

戻すときは、:set nopaste

でもコピペ開発はいけませんよ!

テンプレートスニペットを利用したい際のみに使いましょう。重複は大規模開発の保守における悪!


2. マクロ qaで覚えてqで記録終了@aで実行

aは記憶領域の名前なだけで、同じキーであれば別にどれでも大丈夫です。

同じような入力操作、たとえばgetterやsetterを書いたりするのはすぐにマクロにして効率化した方がよいですよね。


3. 前回の動作を繰り返す . 10回繰り返す10.

同じ操作の繰り返しは、.で実行。それを10000回実行するのもモニターを見ているだけで十分です。


4. ミニバッファでヤンクした文字列を呼び出す C-r"

ミニバッファにて、レジスタ情報を呼び出したい時、よく選択した単語をヤンクして検索した時などに便利です。


5. 数値のインクリメント、デクリメント C-a と C-x

これとマクロを組み合わせると、数値の羅列やテストデータ作成などが非常に楽になります

1, 20, 40

2, 21, 41

3, 22, 42

4, 23, 43

5, 24, 44

こういうのはマクロとインクリメント・デクリメントでサクッと作ってしまいましょう。


6. テキストオブジェクトの選択 viw

マウスダブルクリックと同じなのですが、iwなどで選択できるテキストオブジェクト意識してマクロなどを組みはじめると、一気にいろんな操作ができるようになります


7. 今のファイル比較 :vertical diffsplit [ファイル名]

コマンドが長いので忘れがちですが、2つのファイルdiffをssh上で調べなきゃいけない時に便利です。環境の設定差異を見たりするのに使います


8. 複数行同時編集 C-vで矩形選択、IまたはAの後好きな文字列入力して、Escで反映

これは複数行コメントアウトや、複数行同時編集マクロ化などいろいろなシーンで役に立つテクニックです。


9. ls | vim - などで標準出力をvimに渡す

結果をvimで編集、調査したいときなどに便利です。

またシンタクスハイライト目的に利用することもあります

よく使うのが、diffでの利用

$ svn diff | vim -
$ git diff | vim -

になります


10. gf でカーソル下のパスを開く

これはvim -で読みだした標準出力と非常に相性の良いテクニックです。

$ git diff | vim -

diffを開き、更にそこから、パスの上にカーソルを持って行き、gfで実際のファイルジャンプして:VCSLogなどで、過去の履歴などを調べたりすることもできます


11. :makeシンタックスチェック

まさかシンタックスエラーのあるコードなんてコミットしませんよね。設定によっては保存するたびに:makeが走るようにすることもできます。ただ、:makeが重い場合もあるので、その時に合わせた運用で。


以上が、ssh上でマウススクロールも使える大規模PHP開発向けvim+tmux環境の構築と大規模開発の際に使えるvimテクニックの紹介でした。

お疲れ様でした。

2013年01月02日

エリックエヴァンスドメイン駆動設計に沿ってSymfony2ユーザー管理アプリ作ってみた

あけましておめでとうございます

去年の暮からエリックエヴァンスドメイン駆動設計という5200円、500ページもする本を購入して読み始めた自分です。

あまりに勿体無かったので試しにこのドメイン駆動設計設計思想にそって、簡単なアプリSymfony2で作ってみました。


実際に作られたサイトは、

http://www.soichiro.org/sf

こんな感じです。

  • id: test1@test.com
  • pass: test1

ログインできます。(ユーザー作るだけならadmin/adminpassでもOK)


画面イメージ

f:id:sifue:20130103014921p:image

f:id:sifue:20130103014922p:image

f:id:sifue:20130103014919p:image

f:id:sifue:20130103014923p:image

f:id:sifue:20130103014920p:image

こんな感じです。UIにはtwitterのbootstrapを使っています


ソースコードは、

https://github.com/sifue/UserManagement

からチェックアウトできます。無論MITライセンスです。サンプルとして使えそうな所があったら好きなように改変してご自由にご利用ください。


ドメイン駆動設計はすごく簡単に言うと、システムを作る時って業務モデル(実際のビジネス抽象化した概念、例えばUMLクラス図で書いたようなもの)の共有ってすごく重要だよねって話から始まって、そのモデルシステムいかに近づけるかって話と、実際のシステムを実装するときには、

に分けて実装すれば良いよっていうところから、更に深く実際のいろいろなプラクティスが書かれています


かなりじっくり読まなきゃいけないタイプの本で、読めば読むほど考えさせられる所もあって読み進まないタイプの本でした。オブジェクト指向大規模アプリ設計教科書と言っても過言ではないのでしょうか。


読み進んでビックリしたのは、ここに出てくる概念がほとんどSymfony2で実装されているというところでした。たぶんこの本に相当影響を受けてるんだと思います。例えで言うと、

とかがありました。

残念ながらなかった概念は、値オブジェクトJavaenumのように不変でstaticなインスタンスを作る仕組みがPHPにはないのでやむなしというところなのかもしれません。


実際にアプリ作るにあたってエリックエヴァンスドメイン駆動設計によるとドメイン層はできるだけ集約して一つにして高い凝集にしたほうがよいということだったので、実際に作ったこのユーザー管理システムバンドル設計クラス図はこんな風になりました。

f:id:sifue:20130103014918p:image

Symfony2の思想としては、ドメイン層とアプリ層とUI層を一つのバンドル内で作ってしまうように作られていたのですが、よりドメイン層に全てのビジネスロジックを集約する意図を持たせるために、DomainBundleというもの作りました

赤がインフラ層、オレンジがドメイン層、緑がアプリ層、青がUI層をあらわしていますUI層のテンプレートファイルルーティング設定ファイル類は割愛しています


確かにこの設計で作ってみると非常にアプリの作りがいいように感じます。あと、クラスそれぞれが単一責務になっている。


以下に実際にUserFactoryの実装を書きますが、ここではUserインスタンスができる際に守らせなければならない、インスタンス作成時は有効になっていることや、ランダムハッシュ用のsaltの設定などを守らせることができます

<?php
namespace Sifue\Bundle\DomainBundle\Factory;
use Sifue\Bundle\DomainBundle\Entity\User;

/**
 * Userインスタンスの作成とインスタンスが守らなければいけない整合性を保つ責務を持つクラス
 */
class UserFactory
{
    /**
     * ユーザーのインスタンスを取得する
     * @return Sifue\Bundle\DomainBundle\Entity\User
     */
    public function get()
    {
        $user = new User();
        $user->setIsActive(true);
        $user->setSalt(base_convert(sha1(uniqid(mt_rand(), true)), 16, 36));
        return $user;
    }
}

いい具合に責務が分離されています

これなら大規模開発で拡張リファクタリングを続けていっても耐えられる構成なのではないかなという確信を得ることができました。


とは言えまだドメイン駆動設計ぶっちゃけ業務でいろいろやってみないとわからないことも多そうなので、いろいろなテクニックを取り入れながら少しずつ試して行けたらななんて考えています。まだ初心者な所もあるので、ご指摘などあればコメント下さい。


ちなみにこのアプリSymfony2のインストールのためのPHP環境、MySQL環境を揃えた後、

$ git clone git@github.com:sifue/UserManagement.git
$ vim app/config/parameters.yml
parameters:
    database_driver:   pdo_mysql
    database_host:     127.0.0.1
    database_port:     ~
    database_name:     symfony
    database_user:     root
    database_password: password

    mailer_transport:  smtp
    mailer_host:       127.0.0.1
    mailer_user:       ~
    mailer_password:   ~

    locale:            ja
    secret:            ThisTokenIsNotSoSecretChangeIt
$ php app/console doctrine:database:create
$ php app/console doctrine:schema:update --force

とするだけで、UserManagement/webウェブサーバーに公開すれば動かすことができるようになっています


テストもひと通り実装してあり、PHPUnitインストールしてあれば、

$ phpunit -c app

で全てのテスト実施可能です。

Symfony2PHPUnitをいい具合に拡張してあって、WebUIエミュレーションするテストサービスコンテナテストができるところが便利です。


ぜひ試してみて下さい。


追伸

ちなみに自分PHPなんてオブジェクト指向言語の風上にも置けない言語だと思っていたのですが、Symfony2に触れて全然そんなことはないな、普通に戦えるフレームワークだなと思いました。PHPはひどい言語だけど、捨てたもんじゃない!きっとw