読者です 読者をやめる 読者になる 読者になる

メソッドの呼び出し方

PHPでは、static宣言なしでもメソッドのstatic呼び出しができてしまう。
で、どっちが速いの?という話。
メモリの使用量も比べてみたかったけど、速さのみ。

<?php
require_once 'Benchmark/Timer.php';

class MyTest {
  public function myMethod() {
    return;
  }
  public static function staticMethod() {
    return;
  }
}

$max = 100000;
$timer = new Benchmark_Timer();
$t = new MyTest();

$timer->start();

for($i = 0; $i < $max; $i++) {
  MyTest::staticMethod();
}
$timer->setMarker('static');

for($i = 0; $i < $max; $i++) {
  MyTest::myMethod();
}
$timer->setMarker('static2');

for($i = 0; $i < $max; $i++) {
	$t->myMethod();
}
$timer->setMarker('instance');

$timer->stop();
$timer->display();

/*
------------------------------------------------------
marker    time index            ex time         perct   
------------------------------------------------------
Start     1293934691.81032700   -                0.00%
------------------------------------------------------
static    1293934691.85720200   0.046875        21.74%
------------------------------------------------------
static2   1293934691.99593900   0.138737        64.35%
------------------------------------------------------
instance  1293934692.02592700   0.029988        13.91%
------------------------------------------------------
Stop      1293934692.02593700   0.000010         0.00%
------------------------------------------------------
total     -                     0.215610       100.00%
------------------------------------------------------
*/
$ php --version
PHP 5.3.3 (cli) (built: Aug 22 2010 19:41:55)

static宣言なしのメソッドをstaticに呼ぶのは遅いってことかしら。

ちなみにrubyだとこうなった。
static methodは存在しないので、class method。このへんはうろ覚えなので、ちょっと自信ない・・・

require 'benchmark'

class MyTest
  def myMethod
    1 + 2
  end

  def self.classMethod
    1 + 2
  end
end

module MyModule
  def moduleMethod
    1 + 2
  end
end

module MyModule2
  def moduleClassMethod
    1 + 2
  end
end

max = 100000;

Benchmark.bmbm(10) do |x|
  t = MyTest.new
  x.report("instance: ") {
    max.times do
      t.myMethod
    end
  }

  x.report("class   : ") {
    max.times do
      MyTest::classMethod
    end
  }

  MyTest.class_eval {
    include MyModule
  }
  t = MyTest.new
  x.report("module : ") {
    max.times do
      t.moduleMethod
    end
  }

  MyTest.extend MyModule2
  x.report("module class : ") {
    max.times do
      MyTest::moduleClassMethod
    end
  }
end
Rehearsal ---------------------------------------------------
instance:         0.040000   0.000000   0.040000 (  0.043314)
class   :         0.050000   0.000000   0.050000 (  0.049375)
module :          0.040000   0.000000   0.040000 (  0.042887)
module class :    0.050000   0.000000   0.050000 (  0.045320)
------------------------------------------ total: 0.180000sec

                      user     system      total        real
instance:         0.040000   0.000000   0.040000 (  0.042020)
class   :         0.040000   0.000000   0.040000 (  0.046069)
module :          0.040000   0.000000   0.040000 (  0.041350)
module class :    0.040000   0.000000   0.040000 (  0.045474)
$ ruby --version
ruby 1.8.7 (2010-08-16 patchlevel 302) [i686-darwin10]

マージソート

基本に立ち戻って、マージソートをやってみた。
Ruby, C, Scala, Gaucheの4種類。
最初にRubyで書いて、他に移植という流れ。


ScalaGaucheはほぼ同じ。普通に再帰で書いたけど、Scalaは末尾再帰に最適化されてるそうな。


Cだけは配列をガンガン作ろうとするとmallocが大変なことになるので、1つを使いまわす形に。
tempはmallocしないで静的に定義してもいいかも。
Cはまだまだ慣れない。


Ruby

C

Scala

Gauche

Google Readerの"v"で背面にタブを開くChrome拡張を作りました

た。
Google Reader Open entry in background tab - Google Chrome extension gallery

いくつか既存のがあるのですが、1度に複数タブが開いてしまったりキーが他のだったりで自分の使い方にはあわなかったので、
作ってしまいました。

とりあえず最低限の機能だけ付けて公開しています。
バグとかこうして欲しいみたいなのがあったらコメントでください!

雑感とか

  • Chrome 拡張は開発しやすい。デバッガが素敵!!
  • Javascriptをまともに書いたことなかったので、DOMのイベントリスナ周りで四苦八苦
  • Star openerも付けたい
  • キーも入れ替えられるようにしたい

東京Ruby会議#03に行ってきた

とても内容が濃く、充実した会議(講義?)でした!
スタッフ・講師の皆様お疲れ様でした。


セッションがかなりヘビーというか、Rubyの実装周りの話がてんこ盛りで
ついていくのがやっと or ついていけてない部分もありました。
でも、勉強になる部分がとても多かったです。


勉強不足を痛感したので、さらに頑張ろうっと。

会議自体へのフィードバック

  • 喫茶無償++
  • 今度はGCの話とか聞いてみたい!


というわけでメモ公開。
聞くだけでもいっぱいいっぱいだったので、正確ではないかもしれません。


Yuguiさん メタプログラミング



  • メタプログラミングとは

  • Rubyにおける特性

  • 道具立て

  • 用例


メタプログラミングとは


プログラムをプログラミングすること




  • ループ

    • 繰り返し


  • 例としてのアクセサ

    • getter/setter をメタプロ



Rubyの特性


  1. S式ではない!

  2. First Class Object

  3. コンパイルがない


非S式


  • メタプログラミングといえばLisp

  • Rubyには?

    1. ブロック

      • proc


    2. 文字列

      • 文字列を生成してeval

      • eval<<-EOS, binding,FILE, __LINE__+1を渡して、スタックトレースを読めるようにする




