2010年12月31日金曜日

【翻訳】EventMachine入門

dan sinclairさんのEventMachineの入門記事(PDF)を翻訳しました。
原文はここからダウンロード可能です: http://everburning.com/news/eventmachine-introductions/
(翻訳の公開と画像の利用は本人より許諾済みです)

翻訳・内容の間違い等があればブログコメントやTwitterなどで遠慮無くご指摘ください。

EventMachine入門



Introduction


 うん、これから何を学ぶことになるのか、この導入のくだりがスタート地点として役に立つと思う。EventMachine とは何だろう。そしてそれは私たちのために何をしてくれるのだろう。さて、最初の部分は簡単だね。EventMachine は Reactor パターン(*1)の高性能な実装さ。

すげえ、いや、ちょっと待て、Reactor パターンって何だ? Wikipedia によると:

Reactor デザインパターンとは、一つ以上の入力による、サービスハンドラへ送られた同時並行なリクエストを扱うための並列プログラミングパターンです。サービスハンドラは入ってくるリクエスト群をより分け、関連するリクエストハンドラに同期的に送りつけます。

基本的に、EventMachine(EM) はソケットの受信待機、ネットワーク接続の確立、タイマー処理、そしていくつかの並列プリミティブを含んだ低レベルなもの全てを扱う。EM は高性能なAPIサーバ/サービスを作るのに必要な多くの中核機能を提供する。また EventMachine は Dan Kegel 他による C10K 問題(*2)の教訓を考慮に入れている。



ネットワーク処理能力と共に、EM は長時間かかるタスクをバックグラウンドなスレッドに回すことができるスレッドプールを提供する。これはアプリケーションを素早い・応答性の良いものにしてくれる。みんな応答性は好きだよね? もちろんスレッドプールを使うことに関してはトレードオフがあって、ほとんどは Ruby1.8 のグリーンスレッド(OS ではなく VM がスケジュールするスレッド)の実装に関係するんだ。

訳注: Ruby1.9ではネイティブスレッドになりましたが、Global Interpreter Lock により完全に並列実行されるわけではありません。ただしグリーンスレッドよりもスレッド切り替えコストは軽減されています)

最初に、簡単な例を見てみようか。EM におけるHello World、エコーサーバを例として使ってみよう。
緑色のテキストはサーバからの応答だから注意してね。

require 'eventmachine'

class Echo < EM::Connection
  def receive_data(data)
    send_data(data)
  end
end

EM.run do
  EM.start_server("0.0.0.0", 10000, Echo)
end
Rei:~ dj2$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
helo
helo
goodbye cruel world
goodbye cruel world

詳細は後に見ていくけど大雑把に言うと、ポート10000番上で開始されたサーバは接続を確立したときに、用意しておいた Echo クラスを使っている。ポートにデータが届いた時、EM は receive_data メソッドを実行し、send_data を呼ぶことによって、受け取ったデータをクライアントにエコーし返す。

本質的には、Echo クラスのインスタンスはファイルディスクリプタに結びつけられている。ファイルディスクリプタに動きがあればいつでも、君のクラスのインスタンスはそのアクションをハンドルするために呼ばれるのだ。これがほとんどの EventMachine プログラミングの基礎であり、reactor はファイルディスクリプタを監視し、君のクラスのインスタンスにあるコールバックを実行する。

注目すべき興味深いことは、我々の Echo クラスにはどんなネットワーク原理の概念もないってことだ。実装した Echo#receive_data にはパケットやヘッダの概念はないけれど、ネットワークのデータを取り出すことができる。


Getting Started


 導入はやりのけたので、EventMachine の楽園へのユカイな道のりを始められる。君が邁進するのに使えるいくつかの基本的タスクとコマンドがあるから、そこを原点として始めようか。

最初に、最も簡単で最もばかげた EM アプリケーションを作ってみよう。

require 'eventmachine'

EventMachine::run

ちっとも刺激的じゃない例だが、良い出発点だ。注意が2、3ある。まず最初に、EventMachine を利用するには、eventmachine を require しなくちゃならない。2番目に、抜け目ない人ならお気づきだろうが、最初の例では EM. を使っていたが今回は EventMachine:: を使った。これは EM:: でも EventMachine. でもいい。どれも同等の書き方だ。個人的には EM. が短くて簡潔なので好きだ。最後に、もしこの例を実行させたなら、決して終了しなかったことに気づくだろう。EM#run を呼ぶと、EventMachine reactor は開始され、止まれと言われるまではハッピーに走り続ける。そして実際に今は止まれと言わなかった。

どうやってこの野獣ちゃんを止めたらいい? とっても簡単。

require 'eventmachine'

EM.run do
  EM.add_timer(1) { EM.stop }
end

こっちでは EM#run にブロックを渡している。ブロックの中身は reactor が初期化されたあと、 reactor が走り始める前に実行される。必要な初期化処理があれば、なんでもこのブロックに入れることができる。この場合は、時が来たら EM#stop を実行してくれるタイマーを作成している。EM#stop の代わりに EM#stop_event_loop を呼ぶこともできる。この二つのメソッド呼び出しはどちらも同じもので、reactor を終了させる。reactor が終了すれば、EM#run ブロックのうしろに書かれたコードが実行される。

Timers

 ツアーの次の停留所は EventMachine タイマーだ。タイマーには二つのタイプが存在する。一回限りのタイマーと、周期的なタイマーだ。EventMachine にタイマーを加えるには二つの異なる、だが同等の効果の方法がある。一般的な方法としては、下記で見るように EM#add_timerEM#add_periodic_timer を使うやり方だ。

require 'eventmachine'

EM.run do
  EM.add_timer(5) do
    puts "BOOM"
    EM.stop_event_loop
  end
  EM.add_periodic_timer(1) do
    puts "Tick ... "
  end
end

titania:examples dj2$ ruby timer.rb
Tick...
Tick...
Tick...
Tick...
BOOM



この例では二つのタイマーをシステムに追加する。周期的なタイマーは多くとも1秒に一度実行され、一回限りのタイマーは少なくとも5秒後には実行されるだろう。この(「多くとも」とか「少なくとも」みたいな)言葉づかいは超重要だ。EventMachine はタイマーがいつ実行されるのか保証しない。指定したフレーム時間で実行されるかもしれないだけだ。

以下の同等の例では、メソッドの代わりにクラスを用いている。

require 'eventmachine'

EM.run do
  EM::Timer.new(5) do
    puts "BOOM"
    EM.stop
  end
  EM::PeriodicTimer.new(1) do
    puts "Tick ..."
  end
end

機能面ではこれらの二つの例は同一だ。私は最初に見た方、EM#add_timerEM#add_periodic_timer の方をより多く使う。

訳注:以下の問題は現在の EventMachine(0.12.10) では存在しません。
 EM#add_periodic_timer の返り値は EM::PeriodicTimer オブジェクトであり、
 EM#cancel_timer にそれを渡すと中で EM::PeriodicTimer#cancel メソッドを呼んでくれます)

メソッドではなくクラスを使用しなければならない場合も一つだけある。それは周期的なタイマーをキャンセルする場合だ。 EM#add_timer の返り値のシグネチャを EM#cancel_timer に渡して実行すると、一回限りのタイマーはキャンセル出来る。周期的なタイマーでは、タイマーが再スケジュールされる度に、毎回新しいシグネチャを受け取ってしまうという問題があるんだ。そして、シグネチャを知らなければタイマーをキャンセルことができない。

もし周期的なタイマーをキャンセルさせる必要があるなら、EM::PeriodicTimer を使う必要がある。これは EM::PeriodicTimer#cancel というメソッドを提供しているんだが、もうおわかりの通り、周期的なタイマーをキャンセルできる。

require 'eventmachine'

EM.run do
  p = EM::PeriodicTimer.new(1) do
    puts "Tick ..."
  end

  EM::Timer.new(5) do
    puts "BOOM"
    p.cancel
  end

  EM::Timer.new(8) do
    puts "The googles, they do nothing"
    EM.stop
  end
end
titania:examples dj2$ ruby timer_cancel.rb
Tick...
Tick...
Tick...
Tick...
BOOM
The googles, they do nothing



Deferring and Delaying Work

 Reactor パターンの定義を思い返してみると、 reactor はシングルスレッドだったのに気づくだろう。EventMachine もこのシングルスレッドなアプローチの reactor に当てはまる。reactor 自身はシングルスレッドであり、reactor で扱う EM のメソッドはスレッドセーフではない

これは2つの結果になる。まず第一に、おそらく私たちは長い時間かかるコードを持つってことだ。データベースクエリや、リモートHTTPリクエスト、その他もろもろ。効率のためには、これらのコードをバックグラウンドのスレッドにやらせる必要がある。第二に、コードをバックグラウンドのスレッドに追いやったら、それを動かしてくれるように reactor に命令できるようにする必要もある。

ここで EM#deferEM#next_tick のおでましだ。

EM#defer を使うと EventMachine のスレッドプールへ、実行するコードブロックを一つのスレッドとしてスケジュールすることができる。このスレッドプールは(デフォルトでは)最大で20個までのスレッドを提供する。やべぇ、俺らのコードをバックグラウンドで走らせたら、その結果をどうやってクライアントに伝えるんだ? もし必要なら、EM#defer は第二のパラメータをとる。callback だ。このコールバックはメイン reactor スレッド上で実行され、スレッドプールに回された操作の返り値を提供する。我々は、クライアントとコミュニケーションするために、このコールバックを使うことができる。

EM#defer には悪い面もあって、Ruby1.8 のスレッドの実装で動かさなきゃいけないということだ。 Ruby には本当のOSスレッドがない。グリーンスレッドと呼ばれるものならある。(一つのRubyプロセスの)全てをその上で動かすOSスレッドが一つあり、Ruby はそのOSレベルスレッド上で自分のスレッドを作成する。これは、 Ruby が全てのスレッドスケジューリングを扱っていることを意味していて、そしていずれにしてもあなたのプロセスがブロックするだろうOSレベルスレッドをつかむ。だから、あなたが延期処理を行うどのスレッドの中でも、Ruby をブロックしないと確信できるように注意しなくちゃならない。じゃないと全体をブロックしてしまう。

