WEBrick独書会 第4回

前回の予告通りGenericServer.newで呼び出される、
GenericServerのinitializeメソッドを読みます。

    def initialize(config={}, default=Config::General)
      @config = default.dup.update(config)
      @status = :Stop
      @config[:Logger] ||= Log::new
      @logger = @config[:Logger]

      @tokens = SizedQueue.new(@config[:MaxClients])
      @config[:MaxClients].times{ @tokens.push(nil) }

      webrickv = WEBrick::VERSION
      rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
      @logger.info("WEBrick #{webrickv}")
      @logger.info("ruby #{rubyv}")

      @listeners = []
      unless @config[:DoNotListen]
        if @config[:Listen]
          warn(":Listen option is deprecated; use GenericServer#listen")
        end
        listen(@config[:BindAddress], @config[:Port])
        if @config[:Port] == 0
          @config[:Port] = @listeners[0].addr[1]
        end
      end
    end

インスタンス変数の初期化をたくさんしてます。


まず引数のところ。
initializeメソッドは2つの引数(config,default)を取ることができて、
その2つの引数からインスタンス変数、@configを作ってます。
前回のDaytime Serverのexampleでは2つめの引数を省略してましたが、
省略するとdefaultにはConfig::Generalが入るようになってます。
これは、lib/webrick/config.rb内のGeneralの事です。

   General = {
      :ServerName     => Utils::getservername,
      :BindAdbdress    => nil,   # "0.0.0.0" or "::" or nil
      :Port           => nil,   # users MUST specifiy this!!
      :MaxClients     => 100,   # maximum number of the concurrent connections
      :ServerType     => nil,   # default: WEBrick::SimpleServer
      :Logger         => nil,   # default: WEBrick::Log.new
      :ServerSoftware => "WEBrick/#{WEBrick::VERSION} " +
                         "(Ruby/#{RUBY_VERSION}/#{RUBY_RELEASE_DATE})",
      :TempDir        => ENV['TMPDIR']||ENV['TMP']||ENV['TEMP']||'/tmp',
      :DoNotListen    => false,
      :StartCallback  => nil,
      :StopCallback   => nil,
      :AcceptCallback => nil,
    }


これを設定のベースとして、1つ目の引数で上書きして@configを作る訳ですねぇ。
差分だけ明示的に指定する方法は使う人からすると便利っす。


次行ってみて、
@config[:Logger] ||= Log::new
っていう書き方は便利なのでチェックしておきます。


@config[:Logger] = @config[:Logger] || Log::new
と同義である事はCゲンガーにはわかるでしょう。
が、Cゲンガー用トラップとして、rubyにおいてはnil,false以外は真となるっていうのがあります。
http://www.ruby-lang.org/ja/man/index.cgi?cmd=view;name=trap%3A%3A%BF%BF%B5%B6%C3%CD


x = y || z という式を考えてみましょう。
この式は最初にyが評価されます。
yがnilかfalseなら偽であるため、x = zとなります。
yがnilでもfalseでもなかった場合は真であるため、zの真偽は評価不要です。
実際に全く評価されず、x = y となります。

= の書き方はif文を使わずに簡潔に書けるので大変便利であり、

色んなとこで使われているため覚えておきましょう。


@config[:Logger] ||= Log::new に戻ると、
要は、引数からloggerを指定することができるけど指定無し(nil)の場合は
Logクラスのインスタンスを作ってその結果を@loggerに入れますよ。
ってことで。


疲れたのでinitializeメソッド半ばにして休憩。
次回は続き。