それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

RubyのAPIドキュメントを CGIとして動かす方法

rubyAPIドキュメントをruby-doc-server.exeでなく,CGIとして任意のディレクトリで動かしたい

http://localhost/ruby-doc/ にドキュメント置きたい


localhost にあるとナニカと便利なAPIドキュメント.

rubydoc-serverをローカルホストで動かしたいなとか思った。apache/webrickで動かそうと思ったんです。検索して見つけた!と思ったらrubyAPIドキュメントサーバーをReverseProxyで動かす話で,ガッカリしたので、ソースを調べた。

るりまで検索すると楽だけど,僕はHTMLが欲しいんですね.オフラインでも使うので.
http://www.ruby-lang.org/ja/documentation/ を見ていると、htmlのDLは無く、refeパッケージだけが見つかるのです・・・

CGIで使うために、動作をちゃんと追いかけてみた

起動ファイルの中身

rubydoc サーバーの起動ファイルは次のようになっていた.

server.rb
#!/usr/bin/ruby -Ke
Dir.chdir File.dirname(__FILE__)
standalone = "bitclust/standalone.rb"
src = File.read(standalone).sub(/\$0/) { standalone.dump }
ARGV.unshift "--bind-address=127.0.0.1"
ARGV.unshift "--baseurl="
ARGV.unshift "--debug"
ARGV.unshift "--auto"
ARGV.unshift "--capi"
eval src, binding, standalone, 1

シェルスクリプトを実行するファイルだった.実体はstandalone.rbらしい

起動スクリプトから standalone.rb を見ればいいと分る

呼ばれている standalone.rb を見る

standalone.rb もシェルスクリプトとして実行される.optparseが引数を受け取って展開する.

起動スクリプトに戻り、指定されるオプションを調べる.
次のオプションが指定されている.

standalone に渡されるオプション
autop  = true
debugp = true
capi   = true
baseurl = ""
bind-address=127.0.0.1
$0 = /usr/local/doc/ruby/server.rb #ruby doc インストールした場所。

以上の初期値を持ってWebrickを作成しているようだ.

standalone.rb がWebrickにマウントされるプロセス

webrick起動ー>設定の流れを追いかける.

#optparse の基本設定から導出

set_srcdir = lambda {|path|
  srcdir = path
  datadir ||= "#{srcdir}/data/bitclust"
  themedir ||= "#{srcdir}/theme"
  libdir ||= "#{srcdir}/lib"
}
set_srcdir.call "MY_PATH"
メインの処理部分

ココがメインらしい

if autop #autop=trueなのでここが実行される
  app = BitClust::App.new(
    :dbpath => Dir.glob("db-*"), # インストール済みのRubyドキュメント
    :baseurl => baseurl,         #=> set_srcdir  より
    :datadir => datadir,         #=> set_srcdir  より
    :templatedir => templatedir, #=> set_srcdir  より
    :theme => theme,             #=>default 固定
    :encoding => encoding,       #=> euc固定
    :capi => capi
    )
  app.interfaces.each do |version, interface|
    server.mount File.join(basepath, version), interface
  end
  server.mount(File.join(basepath, '/'), app)
 end
server.mount File.join(basepath, 'theme/'), WEBrick::HTTPServlet::FileHandler, themedir

仕組みが分ったので、webrick で任意の場所にマウントしてみる

毎回、起動するのが面倒なので、いつも常駐しているWebrickにマウントしておく

$:.push "/usr/local/doc/ruby/bitclust/lib" #bitclust をパスに含める
require 'bitclust'
require 'bitclust/app'
# 変数の初期化
baseurl = dbpath = srcdir = libdir = datadir = themedir = theme = templatedir = nil
set_srcdir = lambda {|path|
  srcdir = path
  datadir ||= "#{srcdir}/data/bitclust"
  themedir ||= "#{srcdir}/theme"
  libdir ||= "#{srcdir}/lib"
}
set_srcdir.call "/usr/local/doc/ruby/bitclust" #ドキュメントのインストール場所指定
baseurl="/ruby"                                #webrickのマウントパス
basepath = URI.parse(baseurl).path
encoding = "euc"
capi = true
app = BitClust::App.new(                          
  :dbpath => Dir.glob("/usr/local/doc/ruby/db-*"),#バージョン毎のドキュメントを探す
  :baseurl => baseurl,
  :viewpath => baseurl,
  :datadir => datadir,
  :templatedir => templatedir,
  :theme => theme,                          
  :encoding => encoding,
  :capi => capi
  )
