unite.vimで:UniteWithBufferDirのsourceにfile_recを指定すると失敗する

現在開いているバッファのディレクトリでUniteのfire_rec (file_rec/async)を実行したいことが結構あるのだけど,以下のように:UniteWithBufferDirとfile_recを組み合わせて実行すると何故か結果がひとつも表示されない.

:UniteWithBufferDir file_rec

:Uniteとfire_recの組み合わせは一応動く.

:Unite file_rec

何が原因なのだろう.同様に:UniteWithCurrentDir file_recも動いてくれない.

仕方がないので,.vimrcに以下のように書いてバッファが切り替わるたびにバッファのディレクトリにcdするようにした.これなら:Unite fire_recを使ってカレントバッファのディレクトリでfile_recが実行できる.

augroup AutoCD
  autocmd!
  autocmd BufEnter * lcd %:p:h
augroup END

JavaScriptの等値演算は==ではなく===を使うようにする

JavaScriptの==は予想外の結果を返すことがある

JavaScriptの等値演算子==は,左右のオペランドの型が等しい場合,両者の値が等しければtrueに,そうでなければfalseになります.

しかし,2つのオペランドの型が違う場合,==はオペランドを型変換してから比較することがあります.この型変換がなかなか曲者で,比較する値と型の組み合わせによっては予想外の結果が得られることがあります.

以下に例を示します.

'' == '0'          // false
0 == ''            // true
0 == '0'           // true

0 == []            // true
0 == {}            // false

0 == false         // true
0 == [0]           // true
0 == [false]       // false

false == 'false'   // false
false == '0'       // true

false == undefined // false
false == null      // false
null == undefined  // true

' \t\r\n ' == 0    // true

上の結果は冗談ではなく本当です.ぜひお使いのブラウザで試してみてください.
もはや何が何だかという感じですよね.しかしこれはECMAScriptの仕様通りの評価結果となっています.このように==の結果が予想外だったせいでバグが発生した場合,デバッグは困難を極めるでしょう.

===はオペランドの型変換を行わない

一方,===はオペランドの型と値が等しい時に限りtrueになります.そのため,上記のような型が違うケースはすべてfalseになります.

'' === '0'          // false
0 === ''            // false
0 === '0'           // false

false === 'false'   // false
false === '0'       // false

0 === false         // false
0 === []            // false
0 === {}            // false

0 === false         // false
0 === [0]           // false
0 === [false]       // false

false === undefined // false
false === null      // false
null === undefined  // false

' \t\r\n ' === 0    // false

==と比べると直感的でまともな結果が得られることが分かると思います.
自動的に型変換させてまで異なる型の値を比較したいことはそうそうないと思うので,等値演算では普段から===を使う癖をつけたほうがいいでしょう.また,同じ理由から非等値演算では!=よりも!==を使うようにしましょう.

参考資料

「==」はJavaScript: The Good Partsという本の中でも「JavaScriptのBad Parts」のひとつとして紹介されています.

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

Vimで行末の空白文字をハイライトする

.vimrcに以下のように書いておくと自動的にハイライトされるようになる.

augroup HighlightTrailingSpaces
  autocmd!
  autocmd VimEnter,WinEnter,ColorScheme * highlight TrailingSpaces term=underline guibg=Red ctermbg=Red
  autocmd VimEnter,WinEnter * match TrailingSpaces /\s\+$/
augroup END

便利.

参考資料

Vimテクニックバイブル ?作業効率をカイゼンする150の技

Vimテクニックバイブル ?作業効率をカイゼンする150の技

「Arduinoをはじめようキット」を購入したよ

全くの初心者なのでとりあえずキットを買ってみた.

Arduinoをはじめようキット

Arduinoをはじめようキット

ついでに本も注文してみた.

Arduinoをはじめよう 第2版 (Make:PROJECTS)

Arduinoをはじめよう 第2版 (Make:PROJECTS)

遊ぶぞー.

mecab-rubyのMeCab::Tagger#parseToNodeの戻り値が気に入らないのでアレする

mecab-rubyでテキストを形態素解析するときによく使うMeCab::Tagger#parseToNodeですが,戻り値がMeCab::NodeのArrayやEnumeratorではなく,以下のようにMeCab::Node#nextを使って各要素にアクセスしなければならないので使い勝手が悪いです.

# -*- coding: utf-8 -*-

require "MeCab"

if __FILE__ == $0
  node = MeCab::Tagger.new.parseToNode("俺、この戦争が終わったら結婚するんだ。")

  while node
    puts "#{node.surface}\t#{node.feature}"
    node = node.next
  end
end

while nodeとかnode = node.nextとか,非常にRubyらしくない感じでアレですね.eachとか使いたい.(メソッド名がCamelCaseなのも非常にアレですが,mecab-rubyはSWIGでコードを自動生成しているみたいなのである程度は仕方ないのかも)

幸いなことにRubyは既存のクラスを自由に書き換えられるので(オープンクラス),以下のようにparseToNodeを再定義してNodeのArrayを返すようにすればこの問題は解決します.

# -*- coding: utf-8 -*-

require "MeCab"