(訳注:先述の通り、Ruby1.9ではネイティブスレッドになっています。1.9ではOSがスレッドスケジューリングを扱いますが、GILにより一度に走るスレッドは一つだけです。よって注意すべき点は変わりません)

EM#next_tick を使うと、次の reactor ループイテレーションで発生するように、実行するコードブロックをスケジュールできる。実行はメイン reactor スレッドで起こる。事実上この遅延は瞬時に起っていると考えることができて、これは本来コードが異なるスレッドで動作することを意図してスケジュールしている。EM はスレッドセーフではないから、スレッドプールのとあるスレッドから EM#defer を使おうとすると、深刻な問題に陥ったりクラッシュする可能性がある。

例えば EM#defer なスレッドで何かを動かしていて、EM::HttpClient を使って新しい接続を確立する必要があるとしたら、それはメインスレッド上で行う必要がある。となると接続の作成は、EM#next_tick へ渡すコードブロックの中ですればいいわけだ。

EM#next_tick

 EM#next_tick を使うことは、EM#add_timer を動かすのにとてもよく似ている: EM#next_tick に渡した特定のコードブロックは、reactor ループの次のイテレーションで実行される。

require 'eventmachine'

EM.run do
  EM.add_periodic_timer(1) do
    puts "Hai"
  end
  EM.add_timer(5) do
    EM.next_tick do
      EM.stop_event_loop
    end
  end
end
titania:examples dj2$ ruby next_tick.rb
Hai
Hai
Hai
Hai



EM#next_tick でスケジュールされたものは、メインスレッドで同期的に実行される。EM#next_tick ブロック内のどんな長い時間かかるタスクも、それの実行を終えるまでプログラム全体をブロックしてしまう。通常、これはよくないことだ。

EM#defer

 同様に、EM#defer を使うことは、その実行がバックグラウンドスレッドで終了した後に、メインスレッドで実行されるコールバックを提供する能力を与えてくれる。また、コールバック関数は渡さなくてもよい。

require 'eventmachine'
require 'thread'

EM.run do
  EM.add_timer(2) do
    puts "Main #{Thread.current}"
    EM.stop_event_loop
  end
  EM.defer do
    puts "Defer #{Thread.current}"
  end
end
titania:examples dj2$ ruby defer.rb
Defer #<Thread:0x5637f4>
Main #<Thread:0x35700>




EM#defer に渡したブロックは、バックグラウンドスレッドで実行が開始され、ゴキゲンに走り続ける。注意だが、あなたのコードはこのスレッドを永遠に占有しないようにしなければならない。EventMachine はこの状態を検知しないので、スレッドが無期限に実行されてしまう。スレッドプールのサイズは決っているため、そうやってスレッドを失ったら、その分取り戻せなくなる。

また、コードが走り終わったあとにコールバック関数を実行するという EM#defer の機能を利用できる。コールバック関数に仮引数を指定していたならば、コードの返り値がそこに渡されてから実行される。

require 'eventmachine'

EM.run do
  op = proc do
    2+2
  end
  callback = proc do |count|
    puts "2 + 2 == #{count}"
    EM.stop
  end
  EM.defer(op, callback)
end

Rei:EventMachine dj2$ ruby defer_callback.rb
2 + 2 == 4



ここでは二つの数字を足す proc オブジェクトを作成している。この合計の結果は、EM#defer スレッドでの実行から返ってきて、コールバックへと渡される。そしてコールバックはメイン reactor スレッド上で実行される。このコールバックは結果を出力している。

Lightweight Concurrency

EventMachine は軽量な並行処理(Lightweight Concurrency)(*3)を扱うための2つのメカニズムを内蔵している。spawned process と deferrable だ。注意して欲しいのは、spawned process なんて呼ばれてはいるものの、OSのプロセスとは違うってことだ。この名前は Erlang から来ているのだが少し紛らわしい。

それら二つのメカニズムにひそむ主要なアイデアは、CPU やメモリにとってより軽く、そして標準のRubyスレッドであるってことだ。軽量の並列動作における多くの働きは、あなたのアプリケーション側でハンドルされる必要がある。deferrable と spawned process によるコードはあなたのアプリケーションから実行要求が来るまで、実行されない。

これらのメカニズムがどう動くのか、見て行こう。

EM::Deferrable

EM::Deferrable(*4) を見ていくところから始めよう。あなたのクラスに EM::Defferable をミックスインしたとき、そのクラスのインスタンスには callback と errback 関連の能力が提供される。あなたは実行される callback と errback をいくらでも定義できる。callback と errback は、インスタンスに追加された順番で実行される。

callback と errback を発動させるためには、インスタンスオブジェクトの #set_deferred_status を呼び出す。そのメソッドには :succeeded:failed を渡すことができて、:succeeded なら callback が、:failed なら errback が発動する。これらのブロックは、メインスレッド上ですぐさま実行されるだろう。また、deferrable オブジェクトに状態をセットするために、#succeed#fail というシンタックスシュガーも用意されている。

一旦オブジェクトの状態が指定されると、その後で追加されるどんな callback や errback も、追加された途端にその状態に応じてただちに実行される。

これが実際にどう動くか見てみよう。

require 'eventmachine'

class MyDeferrable
  include EM::Deferrable
  def go(str)
    puts "Go #{str} go"
  end
end

EM.run do
  df = MyDeferrable.new
  df.callback do |x|
    df.go(x)
    EM.stop
  end
  EM.add_timer(1) do
    df.set_deferred_status :succeeded, "SpeedRacer"
  end
end
titania:EventMachine dj2$ ruby deferrable.rb
Go SpeedRacer go



ここで何が起っているか注意深く見てみよう。最初に EM::Deferrable をクラスに include している。これで deferrable するのに必要なメソッドがミックスインされる。

普通に MyDeferrable クラスを作成して、そのインスタンスで #callback#errback を呼んでいる。callback と errback のブロックには、仮引数をいくらでも指定できる。処理が成功したか失敗したかが決まった時、インスタンスの #set_deferred_status を実行している。この場合では、:succeeded を渡し、callback には一つの仮引数を指定して定義したから、"SpeedRacer" が callback に渡される。

デフォルトでは、全ての callback が同じ引数で実行される。callback 内で #set_deferred_status をもう一度呼び、異なる引数を渡すことで、それ以降の callback には違う引数を渡すことも可能だ。これは deferrable のドキュメントでより詳しく解説される。

deferrable なオブジェクトを使うために、わざわざクラス全体を実装する必要がない場合もあるだろう。そういう場合のため、 EventMachine は EM::DefaultDeferrable というクラスを提供している。カスタムクラスでやる代わりに、EM::DefaultDeferrable.new をただするだけで、 EM::Deferrable をミックスインしたものと全く同じ動作をしてくれる。

EM::SpawnedProcess

EventMachine の spwened process は、Erlang のプロセスにインスパイアされている。OSのプロセスではないのにプロセスというネーミングには少し混乱させられるが。spawned process が持つアイデアは、プロセスを作成できて、それにコードを付加することができるということだ。未来のいつかの時点で、spawn されたオブジェクトの #notify メソッドを呼び出すことで、付加したブロックを実行することができる。

deferrable と異なりコードブロックはすぐ実行されないが、#notify 呼び出しがあったならいずれは実行される。

require 'eventmachine'

EM.run do
  s = EM.spawn do |val|
    puts "Received #{val}"
  end

  EM.add_timer(1) do
    s.notify "hello"
  end
  EM.add_periodic_timer(1) do
    puts "Periodic"
  end
  EM.add_timer(3) do
    EM.stop
  end
end
Rei:EventMachine dj2$ ruby spawn.rb
Periodic
Received hello
Periodic



Network Fun

さあて、イイモノの紹介に入ろう。EM は、ネットワークプログラミングを扱うように設計されている。どんなプロトコルだろうと、一連のベースプロトコル実装だろうが、その能力はAPI開発者やサーバ開発者に楽をさせる。

Servers

サーバーサイドから始めることにしよう。クライアント側のコードとはとてもよく似ているけど、それは次のセクションでやる。

イントロダクションで使ったエコーサーバの例に戻ってみよう。

require 'eventmachine'

class Echo < EM::Connection
  def receive_data(data)
    send_data(data)
  end
end

EM.run do
  EM.start_server("0.0.0.0", 10000, Echo)
end
Rei:~ dj2$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
helo
helo
goodbye cruel world
goodbye cruel world



君にも分かるとおり、EM::Connection クラスを継承して Echo クラスを作成している。そして EM#start_server メソッドを使い、さっき定義した Echo クラスを用いて、全てのインターフェースを監視する、ポート10000番上のサーバを作っている。

おもしろいことに、これと同じコードを書く方法がなんと二つ以上存在している。どれを使うかは好きにしていい。

モジュールを使うこともできる:

require 'eventmachine'

module Echo
  def receive_data(data)
    send_data(data)
  end
end

EM.run do
  EM.start_server("0.0.0.0", 10000, Echo)
end

またはブロックでも:

require 'eventmachine'

EM.run do
  EM.start_server("0.0.0.0", 10000) do |srv|
    def srv.receive_data(data)
      send_data(data)
    end
  end
end

3つの全ての例で、新しいコネクションが確立したとき、新しい匿名のクラスがあなたのコードを取り込んで作成される。これは大事なことで、コネクション毎にあなたのクラスの新しいインスタンスを持つことになるってことだ。インスタンスは次の接続の時には存在しないので、コネクション間でインスタンス内には何も保存することはできない。

