2009-11-20

引用文のためのスタイルを定義

引用文(blockquote 要素)を目立たせようと、スタイルを定義した。こんな風(↓)になる。

SICP:
Program must be written for people to read, only incidentally for machine to execute.

色は、Mail.app の「メモ」で使われている色(「#FEF8BC」)。 ノートのような罫線はぐぐって見つけたここからパクり(→ mugu - memo - CSSでノート風罫線)。画像はサイズを変更した上で使用させてもらっている。
作者に感謝。

2009-11-19

MacRuby のこれまで (0.1 〜 0.5 beta 2)

公式ブログのリリース告知をざっとまとめていたんだけど、公式なロードマップが存在していた(→ MacRuby >> Roadmap)。こっちの方がコンパクトなので、それを元に、さらに最新版の 0.5 beta 2 までの特徴を入れ込んでみる。

追記@2010-11-26

0.5 beta 2 の後、0.7 までについてはこちらを参照 → 「MacRuby 0.7 を iMac にインストール」

0.1 (released 2008-03-13): GC をふくむランタイムの統合

Roadmap で特色とされているのは以下の 5 項目。

  • 最初の公開リリース
  • Objective-C のランタイムにもとづくオブジェクトモデル
  • Objective-C のメッセージ伝播の仕組みの基礎部分
  • BridgeSupport ファイルを読み込み可能
  • Objective-C の GC との統合

BridgeSupport ファイルはフレームワークやライブラリの API シンボル情報を記載した XML ファイルで、RubyCocoa や PyObjC のようなスクリプト言語と Objective-C ランタイムとのブリッジ機能で使われる。以上、Snow Leopard の man ページより。

Laurent が MacRuby-devl ML に投げた告知メールによれば、

MacRuby is a version of Ruby that runs on top of Objective-C. More precisely, MacRuby is currently a port of the Ruby 1.9 implementation for the Objective-C runtime and garbage collector.

肝心なことは Objective-C のオブジェクトがそのまま Ruby のオブジェクトになっているよ、というとだろう。MRI 1.9 を Objective-C のランタイムと GC に移植した、と言っている。

2009-11-18

MacRuby を試そう!

追記@2010-11-26

MacRuby に関しては以下の記事も参照のこと:

MacRuby の 0.5 beta 2 がリリースされたというので、試してみる気になった。

アナウンスに貼られたリンクから zip のインストールパッケージをダウンロード。zip を展開し、中の PKG ファイルをダブルクリックすればインストール開始。MacRuby の本体などは /usr/local/bin 以下に、Xcode のプロジェクトテンプレートは /Library/Application Support/Developer/3.0/Xcode 以下にそれぞれインストールされる。

インストールが完了するとこうなる(↓):

[macmini:~] mnbi% which macruby
/usr/local/bin/macruby
[macmini:~] mnbi% macruby -v
MacRuby version 0.5 (ruby 1.9.0) [universal-darwin10.0, x86_64]

また、Xcode の新規プロジェクト作成パネルはこう(↓):

MacRuby のプロジェクトテンプレート
送信者 Macをプログラムする

「RubyによるMac OS Xデスクトップアプリケーション開発入門」を見ながらサンプルを試してみたり(p.224 〜 234)。

2009-11-17

Go のサンプルコードを Ruby で書き直してみる

Go の channel のようなものとして、Ruby には Queue クラスが用意されている。これを使えば、Rob Pike の説明していたサンプル (A multiplexed server) をほぼそのままの形で Ruby に直すことができる。対応するプログラミング要素はこんな感じ(↓):

Go Ruby
channel型→Queue クラス
func型→ブロック
goroutine→Thread クラス

ちなみに、今回使った Ruby は Snow Leopard に標準のもの。バージョンはこれ(↓):

[macmini:~] mnbi% which ruby
/usr/bin/ruby
[macmini:~] mnbi% ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [universal-darwin10.0]

コードはこうなる。コメントもオリジナルのものをそのまま相当する場所に記入しておいた。

(multi_server.rb)
 1: require 'thread'
 2: 
 3: class Request
 4:   def initialize(a, b, q)
 5:     @a = a
 6:     @b = b
 7:     @replyq = q                 # reply queue inside the Request
 8:   end
 9:   attr_reader :a, :b, :replyq
10: end
11: 
12: def run(req, op)
13:   req.replyq.enq(op.call(req.a, req.b))
14: end
15:
16: def server(service, op)
17:   loop {
18:     req = service.deq           # requests arrive here
19:     Thread.start(req) do |r|
20:       run(r, op)
21:     end
22:   }
23: end
24: 
25: def start_server(&op)
26:   req_queue = Queue.new
27:   Thread.start(req_queue, op) do |rq, o|
28:     server(rq, o)
29:   end
30:   return req_queue
31: end
32: 
33: # Start server; recieve a queue on which to send requests.
34: server = start_server {|a, b| (a + b)}
35: 
36: # Create requests
37: req1 = Request.new(23, 45, Queue.new)
38: req2 = Request.new(-17, 1 << 4, Queue.new)
39: 
40: # Send them in arbitrary order
41: server.enq(req1)
42: server.enq(req2)
43: 
44: # Wait for the answers in arbitrary order
45: puts "Answer2: #{req2.replyq.deq}"
46: puts "Answer1: #{req1.replyq.deq}"

オリジナルの Go コードと並べてみれば、ほぼ一対一に対応していることがわかる。

Go のサンプルにあった、channel に対する select を使った server は、Ruby の Queue では簡単に実現できない。Ruby に用意されている select (Kernel.select または IO.select) には IO オブジェクトしか使えない。Queue ではダメなのだ。Queue に対する select に相当する仕組みを Queue や Thread のメソッドを使って作ることは可能だ(と思う)けど、ちょっと面倒なことになる。

ちなみに実行結果は以下のとおり。ちゃんと動いた。

[macmini:~] mnbi% ruby multi_server.rb
Answer2: -1
Answer1: 68

関連リンク

関連記事

参考文献

プログラミング言語 Ruby
まつもと ゆきひろ, David Flanagan
オライリージャパン ( 2009-01-26 )
ISBN: 9784873113944
おすすめ度:アマゾンおすすめ度

2009-11-16

Go サンプルコードを読んでみる: A multiplexed server

Rob Pile が Go の channel の説明で使っていたサンプルを読んでみよう。 以下のコードはどれも、Rob Pike のスライドよりコピペしたもの。

まずはサーバのコード(スライドの 30 枚目)。

[A multiplexed Server]
 1: type Request struct {
 2:     a, b    int;
 3:     replyc  chan int; // reply channel inside the Request
 4: }
 5:
 6: type binOp func(a, b int) int
 7: func run(op binOp, req *request) {
 8:     req.replyc <- op(req.a, req.b)
 9: }
10:
11: func server(op binOp, service chan *request) {
12:     for {
13:         req := <-service; // requests arrive here
14:         go run(op, req);  // don't wait for op
15:     }
16: }
17:
18: func StartServer(op binOp) chan *request {
19:     reqChan := make(chan *request);
20:     go server(op, reqChan);
21:     return reqChan;
22: }

Go の文法はよくわからないが、このコードが何をするものなのかは、なんとなくわかる。

1 〜 4 行目は構造体の定義。replyc が整数の通る channel。その名前から、サーバへのリクエストに対する結果を返すものだと想像がつく。

6 〜 9 行目; サーバにおける処理の定義。2 つの整数に対して、2項演算を適用して、その結果を replyc に送る。

11 〜 16 行目; サーバ本体。引数は処理すべき 2 項演算とリクエストが通ってくる channel。for は無限ループ。13 行目でクライアントからのリクエストを取り出して、14 行目で実行。ところで、この 14 行目にある go が goroutine と呼ばれるスレッドを起動するものらしい。run はすぐ上の 7 行目で定義されている関数。それを別スレッドで処理するってことだ。

18 〜 22 行目が、サーバを起動する関数。引数としてサーバが処理する演算を受け取る。実行する内容は、リクエストを受け付ける channel を用意し(19 行目)、サーバ本体を別スレッドで起動し(20 行目)、リクエストを流す channel をクライアントに返す(21行目)。