| @技術/プログラミング

一月くらい前から Lokka の master ブランチを自分のブログ用のブランチに merge してサイトをデプロイすると謎の白画面が出るようになっていて困っていた。現象は極めて謎で、ローカルの開発環境(RACK_ENV='development')では見られず、本番(RACK_ENV='production')だけで発生した。HTTP ステータスコードは 1054 が返ってきたりする。なんか変な gem でも入れてしまったかなと休みの日に動作検証したりしていたんだけどついぞ分からなかった。

SQL 弱者なので気がついてなかったんだけど、2月15日の commit で Site モデルに新しいフィールドが追加されていた(Add default markup in admin/site/edit · 2243dc5 · lokka/lokka ※この機能便利すね)。なので bundle exec rake db:migrate しないといけなかったわけだった。ローカルで動いている開発環境(データベースは SQLite)では Migration なんて行ってないんだけどエラーは出なかった。本番は MySQL で動いていて、こちらでだけエラーが出るようだった。

しかしいざ migrate しようとすると失敗する。

bundle exec rake db:migrate
Upgrading Database...
rake aborted!
Invalid default value for 'updated_at'

のようなエラーが出る。updated_at のデフォルト値がおかしいらしい。このときのテーブルの構造を見てみると以下のような感じだった。

mysql> desc entries;
+-----------------+--------------+------+-----+---------------------+-----------------------------+
| Field           | Type         | Null | Key | Default             | Extra                       |
+-----------------+--------------+------+-----+---------------------+-----------------------------+
| id              | int(11)      | NO   | PRI | NULL                | auto_increment              |
| user_id         | int(11)      | YES  |     | NULL                |                             |
| category_id     | int(11)      | YES  |     | NULL                |                             |
| slug            | varchar(255) | YES  |     | NULL                |                             |
| title           | varchar(255) | YES  |     | NULL                |                             |
| body            | text         | YES  |     | NULL                |                             |
| type            | text         | NO   |     | NULL                |                             |
| draft           | tinyint(1)   | YES  |     | 0                   |                             |
| created_at      | timestamp    | NO   |     | 0000-00-00 00:00:00 |                             |
| updated_at      | timestamp    | NO   |     | CURRENT_TIMESTAMP   | on update CURRENT_TIMESTAMP |
| frozen_tag_list | text         | YES  |     | NULL                |                             |
| markup          | varchar(255) | YES  |     | NULL                |                             |
+-----------------+--------------+------+-----+---------------------+-----------------------------+

調べてみたところ MySQL の Mode が NO_ZERO_DATE になっている場合、MySQL は timestamp 型のフィールドのデフォルト値に 0000-00-00 00:00:00 みたいな値を設定することを許さないらしい。 mysql - Invalid default value for 'create_date' timestamp field - Stack Overflow

検証用に別にテーブルを用意して bundle exec rake db:setup してみたところ、以下のような構造のテーブルができた。

mysql> desc entries;
+-----------------+------------------+------+-----+---------+----------------+
| Field           | Type             | Null | Key | Default | Extra          |
+-----------------+------------------+------+-----+---------+----------------+
| id              | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| user_id         | int(11)          | YES  |     | NULL    |                |
| category_id     | int(11)          | YES  |     | NULL    |                |
| slug            | varchar(255)     | YES  |     | NULL    |                |
| title           | varchar(255)     | YES  |     | NULL    |                |
| body            | text             | YES  |     | NULL    |                |
| markup          | varchar(255)     | YES  |     | NULL    |                |
| type            | varchar(50)      | NO   |     | NULL    |                |
| draft           | tinyint(1)       | YES  |     | 0       |                |
| created_at      | datetime         | YES  |     | NULL    |                |
| updated_at      | datetime         | YES  |     | NULL    |                |
| frozen_tag_list | text             | YES  |     | NULL    |                |
+-----------------+------------------+------+-----+---------+----------------+

created_atupdated_atdatetime 型になるらしい。なので以下のような ALTER 文を実行した。