サーバとして機能させるためには #receive_data(data) という一つのメソッドを実装する必要がある。もし #receive_data を実装しなかったら、"............>>>6" みたいなものがコンソールに吐出されるのを見るハメになる。もし君が私に似ているなら、それがどこから来ているのか調べるために30分費やすことになるだろう。

#receive_data のようにクライアントとの接続がある間に呼び出される、いくつかのメソッドが他にもある。

post_init
インスタンスの初期化時、コネクションが完全に確立する前に呼ばれる。
connection_completed
コネクションが完全に確立した後に呼ばれる。
receive_data(data)
クライアントからデータを受け取った時に呼ばれる。データはチャンクで受け取る。チャンクの組み立てはあなたの責任だ。
unbind
クライアントとの接続が完全に切れたときに呼ばれる。

私たちの例では、クライアントに返送するために #send_data(data) を使った。巨大なデータファイルを送りたいなら、巨大なデータのチャンクを送り出すのに便利なメソッドである #send_file_data(filename) を使うこともできる。

最後に、ここには示されていないが #close_connection#close_connection_after_writing という二つの便利なメソッドがある。これら2つのメソッドはとても似た操作を行う。両方ともクライアントが接続を閉じた時にシグナルを飛ばす。#close_connection_after_writing は接続が閉じられる前に #send_data で送った全てのデータを確実にクライアントに送るという点で異なる。

以前に言及したように、接続と接続の間で君のクラスのインスタンスはどんな情報も共有できない。幸運にも、いや、設計されたことだろうが、EventMachine はこれを処理するメカニズムを提供する。

require 'eventmachine'

class Pass < EM::Connection
  attr_accessor :a, :b
  def receive_data(data)
    send_data "#{@a} #{data.chomp} #{b}"
  end
end

EM.run do
  EM.start_server("127.0.0.1", 10000, Pass) do |conn|
    conn.a = "Goodbye"
    conn.b = "world"
  end
end
titania:~ dj2$ telnet localhost 10000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
mostly cruel
Goodbye mostly cruel world

EM#start_server へ渡されたブロックの中で、Pass インスタンスは自身が初期化された後、クライアントからデータを受け取る前に、EventMachine から値が渡されている。このどんな状態でもセットされたインスタンスを、必要ならば使うことができる。

Clients

ひとたびサーバを起動したならば、クライアントでそれに接続するのが有益だろう。幸い、サーバの動作を知った後なので、魔法を起こすのに何が必要か大部分は知っているよね。

require 'eventmachine'

class Connector < EM::Connection
  def post_init
    puts "Getting /"
    send_data "GET / HTTP/1.1\r\nHost: MagicBob\r\n\r\n"
  end

  def receive_data(data)
    puts "Received #{data.length} bytes"
  end
end

EM.run do
  EM.connect("www.postrank.com", 80, Connector)
end
titania:EventMachine dj2$ ruby connect.rb
Getting /
Received 1448 bytes
Received 1448 bytes
Received 1448 bytes
Received 1448 bytes
Received 2896 bytes
Received 1448 bytes
Received 1448 bytes
Received 935 bytes

EM#connect によりコネクションが作成される。このコード例は、上でサーバを作成したときに述べられた考えに従っている。コールバックメソッドは同じ名前を持ち、サーバにデータを送るメソッドも、サーバがクライアントにデータを送るときと同じ #send_data だ。


Conclusion


EventMachine の連続公演はこれにておしまい。私たちは、物事の成し遂げ方と、EM#runを使ってそれが走るのを見た。一回限りのタイマーと、周期的なタイマーを作成すること。Deferring と next_tick のコードブロック。deferrable と spawned process をクライアントとサーバで作成すること。

たぶん、全てを見たあとでは、あなたは Eventmachine がどう機能するか、そしてあなたのアプリケーションでどう使えばいいのか、より理解が深まったことだろう。

何か質問やコメントがあるならば、遠慮なく私に連絡を。: dan(at-mark)aiderss.com


Resources


http://rubyeventmachine.com/
http://github.com/eventmachine/eventmachine/tree/master
http://groups.google.com/group/eventmachine/topics
http://eventmachine.rubyforge.org/
http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/
http://20bits.com/articles/an-eventmachine-tutorial/
http://nutrun.com/weblog/distributed-programming-with-jabber-and-eventmachine/
http://www.infoq.com/news/2008/06/eventmachine
http://everburning.com/news/playing-with-eventmachine/
http://blog.nominet.org.uk/tech/2007/10/12/dnsruby-and-eventmachine/
http://devver.net/blog/2008/10/sending-files-with-eventmachine/
http://en.oreilly.com/rails2008/public/schedule/detail/1820
http://nhw.pl/wp/2007/12/07/eventmachine-how-to-get-clients-ip-address
http://simonwex.com/articles/2008/10/22/eventmachine-http-client
http://adrianhosey.blogspot.com/2009/01/eventmachine-tcp-server-module-for-ruby.htm


*1 http://en.wikipedia.org/wiki/Reactor_pattern
*2 http://www.kegel.com/c10k.html
*3 http://rubyeventmachine.com/browser/trunk/docs/LIGHTWEIGHT_CONCURRENCY
*4 http://rubyeventmachine.com/browser/trunk/docs/DEFERRABLES


2010年11月27日土曜日

【翻訳】Fuubar: instafailing な RSpec プログレスバーフォーマッタ

Jeff Kreeftmeijerさんの "Fuubar: the instafailing RSpec progress bar formatter" を翻訳しました。
元記事はこちら: http://jeffkreeftmeijer.com/2010/fuubar-the-instafailing-rspec-progress-bar-formatter/
(翻訳の公開と画像の利用は本人より許諾済みです)

Jeffさんのひとつ前のRSpecの記事もよろしければどうぞ。
 【翻訳】RSpecでテストが失敗したら即停止して結果を出力

翻訳の間違い等があればブログコメントやTwitterなどで遠慮無くご指摘ください。

Fuubar: instafailing な RSpec
プログレスバーフォーマッタ


 気づいたかもしれないけど、私はここ一週間ほど RSpec でテストスイートをより良く・より速く走らせることに時間を費やしていた。そして今週は、RSpec のフォーマッタを調べた。



spec が失敗した時、RSpec が出力する赤い "F" 以外に、あなたがすぐにバグを修正しにいくためのダイレクトなフィードバックがない。あなたは単に全てのテストスイートが走り切るのを待つか、あるいは ^Cを使って割込みをかけるしかない。あなたに出来る他の事は、先週私が書いた --fail-fast オプションを使うか、あるいは残りの spec を走らせ続けている間にも failure の詳細を出力する rspec-instafail を見てみることだ。こりゃあいいや。

それ以外にも、spec の総数を知ったり、既に実行された spec の数を知ったり、例えば 終了予定時刻(ETA)か何かのようなもの知ったり、より良くできるものがあったと気づいた。また、ドットと "F" による大きな文字列は不要であり、この情報を表示するもっと良い方法があるはずだと感じ始めた。

私は RSpec のフォーマッタを調べて、それを書くのがとても簡単だと気づいたので、気紛れに FffuuuFormatter という、RSpec が FFFFF の代わりに FFFUUU を出力するフォーマッタを書いてみたりした。えっ。

Fuubar


 少し見て回ったあと、2008年に @nick_evans によって書かれた、私がプログレスバーフォーマッタで抱えているようないくつかの問題を修正しようとした記事を見つけた。Nick は @peleteiroprogressbar gem を使った本当に良い解決法を書いていた。

私は Nick の仕事をさらに先に進めようと決め、rspec-instafail を使って全ての failure 毎にダイレクトフィードバックを行う、RSpec 2.0 にもちゃんと対応したフォーマッタを作り上げた。全てを gem に入れたところで、@josevalim が名前を考えてくれた: Fuubar

ここに、動作中の Fuubar の短いビデオがある:



Fuubar のインストール法は簡単だ。ただ Gemfile にそれを入れて、これからはあなたの spec をこうやって走らせるだけだ。
訳注:Bundler 前提みたいに書いてありますが、もちろん gem install fuubar でも大丈夫です)

$ rspec --format Fuubar --color spec

デフォルトのフォーマッタとして Fuubar を使いたいなら、.rspec ファイルにオプションを書けばよい。

--format Fuubar
--color

そのあとは、あなたがいつも慣れているように spec を走らせることができる。

$ rspec spec

Fuuture


いつもの: どんな感じか教えて欲しい、そして Github 上で issue を作成し、いいアイデアがあったり、何か問題があったら、Github メッセージを送るか email で連絡して欲しい。もちろん、いつでもプロジェクトを fork して、プルリクエストを送ったり email でパッチを送ることもできる。

Fuubar は今のところ RSpec 2 上でのみ動作するが、旧バージョンと互換性を持たせられない理由はない。また、Nick の元のコードには遅い spec を見つける機能があったが、いい実装が見つからなかったので私はそれを省略した。

それで、しなければならないことはまだたくさんあるが、これは現在のフォーマッタからの確かな進歩だと私は思う。多分、Fuubar を RSpec のデフォルトのフォーマッタの一つにするパッチに変えることもできるだろう。あなたはどう思う?


【翻訳】RSpecでテストが失敗したら即停止して結果を出力

Jeff Kreeftmeijerさんの "Making RSpec stop operation immediately after failing" を翻訳しました。
元記事はこちら: http://jeffkreeftmeijer.com/2010/making-rspec-stop-operation-immediately-after-failing/
(翻訳の公開と画像の利用は本人より許諾済みです)

Jeffさんのその次のRSpecの記事もよろしければどうぞ。
 【翻訳】Fuubar: instafailing な RSpec プログレスバーフォーマッタ

翻訳の間違い等があればブログコメントやTwitterなどで遠慮無くご指摘ください。

