vim-localvimrcで編集するファイルパスごとに異なる設定を保持する

Vim Advent Calendar 2013 の87日目の記事になります。
今年もまだ続いてるようで安心しました。

はじめに

自分はハードタブよりもスペースでタブを表現するソフトタブの方が好きですし、今までの現場/案件も全てソフトタブでコードを書いてきました。

しかしある日突然そいつはやってきました。
フレームワークを使った案件なのですが、フレームワーク内のコーディング規約を見てみると。

すべてのインデントはスペースではなくタブを使用すべきです。

まじかよ。。。

さすがに無視するわけにもいかないので、嫌々ながらもハードタブを使うことになったのですが、.vimrcにハードタブ用の設定(noexpandtab)を書いてしまうとプロジェクトの内外に関わらず全ての編集作業でハードタブが入り込んでしまうようになりました。
複数人で触る大量のファイルにモードラインを入れるとかありえないし。
一体どうしたもんか。

vim-localvimrcの導入

困っていたところ、ひとつのプラギンを発見しました。

embear/vim-localvimrc · GitHub

このプラギンはファイルパスを遡ってローカル用の.vimrc(デフォルトでは.lvimrc)を探し、存在すれば適用してくれます。
目的のプロジェクトのルートにバッファローカルな設定を行う.vimrcを置いてみます。

$ echo 'setlocal noexpandtab tabstop=4' > /path/to/project/.lvimrc

たったこれだけで問題はバッチリ解決しました。
またバージョン管理を使っている場合は.lvimrcを無視パターンに追加するのを忘れずに。

vim-localvimrcの設定可能な項目を以下に書いておきます。

変数 説明 デフォルト
g:localvimrc_name 対象となるローカル設定ファイルの名前 .lvimrc
g:localvimrc_reverse 0: 下位ディレクトリのものほど設定を優先
1: 上位ディレクトリのものほど設定を優先
0
g:localvimrc_count 読み込みを行う上限数 -1(制限なし)
g:localvimrc_sandbox 0: 設定ファイルの評価をサンドボックスで行わない
1: 設定ファイルの評価をサンドボックスで行う
1
g:localvimrc_ask 0: 設定ファイルが見つかったら即読み込む
1: 設定ファイルが見つかったら読み込みを行うかどうかの確認を促す
1
g:localvimrc_persistent 0: g:localvimrc_askでの選択内容を保持しない
1: Y/N/Aなどの大文字の入力時にのみ保持する
2: 常に保持する
0
g:localvimrc_persistence_file g:localvimrc_persistentの情報を保持するファイル名 $HOME/localvimrc_persistent
g:localvimrc_whitelist 読み込みを許可するための正規表現 (なし)
g:localvimrc_blacklist 読み込みを拒否するための正規表現 (なし)

その他

似たプラギンは他にもあります。

中身をすべて確認したわけではありませんが、今回はとりあえず動かしてみて自分にあってそうなものを選びました。

fuelphpのmigrationでカラム追加時にmysqlのafterを指定する

fuelphpはドキュメントが弱いのでイマイチわからなかった。
知ってしまうとまぁまぁ応用が効く感じ。

migrationファイルの生成時に以下のように指定する。

$ php oil generate migration add_nickname_to_users nickname:varchar\[32]:after\[id]

他にもdefaultやnullとか。

$ php oil generate migration add_status_to_users status:tinyint:default\[1]:null

以上。

Solrで日付の加算/減算をする

f:id:saihoooooooo:20140130163127p:plain

Solrを使っていて条件に半年先ってどう書くんだっけなー、と思い調べてみました。

http://docs.lucidworks.com/display/lweug/Solr+Date+Format

日付の加算/減算は、以下のように[日付][+/-][単位]とすればよいそうです。

opened_at:[* TO NOW+6MONTH]

NOWは現在時刻を表す書式で、この部分は日付でも構いません。

opened_at:[* TO 2014-01-30T12:34:56Z+6MONTH]

などと書くこともできます。

ついでにわかったことですが、[日付]/[単位]とすればその単位で丸めた値が取得できるようです。

opened_at:{* TO NOW+6MONTH/DAY}

で今日の6ヶ月後の午前0時未満の日付を持つドキュメントが抽出できます。

加算/減算/丸めに使える単位は以下の通りです。
単数形と複数形には特に挙動の違いはありません。

単位 書式
YEAR / YEARS
MONTH / MONTHS
DAY / DAYS / DATE
HOUR / HOURS
MINUTE / MINUTES
SECOND / SECONDS
ミリ秒 MILLISECOND / MILLISECONDS / MILLI / MILLIS

ミリ秒とか使い道が思い浮かばない。

hubot-scriptを公開する方法(npm編)

hubot-scripts Advent Calendar 2013の7日目の記事になります。
6日目は hubotで突然の死に備える でした。

hubot-scriptの公開

hubot-scriptを書いていて、これを一般にも公開してみたいなと思う瞬間はありませんか?
先日作った>突然の死<ですが、現場でも好評(?)をいただいており練習も兼ねて公開してみることにしました。

ただしこの日本のネット文化丸出しのスクリプトが本家のスクリプト群に取り込んでもらえるとは到底思えません。
そこで、単独でnpmへ公開する方法をとることにしたので、インストール方法と合わせて紹介したいと思います。

