読者です 読者をやめる 読者になる 読者になる

Railsのコードを読む(2)

前回はboot.rbでrails自体を初期化するところまで追った。前回のboot.rbでは以下のようなコードがでてきた。

  rails_gem = Gem.cache.search('rails', "=#{rails_gem_version}.0").sort_by { |g| g.version.version }.last
  if rails_gem
    gem "rails", "=#{rails_gem.version.version}"
    require rails_gem.full_gem_path + '/lib/initializer'
  end

ここでgemというものが登場している。Gemはruby版のcpanというかyumというか、まーライブラリをインストールしたり管理したりするための仕組みかな。上記コードでは"Gem.cache.search()"の呼び出しによってrailsのライブラリを探しているようだ。このsearch()メソッドの実装は以下のようになっている。

    # Search for a gem by short name pattern and optional version
    #
    # gem_name::
    #   [String] a partial for the (short) name of the gem, or
    #   [Regex] a pattern to match against the short name
    # version_requirement::
    #   [String | default=Version::Requirement.new(">= 0")] version to
    #   find
    # return::
    #   [Array] list of Gem::Specification objects in sorted (version)
    #   order.  Empty if not found.
    #
    def search(gem_pattern, version_requirement=Version::Requirement.new(">= 0"))
      gem_pattern = /#{ gem_pattern }/i if String === gem_pattern
      version_requirement = Gem::Version::Requirement.create(version_requirement)
      result = []
      @gems.each do |full_spec_name, spec|
        next unless spec.name =~ gem_pattern
        result << spec if version_requirement.satisfied_by?(spec.version)
      end
      result = result.sort
      result
    end

ここでメソッドのコメントが登場。RubyにはRdocという仕組みがあり、Javajavadocのようにある形式に従ったコメントをコード中に埋め込んでおけば、それをフォーマットしてHTML化してくれる。
上のコメントをみると、メソッドの説明のあとに「引数名::」「return::」という形式の文字列が。これはjavadocの@param, @returnみたいなもんだな。で、Rubyならではの点として[String][Regex]という記述が。Rubyでは型宣言が不要なので、このようにメソッド引数の型がStringの場合と、Regex型の場合の2パターンの説明を書く必要がある。
version_requirementは[String | default = ..]という記述が。第2引数にはString型、省略した場合はVersion::Requirement...が渡されるよ、ということを示している。
で、メソッド本体をみてみると

  1. 引数で指定したバージョンに対応するVersion::Requirementオブジェクトを取得し、
  2. @gemsというマップに格納されたGem::Specificationオブジェクトのnameプロパティを逐次、引数gem_patternで正規表現で一致するかどうかチェックし、
  3. spec名が一致したら次にバージョンを満たしているかどうか調べ、
  4. 満たしていればresult配列にGem::Specificationオブジェクトオブジェクトを追加

と言う感じ。
あんまり大した事やってなかったな。