RSpecでテストが失敗したら
即停止して結果を出力


 RSpec で全てのテストスイートを走らせていて、最初か二番目で spec が失敗したと想像してみて欲しい。その後も走る spec が約200は残っているが、あなたはすぐにでも最初の失敗を修正するのに没頭したい。あなたは多分、それらを修正するための failure の詳細を知るために、spec の実行に割り込もうとするはずだ、そうだろう?

ほとんどの時間こうして作業しているわけだが(Selenium を使っている時、なんらかの問題で実行に割込みをかけるだろう)、もし RSpec が最初の failure で自動的に停止し結果を出力してくれたらすごくないだろうか?



rspec-users グループの3年前のスレッド以外には、役立つデータはほとんど見つからなかったので、私自身で書き始めることにした。

Fail-Fast


 私は RSpec のソースを捜索し始め、そして偶然にも Relish により生成された RSpec のドキュメントを見つけた。そこでは、rspec-core 2.0.0.rc から fail_fast の設定オプションが導入されていることがわかった。それはまさに私が達成したかったことをやってくれる。

この fail_fast オプションは、spec が最初に失敗したときに RSpec をすぐさま停止させて failure の詳細を出力し、spec の失敗を修正するのにいい感じに速度を加速させてくれる。使い方は極々簡単だ:

# spec/spec_helper.rb

RSpec.configure do |c|
  c.fail_fast = true
end

コマンドラインサポート


あなたは時々 fail_fast オプションをなしにして、テストスイート全体を走らせたいとも思っているだろうが、spec/spec_helper.rb に現実にはいいオプションが存在しない。だから私は、あなたがいつでもそれをしたい時に出来るよう、コマンドラインオプションを追加した:

$ bundle exec rspec spec/ --fail-fast
.F

Failures:
  1) Swinger should set the Capybara driver
     Failure/Error: Capybara.current_driver.should_not == :rack_test

Finished in 0.00479 seconds
2 examples, 1 failure

この --fail-fast オプションは、先日リリースされた RSpec 2.1 にのみ含まれているので、アップデートを忘れないように。


2010年11月23日火曜日

【翻訳】あなたの知らないGit Tips

Mislav Marohnićさんの "A few git tips you didn't know about" を翻訳しました。
元記事はこちら: http://mislav.uniqpath.com/2010/07/git-tips/
(翻訳の公開は本人より許諾済みです)

翻訳の間違い等があれば遠慮なくご指摘ください。

あなたの知らないGit Tips

注意:いくつかのコマンドやオプションは Git の version 1.7.2 以降が必要です。
OS Xでは、 Homebrew で簡単にアップグレードできます: brew install git

git log でブランチとタグも見る

$ git log --oneline --decorate
7466000 (HEAD, mislav/master, mislav) fix test that fails if current dir is not "hub"
494a414 fix cherry-pick of a commit URL
4277848 (origin/master, origin/HEAD, master) whoops
d270fae bugfix: git init -g
9307af3 test deps
8ccc17e http://github.com/defunkt/hub/contributors
64bb19c bugfix: variable name
546726a dont need you
3a8d7af (tag: v1.3.1) v1.3.1
197f429 (tag: v1.3.0) v1.3.0
a1e1a50 not important
3c6af16 magic `cherry-pick` supports GitHub commit URLs and "user@sha" notation


diff で行の全てではなく、変更された単語部分のみハイライトする

$ git diff --word-diff
# Returns a Boolean.
def command?(name)
  `type -t [-#{command}`-]{+#{name}`+}
  $?.success?
end
このオプションは git log -pgit show などの、diff のためのオプションを使えるところなら動作する。


短い status 出力

$ git status -sb
## thibaudgg...thibaudgg/master [ahead 1, behind 2]
 M ext/fsevent/fsevent_watch.c
?? Makefile
?? SCEvents/
?? bin/fsevent_watch
git status のデフォルトの冗長な出力は初心者にはいいのだが、一旦 Git に慣れてしまえば必要でなくなる。私は status のチェックをよくやるので、出力はできるだけ簡潔であって欲しい。


ブランチの push と同時に追跡のセッティングも自動的に行う

$ git push -u origin master
# "master" ブランチを "origin" リモートへプッシュして、さらに追跡させる
”追跡”とはつまり、ローカルブランチとリモートブランチの間のリンクのことだ。他のブランチを追跡しているローカルブランチ上で作業しているなら、git pullgit push に何も引数を渡さなくても、Git は何をするかわかってくれる。

しかしながら git push はデフォルトでは、同じブランチ名がリモート上にあるならそれらを全て push してしまう("matching" 戦略)。この振る舞いを現在のブランチのみの push に限定するためには、以下の設定を行う。

$ git config --global push.default tracking
これで、まだ push する準備が整っていないブランチを誤って push することが避けられる。
(2012年03月07日追記) Git 1.7.4.2からは push.default のための "tracking" という値は、"upstream" という名前になりました。意味は同じです。また "tracking" という名前は今後も使えるようです。
(2014年09月19日追記) Git 2.0からは push.default のデフォルトが "simple" という値になりました。"simple" では、カレントブランチと同名のリモートブランチがある場合のみ、カレントブランチをそこへ push します。Git のヘルプでは、これが最も安全で初心者にも向いた設定であると説明されています。

他人のリモートブランチを簡単に追跡する

$ git checkout -t origin/feature
# "feature" ブランチを作成してチェックアウトし、
# "origin/feature" を追跡させる。
チームメイトが作業していたブランチをその人と共有することになり、あなたもそれに対して変更を行うつもりなら、それに対応するローカルブランチを作らないといけない。上記のコマンドではブランチの作成とともに追跡のセットアップもやってくれるので、あなたは変更を作成した後にただ git push するだけでよい。


ブランチをチェックアウトし、master へ rebase して merge する

# "master" ブランチ上にいるとき:
$ git checkout feature && git rebase @{-1} && git checkout @{-2} && git merge @{-1}
# "feature" を "master" へ rebase して、それを master へ merge する
"@{-n}" という特別な構文は「現在から数えてn個前にチェックアウトされていたブランチ」という意味だ。"feature" がチェックアウトされたなら、"@{-1}" は "master" を表している。rebase した後、"@{-1}" は rebase の内部処理により "feature" を指すことになるので、今度は "@{-2}" を使って master をチェックアウトする。

更新: Björn Steinbrinkh がこれはコマンド2つでも可能だと指摘してくれた:

$ git rebase HEAD feature && git rebase HEAD @{-2}
訳注:自分の手元では、このコマンド2つの場合がうまく動かなかった(Gitのバージョンは1.7.3.2)のですが、もし試してくださる方がいたら、結果をブログコメントかTwitterなどで教えてくだされば嬉しいです)


pull のとき merge ではなく rebase する

$ git pull --rebase
# 例) "master" ブランチ上にいるなら、 `git fetch origin` をしてから、
# `git rebase origin/master` を実行したのに等しい。
Git ではブランチのマージはマージコミットを記録するので、それらは深い意味を持つ――例えば、ある機能がリリースブランチにマージされたのがいつなのかを示すなど。しかしながら、ある1つのブランチを何人かのチームメンバと頻繁にやりとりするような日常的なワークフローでは、普通に git pull していると不必要な細かいマージコミットでタイムラインが汚染されてしまう。rebase ならコミットを常に再適用してくれるので、コミット履歴は直線的な一本のままでいられる。

--rebase フラグをつけなくても特定のブランチでは常に rebase するようにしてくれる設定がある:

# master 上で `git pull` するときは常に rebase を使う
$ git config branch.master.rebase true
上の設定を、全ての新しい追跡ブランチでもやるようにする設定もある(グローバルに設定している):

# 全追跡ブランチで rebase を使う
$ git config --global branch.autosetuprebase always
(2012年03月7日追記)Git 1.7.9 からは pull.rebase という config 項目が増え、これを true に設定すると git pull に何もつけなくても rebase になります。これを設定しても、例えば branch.master.rebase が false なら、master での git pull は merge が選択されます。優先されるのは個々のブランチの設定というわけです。

# 全追跡ブランチで rebase を使う・その2
$ git config --global pull.rebase true


ある変更がどのリリースの一部なのか見つける

$ git name-rev --name-only 50f3754
"tags/v2.3.8~6"
コミットの SHA-1 ハッシュはわかるのだが、そのコミットがプロジェクト履歴のどこに位置しているかわからないということは珍しくない。もしあなたが私に似ているなら、多分あなたはその変更があるリリースで発生したのか、それとも違うのかが知りたいだろう。そのコミットに対して git show を使えばコミットメッセージは見れるし、日付も差分も見られるのだが、それらはちっとも助けてはくれない――特に、コミットした日付と、それを成果物に適用した日付が必ずしも一致しないような時には。

name-rev コマンドはプロジェクトにおいてコミットと関係のあるタグを教えてくれる。上記の例は Ruby on Rails リポジトリから持ってきたものだ。この場合は "v2.3.8" とタグ付けされる6つ前にそのコミットが位置していることを教えてくれている――つまりこの変更は Rails 2.3.8 に存在していると確定できる。

このコマンドはさらに有用性がある。いくつかのコミットに言及するような議論に参加したとしよう:

このバグは e6cadd422b72ba9818cc2f3b22243a6aa754c9f8 で混入したものだが、私の記憶が確かなら 50f3754525c61e3ea84a407eb571617f2f39d6fe で修正されている。

上の文章をクリップボードにコピーして git name-rev へパイプで渡すと、文章中にあるコミットの SHA-1 ハッシュを認識してそれぞれにタグ情報を付加してくれる:

$ pbpaste | git name-rev --stdin
"このバグは e6cadd422b72ba9818cc2f3b22243a6aa754c9f8 (tags/v2.3.6~215) で混入したものだが、
私の記憶が確かなら 50f3754525c61e3ea84a407eb571617f2f39d6fe (tags/v2.3.8~6) で修正されている。"
併せて読みたい: git help describe


ある変更が含まれているブランチを見つける