今回実際に公開したものは以下になります。

hubot-suddendeath

https://npmjs.org/package/hubot-suddendeath

公開するための準備

公開を行うにあたりディレクト構成は以下のようにしておきます。

hubot-suddendeath/
|-- README.md
|-- index.coffee
|-- package.json
`-- scripts
    `-- suddendeath.coffee

まずpackage.jsonを用意しましょう。
npmへの公開には必須となります。
手で書くこともできますが、package.jsonを対話的に作成するnpm initというコマンドもあります。

$ cd hubot-suddendeath
$ npm init

一度npm initで作ってからエディタで微調整を行うのがいいかもしれません。
詳しい項目の解説はこちら(英語)を参照してください。
今回の例でいうと、mainとdependenciesが正しく設定されていれば他は割とどうでもいいかと思います。

package.jsonができあがったらエントリポイント(packeage.jsonでいうmain)となるindex.coffeeにスクリプトをロードさせるためのモジュールを書いておきます。

Fs   = require 'fs'
Path = require 'path'

module.exports = (robot) ->
  path = Path.resolve __dirname, 'scripts'
  Fs.exists path, (exists) ->
    if exists
      robot.loadFile path, file for file in Fs.readdirSync(path)

robot.loadFileにパスを渡すとhubotがスクリプトを読み込んでくれます。
ひとまずこれで公開できる形にはなりました。

公開する

npmに公開するにあたって、まずnpm専用のアカウントを取得する必要があります。
アカウントの登録は公式サイト上で行うことができますが、コマンドからでも登録は可能なのでこちらの方法を使います。
以下のコマンドを叩くとユーザ名やパスワード、メールアドレスを求められるので適宜入力してください。

$ npm adduser

アカウントの登録が完了したらpackage.jsonの置いてあるディレクトリ上で

$ npm publish

を行うだけで公開が完了します。
お手軽ですね!

$ npm search hubot-suddendeath

で実際に登録されたかどうか確認できます。

またバグ修正などでスクリプトに変更を加えた場合は、再度npm publishを行うことで更新内容が反映されます。
ただしpackage.jsonのversionを上げておく必要があるのでご注意ください。

公開したスクリプトをインストール

本家が公開しているhubot-scriptsは通常、npm install後にhubot-scripts.jsonに使用するスクリプト名を指定して読み込みを行います。

$ npm install hubot-scripts
$ echo '["redis-brain.coffee", "tweet.coffee", "shipit.coffee"]' > hubot-scripts.json

では外部モジュールの場合はどうするかというと、external-scripts.jsonという仕組みが用意されていて、そこにモジュール名を記述することでスクリプトが利用できるようになっています。

$ npm install hubot-suddendeath
$ echo '["hubot-suddendeath"]' > external-scripts.json

あとはhubotを再起動して好きなだけコマンドを打ってみましょう。

まとめ

npmへの公開はとても簡単に行えます。
本家のhubot-scriptsにプルリクを投げるのはなんか怖いという方もまずはこの方法から始めてみては如何でしょうか?

また自分以外にもたくさんの人がこの方法でhubot-scriptを公開していますので面白い/役に立つスクリプトを是非探してみてください。

hubotで突然の死に備える

hubot-scripts Advent Calendar 2013の6日目の記事になります。
1日空きましたが、4日目はdaxanya2さんによる Hubot-scriptsでサイコロを投げる でした。

_人人人人人人_
> 突然の死 <
 ̄Y^Y^Y^Y^Y ̄

突然の死とは (トツゼンノシとは) [単語記事] - ニコニコ大百科

botでは比較的よく見るベタなネタではありますが、自分の調べた範囲ではhubot用のものがまだ無さそうだったので作ってみました。

対象文字列の長さによって吹き出しの幅を変える必要がありますが、
上の「人」は全角文字数(半角文字は2個で1)+2個分、下は「Y」1つと「^Y」を全角文字数分で表示するようにしました。

全角半角が混ざった場合の幅の計算はなんかメンドそうなのでライブラリに任せてます。
https://npmjs.org/package/eastasianwidth

事前に npm install しておきましょう。

$ npm install eastasianwidth

実際のコードは以下のようになります。

# Description:
#   >Prepare for sudden death.<
#
# Dependencies:
#   "eastasianwidth": "~0.1.0"
#
# Configuration:
#   None
#
# Commands:
#   hubot >< <message> - Ascii art generator for sudden death.
#
# Notes:
#   None
#
# Author:
#   saihoooooooo

eastasianwidth = require 'eastasianwidth'

strpad = (str, count) ->
  new Array(count + 1).join str

module.exports = (robot) ->
  robot.respond />< (.*)$/i, (msg) ->
    message = msg.match[1].replace /^\s+|\s+$/g, ''
    return until message.length

    length = Math.floor eastasianwidth.length(message) / 2

    suddendeath = [
      "_#{strpad '人', length + 2}_"
      "> #{message} <"
      " ̄Y#{strpad '^Y', length} ̄"
    ]
    msg.send suddendeath.join "\n"

簡単ですね!

使い方は

hubot >< 突然の死

とするだけです。
これで例え急にサーバが落ちてしまっても快適なhubot生活を送れること間違いないですね!

次回はnpm化でもしてみようと思います。 → しました。
それでは。