はじめに
MVCにおいてどのように内部処理が行われページ遷移に至るのかフレームワークを使用していると何も気にせずとも開発できてしまいます。
しかしこの基本的な動作の仕組みを理解することで、エンジニアとしての基本的な思考を理解できるのではと考えました。
今回は最も基本的なgetメソッドを見ていきます。
準備
以下のルーティングを作成
Rails.application.routes.draw do
binding.pry
get 'users' => 'users#index'
end
実行
getメソッド
module ActionDispatch
module Routing
class Mapper
(省略)
module HttpHelpers
# Define a route that only recognizes HTTP GET.
# For supported arguments, see match[rdoc-ref:Base#match]
#
# get 'bacon', to: 'food#bacon'
def get(*args, &block)
map_method(:get, args, &block)
end
args: {"users"=>"users#index"}
block: []
学び① 仮引数の* (*args)
仮引数に*をつけることで余りを全て配列として受け取る事ができる。これを可変長引数と呼ぶ。
https://docs.oracle.com/javase/jp/7/technotes/guides/language/varargs.html
引数の数に柔軟に対応したいときに使えそうです。
学び② ブロック
ブロックは「処理の集合体」です。無名関数とかラムダ式とかクロージャのようなものです。
https://qiita.com/genya0407/items/1a34244cba6c3089a317
getに対し処理を追記した場合にblockに処理が入ると思われます。
{ |e| e + 1 }
こちらのような表記です。
map_methodメソッド
module HttpHelpers
private
def map_method(method, args, &block)
options = args.extract_options!
options[:via] = method
match(*args, options, &block)
self
end
end
argsをpopしています。今回要素は1つだけなので、optionsにargsがそのまま代入されます。
map_methodメソッドは、整形してoptionsに
getメソッド
{"users"=>"users#index"}
という2点の情報をまとめる機能を担っています。
module Resources
# Matches a URL pattern to one or more routes.
# For more information, see match[rdoc-ref:Base#match].
#
# match 'path' => 'controller#action', via: :patch
# match 'path', to: 'controller#action', via: :post
# match 'path', 'otherpath', on: :member, via: :get
def match(path, *rest, &block)
if rest.empty? && Hash === path
options = path
path, to = options.find { |name, _value| name.is_a?(String) }
raise ArgumentError, "Route path not specified" if path.nil?
case to
when Symbol
options[:action] = to
when String
if /#/.match?(to)
options[:to] = to
else
options[:controller] = to
end
else
options[:to] = to
end
options.delete(path)
paths = [path]
else
options = rest.pop || {}
paths = [path] + rest
end
if options.key?(:defaults)
defaults(options.delete(:defaults)) { map_match(paths, options, &block) }
else
map_match(paths, options, &block)
end
end
学び③ ===
self === obj -> bool
指定された obj が self かそのサブクラスのインスタンスであるとき真を返します。また、obj が self をインクルードしたクラスか>そのサブクラスのインスタンスである場合にも真を返します。上記のいずれでもない場合に false を返します。
https://docs.ruby-lang.org/ja/latest/method/Module/i/=3d=3d=3d.html
モジュール内で型を確認する場合に使えそうです。
obj.kind_of?(self)
と同じ機能ということですが、===
の方がスッキリかけます。ただobjとselfの並びが逆なことには注意が必要です。
学び④ findメソッドと多重代入の組み合わせ
path, to = options.find { |name, _value| name.is_a?(String) }
ハッシュのname(keyと呼ぶことの方が多いが)がStringの場合は、pathとtoに代入します。
シンボルで表記されていた場合は、代入されないということになります。
変数を_value
と先頭にアンダーバーを付けているのは何故でしょうか。
こちらは、先頭アンダーバーのもので絞り込むことによって探しやすいというメリットがあるようです。処理内の変数なのでこの表記にする理由はいまいちわかりませんでした。
https://anderson02.com/cs/cs-rules/cs-rules10/
最後に
今日はここまでです。前処理の部分でこんなに学びがあるとはという感想です。
まだまだ、routingがどのように処理されているかに踏み込めていないため、この部分のコードリーディング継続する予定です。