$ git branch --contains 50f3754
このオプションはブランチのリストを、指定したコミットがそのブランチの祖先に存在するものだけを表示するようにフィルタリングする。"-a" フラグをつければ、リストにリモートの追跡ブランチも含めてくれる。


あるブランチの上流に既に存在している変更を知る

# "feature" ブランチにいる場合に:
$ git cherry -v master
+ 497034f2 Listener.new now accepts a hash of options
- 2d0333ff cache the absolute images path for growl messages
+ e4406858 rename Listener#run to #start
cherry コマンドは例えば、開発中のブランチから安定しているブランチへ cherry-pick が行われたコミットを調べるのに便利だ。このコマンドは現在(feature)のブランチと上流(master)のブランチを比較して、両方に存在しているものには "-" をつけて表示する。上流にまだ存在しない変更には "+" マークをつける。


正規表現にマッチするコミットメッセージを持つ最後のコミットを表示

$ git show :/fix
# メッセージ中に "fix" を含む最後のコミットを表示

$ git show :/^Merge
# 最後のマージコミットを表示


複数のリモートからまとめて fetch する

$ git config remotes.default 'origin mislav staging'
$ git remote update
# リモートの "origin"、"mislav"、"staging" をfetch
remote updateするコマンドで fetch される対象になる、デフォルトのリストを決めることができる。あなたのチームメイトや、オープンソースプロジェクトでの信頼できるコミュニティメンバ、等からのリモートだ。また、関連するグループに名前をつけて定義することもできる:

$ git config remotes.mygroup 'remote1 remote2 ...'
$ git fetch mygroup


コミットの注釈を書く

$ git notes add
# 最後のコミットに注釈を追加するためにエディタが開く
Git の notes は既に存在するコミットへの注釈だ。それらはリポジトリの歴史を変更しないので、どんなコミットにも自由に追加することができる。notes はあなたのリポジトリにしか保存されないが、他のリポジトリと共有することも可能だ。notes には興味深いユースケースのアイデアだってある。


"hub" をインストール

Hub は Github について Git に教えてくれる。もし日常的に Github のリポジトリを利用しているなら、あなたは間違いなく hub をインストールしてキーストロークを減らしたくなる――特にあなたがオープンソースに関わっているのなら。


Gitに関する翻訳記事はこちらもどうぞ: A successful Git branching model を翻訳しました


2010年10月30日土曜日

A successful Git branching model を翻訳しました

Vincent Driessenさんの "A successful Git branching model" を翻訳しました。
元記事はこちら: http://nvie.com/posts/a-successful-git-branching-model/
(翻訳の公開と画像の利用は本人より許諾済みです)

このブランチモデルの導入を補助してくれる、git-flowというGit用プラグインがあるそうです。

翻訳の間違い等があれば遠慮なくご指摘ください。



A successful Git branching model



 この記事では、私のいくつかのプロジェクト(仕事でもプライベートでも)で約一年ほど導入して、とてもうまくいくことがわかった開発モデルを紹介する。しばらく前からこれについて書くつもりだったんだが、今まですっかりその時間を見つけられずにいた。ここでは私のプロジェクトの詳細については書かず、ブランチ戦略とリリース管理についてだけ述べよう。


以下では、ソースコードのバージョニングのためのツールとしてのGitに注目する。(ところで、Gitに興味があるのなら、我々の会社GitPrimeがソフトウェア開発に関する素晴らしいリアルタイムデータ分析を提供できるので、是非。)


なぜGitか?


 中央管理型のソースコード管理システムと比べた場合のGitの利点と欠点に関する議論については、webを見てみるといい。そこではたくさんのディスり合いが続いている。さておき、開発者としての私は、こんにちの他の全てのツールよりGitが好きだ。Gitは開発者たちのマージとブランチについての考え方を本当に変えてしまった。私のいた古きよき CVS/Subversion の世界では、マージ/ブランチングはちょっと怖いものと考えられていたし(マージの衝突に用心しろ、噛み付かれるぞ!)、それをする機会はたまにしかなかった。

しかしGitでは、そういった作業は非常に手軽かつシンプルで、全くの日常的なワークフローの一部と考えられている。例えば、 CVS/Subversion の書籍では、ブランチングとマージは後ろの方の章(先進的ユーザのための章だ)で扱われているが、どの Gitの 本でも、3章(基本的な章だ)では既に扱われている。

その気軽さゆえに、ブランチングとマージはもはや恐れるような何かではない。バージョン管理ツールはまず何より、ブランチング/マージを手助けするためのものなのだ。


それでは、ツールではなく開発モデルに触れていこう。なお、ここで私が紹介しようとしているモデルは、ソフトウェア開発プロセスを管理されたものにするために各々のチームメンバが従うべき手続きの集まり以上のものではない。


分散だが中央もある


このブランチングモデルを機能させるためには、中央に「正統な」リポジトリをセットアップする。このリポジトリは、単に中央であると仮定しただけ、ということに注意して欲しい(Gitは分散バージョン管理システムだから、技術的なレベルでは、中央リポジトリのようなものは存在しない)。私たちはこのリポジトリを origin として参照する。この名前が Git ユーザーには馴染みがあるからだ。


それぞれの開発者は、 origin から pull または push を行う。だが中央管理的な push-pull の関係の他にも、各開発者はサブチームを形成し、他の同僚から変更を pull することもある。例えば大きな新機能を作る時、origin に対して作業中のものを push してしまうのではなく、事前に2人以上で共同作業できたら便利だろう。上の図の中では、 Alice と Bob 、 Alice と David 、そして Clair と David のサブチームがある。

技術的には、これは Alice が "bob" という名前の、 Bob のリポジトリを指す Git の remote を定義したことを意味する(逆に Bob は Alice のリポジトリを "alice" という名前で Git に定義している)。


メインブランチ


 開発モデルのコアを成すのは、多くの既存のモデルたちにとてもインスパイアされたものだ。中央リポジトリは永遠の生涯ずっと、2つのメインブランチを保持する:

 ・master
 ・develop

origin の master ブランチは全てのGitユーザーに馴染みがあるはずだ。そして master ブランチに平行する、 develop と呼ばれるもうひとつのブランチが存在する。

origin/master は、製品として出荷可能な状態を常に反映する、ソースコードの HEAD のありかであるメインブランチだと考える。

origin/develop は、次のリリースのための最新の開発作業の変更を常に反映する、ソースコードの HEAD のありかであるメインブランチだと考える。これは「統合ブランチ」と呼ぶこともある。これは自動ナイトリービルドのビルド元にもなる。

develop ブランチのソースコードが安定し、リリースの準備ができたとき、 develop ブランチの全ての変更は master ブランチへマージされ、リリース番号をタグ付けされることになる。(これをどうやるかの詳細は、あとで述べる。)

したがって、 master へ変更がマージされる時はいつも、その定義からして新しい製品リリースの時だ。私たちはここで非常に厳密になる傾向にあり、そのため理論的には、 master にコミットがあるときは毎回Gitのフックスクリプトで自動ビルドを行い、そしてプロダクションサーバにソフトウェアをロールアウトする。


サポートブランチ


 master と develop のメインブランチの隣で、私たちの開発モデルはチームメンバ間の平行開発を助ける様々なサポートブランチを用い、機能の追跡、製品リリースの準備、製品に起きた問題をすばやく修正すること、などを容易にする。メインブランチと異なり、これらのブランチは寿命が決まっており、使い終わったら最終的には削除される。

私たちが使う異なるタイプのブランチたちは以下の通り:

 ・Feature branches
 ・Release branches
 ・Hotfix branches

それぞれのブランチは特定の目的を持ち、どのブランチから分岐するか、またどのブランチへマージされるのか、という厳密なルールと結びついている。すぐにそれらをお見せできるだろう。

技術的な見地からすると、これらのブランチは決して「特別な」ものではない。ブランチの種類は、私たちがそれをどう使うかで分類されたものだ。もちろんそれらはどれも、普通のGitブランチだ。

フィーチャーブランチ

分岐元: develop
マージ先: develop
ブランチ名の慣習: master, develop, release-*, hotfix-* 以外なら全てOK

 フィーチャーブランチ(またはトピックブランチとも呼ばれる)は、今度のリリースに入る、または遠い将来のリリースに入るような新しい機能を開発するのに使われる。ある機能を開発し始めるとき、その時点ではその機能を含めるべきリリースがどれなのか不明であるはずだ。フィーチャーブランチの本質は、機能を開発している限りは存在しているが、結局は develop にマージされる(新機能を次のリリースに追加すると決める)か、捨てられる(実験が期待はずれの場合)ということだ。

フィーチャーブランチは典型的には開発者のリポジトリにだけ存在し、 origin には存在しない。

フィーチャーブランチの作成

 新しい機能の作業を始める時、develop ブランチから分岐する。

$ git checkout -b myfeature develop
Switched to a new branch "myfeature"

開発済みの機能を develop ブランチに取り込む

 確実に今度のリリースに追加する、開発済みの機能は、develop ブランチにマージされる:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

--no-ff フラグは、たとえマージがfast-forwardで実行できるとしても、新しいコミットオブジェクトを作成する。これは、履歴にフィーチャーブランチが存在したという情報を失うのを避けるのと、機能の追加に使った全てのコミットをひとまとめにしておける。比べてみよう:


右の場合、ある機能を実装したコミットオブジェクトをGitの履歴から見つけられない――あなたは全てのコミットログメッセージを手動で見なければならなくなるだろう。機能の全て(例えば、一連のコミット)を revert しなきゃいけないなら、右の状況では本当に頭を痛くさせる。だがもし --no-ff フラグを使用したなら、簡単に終わるのだ。

確かに、これだとより多くの(空の)コミットオブジェクトを作成するはめになるが、そこから得られるものはコストよりずっと大きい。