コンパイルがない


  • 実行時間とコンパイル時間が同一=隠蔽している

    • 内部的にはASTに変換、1.9ではコンパイルしている




  • 副作用が気軽に使える

  • classは定義ではなく、副作用を持つ式である

    • クラスの継承元すら動的に定義できる

    • メソッド定義も条件式で分岐させるなど

    • 動的すぎるため、最適化が難しい。rubyを遅くしている原因のひとつ


  • C++では?

    • Templateでできる。けどつらい。

    • コンパイル時に決まってしまう

    • Boost MPLライブラリを使う


  • 副作用の代表格: IO



  • 構文の変更不可

  • Lispだとリーダーマクロ

    • Matzter Yoda はマクロを否定

    • Rubyでは予約語の変更ができない


  • Rubyでは言語内DSLが不能

    • ブロックを使って言語内DSLを実現可能



ex.) Rake
task :a, do... end


  • マクロではなく、ブロックでバランスをとる

  • Rubyのメタプログラミングに不安を感じる人はJavaへ。


道具立て


  • class

    • 特異クラス


  • callable object

  • eval族

  • method_missing, send


class


  • Classクラスのインスタンス

  • クラス階層

    • BasicObject

    • Object

    • Module

    • Class


  • 特異メソッド

    • クラスのあるインスタンスにだけ存在するメソッド

    • クラスメソッドとして頻繁に使用




  • 特異クラス

    • 元クラスから継承したクラスに内部的に付け替える


  • 特異クラスの定義イディオム


eigenclass = (class << obj; self end)


  • 特異メソッドは内部で特異クラスを定義している


obj = Object.new
class << obj
def foo; end
end


  • クラスメソッド

    • 実際はClassオブジェクトの特異メソッドを定義している

    • つまり親クラスの特異メソッドとして扱われているだけ。特殊な定義ではない。

    • クラスのクラスはメタクラス


  • 全てのクラスはClassクラスの特異クラス

    • 図が欲しい。 => yuguiさんのflikr


  • メタクラスのクラスはメタメタクラス

  • boot時にメタクラスを全て作るとメモリがなくなる。


呼び出し可能オブジェクト


  • Object

    • Proc

    • Method

    • UnboundMethod

    • Continuation





  • 相互変換可能


eval族


  • eval

  • instance_eval

  • class_eval



  • current class

  • TOP LEVEL

    • self: main

    • current class: Object


  • class expr

    • self: the class

    • cc: the class


  • def expr

    • self: insatnce

    • cc: NONE




  • コンテキストについて



  • instance_eval

  • self: instance

  • cc: eigenclass

    • レシーバの特異クラス




  • class_eval

  • self: class

  • cc: class



  • eval

  • コンテキストはbindingに依存 (引数で指定)


用例集

メソッド定義


  • define_methodでのブロック定義より、eval+heredoc の方が実行速度は早い

    • railsはeval多用

    • define_methodならシンタックスハイライトとかシンタックスエラーを検出



メソッドをまとめて定義


  • 継承元クラスで実装が必要なメソッドにまとめてエラー定義


クラス定義

DSL


  • メソッド内でサンドボックスとなるオブジェクトを提供し、そこにModuleをextend。instance_evalで評価することで

    そのメソッド内のみでModuleの機能を使用可能


モジュール定義


  • サンドボックス定義

    • 評価するブロック内で変数を定義されたりしても、予期せぬ書き換えなどが防げる



def sandbox(block)
Module.new(&block)
end


  • リモートのdrbのプロセス状態を、手元の端末からirb相手側のプロセスにinstance_eval流し込み

    • リモートプロセスのirbを汚染しないため、生成したirbセッションで特異メソッド定義

    • printなどはリモートから手元の端末のIOに逆転送するようにメタプロ


  • drbのポートを不用意に開けておくとものすごく危険!


Rails 3 ハンズオン 松田さん


Rails 3とは?


  • beta版がリリースされている


インストール


  • gitプロトコルが通らない!

  • gemが入らない!

  • 環境は事前に準備しておきましょう。


アプリケーションを作成


  • コマンド出力がカラフル

  • .gitignore がデフォルト

    • 今後のバージョン管理はgitで!

    • .gitkeep もある




  • Model名にする予定のものはアプリケーション名にできない

  • Rubyのクラス名に使えないものはアプリケーション名にできない


HTML5準拠


  • jsが綺麗になった


Model


  • validates がカラムを基準にかけるようになった



A Reintroduction to Ruby i17n 成瀬さん



  • 日本に生まれたことを後悔したくなるらしい



  • 字体としては、JISでは同じだがUnicodeでは別

  • 符号化文字集合 = コードポイント

  • 文字符号化方式: 符号化文字集合の番号をバイト列に変換する

  • エンコーディングとは?

  • Charset: 各エンコーディングに名前をつけて管理するためのもの

    • 現実と仕様の乖離も存在する


  • 用語の整理


I18N


  • 略語まとめ

    • L10N (地域化)

    • I18N (国際化)

    • M17N (多言語化)



歴史


  • ASCIIが始まり

  • 拡張してみた

    • 大量の文字集合が・・・

    • 敵を知る。知った上で個別撃破


  • ISO 646 – 分裂の始まり

  • Unicode

    • 1つのUnicode文字列には複数の言語を混ぜられない

    • フラットな空間にすべての文字を入れる

    • 漢字統合: 言語の指定が必要

    • ASCIIも言語の指定が必要


  • Unicode以前の文字コードは?

    • CP932



円記号問題


  • バックスラッシュを円記号に変換してしまう

  • Shift_JISでの0x5C

  • Unicodeでは U+005C

    • Windowsでは日本語フォントだけ円記号にしている



波ダッシュ問題


  • U+301C (WAVEDASH)


機種依存文字


処理系の問題


  • 内部コードをどうするか?

    • UCS正規化: 内部では特定の1つに変換する

      • 内部コードを統一

      • 入出力時に変換を行う


    • CSI (Code Set Independent): それぞれの文字コードに対応する



Ruby1.9


  • 文字単位での処理

  • 正規表現エンジンが鬼車に

  • 文字型はなく、1文字Stringを使う

  • 文字型に必要なもの

    • コードポイント、エンコーディング


  • 1.9.1-p3xxや1.9.2では\wがASCIIのみにマッチするようになった

  • 適切にencodingを設定しておく


Magic Comment


  • デフォルトはASCII

  • ERBにも必要



<%= #coding : utf-8 %>



IOとEncoding


  • 入出力のEncodingを指定する

  • open (‘text.txt’, ‘r:UTF-8’)

  • ネットワークではバイナリ扱い => 強制指定 (force_encoding)する

    • socketやnet系のライブラリで必要

    • 濫用は避けましょう


  • KCODEはやめましょう



