日本 Ruby 会議 2007 – The Island of Ruby

生産性

Rubyを愛する理由は他にもある。

自分をかっこよく見せてくれる。生産性を高めてくれるんだ。

そこにはどういう理屈があるか。ある研究によれば、生産性はそれぞれのプログラマでそれぞれ違う。でも、あるプログラマに着目すれば、そのプログラマが時間あたりに書けるコードの行数は、プログラミング言語によらず決まっている、たとえば一年に50,000行なのだそうだ。行数が決まっていたら、どの言語で一番多くのことを達成できる?そう、Rubyだよね。

「行数が決まっていたら、どの言語で一番多くのことを達成できる?」

「そう、プロテインだね

パスワードにはmd5、メールアドレスにはPEAR Crypt_Blowfishが使われてる。Blowfishのキーはconfig.phpに書いてある。

passengerでrailsのpaperclipプラグイン使ってて今日ひとつ失敗した。

開発環境(mongrel)では問題なかったのに本番環境(mod_passenger)上でアップした画像が見えない。

理由は、

「画像はアプリの所有者でアップされるのにapacheの権限で見に行こうとするから。」

Phusion Passenger users guide

8.1. User switching (security)

Phusion Passenger solves this problem by implementing user switching. A Rails application is started as the owner of the file config/environment.rb, and a Rack application is started as the owner of the file config.ru.

passengerではUser switchingといって、rootやapacheではなく、railsではconfig/environment.rb、rackアプリではconfig.ruファイルの所有者でプロセスを立ち上げてくれるそうです。

(嫌ならPassengerDefaultUserディレクティブで他のユーザーに指定できる。)

当然、アップするファイルはそのユーザーで保存される。

しかし、アップした画像やページキャッシュなどの静的ファイルはApacheが直接見に行くのでpaperclipのアップ時のデフォルトのパーミッション(0600)だと見れない。(開発環境では個人のユーザーでmongrelを立ち上げるで問題が出なかった。)

対処方法は色々あるけど、やはりpaperclipが0644で保存してくれるのが一番じゃないだろうか。

ファイルの作成をそもそも0644にしようと思ってみてみると、paperclipでは標準ライブラリのtempfileでアップしたファイルを保存し、それをmvしてる。tempfileが0600で作るのでそのままだ。

例によってconfig/initializers以下で上書きする。

config/initializers/paperclip.rb:

module Paperclip
  module Storage
    module Filesystem
      def flush_writes #:nodoc:
        logger.info("[paperclip] Writing files for #{name}")
        @queued_for_write.each do |style, file|
          FileUtils.mkdir_p(File.dirname(path(style)))
          logger.info("[paperclip] -> #{path(style)}")
          FileUtils.mv(file.path, path(style))
          FileUtils.chmod(0644, path(style))
          file.close
        end
        @queued_for_write = {}
      end
    end
  end
end

mvした後でchmodする。(10行目) もっと局所的に書き換えたかったけどメソッドに切り出されてないのでここを変えた。

今回、本番デプロイ時にtagもbrunchも切ってないというミスを犯していたのでこのファイルだけ手でアップするという荒業に出た。反省・・・。

第七十七景:アプリケーションはemacsに集約してシンプルな作業環境を構築 wadap – デスクトップ百景

■ VMwareで3つのOSを同時に起動

他には、各種OSの検証を行うために「VMwareFusion」をインストールし、いろいろなOSをすぐに立ち上げられる状態にしています。

そういえば3つの環境を使えるのってMacだけですな。欲しいな。

パーマリンクが”“非連続な0を含まない自然数”“と定義できるのが嬉しいなどと、生活力の無さそうな発言が続いてますが(言ってない)、一応、昼間は仕事をしています。

原理主義的な仕様やコードを書くのは癒しのためです。そうしておくと仕事では目を覆いたくなるようなアドホックな実装も楽しめます。

p0t.jp ドメインからこの docs.komagata.org(ついでにMTから自作ツール)に引っ越してしばらく経ちましたが大体ちゃんとリダイレクトできてるみたいです。

Google Analyticsで見てみると・・・

contents_summary

おおお、きもちー!

俺がやりたかったのはこれだー!

/index.csv とかからCSV形式でエクスポート(というか表示形式がCSVなだけ)できるので他の形式への変換とか引越しもいかにも楽そう。パーマリンクが複雑だとそれを移行することを想像してソワソワする(病気)んだけどそれがなくなりました。

そもそもひとつのCSVで全データを表現できるということはエントリーが構造化されてないという証なので機能追加するときは

「ひとつのCSVでエクスポートできるか?」

というのを目安にしようと思った。

ここのAtomをRailsのAtomFeedHelper#atom_feedで出力してたんですが、基本全て数値文字参照で出る。

エンコーディングに関係無く表示されるので正しくはあるんだろうけど、クロールされてるところ(Planet PHP Japanなど)ではもう一度エスケープがかかって数値の羅列になってしまう。

フィードクライアントとしては数値文字参照をHTMLとして解釈した上でエスケープする必要があるだろう。しかし、自分がクロールする側になったら正直、

「面倒だから数値文字参照などにせんでくれ・・・」

と思うだろう。

しかもそういったクライアントを通して見る第三者の人にとってはそんなサーバークライアント間のやり取りなどどうでもいいことで、単に

「文字化けうぜぇえええ」

である。

atom_feedメソッドでのHTMLのエスケープはたくさんのクラスを遡って、最終的にはここ(String#to_xs)でやってるらしい。

/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb:

class Fixnum
  XChar = Builder::XChar if ! defined?(XChar)

  # XML escaped version of chr
  def xchr
    n = XChar::CP1252[self] || self
    case n when *XChar::VALID
      XChar::PREDEFINED[n] or (n<128 ? n.chr : "&##{n};")
    else
      '*'
    end
  end
end

(...snip...)

class String
  # XML escaped version of to_s
  def to_xs
    unpack('U*').map {|n| n.xchr}.join # ASCII, UTF-8
  rescue
    unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252
  end
end

コメントを見ると、そもそもコレ自体XCharライブラリーというのを拝借しているものらしい。

Wikipediaによると、西欧22言語をサポートするISO-8859-1もCP1252も共にLatin1と呼ばれますが、IBM由来のMicrosoft Codepage(CP)では0×80から0×9Fの範囲の文字が拡張されています。(ユーロ、ダガーとか)

要はShift_JISとCP932みたいな問題がLatin1とCP1252にもあるんですな。

何のためのライブラリかというと、多言語化の時に問題になりそうなそのCP1252の拡張部分を適当な文字にマッピングするためのものらしい。(自動的にCP932で書いたら問題が起きそうなことが予想できる)

とりあえずUnicodeをUTF-8で使ってれば問題無いだろうということで下記の様に対処した。

config/initializers/rails_ext.rb:

class String
  def to_xs
    ERB::Util.html_escape(self)
  end
end

大丈夫かな?

ActiveRecordでcreated_atとかupdated_atを自動更新したくない場合はモデルのクラス変数record_timestampsをfalseにすればいいんだって!

class Doc < ActiveRecord::Base
  @@record_timestamps = false
end

ッアース!(Ass)

Googleツールバーってポイントして翻訳する機能があったんですな!(via rono23

translate_rack

うおおおおおべんりいいいいいい!

携帯で自分の住所は、「メニュー」「0(ゼロ)」!!!

いっつも忘れるので。