mysql> alter table entries modify column created_at datetime, modify column updated_at datetime;
mysql> desc entries;
+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| id              | int(11)      | NO   | PRI | NULL    | auto_increment |
| user_id         | int(11)      | YES  |     | NULL    |                |
| category_id     | int(11)      | YES  |     | NULL    |                |
| slug            | varchar(255) | YES  |     | NULL    |                |
| title           | varchar(255) | YES  |     | NULL    |                |
| body            | text         | YES  |     | NULL    |                |
| type            | text         | NO   |     | NULL    |                |
| draft           | tinyint(1)   | YES  |     | 0       |                |
| created_at      | datetime     | YES  |     | NULL    |                |
| updated_at      | datetime     | YES  |     | NULL    |                |
| frozen_tag_list | text         | YES  |     | NULL    |                |
| markup          | varchar(255) | YES  |     | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+

これで最新のコードをデプロイしても真っ白画面になることはなくなった。以前遭遇した更新時に created_at の値が更新されてしまう問題 もフィールドの型が timestamp だったのが原因なのだと思う。SQLite から MySQL への移行は一筋縄では行かないことが分かった。

DataMapper はソースコード内の記述内容から動的に Migration を行えるけど、ActiveRecord みたいに $APP_ROOT/db/ ディレクトリに Migration ファイルを作ってくれたりしないので DB スキーマの変更が必要なことに気がつきにくい。便利だけど不便な感じがする。Rails で $APP_ROOT/db/ 以下にアホみたいにファイルが出来ていくの嫌だと思っていたけど、スキーマ変更に気がつかずコードをデプロイしてウェブアプリケーション停止みたいな自体は防げると思った。

ブログ書こうと思ってパソコン開いて「ついでに最新版の変更を取り込むか」とかやるとデプロイできなくなったりして書きたかった記事が書けず残念な感じになる。はてなブログでブログ書いてて画面が真っ白になったらひとでくんさんに不具合報告して直してもらえば良いので楽だと思う。

| @Mac/iPhone

先日、自宅の MacBook Pro (Mid 2009) 内の MacVim kaoriya で quickrun が実行できないと書いた(Homebrew で入れた MacVim だと quickrun できる)。どうも Python が原因らしいことがわかっていた。

Mac に入っている Python のバージョンが古いのかなと思い(でもそれだとなぜ CUI 版の Vim で quickrun できるの説明がつかない)、 Homebrew で Python を入れてみた。なんか symlink を作成できなかったとかエラーが出たので brew link --overwrite python とかやってかなり無理気味に入れてみた。しかし相変わらず MacVim kaoriya から qiuckrun を実行すると MacVim が落ちる。

そもそも会社の MacBook Pro や自己所有の MacBook Air ではこのような現象は起こらないため、この Mac に入ってる Python が異常なのでは? と思い至った。

確認してないのでテキトーなんだけど、おそらく、この Mac に入ってる Python は 32bit OS 用のやつが入ってたような気がする。というのは /usr/local/bin にあるいくつかの symlink が以下のように 2008 年に作成されたファイルを指していたから。

https://resources.portalshit.net/930-pythons.png

かつて NOKIA の携帯を使っていたときにゴニョゴニョするために Mac OS X 用の Python パッケージをダウンロードしてインストールしていて、それが 32bit OS 用のバイナリだったために問題が発生しているのかも知れないと思った。試しに python.org から 64bit OS 用の Python パッケージをダウンロードしてきてインストールしてみたら無事 MacVim kaoriya で quickrun できるようになった。

CPU が Core Solo、Core Duo の Mac だったら 64bit でしか動作しない Mac OS X (Lion 以降の OS)をインストールできないのでこんな問題には遭遇しないのだろうけど、自宅の MacBook Pro は Core2 Duo なので 32bit OS でも 64bit OS でもインストールできてしまうためにこのような問題に行き当たってしまったのだと思う。

あと OS のアップグレード時にアーカイブインストールではなくクリーンインストールを選んでいたらこのような問題には遭遇しなかったかも知れない。写真や音楽などだけ TimeMachine から復旧するようにして、Mac をアップグレードするときは OS そのものはまっさらな状態でインストールする方が良いということが分かった。アプリケーションもいまは Mac AppStore があるので昔より前の環境に戻すのが難しくない。