エンコーディング


  • ASCII互換

  • ASCII非互換

  • ダミー


エンコーディング変換


  • nkf

  • kconv

  • iconv

  • uconv

  • String#encode

  • Encoding::Converter



  • SJISWindows-31Jは混同しやすい

  • M17N未対応のライブラリを使った時など

    • ASCII-8BIT でかえされるので、明示的にエンコーディングを指定する



Ruby 1.9 での課題


  • 携帯絵文字: 対応中

  • 結合文字

    • 複数のコードポイントを1文字として扱う。濁音や半濁音など


  • 異体字セレクタ (IVS): Ideographic Variation Sequence

    • 結合文字同様、複数のコードポイントを1文字扱いする必要がある


  • 1つのStringに2つの言語を入れたい



  • 文字幅

    • 言語に依存して期待される幅が異なる


  • Unicode大文字小文字

    • ASCIIでしか動作しない


  • String#sort

  • 文字集合によって並び順が変わってしまう

    • sort_byで指定する




  • よいAPIを設計するには、ユースケースの収集が大事。feedbackが重要

  • Magic Commentを書け。


Open 3 のはなし 田中 哲 (akr)さん



  • Rubyからのプロセス起動

    • 問題点: system, IO.popen…




  • 解決

    • spawn メソッドの追加

    • open3ライブラリの追加



プロセス属性


  • ファイルディスクリプタ

  • Unixのプロセス起動はforkとexecを組み合わせる

    • 2つのコマンドの間にプロセス属性を変更することで、パイプやリダイレクトを実現する


  • Unix以外ではプロセス属性変更のために引数が複雑になりがち


Rubyで実現したいこと


  • OSが提供するプロセス起動機能を使いたい

  • シェルで出来ることをRubyでもやりたい

  • Unixと非Unixでの差異を吸収したい

  • よくやることは簡単に

  • できることはなんでもできる


API

既存のメソッドを拡張する?


  • forkは非Unixでは動きそうにない

  • system: プロセスを待たないようにするのは変

  • IO.popen: パイプなしは変

  • `command`: 構文上、指定を付加しづらい


新しいメソッドを作る


  • 要求が衝突する

  • よくやることを簡単にできる

  • なんでも可能なのが欲しい

  • => ひとつのメソッドで全ての要求を満たすのは困難



  • 高位・低位APIへ分割


ライブラリのレイヤ



  • どのレイヤのライブラリを提供するか?

  • 高位になるほどライブラリの自由度が高く「賢い」

  • 低位になるほど詳細な制御が可能になる

低位API: spawn


  • OS固有の機能も利用可能

  • OS間で共通の機能については差を気にしなくてよいくらいには高位


既存メソッドへの不満


  • 既存メソッドはシェルを呼び出す

    • シェルを呼びたくないこともある



基本の使い方

spawn(env, command, option)


pid = spawn("make all")
Process.wait pid


  • 引数を分けて与えるとシェルを経由しない


spawn("make", "all")


  • 最初の引数を配列にするとargv0も指定できる



  • リダイレクト


spawn("make all", :out => "make.log")

spawn("make all", :err => :out)

spawn("make akk", :out => :err, :err => :out)


  • パイプ


IO.pipe {|r,w|
spawn("ls", :out => w)
spawn("sort -r", :in => r)
}


spawn({LC => 'env'}, "ls -l")

spawnのデザイン


  • 多機能なものが単一関数でいいのか?

  • 簡単なことが難しくなっていいのか?

    • posix_spawnの複雑な引数を吸収している


  • 将来の拡張に耐えられるか?

    • キーワード引数


  • fdの扱いは適切か?

    • 最終的な状態を指定する

    • 3番以降のfdを継承しない

    • 子と親のfdの関係を書く




  • fork はメモリ内部もコピーする

  • Rubyでforkを避ける理由

    • NetBSD4ではforkした子プロセスではスレッドが動かない

    • Ruby1.9 ではタイマースレッドというスレッドを常に必要とするから




  • POSIXではfdに空きがないなどの理由で今のposix_spawnになった


spawnのまとめ


  • プロセスを起動するプリミティブ

  • fork + プロセス属性変更 + exec


高位API: open3


  • とりあえずシェルのパイプラインくらいまで提供

  • シェルの嫌なところは避ける

  • パイプよりも複雑な用途は今後の課題



  • 標準添付ライブラリ

  • 3つの標準パイプでコマンドと通信する

  • 命名はPerl由来


Open3.popen3("command") {|i, o, e|
# some script
}

既存のopen3nの問題


  • ゾンビの回収とdouble fork

    • 親がwaitせずに死ぬと、子はinitの養子になる

    • initはwaitしまくって亡骸を回収する

    • 意図的にdouble forkすることでゾンビを防止




  • double forkの問題点

    • pidを得られない: シグナルを送りづらい

    • 終了ステータスを得られない




  • open3 類が乱立


解決法


  • Process.detach によってwaitスレッドを生成することで解決



  • 標準エラー出力はパイプにしない方がよいことも多い

  • ひとつのパイプにして提供して、制御しやすくもできる


Open3で解決した問題

※ (問題自体を書き逃した)

  • Open3.capture*

  • Open3.popen2e*

  • Open3.pipeline*



  • spawnによるパイプラインは厄介

    • 大学の試験になるくらい




  • shell ライブラリ

    • shellの記法を模したDSL


*1:帰宅後にedgeの環境用意したけど、まだ試せていない

Rails3 リリースノート全文和訳 (ただし適当)

英語は苦手ですが、Rails 3 での変更を知りたかったのと和訳の練習を兼ねて訳してみました。
英語力がないのでかなり出来が悪いですが・・・
公開するか迷いましたが、恥を晒します。

間違いなどがありましたらご連絡を頂けるとうれしいです m(_ _)m

(追記)
id:willnet さんも和訳をされていました。
実際にRailsを触っている方なので、内容も詳しく正確と思われます。
後編にも期待!!
Rails 3.0 リリースノート和訳 - 前編 - おもしろWEBサービス開発日記


原文: Rails 3.0: Release Notes

1 Rails 2.3.5 から Rails 3 へのアップグレード