残念ながら、 --no-ff をGitのマージのデフォルトの動作にする方法をまだ見つけてないけれど、それは本当に必要なことだ。

(2013年3月24日追記)Git1.7.6からは、以下のコマンドで --no-ff をデフォルトに出来ます。システム全体ではなくそのリポジトリだけに適用したいならば、 --global をはずしてください。
git config --global merge.ff false


リリースブランチ

分岐元: develop
マージ先: develop と master
ブランチ名の慣習: release-*

 リリースブランチは新しい製品リリースの準備をサポートする。それらは最後の瞬間の詰めをしっかりと行わせてくれる。その上、マイナーなバグフィクスや、リリースのためのメタデータ(バージョン番号、ビルド日時、他)の準備までさせてくれる。これらの全ての作業をリリースブランチ上で行うことで、 develop ブランチは次の大きなリリースのための機能を受け取るために、キレイな体でいられる。

develop から新しいリリースブランチを分岐する主要なタイミングは、develop ブランチが新しいリリースの望ましい状態を(ほぼ)反映しているときだ。少なくとも、そのリリースのビルドのターゲットとされる全ての機能は、この時点で develop にマージされていなければならない。将来のリリース向けの全ての機能は違う――それらはリリースブランチを分岐させるまでは、まだマージを待っていなければいけない。

正確には次のリリースがバージョン番号を割り当てられた時が、リリースブランチを始める時だ――それより早くてはいけない。その瞬間までずっと、 develop ブランチは「次のリリース」のための変更を反映するが、リリースブランチを始めるまで、「次のリリース」が結局0.3なのか1.0なのかは不明確だ。その決定はリリースブランチを始める時に、プロジェクトのバージョン番号を増加させるルールに則って、執り行われる。

リリースブランチの作成

 リリースブランチは develop ブランチから作成される。例えば、現在の製品リリースがバージョン1.1.5で、大きいリリースが近づいているとしよう。develop が「次のリリース」への準備が出来ている状態で、それをバージョン1.2(1.1.6や2.0ではなく)と決めた。そしたら、ブランチを切って、それに新しいバージョン番号を反映させた名前をつけるんだ。以下のように。

$ git checkout -b release-1.2 develop
Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
Files modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)

新しいブランチを作ってそれにスイッチした後、バージョン番号を増加させる。ここでは、 bump-version.sh はワーキングコピーのいくつかのファイルを、新しいバージョン番号を反映させるために変更を行うシェルスクリプトだ(もちろんこれは手動でも可能だ――このポイントは、何かしらのファイルを変更しているってことだ)。それから、バージョン番号の増加をコミットする。

リリースが確実にロールアウトするまで、この新しいブランチはしばらく存在するかもしれない。この間、バグフィックスがこのブランチに適用される場合もある(develop ブランチではなく)。ここで新しい大きな機能を加えるのは、厳禁だ。それらは develop ブランチにマージする、つまりその次の大きなリリースを待たなくちゃいけない。

リリースブランチを終える

 リリースブランチが本当にリリースされてもよい状態になったら、いくつかの動作が実行される必要がある。まず最初に、リリースブランチは master にマージされる(その定義から、master にあるコミットは全て新しいリリースだということを思い出そう)。次に、そのマージコミットにはタグをつけて、後で簡単に見直せるようにしなければならない。最後に、リリースブランチで行われた変更を develop にマージしなくちゃいけない。リリースブランチでやったバグフィックスなんかを将来のリリースに含めるためにね。

最初の2つのステップはGitだと:

$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2

リリースは完了し、そして後日のためにタグづけされる。
注: -s または -u <key> フラグを使って、タグに署名をした方が良いでしょう。

リリースブランチで作られた変更をまた使い続けたいから、 それらを develop にマージする必要があった。Gitでは:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)

このステップは、多分マージのコンフリクトを起こすだろう(ここでは私たちはバージョン番号を変更したから、起きる)。もしそうだったら、修正してコミットしよう。

今完全にリリースが終わり、もう必要ないので、リリースブランチは削除される:

$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).

ホットフィックスブランチ

分岐元: master
マージ先: develop と master
ブランチ名の慣習: hotfix-*

 ホットフィックスブランチは、新しい製品リリースへの準備であるという意味でリリースブランチに似ているが、計画されて行われるわけではない。それらは、現在の製品バージョンの望まざる状態への必要性から発生する。製品バージョンにあるクリティカルなバグがすぐに解決されなければならないとき、ホットフィックスブランチは、そのバージョンのタグがつけられている master のコミットから分岐されることになるだろう。

その本質は、(develop ブランチ上で)作業しているチームメンバーが作業を続けられながら、別の人間が製品のすばやい修正を準備できることにある。

ホットフィックスブランチの作成

 ホットフィックスブランチは master ブランチから作成される。例えば現在の製品バージョンが1.2で、深刻なバグがトラブルを起こしているとしよう。だが develop はまだ不安定だ。ならばホットフィックスブランチを切って、問題を修正し始めるんだ:

$ git checkout -b hotfix-1.2.1 master
Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)

ブランチを切ったあと、バージョン番号を増加させるのを忘れないように!

それからバグを修正して、一つ以上のコミットを行う。

$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)

ホットフィックスブランチを終える

 修正が終わった時、そのバグフィックスを次のリリースにもちゃんと含められるように保護するために、 master にマージされるだけでなく develop にもマージされる必要がある。これはリリースブランチを終える時ととてもよく似ている。

最初に、master をアップデートして、タグをつける。

$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1

注: -s または -u <key> フラグを使って、タグに署名をした方が良いでしょう。

次に、バグフィックスを develop にも含めさせる。

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)

ここで一つルールの例外があって、リリースブランチがこの時に存在していたら、ホットフィックスの修正を develop の代わりにリリースブランチにマージしなきゃいけない。リリースブランチにバグフィックスをマージすると、リリースブランチを終えたときに結局 develop にも含まれることになる(develop での作業にこの修正がすぐに必要で、リリースブランチを終えるのを待てないなら、今ここでも develop にマージする場合もある)。

最後に、一時的なブランチを削除しよう:

$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).


まとめ


 このブランチモデルには驚くような新しいことは一つもないが、この記事の最初の「大きな絵」は、私たちのプロジェクトにものすごく役立つと判明した。それは理解しやすいエレガントなメンタルモデルを形成し、チームメンバーにブランチングと、リリースプロセスの理解の共有を発展させる。

高品質な図のPDF版はここに用意した。持って行って、そしていつでもクイックリファレンスとして壁に掛けておいて欲しい。



更新:それと誰かがリクエストしていたので:ここに gitflow-model.src.key として主な図の画像を置く(Apple Keynote)。





Gitに関する翻訳記事はこちらもどうぞ: 【翻訳】あなたの知らないGit Tips

2010年10月9日土曜日

Ruby1.9.2で日本語を含むYAMLを出力する時、バイナリ文字列化されないようにする

RubyのYAML

Ruby(1.8以上)ではYAMLライブラリが標準添付ライブラリです。
そのため、YAMLを扱うには「require 'yaml'」とするだけです。

これでYAML.load(YAML形式から読み込み)、YAML.dump(YAML形式への出力)、
さらに様々なオブジェクトで to_yaml メソッドが使えるようになります。


日本語を含むYAMLを出力

しかしこのままでは、日本語文字列を含んだオブジェクトを
YAMLドキュメントとして出力すると、日本語部分がバイナリ文字列になってしまいます。
これでは人間にも読みやすいというYAMLの特徴が台なしです。

# -*- coding: utf-8 -*-
require 'yaml'

puts YAML.dump({'あ' => 'い'}) 


# 【出力結果】
# --- 
# "\xE3\x81\x82": "\xE3\x81\x84"

これを解消する方法を軽く検索してみると、
gemで違うYAMLライブラリを入れるとか、パッチをあてるなどの情報が出てきます。

Ruby1.9.2では:Psych

Ruby1.9.2からは、PsychというYAMLパーサも標準添付ライブラリになっています。
(以前からあるのは、Syckというライブラリ)
このPsychは「require 'yaml'」するだけでは有効にならないので、以下のようにします。

# -*- coding: utf-8 -*-
require 'yaml'

YAML::ENGINE.yamler = 'psych'

puts YAML.dump({'あ' => 'い'})


# 【出力結果】
# ---
# あ: い

今度は日本語がバイナリ文字列化されませんでした。


この方法はTwitter上で @sakuro さんに教えて頂きました。
ありがとうございました!

(2010年10月9日夜に追記↓)

YAML::ENGINE.yamlerを使わなくとも、「yamlの前にpsychがロードされていればOK」とのことです。
つまり以下の方法でも良いということになります。

# -*- coding: utf-8 -*-
require 'psych' # 追加
require 'yaml'

puts YAML.dump({'あ' => 'い'})


# 【出力結果】
# ---
# あ: い

上記の追記はTwitterで @n0kada さんに教えて頂きました。感謝です!

ちょっと実験

require 'psych'だけではどうでしょうか。

# -*- coding: utf-8 -*-
require 'psych'

puts YAML.dump({'あ' => 'い'})

# 【出力結果】
# uninitialized constant Object::YAML (NameError)

エラーになります。YAMLは使えません。

ではrequire 'yaml'が先で、require 'psych'が後だったら?

# -*- coding: utf-8 -*-
require 'yaml'
require 'psych'

puts YAML.dump({'あ' => 'い'})

# 【出力結果】
# --- 
# "\xE3\x81\x82": "\xE3\x81\x84"

Syckが使われてしまうようです。

1.9.2なのにPsychが使えないよ?

Ruby1.9.2なのにPsychが使えない場合は、 libyaml-dev を入れてからRubyを再コンパイルしましょう(パッケージ名は、Ubuntu 等の場合)。

Psychという名前

PsychであってPsyckじゃないんですね。
前のライブラリがSyckなのでちょっと紛らわしい。

Ruby1.9.3では(2011年11月28日追記)

