普段仕事で使っているRuby on Railsですが、ソースコードを読む機会もなかなかないので、試しにやってみることにしました
読めるようにするまで
以前書いた記事に読めるようにするまでの設定を画像キャプチャ付きで解説しましたので、よろしければこちらをご参照ください
shitake4.hatenablog.com
読んだ箇所
to_param
を今日は読んでみようと思います
どんな使い方だっけ?
読んでみる前にまずは使い方を調べてみます
RailsGuidのActive Support コア拡張機能を見てみると
Railsのあらゆるオブジェクトはto_paramメソッドに応答します。
これは、オブジェクトを値として表現するものを返すということです。返された値はクエリ文字列やURLの一部で使用できます。
引用:Active Support コア拡張機能:to_param
ソースコードを読んでみる
1. railsプロジェクトのactivesupportにある機能ですので、activesupportディレクトリのlib配下で def to_param
を探してみます
2. 該当箇所が8個ほどあったので、それぞれみてみます
1. activesupport > lib > active_support > core_ext > object > to_query.rb
1. class Object
# frozen_string_literal: true require "cgi" class Object # Alias of <tt>to_s</tt>. def to_param to_s end
単純にto_s
しているだけです
オブジェクトに対して行いたい場合は、オーバーライドして使うということを想定しているのでしょう
2. class NilClass
class NilClass # Returns +self+. def to_param self end end
レシーバ自身を返しています NilClassの戻り値はnilですので、このようなコードでもいいのではないか?と思いました
def to_param nil end
もしかしたらコミットログに戻り値をselfにした理由や経緯があるかもしれないと思ったので、調べてみます
RubyMineの機能で選択範囲のコミットログを見る機能がある為、それを使います
残念ながら1コミットしかなかったため、わかりませんでした
3. class TrueClass
class TrueClass # Returns +self+. def to_param self end end
4. class FalseClass
class FalseClass # Returns +self+. def to_param self end end
5. class Array
class Array # Calls <tt>to_param</tt> on all its elements and joins the result with # slashes. This is used by <tt>url_for</tt> in Action Pack. def to_param collect(&:to_param).join "/" end
レシーバに対して collect
を実行しています
collectとはどういうものかというと
collectメソッドは、要素の数だけ繰り返しブロックを実行し、ブロックの戻り値を集めた配列を作成して返します。ブロック引数itemには各要素が入ります。
mapメソッドはcollectメソッドの別名です。
次の例では、16進数を表す文字列を数値に変換した配列を作成しています。
引用: Rubyリファレンス:collect
numbers = ["68", "65", "6C", "6C", "6F"] p numbers.collect {|item| item.to_i(16) } => [104, 101, 108, 108, 111]
mapも同じ処理を行うメソッドです
(&:to_param)
の&:は配列の各要素に対して to_param
を実行しています
たとえば、
[1, 2, 3].map(&:to_s) => ["1", "2", "3"]
という感じです ※詳しい解説は@kasei-san氏のこちらの記事がわかりやすいかと思います
qiita.com
各要素に to_param
した配列に対して .join
しています
joinについて調べてみると
joinメソッドは、配列の各要素を文字列に変換し、引数sepを区切り文字として結合した文字列を返します。
引数のデフォルト値は組み込み変数$,の値です。$,の初期値はnilなので、引数を省略すると区切り文字なしで要素を結合した文字列になります。
引用: Rubyリファレンス:join
配列の中身を連結し文字列に変換する処理です
たとえば、
array = ["Ruby", "Mine"] puts array.join(", ")
の場合は Ruby, Mine
と出力されます
区切り文字がなが場合は
array = ["Ruby", "Mine"] puts array.join
RubyMine
というようにそのまま連結し出力します
ということで .join "/"
ではto_param
された各要素を"/"で連結し、文字列として出力するという処理になります
2. activesupport > lib > active_support > core_ext > string > output_safety.rb
module ActiveSupport #:nodoc: class SafeBuffer < String 中略 def to_param to_str end
Stringを拡張したSafeBufferクラスのインスタンスに対して to_param
するのは to_str
と同様になります
SafeBufferクラスがどのような用途で使われるものなのか分からない為、さきほどと同様にコミットログから理由、経緯を調べてみます
選択範囲をSafeBufferクラス内にしコミットログを調べます
class SafeBuffer < String 省略 end
一番古いコミットログを見付け足ので、こちらのリビジョンナンバーをコピーしRailsのリポジトリで調べます
GitHubの検索窓にさきほどコピーしたリビジョンナンバーをペーストし検索します
該当のコミットを見てみると
パフォーマンスの改善の為 html_safe
を呼び出す場合にはSafeBufferを使うということでした
コメントも読んでみると
Stringに追加していると +
や <<
を実行する時に遅くなっているということでした
読んでみて
コミットログを追ってみるとなぜ実装されているのかが分かるので、コードを読み込むだけでなく、歴史まで追ってみるとより理解が深まるなと思いました