ソースを読む - bitchannel

起動

index.cgi
load './bitchannelrc'
setup_environment
require 'bitchannel/cgi'
BitChannel::CGI.main bitchannel_context()

BitChannel::CGI.main に Wikispace のオブジェクトを渡す(bitchannel_context()の返り値)と開始。

cgi.rb
module BitChannel
  class CGI < WEBrick::CGI
    def CGI.main(wiki, webrickconf = {})
      super(webrickconf, wiki)
    end

    def do_GET(req, res)
      wiki, = *@options
      wiki.session(guess_cgi_url(req)) {
        bcres = Handler.new(wiki).handle(Request.new(req, wiki.locale, false))
        bcres.update_for res
      }
    end

Webrick 使用。BitChannel::CGI.mainを呼び出すと、下記のとおりリクエストに対し start() を呼び出す。do_GET() にて Handlerオブジェクトを生成、それに対し Requestオブジェクトをつくり引数として handle()に渡す(後述)。

webrick_cgi.rb
module WEBrick
  class CGI
    def CGI.main(conf, *context)
      new(conf, *context).run
    end

    def CGI.each_request(&block)
      yield ENV, $stdin, $stdout
    end

    def run
      CGI.each_request do |env, stdin, stdout|
        start env, stdin, stdout
      end
    end
  end
end

WikiSpace

wikispace.rb
module BitChannel
  class WikiSpace
    include TextUtils
    def initialize(config, repo)
      @config = config
      @repository = repo
      @repository.syntax ||= Syntax.new(config, repo)
    end

@repository.syntax としてシンタックスを保持、か。。。

    def session(guess_cgi_url)
      @config.cgi_url ||= guess_cgi_url
      raise 'CGI url could not fixed; give up' unless @config.cgi_url
      return yield
    ensure
      @repository.clear_per_request_cache
    end

do_GET()から呼ばれる session()。yield して ensure させる。

    def exist?(name)
      @repository.exist?(name)
    end

    def view(name)
      ViewPage.new(@config, @repository[name])
    end

    def viewrev(name, rev)
      ViewRevPage.new(@config, @repository[name], rev)
    end

    def edit(name)
      unless @repository.exist?(name)
        return edit_new(name)
      end
      page = @repository[name]
      rev = page.revision  # fix revision
      EditPage.new(@config, page, page.source(rev), rev)
    end

    def edit_revision(name, srcrev)
      page = @repository[name]
      EditPage.new(@config, page, page.source(srcrev), page.revision)
    end

    def edit_new(name)
      EditPage.new(@config, @repository.fetch(name), '', nil)
    end

    def edit_again(name, src, cirev, reason = :edit_conflicted)
      page = @repository[name]
      EditPage.new(@config, page, src, (cirev || page.revision), reason)
    end

    def preview(name, orgrev, text)
      PreviewPage.new(@config, @repository.fetch(name), text, orgrev)
    end

    def save(name, origrev, text)
      @repository.fetch(name).checkin origrev, text
      ThanksPage.new(@config, name)
    end

wikiに対する操作関数郡。ViewPage, EditPage, PreviewPageなど対応するクラスオブジェクトを生成。おそらくhandler から呼び出される。

Page

page.rb
module BitChannel
  class Page
  end
  class RhtmlPage < Page
    include ErbUtils
    include TextUtils
    ...
    def content
      run_erb(@config.templatedir, template_id())
    end
  end
  class WikiPage < RhtmlPage
    ...
  end
  class NamedPage < WikiPage
    def initialize(config, page)
      super config
      @page = page
    end
    def compile_page(content)
      @page.syntax.compile(content, @page.name)
    end
    def page_name
      escape_html(@page.name)
    end
    def page_url
      escape_url(@page.name)
    end
  class ViewPage < NamedPage
    ...
    def body
      compile_page(@page.source)
    end
    ...
  end
  class EditPage < NamedPage
    def initialize(config, page, text, origrev, reason = nil)
      ...
    end
  end

Erb使用。Page > RhtmlPage > WikiPage > NamedPage > {View, Edit....}

handler

handler.rb
module BitChannel

  class Handler
    include TextUtils

    def initialize(wiki)
      @wiki = wiki
    end

    def handle(req)
      _handle(req) || @wiki.view(FRONT_PAGE_NAME).response
    rescue Exception => err
      error_response(err, true)
    end
    def _handle(req)
      mid = "handle_#{req.cmd || 'view'}"
      return nil unless respond_to?(mid, true)
      __send__(mid, req)
    end

handle_#{req.cmd}()に __send__

    def handle_view(req)
      if req.rev
      then __handle_viewrev(req)
      else __handle_view_latest(req)
      end
    end

    def __handle_view_latest(req)
      return nil unless req.page_name
      return nil unless @wiki.valid?(req.page_name)
      unless @wiki.exist?(req.page_name)
        return nil if @wiki.read_only?
        return @wiki.edit_new(req.page_name).response
      end
      @wiki.view(req.page_name).response
    end

@wiki の対応する操作関数を呼び出し、response を返す。page.rb では define されてないが、

  class Page   # redefine
    def response
      Response.new_from_page(self)
    end
  end

と redefine。Responseクラスは handler.rb にて定義:

  class Response
    def Response.new_from_page(page)
      res = new()
      res.last_modified = page.last_modified
      res.set_content_body page.content, page.type, page.charset
      res
    end

    def initialize
      @status = nil
      @header = {}
      @cookies = []
      @body = nil
      self.no_cache = true
    end

    attr_accessor :status
    attr_reader :body

    def set_content_body(body, type, charset)
      @body = body
      @header['Content-Type'] = "#{type}; charset=#{charset}"
    end

Pageオブジェクトが Respose.new_from_page() に self を渡すことにより、その情報から Responseオブジェクトを生成し、それを返す。