コメントで教えて頂いた情報によると、
Ruby1.9.3からは、Psychの方がデフォルトになっているようです。
ですので、require 'yaml' 以外に余計な事を書かなくても、日本語を正しく扱うことができます。

逆に Syck を使いたい場合は、YAML::ENGINE.yamler='syck' としなければなりません。

2010年9月13日月曜日

Rubyのprivateメソッドルールの例外

privateメソッドのルール

『メタプログラミングRuby』P.65のコラムに、
privateメソッドのルールについて書かれていました。

 ”プライベートメソッドには1つのシンプルなルールが適用される。それは、「明示的なレシーバをつけてプライベートメソッドを呼び出すことはできない」というものだ。つまり、プライベートメソッドは、暗黙的なレシーバselfに対するものでなければならない。”

「privateメソッドは、明示的なレシーバをつけられない」。
レシーバがない状態といえば、「(暗黙的に)selfをレシーバとする状態」しかないわけですから、
通常はそのprivateメソッドを持っているオブジェクトからじゃないとメソッドを参照する経路がありません。
これによってRubyのprivateメソッドが「プライベートな」存在になるのですね。
(本気を出せば破ってしまえますが、それはまた別の話。)

これはわかりやすい覚え方です。
具体的に、極端な例を試してみると以下のようになります。

class A
  def foo
    self.bar
  end

  private

  def bar
    puts "bar is private method"
  end
end

A.new.foo # => error

例え同じクラス内からでも、明示的にレシーバ(ここではself)を
書いてしまうとエラーが起きます。

ルールの例外

しかし、このルールには例外が一つあります。
それは「セッターメソッドには明示的なレシーバが必要」、ということです。
(セッターメソッドというのは、メソッド名が「=」で終わるもののこと)

先程の例を、privateメソッドをセッターメソッドに変えてやってみましょう。

class B
  def foo
    self.bar = 1
  end

  private

  def bar=(arg)
    puts "bar= is private method"
  end
end

B.new.foo # => "bar= is private method"

この通りエラーが起きません。
privateメソッドがセッターメソッドの場合には、
明示的にレシーバを書いてもよいのです。

というよりも、明示的にレシーバを書かないとおかしなことになるからです。
以下にそれを示します。

class C
  def foo
    bar = 1 # ただのローカル変数の代入と見なされる
  end

  private

  def bar=(arg)
    puts "bar= is private method"
  end
end

C.new.foo # => 当然何も起こらない

セッターメソッドには明示的なレシーバが必要。
また、それはメソッドがprivateでもpublicでも変わることはありません。

この、privateメソッドのルールの例外については、
Twitterで @n0kada さんに教えていただきました。ありがとうございました。
http://twitter.com/n0kada/status/11625643920

2010年9月7日火曜日

RubyでNoMethodError時にObject#inspectが使われている

RubyKaigi2010での関 将俊さんの発表で聞いた話。

dRubyアプリケーション(RWiki)にirbから接続した時、
メソッド名の打ち間違えをするとなんだかとても遅い。

原因は、NoMethodError時にObject#inspectが走っており、
たくさんのデータ(配列やハッシュに入った数万のオブジェクト)を抱えているオブジェクトを
見えるように印字したらそりゃ遅いよねという話だった。

ruby-1.9.2-p0 > Object.new.does_not_exist_method
NoMethodError: undefined method `does_not_exist_method' for #<Object:0x00000001088288>
 from (irb):1
 from /home/oshow/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'

ruby-1.9.2-p0 > class Object
ruby-1.9.2-p0 ?>  def inspect
ruby-1.9.2-p0 ?>    "HELLO"
ruby-1.9.2-p0 ?>  end
ruby-1.9.2-p0 ?>end
 => nil 

ruby-1.9.2-p0 > Object.new.does_not_exist_method
NoMethodError: undefined method `does_not_exist_method' for HELLO:Object
 from (irb):7
 from /home/oshow/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'

確かに、「for #<Object:0x00000001088288>」ってところが
「for HELLO」に変わった。inspectが使われているらしい。

実際にも、関さんはObject#inspectを再定義して遅くなるのを回避したそうです。
(しかたなく…らしい(笑)。発表の動画を見るとわかります)

2010年9月5日日曜日

Ubuntu10.04でデスクトップに流れる音声を録音したい

インターネットラジオや生配信の音声を録音しておきたい、ということがあると思います。
Ubuntuには標準でサウンドレコーダーがついていますが、
ブラウザ等で音声を流しながらこれを使って録音してみても、
そのままでは何も録音することができません。

標準のサウンドレコーダーで録音できるようにするためには、
以下のような作業が必要です。

まず、padevchooserをインストールします。
$ sudo apt-get install padevchooser

次に「アプリケーション」→「サウンドとビデオ」→「PulseAudio Device Chooser」を起動。
パネルの通知領域にアイコンが出てくるので、左クリックして「Manager...」を選択。

Devicesタブの中のSourcesに「alsa_output〜」というものがあるので、
選択して右下の「Properties」ボタンを押す。

出てきたウィンドウの中の、Nameに書かれている内容をコピー。
自分の場合は「alsa_output.pci-0000_00_1b.0.analog-stereo.monitor」でした。

Managerを閉じたら、もう一度パネルのアイコンを左クリックして
「Default Source」→「Other...」を選択。

出てきたウィンドウに先程コピーした内容を張り付けて、OKを押します。


これで、標準のサウンドレコーダーを使って、
デスクトップに流れている音声を録音できるようになりました。


参考: recordMyDesktopでデスクトップを録画してみる on Ubuntu 9.10

(2010年10月25日 追記)

こちらの記事に書かれている方法でもよいようです。

2010年3月3日水曜日

Ubuntu9.10作業メモ6:rvmを使って複数バージョンのRubyを同時に利用する

rvm(Ruby Version Manager)を使うと、複数バージョンのRubyの
同時利用が非常に簡単にできます。
1.8.7と1.9.1を切り替えて使ったり、最新の1.9.2のtrunkを試してみたり、
JRuby・Ruby Enterprise Editionのような異なる処理系のRubyを管理する
といったことが手軽に出来るようになります。

主な効能としては、以下のようなものがあります。
  • コマンド一発で新しいRubyをインストール、アンインストール
  • 元からシステムに入っているRubyの環境を一切汚さない(全てのファイルは $HOME/.rvm/ の下に格納)
  • ディレクトリに設定ファイル(.rvmrc)を置くことで、そのディレクトリ下でrubyコマンドが実行されたときに呼び出されるバージョンを指定できる
  • あるスクリプトに対して、インストール済みの全てのRubyをまとめて走らせられる
  • 同様のことがrakeでも可能なので、例えばrake specを全Rubyで試すといったことができる
  • ある一つのバージョンのRubyに対して複数のgem環境を使い分けるGem Sets機能(例えば1.9.1に対して複数のrailsのバージョンを切り替える等ができる)
  • 他多数
なお、現在rvmは頻繁にアップデートを繰り返していますので、
説明した動作と異なる可能性もあることに注意してください。
執筆時点のrvmのバージョンは、0.1.21です。

ちなみに、Windowsにも似たソフトとして、pikというものがあるそうです。
(上記に挙げた機能と同じものが全て存在するかは、わかりませんが)

この記事では、rvmをインストールし、rvm経由でRuby1.8.7と1.9.1をインストールし、
それらが切り替えられるのを確認するところまでやってみます。



それでは、rvmをインストールしてみましょう。
rvmの公式サイトのインストール手引きを見ると、Githubからのインストールが
オススメとありますので、ここではそれで進めてみます。(Gitが必要です)

公式サイトには何やら長いコマンドが書いてありますが、要するに

$ git clone git://github.com/wayneeseguin/rvm.git
$ cd rvm
$ ./install

という手順が守られていれば問題はありません。
公式の手引きで、 $HOME/.rvm/src に対してgit cloneしようとするのは、
rvm本体に備わったアップデート機能を使うとどうせまたそこにgit cloneされるからだと思われます。

また、git cloneに対して「--depth 1」というオプションがついているのは、
要は「私はリポジトリをいじったりしないから、履歴とかなしで
最新のリビジョンのファイルだけコピーしてください」という指定です。
その方がダウンロードする容量が少なくて済むという配慮でしょう。




さて、installスクリプトの実行が完了すると色々とメッセージが表示されます。

重要なのは後半の「You must now finish the install manually:」以下の部分です。
指示通り、そこに表示された一行をシェルの設定ファイルの最後に書き込みましょう。
自分の場合は、 $HOME/.bashrc の最後に以下を書き込みました。(人によって内容が違うはずです)
if [[ -s /home/oshow/.rvm/scripts/rvm ]] ; then source /home/oshow/.rvm/scripts/rvm ; fi

(※2010年12月30日追記:現在は以下のような一行を追加せよと指示されます。意味は同じです)
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"


もう一つ重要なのは、rvmでRubyをインストールする際に必要なパッケージ類の説明です。
rvmではRubyのインストールは基本的にソースからのビルドなので、
ビルドのためのパッケージを準備しなければなりません。
ここでは普通に1.8.7と1.9.1をインストールしたいので、
「*  For MRI & ree (if you wish to use it) you will need:」と書かれた行を探してみてください。

$ aptitude install curl bison build-essential zlib1g-dev libssl-dev libreadline5-dev libxml2-dev git-core

と書かれています。これらがビルドに必要なパッケージです。
自分の場合はGitが既に入っているので、それを除いて、

$ sudo aptitude install curl bison build-essential zlib1g-dev libssl-dev libreadline5-dev libxml2-dev

のように実行しました。

また、上記の説明文を見逃してしまっても、
rvmのアップデートコマンド( rvm update --head )を使う度に見れますので安心してください。
(※2010年6月8日追記:現在は rvm notes コマンドで見られるようです。)

(※2010年12月30日追記:rvm update --head というコマンドは古くて、現在は rvm get head を使うようです。)

