Railsで学ぶフレームワーク作り - Dispatcher編 その4 Routeの構築部分
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(/^\//,'')}#{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部分に近づいてきたので、めげずに少し何をやっているかくらいはみていきましょう。ここは次回に。