Permalink
Browse files

no comment

  • Loading branch information...
1 parent bc36186 commit 2f2f185c3ffcb4642ab6187d082e16b73d1b72fa @seki committed Sep 2, 2011
Showing with 62 additions and 47 deletions.
  1. +62 −47 drip.txt
View
109 drip.txt
@@ -94,7 +94,10 @@ Dripにquitメソッドを追加しています。これはRMI経由でこのプ
***MyDrip
-MacOSXなどPOSIXなOS専用ですが、MyDripという1人用の起動が簡単なDripサーバも用意されています。これは、ホームディレクトリの直下に.dripというディレクトリを作成し、この中をストレージとするDripで、UNIXドメインソケットを使ってサービスします。UNIXドメインソケットですから、ファイルの権限、可視性によって利用者を制限できます。また、UNIXドメインソケットのファイル名はホームディレクトリ以下のいつも決まったパスで接続できます。MyDripを利用するにはmy_dripをrequireします。
+MacOSXなどPOSIXなOS専用ですが、MyDripという1人用の起動が簡単なDripサーバも用意されています。これは、ホームディレクトリの直下に.dripというディレクトリを作成し、この中をストレージとするDripで、UNIXドメインソケットを使ってサービスします。UNIXドメインソケットですから、ファイルの権限、可視性によって利用者を制限できます。また、UNIXドメインソケットのファイル名はホームディレクトリ以下のいつも決まったパスで接続できます。
+TCPの場合、固定にするにはそのマシンの中である番号のポートをあるサービスに割り当てる、とみんなで約束を守る必要があり、dRubyのURIを固定にするのに面倒なところがあります。それに対して、各ユーザのホームディレクトリの下のファイルを使う場合にはみんなで約束しあう必要がありませんから、URIを機械的に決めるのが簡単です。
+
+MyDripを利用するにはmy_dripをrequireします。
起動してみましょう。
>||
@@ -1087,29 +1090,57 @@ queryメソッドで使用しているboundは、二つのキーの内側にあ
boundの仲間にはlower_bound、upper_boundというバリエーションもあります。狙ったキーの直前、直後(そのキーを含みます。以上、以下みたいな感じ。)などを調べられます。並んでいるキーとlower_boundを使ってand検索やor検索も効率よく行えます。次のコード片はand検索を行うものです。二つのカーソルを使い、カーソルが一致したときがand成功、カーソルが異なる場合には後側の単語のカーソルを先行する単語のカーソルの点からlower_boundさせます。これを繰り返すと、スキップしながらand検索が可能です。
+次のスクリプトは、lower_boundを使ったand検索のアルゴリズムを実験するものです。起動引数に与えたファイルの中から'def'と'initialize'が同時に出現する行を探します。文書の「位置」はこのケースでは「ファイル名」「行番号」を選びました。
+
>|ruby|
- def fwd(w1, fname)
- k, v = @tree.lower_bound([w1, fname])
+require 'rbtree'
+require 'nkf'
+
+class Query2
+ def initialize
+ @tree = RBTree.new
+ end
+
+ def push(word, fname, lineno)
+ @tree[[word, fname, lineno]] = true
+ end
+
+ def fwd(w1, fname, lineno)
+ k, v = @tree.lower_bound([w1, fname, lineno])
return nil unless k
return nil unless k[0] == w1
- k[1]
+ k[1..2]
end
def query2(w1, w2)
- f1 = fwd(w1, '')
- f2 = fwd(w2, '')
+ f1 = fwd(w1, '', 0)
+ f2 = fwd(w2, '', 0)
while f1 && f2
- if f1 > f2
- f2 = fwd(w2, f1)
- elsif f2 > f1
- f1 = fwd(w1, f2)
+ cmp = f1 <=> f2
+ if cmp > 0
+ f2 = fwd(w2, *f1)
+ elsif cmp < 0
+ f1 = fwd(w1, *f2)
else
yield(f1)
- f1 = fwd(w1, f1 + "\0")
- f2 = fwd(w2, f2 + "\0")
+ f1 = fwd(w1, f1[0], f1[1] + 1)
+ f2 = fwd(w2, f2[0], f2[1] + 1)
end
end
end
+end
+
+if __FILE__ == $0
+ q2 = Query2.new
+
+ while line = ARGF.gets
+ NKF.nkf('-w', line).scan(/\w+/) do |word|
+ q2.push(word, ARGF.filename, ARGF.lineno)
+ end
+ end
+
+ q2.query2('def', 'initialize') {|x| p x}
+end
||<
boundでなくlower_bound、upper_boundを使うメリットはもう一つあります。
@@ -1138,13 +1169,14 @@ Rindaの場合は強力なパターンマッチと引き換えに、Arrayを基
***まとめにかえて
-この章の最後に、この小さな検索システムにERBの章で見せたようなWeb UIを追加してみましょう。この検索システムはクロウラとインデクサ、そしてミドルウェアのDripで構成されていました。ここにWeb UIを実現するWEBrick::CGIサーバが追加されます。
-こんなにたくさんのプロセスを起動するのは面倒ですよね。そこで、クロウラ、インデクサ、Web UIを一つのプロセスに配置することにしましょう。dRubyを使って作ったシステムは、もともとプロセスの境界はRubyそっくりにできています。このためプロセス構成、オブジェクトの配置を変更するのは意外と簡単です。全部を一つに入れた完成版のスクリプトを次ぎに示します。ERBの章やdRubyの章を思い出しながら読んで下さい。
+この章の最後に、この小さな検索システムにERBの章で見せたようなWeb UIを追加してみましょう。この検索システムはクロウラとインデクサ、そしてミドルウェアのDripで構成されていました。ここにWEBrick::HTTPServerとサーブレットによるWeb UIを追加してみましょう。ERBの章ではWEBrick::CGIサーバを使って実験しました(覚えてますか?)。今回はHTTPServerを載せてみます。
+
+こんなにたくさんのプロセスを起動するのは面倒ですよね。そこで、クロウラ、インデクサ、HTTPServer、Web UIを一つのプロセスに配置することにしましょう。dRubyを使って作ったシステムは、もともとプロセスの境界はRubyそっくりにできています。このためプロセス構成、オブジェクトの配置を変更するのは意外と簡単です。全部を一つに入れた完成版のスクリプトを以下に示します。
>|ruby|
require 'index'
require 'crawl'
-require 'webrick/cgi'
+require 'webrick'
require 'erb'
class DemoListView
@@ -1165,12 +1197,12 @@ class DemoListView
EOS
end
-class DemoUICGI < WEBrick::CGI
- def initialize(crawler, indexer, *args)
- super(*args)
+class DemoUIServlet < WEBrick::HTTPServlet::AbstractServlet
+ def initialize(server, crawler, indexer, list_view)
+ super(server)
@crawler = crawler
@indexer = indexer
- @list_view = DemoListView.new
+ @list_view = list_view
end
def req_query(req, key)
@@ -1181,11 +1213,6 @@ class DemoUICGI < WEBrick::CGI
end
def do_GET(req, res)
- if req.path_info == '/quit'
- Thread.new do
- @crawler.quit
- end
- end
word = req_query(req, 'w') || ''
list = word.empty? ? [] : @indexer.dict.query(word)
res['content-type'] = 'text/html; charset=utf-8'
@@ -1199,7 +1226,7 @@ if __FILE__ == $0
crawler = Crawler.new
Thread.new do
while true
- crawler.do_crawl
+ pp crawler.do_crawl
sleep 60
end
end
@@ -1208,36 +1235,24 @@ if __FILE__ == $0
Thread.new do
indexer.update_dict
end
-
- cgi = DemoUICGI.new(crawler, indexer)
- DRb.start_service('druby://localhost:50830', cgi)
- DRb.thread.join
-end
-||<
-あたらしいクラスは二つです。一つはDemoUICGIで、CGIサーバの主処理を司ります。もう一つはDemoListViewクラス、CGIの見た目を生成するViewオブジェクトです。
-「if __FILE__ == $0」で囲まれたメイン部を見てみます。ここではcrawl.rbやindex.rbのメイン部で行っていたサブスレッドの生成のあと、CGIサーバを起動しています。"/quit"へのアクセスがあるとこのサーバはクロウラの仕事の合間に終了します。なお、この時点で終了してしまうので正しいレスポンスは返しません。
-
-実際にWebサーバから起動されるCGIスクリプトはいつものように次の5行です。
-
->|ruby|
-#!/usr/local/bin/ruby
-require 'drb/drb'
-DRb.start_service('druby://localhost:0')
-ro = DRbObject.new_with_uri('druby://localhost:50830')
-ro.start(ENV.to_hash, $stdin, $stdout)
+ server = WEBrick::HTTPServer.new({:Port => 10080,
+ :BindAddress => '127.0.0.1'})
+ server.mount('/', DemoUIServlet, crawler, indexer, DemoListView.new)
+ trap('INT') { server.shutdown }
+ server.start
+ crawler.quit
+end
||<
-このようにWebサーバと本当のCGIの助けを借りなくても、WEBrickのHTTPサーバを利用するというのもよいでしょう。
+あたらしいクラスは二つです。一つはDemoUIServletで、Web UIを司ります。もう一つはDemoListViewクラス、CGIの見た目を生成するViewオブジェクトです。
+「if __FILE__ == $0」で囲まれたメイン部を見てみます。ここではcrawl.rbやindex.rbのメイン部で行っていたサブスレッドの生成のあと、HTTPサーバを起動しています。Ctrl-Cなどでシグナルを使ってサーバを終了させると、クロウラの仕事の合間に終了します。
クロウラとインデクサが一つプロセスでは、Dripの意味がないのではないか?という気がしなくもないですが、デスクトップのアプリケーションのように起動は簡単になりました。関連するプロセスが少ないのでデーモン化するのも楽です。ところで、プロセス間でオブジェクトの配置を変えるのは簡単でしたよね。このプロセス構成が気に入らなければ、クロウラとインデクサを分けるようなプロセス構成にすることも簡単です。
-Dripの章の最後に、久しぶりにdRubyをERBを使って小さなシステムを組み立てました。dRuby、ERB、Rinda、Dripなどの私のライブラリは、あなたの手の中にある問題をあなた自身が解くのを支援できるように意図して作りました。どれも仕組みは単純でおもちゃみたいなライブラリですが、とても手軽にはじめることができます。
+Dripの章の最後に、久しぶりにdRuby(プログラムリストには現れないけど、MyDripへのアクセスで使ってました)をERBを使って小さなシステムを組み立てました。dRuby、ERB、Rinda、Dripなどの私のライブラリは、あなたの手の中にある問題をあなた自身が解くのを支援できるように意図して作りました。どれも仕組みは単純でおもちゃみたいなライブラリですが、とても手軽にはじめることができます。
本当に大きな問題、たとえばメインメモリにも一つのマシンのディスクにも入りきらないようなデータを扱ったり、無数のクライアントを本当に同時にハンドリングしたり、そういうのには向かないかもしれませんが、自分のPCや家庭のネットワークにあるようなあなたのデータをつかってミニチュアを書くのにはぴったりなツール群です。この本で紹介したライブラリやその考え方があなたのデザインのバリエーションを増やすことになれば、本当にうれしいことです。
おしまい
-
-
-

0 comments on commit 2f2f185

Please sign in to comment.