以上で準備が整ったので、rvmを使っていきましょう。
rvmを使い始める前に、端末を一旦閉じて開き直してください。

まずrvm経由のRubyのインストールです。

$ rvm install 1.8.7
$ rvm install 1.9.1

このようにバージョンを指定するだけでインストールが可能です。
ダウンロード→ビルドと実行されるので、それなりに時間がかかります。
完了したら、バージョンを切り替えられることを確認してみましょう。

$ rvm use 1.8.7
$ ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-linux]


$ rvm use 1.9.1
$ ruby -v
ruby 1.9.1p378 (2010-01-10 revision 26273) [i686-linux]

となるはずです。
元々入っているRubyに戻すには、

$ rvm use system

とします。


----

rvmの実体はシェルスクリプトの集合体です。rvmはシェルに対して細工を行います
(例えば、cdコマンドを再定義する等)。その辺りが気にかかる方は、十分考慮してから利用してください。

2010年2月17日水曜日

Ubuntu9.10作業メモ5:Gitをソースからインストール

分散バージョン管理システムであるGitをソースからインストールしてみます。
執筆時点の最新バージョンは1.7.0です。

Linux等では普通、パッケージ管理システムを使ってソフトをインストールします。
そうすることで現在何がインストールされているか把握でき、
統一的な操作でアップデートやアンインストールができ、
ソフトウェア同士の依存関係の問題も起こりにくくなります。

ソフトウェアをソースから自分でインストールする場合はそれらの恩恵が
受けられなくなる代わりに、パッケージ管理システムが用意していない最新版を
インストールすることができます。メリットとデメリットを考えて実行してください。

Ubuntuでソフトウェアをソースからインストールする場合、paco などを使って
インストールの事実を管理すると良いようですが、ここでは特に考えずにインストール手順を示します。


ソースからインストールするということは、インストール作業は持ってきたファイルを
コピーするだけでは済まず、ビルドというコンパイルも含んだ作業ができなければなりません。

あるソフトをビルドするのに何が必要なのかは、そのソフトによります。
通常はそのソフトのインストール手順書などを見てビルドの準備をしますが、
ここでは楽をしてパッケージ管理システムの機能を利用しましょう。

Ubuntuでは、最初からパッケージ管理システムにやや古い版のGitが用意されています。
「git-core」というものがそれです。ここにGitがあるということは、
Gitをビルドするのに必要なソフト類をパッケージ管理システムは知っていることになります。

これを利用して、「Gitをビルドするのに必要なソフト類を選択してインストールしてください」
というように指示することができます。以下の通りです。

$ sudo apt-get build-dep git-core

これで、ビルドの準備が整いました。
(この方法は、『入門Git』の記述からお借りしました。)

 【2012年2月3日追記】
 現在ではパッケージ名は「git-core」ではなく「git」になっているようです。
 ですので、「sudo apt-get build-dep git」と実行します。


それではGit本体のインストールです。
Gitの公式サイトから最新版をダウンロードして解凍し、解凍したディレクトリに移動してください。

ここではドキュメント類も一緒にビルドします。
また、システム全体で使うように /usr/local へインストールします。

$ ./configure
$ make prefix=/usr/local all doc
$ sudo make install install-doc

【2010年11月19日追記】
以下の方がいいかもしれません。
$ ./configure --prefix=/usr/local
$ make all doc
$ sudo make install install-doc


以上です。
インストールに成功したか確認してみましょう。

$ git --version
git version 1.7.0

となるはずです。

2010年2月16日火曜日

Ubuntu9.10作業メモ4:nautilus-open-terminalを使って対象ディレクトリからターミナルを簡単に開く

Ubuntuの標準のファイラーはNautilusというエクスプローラ風のものですが、
これを使ってディレクトリを操作している際に、対象のディレクトリを現在位置として
ターミナルを開きたくなるということがあります。

対象ディレクトリの場所を覚えておいてから、普通にターミナルを立ち上げて
cdコマンドで移動するのは少々不便です。そこで、Nautilusの方から一発で
ターミナルを開けるようにしてくれるソフトウェアがあります。

それが nautilus-open-terminal です。Synapticで探してインストールすると、
Nuatilusでディレクトリアイコンを右クリックしたときのメニューに
「Open in Terminal」というものが増えています。

これで、対象のディレクトリを現在位置としてターミナルを開くことができるようになります。

2010年2月15日月曜日

Ubuntu9.10作業メモ3:UbuntuTweakを使って標準以外のソフトウェアをインストール

UbuntuにはUbuntu Tweakという便利なソフトがあります。
Windowsでいうところの「窓の手」のようなソフトでしょうか。

標準のメニューからでは設定しにくい部分をカスタマイズしたり、
元々用意されている以外のアプリケーションのインストールを手助けしてくれます。
例えば、Firefoxの最新版、GoogleChromeの最新版、Chromiumのデイリービルド、
Dropbox、Skypeなどが簡単にインストールでき、目的のリポジトリを探し回る手間を省けます。

それでは、UbuntuTweakをインストールしてみましょう。

「システム」→「システム管理」→「ソフトウェア・ソース」を開きます。
「他のソフトウェア」タブで「追加」ボタンを押して

ppa:tualatrix/ppa

を追加します。その後、Synapticで「ubuntu-tweak」を検索してインストールします。
UbuntuTweakは、「アプリケーション」→「システムツール」の所に入ります。

試しに、UbuntuTweakからGoogleChromeをインストールしてみましょう。
UbuntuTweakを立ち上げたら左側のメニューから「ソースセンター」を選びます。
「Browser」の中にある「Google Stable Source」をチェックして「更新」を押します。

次に左側のメニューの「アプリケーションセンター」を選ぶと、
「Brwoser」の中で「Google-Chrome-Beta」と「Google-Chrome-Unstable」というのが
選べるようになっていると思います。
好みの方をチェックして、「適用」ボタンを押してください。

また、当然ですが、UbuntuTweakで追加したソース・リポジトリにあるソフトは、
Synapticの方にも現れるようになります。

2010年2月14日日曜日

Ubuntu9.10作業メモ2:.Xmodmapを使ってキーバインドを変更する

Ubuntuでは、 $HOME/.Xmodmap ファイルに設定を書き込むことで
キーバインドを変更することができます。

設定を書くためには、変更したいキーを特定するための
「番号」あるいは「呼び方」がわからなければなりません。
この「番号」と「呼び方」がキーコードとKeySym名です。

キーコードとKeySym名を調べるためには、xevコマンドを使います。
端末で xev と打つとキーボードやマウスの操作内容が端末に
反映されるようになるので、他の箇所に触らないように目的のキーを押してください。

例えば自分の環境でEnterキーを押すと以下のように表示されました。

KeyRelease event, serial 36, synthetic NO, window 0x5200001,
root 0x109, subw 0x0, time 96083768, (110,502), root:(701,553),
state 0x10, keycode 36 (keysym 0xff0d, Return), same_screen YES,
" XLookupString gives 1 bytes: (0d) "
XFilterEvent returns: False

ここでは、keycodeと書かれている横にある「36」がキーコード、
keysymと書かれている横にある「Return」がKeySym名になります。

キーの特定方法がわかったところで設定の具体的な書き方ですが、
普通のキーとAlt/Ctrl/Shift/Superキー/Caps Lockキー(修飾キー)では
書き方が少し異なります。

普通のキーを塗り替えたい場合は、

keycode [keycode] = [keysym]

と書きます。[keycode]の所にxevで調べたキーコード、
[keysym]の所にxevで調べたKeySym名を指定するわけです。
これで、=の左のキーコードに指定したキーが、
=の右のKeySym名で指定したキーに変わります。

もしくは

keysym [keysym] = [keysym]

という書き方もあるようです。

次に、修飾キーが絡む場合ですが、こっちはaddとremoveを使って
修飾キーの機能をキーに付加したり外したりします。
キーを塗り替えるのとは考え方が違うので注意してください。

修飾キーの機能を取り去るには、

remove [修飾キー名] = [keysym]

修飾キーの機能を付加するには

add [修飾キー名] = [keysym]

とります。=の右側で指定したキーが修飾キーになる(ならなくなる)キーです。

修飾キー名ですが、ターミナルで xmodmap -pm と打った時に
左側に並んでいるshift、lock、control、mod1などのことです。
また、このコマンドで現在の修飾キーの割り当てがわかるので、参考にしてください。

設定を書き終わったら一旦ログインしなおすとキーバインドが反映されるはずです。
もっと詳しく調べたい場合は、「xmodmap」等で検索してみてください。

Ubuntu9.10作業メモ1:本家版のCDで英語でインストールした場合に日本語入力をする

Ubuntuには日本語環境にカスタマイズされたバージョンのイメージが用意されています。

Ubuntu Japanese Team

これを利用してUbuntuをインストールするか、Ubuntu Japanese Team様が用意した
リポジトリから日本語セットアップヘルパをインストールすることでも
日本語環境を使用することができます。

しかし、以上の方法を用いない本家版のCDイメージのみでも、
日本語入力を行うことは可能です。
(ただ、Ubuntu Japanese Team版では「日本語入力」以外にも様々な日本語向け
 カスタマイズがされているので、普通はそちらを使った方がいいと思います)

やり方は、「System」→「Administration」→「Language Support」を選択し、
日本語をインストールしてメニューを日本語に変更するだけです。

ただし、この作業を行う前に自分でiBusの設定をいじっていると、
Language Supportから日本語に変更しても何故かうまく日本語入力できません。
(ひらがな入力はできるけど、スペースキーを押しても変換できない)
本当は後からでもちゃんとした設定方法があるのかもしれませんが…

ということで、本家版を使うけどとりあえず日本語入力だけをやりたいという場合は、
まっさきにLanguage Supportから日本語に変更すると、日本語入力ができるようになります。

フォロワー