ただ Adobe 製品のライセンス認証解除とかは OS のクリーンインストール前にぬかりなく行っておかないとシリアルキーが通らなくなって死ねそう。

そういうわけで、Snow Leopard 時代から Core2 Duo CPU の Mac を Mountain Lion まで Upgrade して使っていて MacVim の quickrun が動かない人は Python をインストールし直すことを試してみてください。

| @散財

一昨年、会社を変わったときに Happy Hacking Keyboard Professional 2 を買った んだけど、貧乏性のためなかなか会社に持っていって使うという気にならず、会社では3年前に買った HHK Lite2 を使い、Pro の方は家で使っていた。

しかしよくよく考えると家でコードを書く時間よりも会社でコードを書く時間の方が圧倒的に長いわけで、一番長くコードを書く時間を一番良いキーボードととともに過ごした方がよいのではないかと考えを改めて HHK Pro を会社で使うことにした。

連休明けの火曜から HHK Pro でコードを書いていて一週間が終わったところだけど、会社で毎日8時間以上使うことで初めて良さが分かったような気がする。Lite に比べてしっかりしている。Lite はカチャカチャとうるさいけど Pro は激しくキーを叩いても静かだ。それなのに押したときの反発は Lite の方が重く、Pro の方が軽い。Lite はカチャカチャしていておもちゃのようで、音を聞くだけで疲れる。

キー配列に関しても、HHK Pro はただの US 配列とは異なっていて、チルダキーの位置や Control キーの位置が一般的な US 配列よりも利用しやすい位置に置いてある。正直プログラミングしやすい。

HHK Pro を使うことで困ることと言ったら、それ以外のキーボードを利用したくなくなることだと思う。家でも職場でも HHK Pro が使いたくなる。自分の場合は HHK Pro を二つも買えるような財力はないので、そもそも HHK Pro を買ってしまったのが失敗だったのかも知れない。毎日 Amazon を開いてため息をつきながら HHK Pro をカートに入れたり戻したりしている。

| @Mac/iPhone

Mountain Lion な Mac (MacBook Pro Mid 2009)で MacVim (kaoriya版) から quickrun を実行すると以下のようなエラーが出て困ってる。

⚡ Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site.py", line 62, in <module>
    import os
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.py", line 398, in <module>
    import UserDict
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/UserDict.py", line 83, in <module>
    import _abcoll
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_abcoll.py", line 11, in <module>
    from abc import ABCMeta, abstractmethod
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/abc.py", line 8, in <module>
    from _weakrefset import WeakSet
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/_weakrefset.py", line 5, in <module>
    from _weakref import ref
ImportError: No module named _weakref

CUI の Vim で quickrun してもエラーは出ないし、会社で使ってる Mac (Mountain Lion MacBook Pro Early 2011) の MacVim (同じくkaoriya 版)で quickrun やってもエラーは出ない。

どうやらこの辺が関係ありそう。リンク先には ujihisa さんバージョンの quickrun ではなく thinca さんバージョンのやつを使えばエラーは出なくなる、とあるけど、自分が使っている quickrun は thinca さんバージョンのやつで、どうすればいいかさっぱりわからない。

MacVim が想定する Python とパスが通ってる Python のバージョンが違うのが問題なような気がする(調べてみたら、Python は 2.5 と2.6 と 2.7 がインストールされていた。なんでこんなに入ってるの…。パスが通ってるのは 2.7 らしい)ので、とりあえず MacVim を kaoriya 版から Homebrew のやつに変えてみることにする(brew install macvim)。brew でインストールするとコンパイルを行うので、パスが通ってる Python を利用するようになるはず。

と思ってやってみたら案の定、エラーはでなくなった。

| @Mac/iPhone

46dd7418f43fe24786c47fada3fe4916.png (975×595)

