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

Railsで学ぶフレームワーク作り - Dispatcher編 その4 Routeの構築部分

rails waf

config/routes.rbをみると、以下のようなブロックで囲まれています。ここがディスパッチルールの設定部分ですね。

    ActionController::Routing:Routes.draw do |map|
      map.connect ':controller/:action/:id', :controller => 'blog'
    end


RoutesはActiveController::Routing::RouteSetのインスタンスであることは前に説明しました。では、このクラスのdrawメソッドを読んでいきましょう。

drawメソッドは、以下のようになっているので、config/routes.rb のブロック引数 map は Mapper クラスのインスタンスということになりますね。

      def draw
        yield Mapper.new(self)
        install_helpers
      end

ということは、map.connectをよぶと、Routes(RouteSetのインスタンス)に、以下のようにrouteが追加されていくということになりますね。

        def connect(path, options = {}) 
          @set.add_route(path, options)
        end

add_routeの実装をみると、builder(RouteBuilder)によって、routeがbuildされて、RouteSet の routesインスタンス変数に追加されるいう形になってます。

      def add_route(path, options = {}) 
        route = builder.build(path, options)
        routes << route
        route
      end 


RouteBuilderでpathとかの解析やってますね。各種Segmenterで文字列分解してroute作ってます。

      # Construct and return a route with the given path and options.
      def build(path, options)
        # Wrap the path with slashes
        path = "/#{path}" unless path[0] == ?/
        path = "#{path}/" unless path[-1] == ?/

        path = "/#{options[:path_prefix].to_s.gsub(/^\//,&#39;&#39;)}#{path}" if options[:path_prefix]

        segments = segments_for_route_path(path)
        defaults, requirements, conditions = divide_route_options(segments, options)
        requirements = assign_route_options(segments, defaults, requirements)

        # TODO: Segments should be frozen on initialize
        segments.each { |segment| segment.freeze }

        route = Route.new(segments, requirements, conditions)

        if !route.significant_keys.include?(:controller)
          raise ArgumentError, "Illegal route: the :controller must be specified!"
        end

        route.freeze
      end 

で、ここはさほど難しくないんですが、route.freezeの中身がかなり黒魔術的で、やる気をごっそりもってかれてしまっていたわけです。

routeは、ActionController::Routing::Routeで、
actionpack/lib/action_controller/routing/route.rb
で定義されています。

freezeメソッドの中の実装は、かなり黒魔術的ですが、段々と本丸のDispatch部分に近づいてきたので、めげずに少し何をやっているかくらいはみていきましょう。ここは次回に。