いつものように、アップグレードの時はカバー率の高いテストスイートがあなたの味方です。
Rail3 にアップグレードする前に、まず最初に Rails2.3.5 にアップグレードし、アプリケーションがちゃんと動作することを確認してください。
一般的に、 Rails 2.x 系から Rails 3 へは大きく3つの変更があります。

1.1 Ruby 1.8.6 はサポート対象外になりました

Rails 3 は Ruby 1.8.7 以上が必要です。Ruby 1.9.2 は現在、完全にサポート対象になりました。
以前のRubyバージョンは公式サポートから外れるので、早急にアップグレードする必要があります。

1.2 Rails Application Object

1 つのプロセスで複数の Rails アプリケーションを動作させる基板の一部として、 Rails 3 Application Object の概念を導入しました。

Rails アプリケーションは、対応する Application Objectを持つ必要があります。
Application Objectは通常 config/application.rb に定義されます。
既存のアプリケーションを Rails 3 にアップグレードするなら、このファイルを追加し、適切な設定を config/environment.rb 移動させる必要があります。

1.3 script/* は script/rails に移動しました

rails バイナリは Rails 3 で更新され、 script/rails となりました。
script/ 以下にあったコマンドの代わりに、rails コマンドを使ってください。

$ rails console                      # => ./script/console
$ rails g scaffold post title:string # => ./script/generate scaffold post title:string
1.4 config.gem の依存関係

config.gem メソッドは、 bundler と Gemfile に置き換えられました。
詳しくは Vendoring Gems の項を参照してください。

1.5 新しい API

ルーターとクエリのインターフェースが大幅に変更されました。
Rails 3.1 までは後方互換性がサポートされます。

1.6 アップグレード作業

アップグレードの一部を自動化するため、Rails Upgradeというプラグインが作成されました。

プラグインのインストール後、 rake:upgrade:check でアプリケーション内でアップデートする必要のある部分を確認します(アップデートの方法はリンク先にあります)。
またプラグインは、今の config.gem ファイルをもとに Gemfile を作成し、新しいroutesファイルを作成します。
プラグインのインストールは簡単です。

$ rails plugin install git://github.com/rails/rails_upgrade.git

仕組みの解説は以下のリンクを参照してください。
Rails Upgrade is now an Official Plugin

Rails アップグレードツールはともかく、さらに情報が欲しければ、IRCgoogle groupの rubyonrails-talkに同じ問題を持っていたり、解決できる人がいるかもしれません。
アップグレードの体験は必ずブログに書き、他の人と知識を共有しましょう!

詳細: The Path to Rails 3: Approaching the upgrade

2 アプリケーション作成

上記のように、Ruby 1.8.7 以上で Rails アプリケーションを作成する必要があります。Ruby 1.8.6 以下ではもはや動作しません。
Rails 3.0 は 1.8.7 で動作するようになっており、1.9.x サポートはまだテスト中です。

Rails アプリケーション作成をしていた rails スクリプトはいくつかの変更がありました。
 ・rails my_app とアプリケーション名を指定する代わりに、パスを指定することができます(rails ~/code/my_app)。rails アプリケーションは rails に指定したアプリケーション名を名前空間として持ちます。???
 ・さらに、アプリケーションを作成するのに必要なフラグはアプリケーションパスの下に置く必要があります。???

新しいrailsのインストール方法は以下の通りです(beta用)。

$ gem install rails --prerelease
$ rails myapp
$ cd myapp
2.1 Gems ベンダー

Rails は Gemfile を使うようになりました。アプリケーションに必要なgemを探し出します。
Gemfile は新しい Bundler という gem で読み込まれます。Bundlerは必要なgemをvendorディレクトリに置き、Railsアプリケーションをシステムの gem から切り離します。
(訳注: アプリケーションはvendorディレクトリ内のgemのみを見ると思われる)

さらに詳細はUsing bundlerを見てください。

2.2 Edgeオプション

Bundler gemとGemfileを使うことによって、bundle コマンドでいつでもRailsアプリを'凍結'することができます。そのため、 rake freeze はなくなりました。

Gitリポジトリから直接bundleする場合は、 --edge オプションを使用してください。

$ rails myapp --edge


ローカルにRailsリポジトリをチェックアウトし、そこからアプリケーションを生成する場合は --dev オプションを使用してください。

$ ruby /path/to/rails/railties/bin/rails myapp --dev

詳細:
Spinning up a new Rails app
Rails 3 and Passenger

3 Rails アーキテクチャの変更

Rails アーキテクチャには6つの大きな変更がありました

3.1 Railsties の再構成

(訳注: restrungが不明)

Railstiesは一貫したプラグインAPIを提供するように改善されました。Rails フレームワークはジェネレータと結合部分をほぼ書きなおしました。
これにより、開発者は決められた方法に従うことで、ジェネレータとフレームワークのあらゆる場所へアクセスできます。

3.2 Railsの全主要コンポーネントの切り離し

MerbとRailsのマージによる大きな変更のひとつは、密結合だった Rails コアコンポーネントの切り離しです。すべてのRailsコアコンポーネントは、あなたが開発するプラグインと同じAPIを通して動作します。
これはどんなプラグインでも、コアコンポーネントを置き換えるもの(DataMapperやSequelなど)でも、Railsコアコンポーネントがアクセスしているすべての機能にアクセスできるということです。機能の拡張や強化も可能です。

詳細:
The Great Decoupling

3.3 Active Modelの抽象化

コアコンポーネントの切り離しによって、Active Record は Action Pack から解放されました。
これはすでに達成しています。新しいO/RマッパープラグインをAction Packとシームレスに繋ぐには、Active Model インターフェースを実装してください。

詳細: Make Any Ruby Object Feel Like ActiveRecord

3.4 Controllerの抽象化

もうひとつの大きな切り離しは、ベースとなるスーパークラスを作成したことです。
これはビューの描画を行うためにHTTPの概念を分離しました。
AbstractControllerの追加はActionControllerとActionmailerをたいへん簡略化しました。共通のコードを削除し、AbstractControllerに置き換えました。

詳細: Rails Edge Architecture

3.5 Arel の統合

Arel(Active Relation)はActive Recordの基礎であり、Railsに必要なものとなっています(gem bundleを実行する時にインストールされます)。
ArelはActive Recordを簡略化するSQL抽象化と、リレーション機能の基礎を提供します。

詳細: Why I wrote Arel

3.6 Mail 抽出

Action Mailerは始まって以来ずっとソースツリーにTMailを持っていることに加えて、モンキーパッチやプリパーサ、送受信エージェントさえ持っていました。
Rail 3 では emailメッセージ に関わる機能を抽象化して Mail gem に分けました。
コードの重複を減らし、Action Mailerとemailパーサの境界を作ることにも成功しています。

詳細: New Action mailer API in Rails 3

4 ドキュメント

Railsでの文書化についてはは、APIの変更が更新されています。それに加え、Rails Edge guidesにRails 3.0での変更が一つずつ反映されています。
guides.rubyonrails.org のガイドは安定バージョンのみを含んでいます(現時点では3.0がリリースされるまでは2.3.5)。

詳細: Rails Documentation Progects

5 国際化

Rails 3 での i18n サポートはほとんど完了しています。最新の i18n gem は多くの速度改善を含んでいます。


  • i18n はActiveModel::TransLationやActiveModel::Validationsを含むすべてのオブジェクトに追加できます。また、翻訳が失敗するとerrors.messageにエラーメッセージが格納されます。

  • 属性にデフォルトの翻訳を持つことができます

  • FormのSubmitタグはオブジェクトの状態にしたがって自動的に状態を取得します。その時に翻訳も取得します

  • i18nを持つラベルは属性名を通して実行されます

詳細: Rails 3 I18n changes

6 Railties

Rails フレームワークの切り離しで、Railtiesは互換性と拡張性を可能な限り保ったままengineやプラグインと連携するために、大きくオーバーホールされました。


  • 各アプリケーションは各自の名前空間を持ちます。例えば、アプリケーションが YourAppName.boot で開始されたら、他のアプリケーションと連携させるのは簡単です。

  • Rails.root/app 以下にあるものはロードパスに追加され、 app/observers/user_observer.rb を作成することで、変更なしにRailsに読み込まれます。

  • Rails 3 は Rails.config オブジェクトを提供します。これはRailsの多くの設定オプションの中央リポジトリを提供します。

アプリケーション作成時に、オプションを受け取ります。test-unit、Active Record, Prototype, Gitのインストールを行わないオプションです。
また、新しい -dev オプションが追加されました。Gemfile があなたの使用しているRailsバージョンを指すように変更します(railsバイナリのおかれているパスを元に決まります)。詳しくは rails -help を参照してください。

Rails 3 でのジェネレータは多くの注意が必要です。


  • ジェネレータは書き換えられており、後方互換性はありません。

  • RailsテンプレートAPIとジェネレータAPI はマージされました(前者と同じです)。

  • ジェネレータは特別なパスからは読み込まれません。Rubyのロードパスを検索し、 rails generate foo で呼び出されれば generators/foo_generator を読み込みます

  • 新しいジェネレータはフックを提供します。テンプレートエンジンやO/Rマッパー、テストフレームワークは簡単にフックを利用できます

  • 新しいジェネレータは RAILS_ROOT/lib/templates にコピーを置くことで、テンプレートの上書きができます

  • Rails::Generators::TestCase は独自ジェネレータとそのテストを作成する助けになります

また、Railtiesのジェネレータで作成されたビューも見直されました。


  • p タグの代わりに div タグを使うようになりました。

  • Scaffold作成時に、editとnewビューでコードが重複していた部分を _form partialに変更しました

  • Scaffoldのフォームがf.submitを使うようになりました。これはオブジェクトの状態にしたがって"Create ModelName"か"Update ModelName"を返します

最終的にrakeタスクに機能が追加されました。


  • rake db:forward マイグレーションを個別またはグループでロールフォワードします

  • rake routes CONTROLLER=x 1つのコントローラに関するroutesを参照します

非推奨となったのは以下の通りです。


  • RAILS_ROOT は Rails.root に変更されます

  • RAILS_ENV は Rails.env に変更されます

  • RAILS_DEFAULT_LOGGER は Rails.logger に変更されます

PLUGIN/rails/tasks, PLUGIN/tasks は参照されません。
PLUGIN/lib/tasks を使ってください。

詳細:
Discovering Rails 3 generators
Making Generators for Rails 3 with Thor

7 Action Pack

Action Pack では、内部・外部ともに重要な変更がされています。

7.1 Abstract Controller

Abstract Controller は再利用可能なモジュールから Action Controller の汎用パーツを取り出します。
ライブラリは、テンプレートの描画、ビューの一部の描画、ヘルパー、翻訳、ロギング、リクエストからレスポンスの周期のあらゆる部分を使用できます。
この抽象化によって、ActionMailer::Base は AbstractController を継承し、Mail gemを Rails DSL でラップすることが可能になりました。

Abstract Controller は Action Controller をきれいにする良い機会をもたらし、抽象化によってシンプルなコードにできました。

しかし注意としては、 Abstract Controller はユーザ向けのAPIではありません。 Rails を日々使っていく中では出会うことはないでしょう。

詳細: Rails Edge Architecture

7.2 Action Controller


  • application_controller.rb はデフォルトで protect_from_forgery を持つようになります

  • cookie_verifier_secret は initializers/cookie_verification_secret.rb に移動しました

  • session_store 設定は initializers/session_store.rb に移動しました

  • cookies.secure によってcookieの値を暗号化できます。 cookie.secure[:key] => value

  • cookies.permanent によってcookieに永続的な値をセットできます。値が検証に失敗したら、例外が発生します。 cookie.permanent[:key] => value

  • respond_to ブロックの中で :notice => ‘This is a flash message’ または :alert => ‘Something went wrong’ という形で format メソッドに渡せます。flash[]ハッシュはまだ以前のように動作します。

  • respond_with メソッドが追加されました。古い format ブロックを簡略化します

  • ActionController::Responder が追加されました。柔軟なレスポンス作成方法を提供します。

非推奨:


  • filter_parameter_logging は廃止されました。config.filter_parameters << :password を使ってください

詳細:
Render Options in Rails 3
Three reasons to love ActionController::Responder

7.3 Action Dispatch

Action Dispatch は Rails 3.0 で追加された、シンプルで新しいルーティング実装です。


  • ルーターを大幅に書き換えました。現在Railsのルータは DSLを乗せた rack_mount です。スタンドアロンソフトウェアになっています。()

  • 各アプリケーションで定義されるルーティング情報は、名前空間を持ちます。
  • # Instead of:
    
    ActionController::Routing::Routes.draw do |map|
      map.resources :posts
    end
    
    # You do:
    
    AppName::Application.routes do
      resources :posts
    end
    

  • ルーターに match メソッドが追加されました。マッチしたルート情報にRackアプリケーションを渡すことができます。

  • constraintsメソッドが追加されました。制約を定義しておくことで、ルーティング情報を保護することができます。

  • scope メソッドが追加されました。異なる言語やアクションに名前空間を定義することができます。
  • scope 'es' do
      resources :projects, :path_names => { :edit => 'cambiar' }, :as => 'projeto'
    end
    
    # Gives you the edit action with /es/projeto/1/cambiar
    

  • rootメソッドが追加されました。 match '/', :to => path の省略です

  • match メソッドでは任意にマッチする文字列を渡せます。例えば、 match "/:controller(/:action(/:id))(.:format)"という表現では、各括弧内は任意にマッチされます。(訳注: 括弧内の表現がなくてもマッチされ、あれば変数として評価されるものと思われる。うまい表現が見つからない)

  • ルーティング情報はブロックでも表せます。例えば、こんな呼び方ができます。 controller :home { match '/:action' }

※ 昔ながらの map コマンドは後方互換性を保つため、Rails 3.1 リリースまでは動作します。


非推奨:


  • 非RESTアプリケーションのルーティングの問題 (/:controller/:action/:id)はコメントアウトされました

  • :path_prefixは廃止されました。:name_prefixは値の末尾に自動的に"_"を追加します

詳細:

  • The Rails 3 Router: Rack it Up

  • Revamped Routes in Rails 3

  • Generic Actions in Rails 3
  • 7.4 Action View

    Action View ヘルパーは大幅に書き直されました。Unobtrusive JavaScript (UJS) フックが実装され、古いインラインAJAXコマンドは削除されました。
    ヘルパー内でUJSフックを実装することでUJS準拠のドライバを使用することができます。

    これは、以前の remote_ ヘルパーはRailsコアから削除され Prototype Legacy Helper に移動しました。HTMLでUJSフックを使うには、 :remote => true を指定してください。

    form_for @post, :remote => true
    

    生成されるタグ:

    <form action="http://host.com" id="create-post" method="post" data-remote="true">
    


    • HTMLのエスケープメソッド h(string) を使う必要はありません。すべてのビューでデフォルトで実行されるようになりました。もしエスケープしたくなければ、 raw(string)を使ってください

    • ヘルパーの出力はHTML5になりました

    • FormラベルヘルパーはI18nから値を取得します。f.label :name は :name の翻訳文を表示します。

    • I18n のselectラベルは :en.support.select の代わりに :en.helpers.select に変更されました

    • ERbテンプレート内にRubyコードを書く時に、最後にマイナス記号が不要になりました。HTML出力の最後のキャリッジリターンを削除しています

    • grouped_collection_select ヘルパーを Action View に追加しました

    • javascript_include_tagやstylesheet_include_tagヘルパーに含まれているCSS/JSファイルが見つからない場合、Action Viewは例外を発生します。

    • content_for? メソッドが追加されました。Viewの描画前にコンテンツが存在するかを確認できます。

    8 Active Model

    Active Model は Rails 3.0 で新しく追加されました。これはどんなORMライブラリもActive Model インターフェースを実装することで、Railsとの対話に使用する抽象レイヤを提供します。

    8.1 ORM 抽象化 と Action Pack のインターフェース

    コアコンポーネントの分離で、Active Record は Action Pack から解放されました。
    これはすでに達成されています。すべての新しいORMプラグインは Active Model インターフェースを実装することで、Action Pack とシームレスにやりとりできます。

    詳細: Make Any Ruby Object Feel Like ActiveRecord

    8.2 値の検証 (ヴァリデーション)

    validationは Active Record から Active Model に移動しました。ORMライブラリを問わず動くvalidationインターフェースを提供します。


    • validates :attribute, options_hash ショートカットメソッドが追加されました。すべての validate メソッドにそれぞれ複数のオプションを渡すことができます。

    • validatesメソッドは次のオプションをもっています:

    • :acceptance => Boolean.

    • :confirmation => Boolean.

    • :exclusion => { :in => Ennumerable }.

    • :inclusion => { :in => Ennumerable }.

    • :format => { :with => Regexp, :on => :create }.

    • :length => { :maximum => Fixnum }.

    • :numericality => Boolean.

    • :presence => Boolean.

    • :uniqueness => Boolean.

    Rails 2.3 形式のすべてのヴァリデーションメソッドはRails 3.0 ではサポートされています。
    新しいvalidates メソッドは既存のヴァリデーションAPIを置き換えなくて良い場合のために用意されています。


    validator オブジェクトはActive Model を使うオブジェクト間で再利用できます。

    class TitleValidator &lt; ActiveModel::EachValidator
      Titles = ['Mr.', 'Mrs.', 'Dr.']
      def validate_each(record, attribute, value)
        unless Titles.include?(value)
          record.errors[attribute] &lt;&lt; 'must be a valid title'
        end
      end
    end
    
    class Person
      include ActiveModel::Validations
      attr_accessor :title
      validates :title, :presence =&gt; true, :title =&gt; true
    end
     
    # Or for Active Record
     
    class Person &lt; ActiveRecord::Base
      validates :title, :presence =&gt; true, :title =&gt; true
    end
    


    詳細:

    9 Active Record

    Rails 3.0 の Active Record は多くの注意が必要です。Active Model を内包している、クエリインターフェースがArelを使って全面的に見直されている、ヴァリデーションが変更されているなど、多くの機能追加と修正が行われいています。
    Rail 2.x で使えたAPIの多くは互換性レイヤで使えるようになっており、Rails 3.1 のリリースまではサポートされます。

    9.1 クエリインターフェース

    Active Record は Arel を使うようになり、コアメソッドでリレーションを返します。Rails 2.3.x の既存のAPIRails 3.1 まではサポートされ、非推奨ではありません。 Rails 3.2 までは廃止されませんが、新しい API は次のような新しいメソッドを提供し、すべて関係性を返すので、チェーンのようにつなぐことができます。


    • where - 返される値の状態を指定します

    • select - データベースから返して欲しい、モデルの属性を選択します

    • group - 属性による関係性でグループ化します

    • having - GROUP BY使用時にグループの絞り込み条件を指定します

    • joins - テーブル同士を結合します

    • clause - JOIN時に結合条件を指定します

    • includes - 関係のあるテーブルを先に読み込みます

    • order - 表現に従って並べ替えます

    • limit - 指定された数のレコードを取得します

    • lock - テーブルから返されたレコードをロックします

    • readonly - データの読み取り専用コピーを返します

    • from - 選択するテーブルを1つ以上指定します

    • scope - 以前のnamed_scope。他のメソッドとチェーンできる関係を返します

    • with_scope - with_exclusive_scope はどちらもチェーンできる関係を返します

    • default_scope - これも関係として働きます

    詳細:

    9.2 機能の追加


    • destroyed? メソッドが追加されました

    • inverse_of メソッドが追加されました。DBを叩かずにロード済みのインスタンスを返します。

    9.3 修正と廃止予定

    Active Record ブランチにはたくさんの修正が入りました


    • SQLite 2 のサポートが廃止されます。SQLite 3 を使ってください。

    • MySQLのカラムオーダーがサポートされます

    • PostgreSQLアダプタはタイムゾーンサポートが修正されました。間違った値は挿入されなくなります

    • PostgreSQLのマルチプルスキーマがサポートされました

    • PostgreSQLXMLデータ型カラムがサポートされました

    • table_name はキャッシュされます

    • Oracle アダプタの多くの不具合修正が行われました

    非推奨:


    • Active Record クラスの named_scope は非推奨になり、scope メソッドに変更されました

    • scope メソッドでは、関連するメソッドを移動する必要があります。:conditions => {} の代わりに例えば scope :since, lamda{|time| where("created_at > ?", time)} を使ってください

    • save(false) は非推奨になりました。 save(:validate => false)を使ってください

    • Active RecordのI18nのエラーメッセージは:en.activerecord.errors.template から :en.errors.template に変更されます

    • model.errors.on は非推奨になりました。model.errors[]を使ってください。

    • validates_presence_of は変更されました。validates... :presence => true

    • ActiveRecord::Base.colorize_logging と config.active_record.colorize_logging は非推奨になりました。Rails::Subscriver.colorize_logging か config.colorize_logging を使ってください。

    ここ数カ月のActive Record 最新版に実装されていた State Machine は Rails 3.0 リリースからは除外されました。

    10. Active Resource

    Active Resource も Active Model を使うことで、Action Pack からシームレスに扱うことができます。


    • Active Model 経由のvalidationを追加しました

    • 監視用のフックを追加しました

    • HTTPプロクシをサポートしました

    • ダイジェスト認証をサポートしました

    • モデル名をActive Modelの中に移動しました

    • Changed Active Resource attributes to a Hash with indifferent access.

    • first, last, allエイリアスをfindスコープと同等のものとして追加しました

    • find_everyは返すものがない場合、 ResourceNotFound エラーを返さなくなりました。

    • save! はオブジェクトが valid? でない場合に ResourceInvalid エラーを返すようになりました

    • update_attribute と update_attributes は Active Resource モデルに追加されました

    • exists? メソッドが追加されました

    • SchemaDefinition を Schema に、define_schema を schema にリネームしました

    • リモートのエラーを呼び出す時は content-type よりも Active Resources の format を使用してください

    • instance_eval が スキーマブロックで使われます

    • ActiveResource::ConnectionError#to_sが修正されました。@responseが#codeか#messageを持たない場合、Ruby 1.9 に対応します

    • JSONフォーマットのエラーをサポートしました

    • load は数値配列で動くことを保証します

    • リモートからの410レスポンスをリソースの削除として受け入れます

    • Active Resource接続にSSLオプションをセットする機能が追加されました

    • 接続タイムアウトの設定はNet::HTTPのopen_timeout に影響します

    非推奨:


    • save(false)は非推奨です。save(:validate => false) を使ってください。

    • Ruby 1.9.2: URI.parseと .decode は非推奨です。ライブラリ内でも使われていません。

    11 Active Support

    大きな努力によって、Active Support は好きな部分だけを使えるようになりました。Active Support 全体を読み込む必要なく、部分的に使用できます。
    そのため、Rails のコアコンポーネントがよりスリムに実行されます。

    Active Support の主な変更:


    • 不要なメソッドを削除して、ライブラリをきれいにしました

    • Active Support は TZInfo, Memcache_Client, Builder を提供しなくなりました。これらは依存として含まれ、bundle install コマンドでインストールできます

    • 安全なバッファが ActiveSupport::SafeBuffer に実装されました

    • Array.uniq_by と Array.uniq_by! が追加されました

    • TimeZone.seconds_to_utc_offset が誤った値を返していた不具合を修正しました

    • ActiveSupport::Notifications ミドルウェアが追加されました

    • ActiveSupport.use_standard_json_time_format のデフォルト値が true になりました

    • ActiveSupport.escape_html_entities_in_json のデフォルト値が false になりました

    • Integer#multiple_of? は0を受け入れるようになりました。レシーバが0でなければfalseを返します

    • string.chars は string.mb_chars に名前が変更されました

    • ActiveSupport::OrderedHash は YAML を通してデシリアライズされます

    • XmlMiniのSAXベースのパーサが追加されました。LibXMLとNokogiriが使われます。

    • Object#presenceが追加されました。#present? がtrueならばオブジェクトが返されます。そうでなければ nil が返されます。

    • DateTime に to_i が追加されました。DateTime属性を持つモデルでのto_yamlが正確になります。

    • Enumerable#exclude? が追加されました。Enumerable#include? と同等なので、!x.include? という書き方を避けましょう。

    • XSSエスケープが Rails でデフォルトになりました。

    • ActiveSupport::HashWithIndifferentAccess でディープマージがサポートされました。

    • Enumerable#sum がすべての enumerable で使用できます。:size に対応してなくても動作します。

    • inspect が0の長さのとき、空文字列の代わりに'0 seconds' を返すようになりました。

    • ModelName に element と collection が追加されました。

    • String#to_time と String#to_datetme が細かい秒数を返すようになりました。

    • :before と :after コールバックが filter オブジェクトに追加されました。

    • ActiveSupport::OrderedHash#to_a メソッドは並べかえられた配列を返します。Ruby 1.9 の Hash#to_a と同じです

    • MissingSourceFile 定数が追加されました。 LoadError と同じです。

    • Class#class_attribute が追加されました。サブクラスで継承とオーバーライドが可能な属性が宣言できます

    • 最終的に、ActiveRecord::Associations の DeprecatedCallbacks は削除されました

    次のメソッドは Ruby 1.8.7 と 1.9 に搭載されたため、削除されました。


    • Integer#even? と Integer#odd?

    • String#each_char

    • String#start_with? と String#end_with? (第3者のエイリアスは保持されています)

    • String#bytesize

    • Object#tap

    • Symbol#to_proc

    • Object#instance_variable_defined?

    • Enumerable#none?

    Active Suppor の REXML のセキュリティパッチは残ります。Ruby 1.8.7 のパッチレベルによっては必要だからです。Active Support はパッチが必要かを判断します。

    次のメソッドはフレームワーク内で使われていないため、削除されました。


    • Object#remove_subclass_of, Object#subclassed_of, Object#extend_with_included_modules_from, Object#extended_by

    • Class#subclasses, Class#reachable?, Class#remove_class

    • Regexp#number_of_captures

    • Regexp.unoptionalize, Regexp.optionalize, Regexp#number_of_captures

    12 Action Mailer

    Action Mailer は TMail の代わりに新しい Mail という Email ライブラリを使って、新しい API を提供します。
    Action Mailer は全面的に書き換えられました。シンプルに Abstract Controller を継承し、Mail gem をラップしています。他のライブラリとの重複部分などの多くが削除されています。


    • 全てのデフォルトのメーラーは、app/mailers にあります

    • 新しい3つのAPIでemailが送信できます。attachments, headers そして mail です

    • Action Mailer のemailメソッドは Mail::Message オブジェクトを返します。deliver メッセージで自分自身を送信します

    • すべての配信メソッドは 抽象化されて Mail gem に出されました
    • メール配信メソッドの動作は、 Action Controller の respond_to ブロックと似ており、はっきりとまたは暗黙的にテンプレートを描画します。Action Mailer は必要に応じてマルチパートメールに変更します

    • format.mime_type をメールブロックなしで呼ぶときに proc を渡すことができます。そしてテキストを描画したり、レイアウトを追加したり、違うテンプレートを描画することができます。Abstract Controller の proc 内で render を呼ぶとき、Action Controller から呼ぶときと全く同じオプションが使用できます

    • メーラーのユニットテストは機能テストに移動しました

    非推奨:


    • :charset, :content_type, :mime_version, :implicit_parts_order らはすべて非推奨となります。 ActionMailer.default :key => value 形式を使ってください

    • Mailerが動的に生成するメソッド create_method_name と deliver_method_name は非推奨になりました。method_name を呼んで Mail::Message オブジェクトを返させてください

    • ActionMailer.deliver(message) は非推奨になりました。message.deliver を使ってください

    • template_root は非推奨になりました。mail 生成ブロック内のformat.mime_typeメソッドから proc 内の render にオプションを指定してください。

    • インスタンス変数に定義された body メソッドは非推奨になりました(body {:ivar => value})。メソッド内で直接インスタンス変数を宣言することで、ビュー内で使用できます。

    • メーラーは app/models ではなく app/meilers を使用してください。

    詳細:

    13 クレジット

    See the full list of contributors to Rails for the many people who spent many hours making Rails 3. Kudos to all of them.

    Rails 3.0 Release Notes were compiled by Mikel Lindsaar.

    2009年のまとめ

    反省しきり。

    記事一覧を見た雑感

    • コード書いた量: PHP >> Ruby
      • 後半は全然Ruby触れてない
    • ブログの本数が去年の半分
    • その半分くらいが勉強会(または飲み会)レポート
    • emacsの設定いじってばっか


    もう少し意識してRuby書かないといかんなと思う今日このごろ。
    でも今はなぜかC/C++のお勉強中。ダメだこりゃw

    来年のほーふ?

    来年はRuby/C/関数型言語のどれか/ネットワーク、辺りを中心に書いていければなーと思ってます。
    思ってるだけですが。

    というわけで

    今年も1年ありがとうございました。
    来年もよろしくお願いします。

    ビット演算子の恐怖

    PHPは暗黙の型変換をしてくれます。
    余計なお世話なことが多いですが、適当プログラマには便利な場面もあります。

    さて、ビット演算。フラグを複数設定したい場合なんかにたまに使いますが、こいつがまた余計なことをしてくれます。
    なんと、文字列がビット演算できる!

    データ型の変換に注意しましょう。両辺のパラメータが文字列の場合、 ビット演算子は文字の ASCII コードで演算を行います。

    PHP: ビット演算子 - Manual

    どうしてこうなるんだよ!!!!!!

    じゃあ、文字列同士じゃない場合は?

    試してみた。

    <?php
    $a = '100';
    $b = '20';
    $c = 20;
    $d = 'foo';
    
    var_dump($a | $b); // 数値へ変換可能な文字列同士
    var_dump($a | $c); // Intと数値へ変換可能な文字列
    var_dump($a | $d); // 数値へ変換可能な文字列と変換できない文字列
    var_dump($c | $d); // Intと数値へ変換できない文字列
    
    /* Output:
    string(3) "300"
    int(116)
    string(3) "w"
    int(20)
    */
    
    • 文字列同士だと、asciiコードによる演算を行う
    • 文字列同士じゃない場合は、Intへ暗黙の型変換されてるっぽい

    もっとも考え得るはまりポイントとしては・・・「数値文字列同士をビット演算して、意図とは全く異なる結果が返ってくる。」ですかね。
    いつも型を意識していない場合や、DBやテキストから数字を取得した時なんかは特に要注意。

    おまけ

    本当に内部でIntに型変換 しているらしい。あほか。

    <?php
    var_dump(true | 20);  // true と Int
    var_dump(false | 20); // false と Int
    var_dump(2.5 | 3.3);  // float同士
    
    /* Output:
    int(21)
    int(20)
    int(3)
    */
    

    というわけで

    PHP本当に余計なおせっかい焼きのkuso
    素晴らしい言語ですね!!!!