会社は IRC を多用してて、入社してすぐに横の席の人が使ってた Linkinus を真似して入れて使ってた。なんで LimeChat を使わないのかというと、LimeChat だと Growl とかの通知がメッセージ全体ではなく冒頭の数文字だけだから。これでは LimeChat のウィンドウにフォーカスを移さないと続きを読むことが出来ない。Linkinus の通知は全文表示されるので、ちょっとしたメッセージなら Growl 通知だけで内容を把握できる。そいうわけで Linkinus を使っていた。

しかし Linkinus にも問題があって、最近は全然メンテされてないし、ときどきテキストフィールドがどんどん狭くなっていく現象に遭遇するようになって、自分の人間の器がテキストフィールドの大きさに反映されてるみたいで非常に使い心地が悪かった。なんかいい IRC クライアントないかなー、と物色していたら、 Textual というやつを発見した。試用版を入れてみたところなかなかいい。Retina Display の MacBook Pro にも対応していて(つまりちゃんとメンテされてる)、テーマは良い感じのやつがあるし(Monokai みたいな色合いでかっこいい)、Linkinus と同じ3カラムレイアウトなので違和感もなかった。テキストフィールドが入力不能になることはないし、 Linkinus では Growl 通知されなかった Notice status を通知させることもできる。非常におすすめです。

| @技術/プログラミング

まえ作った Amazonの検索結果が新規ウィンドウで開かれるのを殺すユーザースクリプト が Amazon の HTML 変更により動かなくなってたので更新した。Amazon 見てたら無限に新しいタブが開いていく現象にお困りの方はご利用ください。

| @技術/プログラミング

Lokka で Syntax Highlight するプラグイン(morygonzalez/lokka-pygmentize · GitHub)、これまで Ajax で Syntax Highlight させてたんだけど、HTTP リクエストが増えていけてないと感じたのでサーバーサイドでハイライトが完結するように変更した。Railscasts の #272 Markdown with Redcarpet - RailsCasts を参考にして、プラグインの中で Entry クラスを再オープンした。こんな感じ。

class Entry
  def body
    doc  = Nokogiri::HTML(self.long_body)
    doc.search("//pre").each do |pre|
      code = pre.css("code")[0]
      pre.replace Pygments.highlight(
        code.text.rstrip,
        :lexer   => code[:class],
        :options => { :encoding => 'utf-8' }
      )
    end
    doc.to_s
  end
end

前の実装はだいぶいけてなかったと思うので随分マシになったと思う。あと この Pull Request でレンダリングエンジンに Redcarpet が追加されたので、GitHub と同じように

```ruby

```

みたいな感じの書き方でコードがハイライトされるようになった。便利。

追記1

ちゃんと動いてなかった…。夜直します…

追記2 2013/02/04 0:45

最終的にオープンした Entry クラスのコードは以下のようになった。

class Entry
  alias_method :original_long_body, :body
  def highlighted_long_body
    syntax_highlight(self.original_long_body)
  end
  alias_method :body, :highlighted_long_body

  alias_method :original_short_body, :short_body
  def highlighted_short_body
    syntax_highlight(self.original_short_body)
  end
  alias_method :short_body, :highlighted_short_body

  def syntax_highlight(body)
    doc = Nokogiri::HTML(body)
    doc.search("//pre").each do |pre|
      code  = pre.css("code")[0]
      lexer = if pre[:class].present?
                pre[:class]
              elsif code.present? && code[:class].present?
                code[:class]
              else
                nil
              end
      begin
        pre.replace Pygments.highlight(
          code.text.rstrip,
          :lexer   => lexer,
          :options => { :encoding => 'utf-8' }
        ) if code
      rescue MentosError
        next
      end
    end
    doc.to_s
  end
end

Lokka、結構メタプログラミングが多くて、Entry クラスのインスタンスの body メソッドは単なるゲッターではなく、 index アクションのときと show アクションのときで別々にエイリアスが設定されていて、index アクションのときは Entry#short_body 、show アクションのときは Entry#long_body が呼ばれるようになっていた。アラウンドエイリアス使って力業で解決したけど他のプラグインが同じように振る舞ったら破滅を招きそうな気がする…。それにしても『メタプログラミング Ruby』読んでなかったらどうすればいいか皆目検討付かなかっただろうなー。