#CGIマウント処理
app.interfaces.each do |version, interface|
  # バージョン毎のドキュメントをそれぞれマウントする /1.8.7/... /1.9.2/... を実現している箇所
  srv.mount File.join(basepath, version), interface 
end
# cssを設定
srv.mount File.join(basepath, 'theme/'), WEBrick::HTTPServlet::FileHandler, themedir 
#メインページ
srv.mount(File.join(basepath, '/'), app)

起動した!

以上の設定で webrick を起動すると

http://localhost/ruby-doc

でリファレンスマニュアル刷新計画 パッケージ版が動いた



それでは、これをメソッドにしたいと思う.

BitClust::Appの適当な実装を修正

readme.htmlの探し先が結構適当なので、デフォルトの場所から詠むように修正.

100:          if File.exist?("readme.html")
101:            @index = File.read("readme.html").sub(%r!\./bitclust!, '').sub(/<!--links-->/) { links }
102:          else
103:            @index = "<html><head><title>bitclust</title></head><body>#{links}</body></html>"
104:          end

以下のように書換え

100:          if File.exist?("readme.html")
101:            @index = File.read("readme.html").sub(%r!\./bitclust!, '').sub(/<!--links-->/) { links }
102:            elsif File.exist?(File.join(@options[:datadir],"../../../readme.html"))
103:            @index = File.read(File.join(@options[:datadir],"../../../readme.html")).sub(%r!\./bitclust!, './').sub(/<!--links-->/) { links }
104:          else
105:            @index = "<html><head><title>bitclust</title></head><body>#{links}</body></html>"
106:          end

最後に関数に仕上げた.

好きな場所にマウントしたくなったので関数にして置いた.

def mount_rubydoc(server,mount_point_uri_path,path_to_ruby_doc)
  $:.push File.join(path_to_ruby_doc, "bitclust/lib")
  require 'bitclust'
  require 'bitclust/app'
  baseurl = dbpath = srcdir = libdir = datadir = themedir = theme = templatedir = nil
  set_srcdir = lambda {|path|
    srcdir = path
    datadir  ||= "#{srcdir}/data/bitclust"
    themedir ||= "#{srcdir}/theme"
    libdir   ||= "#{srcdir}/lib"
  }
  set_srcdir.call  File.join(path_to_ruby_doc,"bitclust")
  baseurl=mount_point_uri_path
  basepath = URI.parse(baseurl).path
  app = BitClust::App.new(                          
    :dbpath => Dir.glob(File.join(path_to_ruby_doc,"db-*"),
    :baseurl => baseurl,
    :viewpath => baseurl,
    :datadir => datadir,
    :templatedir => templatedir,
    :theme => theme,
    :encoding => "euc",
    :capi => true
    )
  app.interfaces.each do |version, interface|
    server.mount File.join(basepath, version), interface
  end
  server.mount(File.join(basepath, '/'), app)
  server.mount File.join(basepath, 'theme/'), WEBrick::HTTPServlet::FileHandler, themedir
end

使い方

srv = WEBrick::HTTPServer.new({:BindAddress => '127.0.0.1',:Port => 80})
mount_rubydoc(srv,"/ruby-doc","/usr/local/doc/ruby")
trap("INT"){ srv.shutdown }
srv.start

感想

役に立つか立たないかは分らない.だけどただ動いている.それだけでチョッと幸せになれます.

参考資料

リバプロでやってる人.
http://d.hatena.ne.jp/msh_trumpet/20080103/1199371363