module MeCab
  class Tagger
    # parseToNodeの別名(エイリアス)を作ってprivate化する
    alias_method :parseToNode_org, :parseToNode
    private :parseToNode_org

    # parseToNodeを再定義する
    def parseToNode(*args)
      #オリジナルのparseToNodeを呼び出す
      node = parseToNode_org(*args)
      # NodeのArrayを作って返す
      nodes = []
      while node
        nodes.push(node)
        node = node.next
      end
      nodes
    end
  end
end

if __FILE__ == $0
  nodes = MeCab::Tagger.new.parseToNode("俺、この戦争が終わったら結婚するんだ。")

  # Array#eachが使える!
  nodes.each do |node|
    puts "#{node.surface}\t#{node.feature}"
  end
end

オープンクラスって素敵.

上のRubyスクリプトをMeCabの代わりにrequireするだけでNodeのArrayを返すparseToNodeが使えるようになるので,while nodeとnode = node.nextに嫌気が差したら是非試してみてください.

Ubuntu 10.04でMeCabをRubyから使えるようにする

MeCabのインストール

MeCabと辞書のインストールはapt先生にお任せします.辞書はUTF-8のものを使います.

$ sudo apt-get install mecab mecab-ipadic-utf8

MeCabが正常に動くことを確認します.

$ echo "俺、この戦争が終わったら結婚するんだ。" | mecab
俺      名詞,代名詞,一般,*,*,*,俺,オレ,オレ
、      記号,読点,*,*,*,*,、,、,、
この    連体詞,*,*,*,*,*,この,コノ,コノ
戦争    名詞,サ変接続,*,*,*,*,戦争,センソウ,センソー
が      助詞,格助詞,一般,*,*,*,が,ガ,ガ
終わっ  動詞,自立,*,*,五段・ラ行,連用タ接続,終わる,オワッ,オワッ
たら    助動詞,*,*,*,特殊・タ,仮定形,た,タラ,タラ
結婚    名詞,サ変接続,*,*,*,*,結婚,ケッコン,ケッコン
する    動詞,自立,*,*,サ変・スル,基本形,する,スル,スル
ん      名詞,非自立,一般,*,*,*,ん,ン,ン
だ      助動詞,*,*,*,特殊・ダ,基本形,だ,ダ,ダ
。      記号,句点,*,*,*,*,。,。,。
EOS

mecab-rubyのインストール

apt-getでインストールされたRubyのgemにmecab-rubyを追加する場合は,libmecab-ruby(もしくはlibmecab-ruby1.9.1など)をインストールすれば大丈夫だと思います(未確認).

$ sudo apt-get install libmecab-ruby

RVMrbenvでインストールしたRuby,ソースから自前でインストールしたRubyなど,aptの管理下にないRubyを使っている場合は,以下のように自前でmecab-rubyをインストールする必要があります.

mecab-rubyを自前で入れる前にlibmecab-devをインストールしておきます.これがないとmecab-rubyのビルド時に大量のエラーが出て失敗します.

$ sudo apt-get install libmecab-dev

mecab-rubyはgem installですぐインストールできるわけではなく,自前でソースをダウンロードしてくる必要があります.
MeCabのバージョンを確認し,それに近いバージョンのmecab-rubyをMeCabのGoogle Codeからダウンロードします.MeCabとmecab-rubyのバージョンがあまりにも違いすぎるとmecab-rubyのインストールに失敗することがあるので注意が必要です.

$ mecab --version
mecab of 0.97

Ubuntu 10.04のMeCabのバージョンは0.97のようです.mecab-ruby-0.97はGoogle Codeにはないため,ここではmecab-ruby-0.98を使います.

$ wget http://mecab.googlecode.com/files/mecab-ruby-0.98.tar.gz 
$ tar zxvf mecab-ruby-0.98.tar.gz
$ cd mecab-ruby-0.98
$ gem build mecab-ruby.gemspec
$ gem install mecab-ruby-0.97.gem  # 環境によってはsudoが必要

インストール完了.

動作確認

あとは以下のようなRubyスクリプトを動かして,mecab-rubyが正常に動くことを確認すればOKです.

# -*- coding: utf-8 -*-

require "MeCab"

if __FILE__ == $0
  node = MeCab::Tagger.new.parseToNode("俺、この戦争が終わったら結婚するんだ。")
  while node
    puts "#{node.surface}\t#{node.feature}"
    node = node.next
  end 
end

rbenvでインストールしたRubyのgemコマンドがzlib云々ほざいて動かない時の対処法

rbenvでインストールしたRubyのgemを動かしたら以下のようなエラーを吐いて死にました.

$ gem install -V twitter
ERROR:  Loading command: install (LoadError)
    no such file to load -- zlib
ERROR:  While executing gem ... (NameError)
    uninitialized constant Gem::Commands::InstallCommand

何が原因だろうと思ったら単純にzlib1g-devがインストールされてないだけでした.ついでにopensslやlibreadline-devも必要みたいなので念のためapt-getで入れて,再度Rubyをインストールします.

$ sudo apt-get install zlib1g-dev openssl libreadline-dev
$ rbenv install ruby 1.9.2-p290
$ rbenv rehash
$ rbenv global 1.9.2-p290

もう一度gemコマンドを実行.

$ gem install -V twitter
GET http://rubygems.org/latest_specs.4.8.gz
302 Moved Temporarily
GET http://production.s3.rubygems.org/latest_specs.4.8.gz
200 OK
...

動いた.

こういう基本的なパッケージが初期インストールされてないことも意外とあるんですね….